Android App开发语音处理之系统自带的语音引擎、文字转语音、语音识别的讲解及实战(超详细 附源码)

需要源码请点赞关注收藏后评论区留下QQ~~~

一、系统自带的语音引擎

语音播报的本质是将书面文字转换成自然语言的音频流,这个转换操作被称作语音合成,又称TTS(从文本到语音)在转换过程中,为了避免机械合成的呆板和停顿感,语音合成技术还得对语音流进行平滑处理,以确保输出得语音音律流畅自然。

不管是Android原生的西文引擎还是手机厂商集成的中文引擎,都支持通过系统提供的API处理语音,其中的语音合成工具是TextToSpeech 常用方法如下

构造方法:第二个输入参数为语音监听器

setLanguage:设置引擎语言

setSpeechRate 设置语速

setPitch 设置音调

synthesizeToFile 把指定文本的朗读语言输出到文件

实战效果如下

 代码如下

Java类

package com.example.voice;import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Spinner;import androidx.appcompat.app.AppCompatActivity;import com.example.voice.adapter.LanguageListAdapter;
import com.example.voice.bean.Language;import java.util.ArrayList;
import java.util.List;
import java.util.Locale;public class SpeechEngineActivity extends AppCompatActivity {private final static String TAG = "SpeechEngineActivity";private TextToSpeech mSpeech; // 声明一个文字转语音对象@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_speech_engine);findViewById(R.id.btn_jump_setting).setOnClickListener(v -> {Intent intent = new Intent();intent.setAction("com.android.settings.TTS_SETTINGS");startActivity(intent);});// 创建一个文字转语音对象,初始化结果在监听器TTSListener中返回mSpeech = new TextToSpeech(this, new TTSListener());}private List<TextToSpeech.EngineInfo> mEngineList; // 语音引擎列表// 定义一个文字转语音的初始化监听器private class TTSListener implements TextToSpeech.OnInitListener {// 在初始化完成时触发@Overridepublic void onInit(int status) {if (status == TextToSpeech.SUCCESS) { // 初始化成功if (mEngineList == null) { // 首次初始化// 获取系统支持的所有语音引擎mEngineList = mSpeech.getEngines();initEngineSpinner(); // 初始化语音引擎下拉框}initLanguageList(); // 初始化语言列表}}}// 初始化语音引擎下拉框private void initEngineSpinner() {String[] engineArray = new String[mEngineList.size()];for(int i=0; i<mEngineList.size(); i++) {engineArray[i] = mEngineList.get(i).label;}ArrayAdapter<String> engineAdapter = new ArrayAdapter<>(this,R.layout.item_select, engineArray);Spinner sp_engine = findViewById(R.id.sp_engine);sp_engine.setPrompt("请选择语音引擎");sp_engine.setAdapter(engineAdapter);sp_engine.setOnItemSelectedListener(new EngineSelectedListener());sp_engine.setSelection(0);}private class EngineSelectedListener implements AdapterView.OnItemSelectedListener {public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {//recycleSpeech(); // 回收文字转语音对象// 创建指定语音引擎的文字转语音对象mSpeech = new TextToSpeech(SpeechEngineActivity.this, new TTSListener(),mEngineList.get(arg2).name);}public void onNothingSelected(AdapterView<?> arg0) {}}private String[] mLanguageArray = {"中文普通话", "英语", "法语", "德语", "意大利语",  };private Locale[] mLocaleArray = { Locale.CHINA, Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN, Locale.ITALIAN };// 初始化语言列表private void initLanguageList() {List<Language> languageList = new ArrayList<>();// 下面遍历语言数组,从中挑选出当前引擎所支持的语言列表for (int i=0; i<mLanguageArray.length; i++) {String desc = "正常使用";// 设置朗读语言int result = mSpeech.setLanguage(mLocaleArray[i]);if (result == TextToSpeech.LANG_MISSING_DATA) {desc = "缺少数据";} else if (result == TextToSpeech.LANG_NOT_SUPPORTED) {desc = "暂不支持";}languageList.add(new Language(mLanguageArray[i], desc));}// 下面把该引擎对各语言的支持情况展示到列表视图上ListView lv_language = findViewById(R.id.lv_language);LanguageListAdapter adapter = new LanguageListAdapter(this, languageList);lv_language.setAdapter(adapter);}}

二、文字转语音

既然明确了一个引擎能够支持哪些语言,接下来就可以大胆设置朗读的语言了,并且设置好语言后,还得提供对应的文字才可以,下面是一个语音播报页面的实例

中文普通话播报

英文版播报 

可以在下拉框中选择自己想要朗读的语言 

 代码如下

Java类

package com.example.voice;import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import com.example.voice.bean.Language;import java.util.ArrayList;
import java.util.List;
import java.util.Locale;public class SpeechComposeActivity extends AppCompatActivity {private final static String TAG = "SpeechComposeActivity";private TextToSpeech mSpeech; // 声明一个文字转语音对象private EditText et_tts; // 声明一个编辑框对象private List<TextToSpeech.EngineInfo> mEngineList; // 语音引擎列表@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_speech_compose);et_tts = findViewById(R.id.et_tts);findViewById(R.id.btn_read).setOnClickListener(v -> {String content = et_tts.getText().toString();// 开始朗读指定文本int result = mSpeech.speak(content, TextToSpeech.QUEUE_FLUSH, null, null);String desc = String.format("朗读%s", result==TextToSpeech.SUCCESS?"成功":"失败");Toast.makeText(this, desc, Toast.LENGTH_SHORT).show();});// 创建一个文字转语音对象,初始化结果在监听器的onInit方法中返回mSpeech = new TextToSpeech(this, mListener);}// 创建一个文字转语音的初始化监听器实例private TextToSpeech.OnInitListener mListener = status -> {if (status == TextToSpeech.SUCCESS) { // 初始化成功if (mEngineList == null) { // 首次初始化mEngineList = mSpeech.getEngines(); // 获取系统支持的所有语音引擎initEngineSpinner(); // 初始化语音引擎下拉框}initLanguageSpinner(); // 初始化语言下拉框}};// 初始化语音引擎下拉框private void initEngineSpinner() {String[] engineArray = new String[mEngineList.size()];for(int i=0; i<mEngineList.size(); i++) {engineArray[i] = mEngineList.get(i).label;}ArrayAdapter<String> engineAdapter = new ArrayAdapter<>(this,R.layout.item_select, engineArray);Spinner sp_engine = findViewById(R.id.sp_engine);sp_engine.setPrompt("请选择语音引擎");sp_engine.setAdapter(engineAdapter);sp_engine.setOnItemSelectedListener(new EngineSelectedListener());sp_engine.setSelection(0);}private class EngineSelectedListener implements AdapterView.OnItemSelectedListener {public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {recycleSpeech(); // 回收文字转语音对象// 创建指定语音引擎的文字转语音对象mSpeech = new TextToSpeech(SpeechComposeActivity.this, mListener,mEngineList.get(arg2).name);}public void onNothingSelected(AdapterView<?> arg0) {}}// 回收文字转语音对象private void recycleSpeech() {if (mSpeech != null) {mSpeech.stop(); // 停止文字转语音mSpeech.shutdown(); // 关闭文字转语音mSpeech = null;}}@Overrideprotected void onDestroy() {super.onDestroy();recycleSpeech(); // 回收文字转语音对象}private String[] mLanguageArray = {"中文普通话", "英语", "法语", "德语", "意大利语"};private Locale[] mLocaleArray = { Locale.CHINA, Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN, Locale.ITALIAN };private String[] mValidLanguageArray; // 当前引擎支持的语言名称数组private Locale[] mValidLocaleArray; // 当前引擎支持的语言类型数组private String mTextCN = "离离原上草,一岁一枯荣。野火烧不尽,春风吹又生。";private String mTextEN = "Hello World. Nice to meet you. This is a TTS demo.";// 初始化语言下拉框private void initLanguageSpinner() {List<Language> languageList = new ArrayList<>();// 下面遍历语言数组,从中挑选出当前引擎所支持的语言列表for (int i=0; i<mLanguageArray.length; i++) {// 设置朗读语言。通过检查方法的返回值,判断引擎是否支持该语言int result = mSpeech.setLanguage(mLocaleArray[i]);Log.d(TAG, "language="+mLanguageArray[i]+",result="+result);if (result != TextToSpeech.LANG_MISSING_DATA&& result != TextToSpeech.LANG_NOT_SUPPORTED) { // 语言可用languageList.add(new Language(mLanguageArray[i], mLocaleArray[i]));}}mValidLanguageArray = new String[languageList.size()];mValidLocaleArray = new Locale[languageList.size()];for(int i=0; i<languageList.size(); i++) {mValidLanguageArray[i] = languageList.get(i).name;mValidLocaleArray[i] = languageList.get(i).locale;}// 下面初始化语言下拉框ArrayAdapter<String> languageAdapter = new ArrayAdapter<>(this,R.layout.item_select, mValidLanguageArray);Spinner sp_language = findViewById(R.id.sp_language);sp_language.setPrompt("请选择朗读语言");sp_language.setAdapter(languageAdapter);sp_language.setOnItemSelectedListener(new LanguageSelectedListener());sp_language.setSelection(0);}private class LanguageSelectedListener implements AdapterView.OnItemSelectedListener {public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {if (mValidLocaleArray[arg2]==Locale.CHINA) { // 汉语et_tts.setText(mTextCN);} else { // 其他语言et_tts.setText(mTextEN);}mSpeech.setLanguage(mValidLocaleArray[arg2]); // 设置选中的朗读语言}public void onNothingSelected(AdapterView<?> arg0) {}}}

三、原生的语音识别

Android提供了语音识别器SpeechRecognizer 该工具常用方法如下

isRecognitionAvailable  检查系统是否支持原生的语音识别

createSpeechRecognizer 创建原生的语音识别器对象

setRecognitionListener 设置语音识别监听器

startListening 开始语音识别

stopListening 停止语音识别

cancel 取消语音识别

destroy 销毁语音识别器

识别结果监听器提供了许多回调方法,其中onResults方法可获得识别后的文本信息,然而每个引擎对文本结果的包装结构不尽相同,比如百度语音返回JSON格式的字符串,而讯飞语音返回字符串列表,为此要分别尝试几种格式的文本识别  效果如下

 

 结果如下 点击开始识别后对着麦克风说话 停止识别后则会自动输出识别内容

此处连接真机测试更佳 模拟机可能没有麦克风~~~

 代码如下

java类

package com.example.voice;import androidx.appcompat.app.AppCompatActivity;import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.provider.Settings;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;import org.json.JSONArray;
import org.json.JSONObject;import java.util.List;
import java.util.Locale;@SuppressLint("SetTextI18n")
public class SpeechRecognizeActivity extends AppCompatActivity implements RecognitionListener {private final static String TAG = "SpeechRecognizeActivity";private TextView tv_result; // 声明一个文本视图对象private Button btn_recognize; // 声明一个按钮对象private SpeechRecognizer mRecognizer; // 声明一个语音识别对象private boolean isRecognizing = false; // 是否正在识别@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_speech_recognize);tv_result = findViewById(R.id.tv_result);btn_recognize = findViewById(R.id.btn_recognize);// 检查系统是否支持原生的语音识别boolean enable = SpeechRecognizer.isRecognitionAvailable(this);if (enable) {initRecognize(); // 初始化语音识别} else {tv_result.setText("原生的语音识别服务不可用");btn_recognize.setEnabled(false);btn_recognize.setTextColor(Color.GRAY);}}// 初始化语音识别private void initRecognize() {String serviceComponent = Settings.Secure.getString(getContentResolver(), "voice_recognition_service");// 获得系统内置的语音识别服务ComponentName component = ComponentName.unflattenFromString(serviceComponent);Log.d(TAG, "getPackageName="+component.getPackageName()+",getClassName="+component.getClassName());tv_result.setText("原生的语音识别服务采用"+component.getPackageName()+"里的服务"+component.getClassName());// 创建原生的语音识别器对象mRecognizer = SpeechRecognizer.createSpeechRecognizer(this);mRecognizer.setRecognitionListener(this); // 设置语音识别监听器btn_recognize.setOnClickListener(v -> {if (!isRecognizing) { // 未在识别Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.CHINA);intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);mRecognizer.startListening(intent); // 开始语音识别} else { // 正在识别mRecognizer.stopListening(); // 停止语音识别//mRecognizer.cancel(); // 取消语音识别}isRecognizing = !isRecognizing;btn_recognize.setText(isRecognizing?"停止识别":"开始识别");});}@Overridepublic void onReadyForSpeech(Bundle params) {}@Overridepublic void onBeginningOfSpeech() {}@Overridepublic void onRmsChanged(float rmsdB) {}@Overridepublic void onBufferReceived(byte[] buffer) {}@Overridepublic void onEndOfSpeech() {}@Overridepublic void onError(int error) {Log.d(TAG, "Recognize error:"+error);}@Overridepublic void onResults(Bundle results) {Log.d(TAG, "onResults Start");String desc = "";String key = SpeechRecognizer.RESULTS_RECOGNITION;try { // 百度语音分支String result = results.getString(key);Log.d(TAG, "result="+result);JSONObject object = new JSONObject(result);String recognizeResult = object.getString("recognizeResult");JSONArray recognizeArray = new JSONArray(recognizeResult);for (int i=0; i<recognizeArray.length(); i++) {JSONObject item = (JSONObject) recognizeArray.get(i);String se_query = item.getString("se_query");desc = desc + "\n" + se_query;Log.d(TAG, "desc="+desc);}} catch (Exception e) { // 讯飞语音分支e.printStackTrace();List<String> resultList = results.getStringArrayList(key);for (String str : resultList) {desc = desc + "\n" + str;Log.d(TAG, "desc="+desc);}}tv_result.setText("识别到的文字为:"+desc);Log.d(TAG, "onResults End");}@Overridepublic void onPartialResults(Bundle partialResults) {Log.d(TAG, "onPartialResults");}@Overridepublic void onEvent(int eventType, Bundle params) {}@Overrideprotected void onDestroy() {super.onDestroy();if (mRecognizer != null) {mRecognizer.destroy(); // 销毁语音识别器}}}

创作不易 觉得有帮助请点赞关注收藏~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/56855.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动聊天挂机项目

三木智能聊天云控脚本

拼多多顶级佣金助手-微信群自动发单

注意&#xff1a;微信版本必须使用软件根目录下的安装包安装 1.进入多多进宝网站-注册多多进宝-并创建推广位... 2.打开软件点击-多多授权-授权页面-授权成功会跳转百度,复制百度地址栏code后面的code码... 3.粘贴到软件CODE输入框-点击-确定授权... 4.推广位ID框中出现你自…

30行python代码实现微信自动陪女盆友聊天(itchat-uos + 无限制调用)

先放代码&#xff1a; 再放个文字的&#xff08;方便复制&#xff09;&#xff1a; import itchat import requestsdef get_reply(keyword):try:url f"https://open.drea.cc/bbsapi/chat/get?keyWord{keyword}&userNametype%3Dbbs"res requests.get(url)data…

[做初中数学题做到打起来了]跟同事为了他小孩的数学题杠上了

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的博客 &#x1f34a;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;…

Whatsapp有效号码筛选 – 号码过滤器 | 电话号码过滤筛选 |配合 Whatsapp营销协议群发软件

Whatsapp号码过滤器能进行快速电话号码过滤筛选&#xff0c;过滤已开通whatsapp号码有效性&#xff0c;精准筛选出有用的whatsapp号码。Whatsapp号码筛选器可与各类Whatsapp群发软件、电话号码采集软件搭配使用&#xff0c;有助于辨识有效Whatsapp号码&#xff0c;过滤无效号码…

网络流量pcap包特征提取并保存

前言 新手写博客&#xff0c;写博客主要目的是为了记录自己做项目的一些过程。关于网络流量项目&#xff0c;刚开始做项目一个月左右&#xff0c;所写的博客必然有很多不足的地方&#xff0c;欢迎大家交流和指教。 获取pcap包 pcap包特征提取第一步是要获得pcap包。pcap一般…

TCP、UDP数据包大小的限制

一、概述 首先要看TCP/IP协议&#xff0c;涉及到四层&#xff1a;链路层&#xff0c;网络层&#xff0c;传输层&#xff0c;应用层。    其中以太网&#xff08;Ethernet&#xff09;的数据帧在链路层    IP包在网络层    TCP或UDP包在传输层    TCP或UDP中的数据&…

为程序员准备的英语学习资料

程序员学习英语有用吗&#xff1f;当然有用&#xff0c;而且有很大用&#xff01; 当我们浏览StackOverFlow的时候&#xff0c;当我们和外国技术大牛交流的时候&#xff0c;当我们去面试FLAG&#xff08;Facebook&#xff0c;LinkedIn&#xff0c;Amazon&#xff0c;Google&…

黑马程序员python培训PDF下载

在分享资源之前&#xff0c;大家可以先想清楚未来的职业发展方向。毕竟只有找到未来职业发展方向&#xff0c;才更清楚当下重点学习的内容。 根据上图我们基本上一目了然&#xff0c;找到自己未来要发展的方向。在找到之后可以在各个招聘app上了解一下相关岗位的技能要求是什么…

黑马程序员7

算数运算符重载 运算符重载概念&#xff1a;对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型 加号运算符 通过自己写函数&#xff0c;实现两个对象相加属性后返回新的对象 两种方式重载 成员函数方式重载 全局函数重载 上来 perso…

黑马程序员14套经典IT教程+面试宝典

很多同学对互联网比较感兴趣 &#xff0c;奈何苦恼不知道如何入门。今天免费给大家分享一波&#xff0c;黑马程序员14套经典IT教程程序员面试宝典&#xff01;涉及Java、前端、Python、大数据、软件测试、UI设计、新媒体短视频等。从厌学到学嗨&#xff0c;你只差一套黑马教程&…

latex添加参考文献(I found no \citation commands、I found no \bibdata command、I found no \bibstyle comma)

1、处理模板里的reference.bib文件 2、使用reference.bib文件 3、添加引用 4、配置编译器&#xff0c;否则编译会报错。在该目录填写如下代码&#xff1a; {"latex-workshop.latex.outDir": "%DIR%/.build","latex-workshop.view.pdf.viewer": &…

八股文总是忘?一张图牢记JVM内存结构|金三银四系列

金三银四又来啦&#xff01;八股文还是得复习起来&#xff0c;最近准备把一些常见的八股文知识点聊聊。 本文详解了JVM内存结构和各个部分详细内容&#xff0c;应付面试绰绰有余&#xff01; 点击上方“后端开发技术”&#xff0c;选择“设为星标” &#xff0c;优质资源及时送…

【Android面试】2023最新面试专题:Java虚拟机原理(一)

1 描述JVM类加载过程 这道题想考察什么&#xff1f; 了解JVM是如何加载类的&#xff0c;并且通过JVM类加载过程能更直观了解掌握如APT注解处理器执行、热修复等技术的本质 考察的知识点 JVM类加载过程 考生如何回答 类加载的本质 一般情况下&#xff0c;类的数据都是在C…

JVM 锁优化和逃逸分析详解

1 锁优化 JVM 在加锁的过程中&#xff0c;会采用自旋、自适应、锁消除、锁粗化等优化手段来提升代码执行效率。 1.1 自旋锁和自适应自旋 现在大多的处理器都是多核处理器 &#xff0c;如果在多核心处理器&#xff0c;有让两个或者以上的线程并行执行&#xff0c;我们可以让一个…

kubernetes学习之路--BadPods(Part1)

摘要&#xff1a;对Pod配置进行实战学习&#xff0c;以BadPods项目为例学习危险配置。 目录 一.BadPods介绍及使用 二.BadPods配置学习 2.1 less1--Everything allowed 基本操作学习 2.2 less1--Everything allowed 渗透学习 一.BadPods介绍及使用 项目地址&#xff1a;h…

基于GPT3.5实现本地知识库解决方案-利用向量数据库和GPT向量接口-实现智能回复并限制ChatGPT回答的范围...

标题有点长&#xff0c;但是基本也说明出了这篇文章的主旨&#xff0c;那就是利用GPT AI智能回答自己设置好的问题 既能实现自己的AI知识库机器人&#xff0c;又能节省ChatGPT调用的token成本费用。 代码仓库地址 document.ai: 基于GPT3.5的通用本地知识库解决方案 下面图片是整…

英语语法大全

文章目录 一、主语1、名词、代词和动词做主语2、主语从句做主语&#xff0c;谓语动词用单数3、主语从句练习 二、谓语动词1、谓语动词种类2、主谓一致 三、宾语1、单宾语2、双宾语3、复合宾语4、宾语从句 四、定语1、定语从句2、定语从句的翻译 五、状语1、分词做状语2、独立主…

规模效应和网络效应

前几天小米造车、华为造车、大疆造车、滴滴造车、百度造车集中PR。群中讨论智能新能源汽车的未来集中。甚至延伸讨论到了&#xff1a;云计算的未来集中度、SaaS的未来集中度。怎么能提高行业集中度&#xff0c;是我们都在苦苦思考的。 于是就讨论到两个词&#xff1a;规模效应、…

真*加班狗聚众舔福豹《打工人的那些事》

真*加班狗聚众舔福豹《打工人的那些事》 文章目录 近日的杭州金钱豹外逃新闻&#xff0c;相信大家都听说了。 没看过的也不急&#xff0c;我在这里帮大家简单理一理。 根据杭州市富阳区8日官方发布&#xff0c;5月7日20时许&#xff0c;群众报警称在富阳区银湖街道受降四联村…