0


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

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

一、系统自带的语音引擎

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

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

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

setLanguage:设置引擎语言

setSpeechRate 设置语速

setPitch 设置音调

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

实战效果如下

代码如下

Java类

  1. package com.example.voice;
  2. import android.content.Intent;
  3. import android.os.Bundle;
  4. import android.speech.tts.TextToSpeech;
  5. import android.view.View;
  6. import android.widget.AdapterView;
  7. import android.widget.ArrayAdapter;
  8. import android.widget.ListView;
  9. import android.widget.Spinner;
  10. import androidx.appcompat.app.AppCompatActivity;
  11. import com.example.voice.adapter.LanguageListAdapter;
  12. import com.example.voice.bean.Language;
  13. import java.util.ArrayList;
  14. import java.util.List;
  15. import java.util.Locale;
  16. public class SpeechEngineActivity extends AppCompatActivity {
  17. private final static String TAG = "SpeechEngineActivity";
  18. private TextToSpeech mSpeech; // 声明一个文字转语音对象
  19. @Override
  20. protected void onCreate(Bundle savedInstanceState) {
  21. super.onCreate(savedInstanceState);
  22. setContentView(R.layout.activity_speech_engine);
  23. findViewById(R.id.btn_jump_setting).setOnClickListener(v -> {
  24. Intent intent = new Intent();
  25. intent.setAction("com.android.settings.TTS_SETTINGS");
  26. startActivity(intent);
  27. });
  28. // 创建一个文字转语音对象,初始化结果在监听器TTSListener中返回
  29. mSpeech = new TextToSpeech(this, new TTSListener());
  30. }
  31. private List<TextToSpeech.EngineInfo> mEngineList; // 语音引擎列表
  32. // 定义一个文字转语音的初始化监听器
  33. private class TTSListener implements TextToSpeech.OnInitListener {
  34. // 在初始化完成时触发
  35. @Override
  36. public void onInit(int status) {
  37. if (status == TextToSpeech.SUCCESS) { // 初始化成功
  38. if (mEngineList == null) { // 首次初始化
  39. // 获取系统支持的所有语音引擎
  40. mEngineList = mSpeech.getEngines();
  41. initEngineSpinner(); // 初始化语音引擎下拉框
  42. }
  43. initLanguageList(); // 初始化语言列表
  44. }
  45. }
  46. }
  47. // 初始化语音引擎下拉框
  48. private void initEngineSpinner() {
  49. String[] engineArray = new String[mEngineList.size()];
  50. for(int i=0; i<mEngineList.size(); i++) {
  51. engineArray[i] = mEngineList.get(i).label;
  52. }
  53. ArrayAdapter<String> engineAdapter = new ArrayAdapter<>(this,
  54. R.layout.item_select, engineArray);
  55. Spinner sp_engine = findViewById(R.id.sp_engine);
  56. sp_engine.setPrompt("请选择语音引擎");
  57. sp_engine.setAdapter(engineAdapter);
  58. sp_engine.setOnItemSelectedListener(new EngineSelectedListener());
  59. sp_engine.setSelection(0);
  60. }
  61. private class EngineSelectedListener implements AdapterView.OnItemSelectedListener {
  62. public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
  63. //recycleSpeech(); // 回收文字转语音对象
  64. // 创建指定语音引擎的文字转语音对象
  65. mSpeech = new TextToSpeech(SpeechEngineActivity.this, new TTSListener(),
  66. mEngineList.get(arg2).name);
  67. }
  68. public void onNothingSelected(AdapterView<?> arg0) {}
  69. }
  70. private String[] mLanguageArray = {"中文普通话", "英语", "法语", "德语", "意大利语", };
  71. private Locale[] mLocaleArray = { Locale.CHINA, Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN, Locale.ITALIAN };
  72. // 初始化语言列表
  73. private void initLanguageList() {
  74. List<Language> languageList = new ArrayList<>();
  75. // 下面遍历语言数组,从中挑选出当前引擎所支持的语言列表
  76. for (int i=0; i<mLanguageArray.length; i++) {
  77. String desc = "正常使用";
  78. // 设置朗读语言
  79. int result = mSpeech.setLanguage(mLocaleArray[i]);
  80. if (result == TextToSpeech.LANG_MISSING_DATA) {
  81. desc = "缺少数据";
  82. } else if (result == TextToSpeech.LANG_NOT_SUPPORTED) {
  83. desc = "暂不支持";
  84. }
  85. languageList.add(new Language(mLanguageArray[i], desc));
  86. }
  87. // 下面把该引擎对各语言的支持情况展示到列表视图上
  88. ListView lv_language = findViewById(R.id.lv_language);
  89. LanguageListAdapter adapter = new LanguageListAdapter(this, languageList);
  90. lv_language.setAdapter(adapter);
  91. }
  92. }

二、文字转语音

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

中文普通话播报

英文版播报

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

代码如下

Java类

  1. package com.example.voice;
  2. import android.os.Bundle;
  3. import android.speech.tts.TextToSpeech;
  4. import android.util.Log;
  5. import android.view.View;
  6. import android.widget.AdapterView;
  7. import android.widget.ArrayAdapter;
  8. import android.widget.EditText;
  9. import android.widget.Spinner;
  10. import android.widget.Toast;
  11. import androidx.appcompat.app.AppCompatActivity;
  12. import com.example.voice.bean.Language;
  13. import java.util.ArrayList;
  14. import java.util.List;
  15. import java.util.Locale;
  16. public class SpeechComposeActivity extends AppCompatActivity {
  17. private final static String TAG = "SpeechComposeActivity";
  18. private TextToSpeech mSpeech; // 声明一个文字转语音对象
  19. private EditText et_tts; // 声明一个编辑框对象
  20. private List<TextToSpeech.EngineInfo> mEngineList; // 语音引擎列表
  21. @Override
  22. protected void onCreate(Bundle savedInstanceState) {
  23. super.onCreate(savedInstanceState);
  24. setContentView(R.layout.activity_speech_compose);
  25. et_tts = findViewById(R.id.et_tts);
  26. findViewById(R.id.btn_read).setOnClickListener(v -> {
  27. String content = et_tts.getText().toString();
  28. // 开始朗读指定文本
  29. int result = mSpeech.speak(content, TextToSpeech.QUEUE_FLUSH, null, null);
  30. String desc = String.format("朗读%s", result==TextToSpeech.SUCCESS?"成功":"失败");
  31. Toast.makeText(this, desc, Toast.LENGTH_SHORT).show();
  32. });
  33. // 创建一个文字转语音对象,初始化结果在监听器的onInit方法中返回
  34. mSpeech = new TextToSpeech(this, mListener);
  35. }
  36. // 创建一个文字转语音的初始化监听器实例
  37. private TextToSpeech.OnInitListener mListener = status -> {
  38. if (status == TextToSpeech.SUCCESS) { // 初始化成功
  39. if (mEngineList == null) { // 首次初始化
  40. mEngineList = mSpeech.getEngines(); // 获取系统支持的所有语音引擎
  41. initEngineSpinner(); // 初始化语音引擎下拉框
  42. }
  43. initLanguageSpinner(); // 初始化语言下拉框
  44. }
  45. };
  46. // 初始化语音引擎下拉框
  47. private void initEngineSpinner() {
  48. String[] engineArray = new String[mEngineList.size()];
  49. for(int i=0; i<mEngineList.size(); i++) {
  50. engineArray[i] = mEngineList.get(i).label;
  51. }
  52. ArrayAdapter<String> engineAdapter = new ArrayAdapter<>(this,
  53. R.layout.item_select, engineArray);
  54. Spinner sp_engine = findViewById(R.id.sp_engine);
  55. sp_engine.setPrompt("请选择语音引擎");
  56. sp_engine.setAdapter(engineAdapter);
  57. sp_engine.setOnItemSelectedListener(new EngineSelectedListener());
  58. sp_engine.setSelection(0);
  59. }
  60. private class EngineSelectedListener implements AdapterView.OnItemSelectedListener {
  61. public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
  62. recycleSpeech(); // 回收文字转语音对象
  63. // 创建指定语音引擎的文字转语音对象
  64. mSpeech = new TextToSpeech(SpeechComposeActivity.this, mListener,
  65. mEngineList.get(arg2).name);
  66. }
  67. public void onNothingSelected(AdapterView<?> arg0) {}
  68. }
  69. // 回收文字转语音对象
  70. private void recycleSpeech() {
  71. if (mSpeech != null) {
  72. mSpeech.stop(); // 停止文字转语音
  73. mSpeech.shutdown(); // 关闭文字转语音
  74. mSpeech = null;
  75. }
  76. }
  77. @Override
  78. protected void onDestroy() {
  79. super.onDestroy();
  80. recycleSpeech(); // 回收文字转语音对象
  81. }
  82. private String[] mLanguageArray = {"中文普通话", "英语", "法语", "德语", "意大利语"};
  83. private Locale[] mLocaleArray = { Locale.CHINA, Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN, Locale.ITALIAN };
  84. private String[] mValidLanguageArray; // 当前引擎支持的语言名称数组
  85. private Locale[] mValidLocaleArray; // 当前引擎支持的语言类型数组
  86. private String mTextCN = "离离原上草,一岁一枯荣。野火烧不尽,春风吹又生。";
  87. private String mTextEN = "Hello World. Nice to meet you. This is a TTS demo.";
  88. // 初始化语言下拉框
  89. private void initLanguageSpinner() {
  90. List<Language> languageList = new ArrayList<>();
  91. // 下面遍历语言数组,从中挑选出当前引擎所支持的语言列表
  92. for (int i=0; i<mLanguageArray.length; i++) {
  93. // 设置朗读语言。通过检查方法的返回值,判断引擎是否支持该语言
  94. int result = mSpeech.setLanguage(mLocaleArray[i]);
  95. Log.d(TAG, "language="+mLanguageArray[i]+",result="+result);
  96. if (result != TextToSpeech.LANG_MISSING_DATA
  97. && result != TextToSpeech.LANG_NOT_SUPPORTED) { // 语言可用
  98. languageList.add(new Language(mLanguageArray[i], mLocaleArray[i]));
  99. }
  100. }
  101. mValidLanguageArray = new String[languageList.size()];
  102. mValidLocaleArray = new Locale[languageList.size()];
  103. for(int i=0; i<languageList.size(); i++) {
  104. mValidLanguageArray[i] = languageList.get(i).name;
  105. mValidLocaleArray[i] = languageList.get(i).locale;
  106. }
  107. // 下面初始化语言下拉框
  108. ArrayAdapter<String> languageAdapter = new ArrayAdapter<>(this,
  109. R.layout.item_select, mValidLanguageArray);
  110. Spinner sp_language = findViewById(R.id.sp_language);
  111. sp_language.setPrompt("请选择朗读语言");
  112. sp_language.setAdapter(languageAdapter);
  113. sp_language.setOnItemSelectedListener(new LanguageSelectedListener());
  114. sp_language.setSelection(0);
  115. }
  116. private class LanguageSelectedListener implements AdapterView.OnItemSelectedListener {
  117. public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
  118. if (mValidLocaleArray[arg2]==Locale.CHINA) { // 汉语
  119. et_tts.setText(mTextCN);
  120. } else { // 其他语言
  121. et_tts.setText(mTextEN);
  122. }
  123. mSpeech.setLanguage(mValidLocaleArray[arg2]); // 设置选中的朗读语言
  124. }
  125. public void onNothingSelected(AdapterView<?> arg0) {}
  126. }
  127. }

三、原生的语音识别

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

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

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

setRecognitionListener 设置语音识别监听器

startListening 开始语音识别

stopListening 停止语音识别

cancel 取消语音识别

destroy 销毁语音识别器

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

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

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

代码如下

java类

  1. package com.example.voice;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.annotation.SuppressLint;
  4. import android.content.ComponentName;
  5. import android.content.Intent;
  6. import android.graphics.Color;
  7. import android.os.Bundle;
  8. import android.provider.Settings;
  9. import android.speech.RecognitionListener;
  10. import android.speech.RecognizerIntent;
  11. import android.speech.SpeechRecognizer;
  12. import android.util.Log;
  13. import android.widget.Button;
  14. import android.widget.TextView;
  15. import org.json.JSONArray;
  16. import org.json.JSONObject;
  17. import java.util.List;
  18. import java.util.Locale;
  19. @SuppressLint("SetTextI18n")
  20. public class SpeechRecognizeActivity extends AppCompatActivity implements RecognitionListener {
  21. private final static String TAG = "SpeechRecognizeActivity";
  22. private TextView tv_result; // 声明一个文本视图对象
  23. private Button btn_recognize; // 声明一个按钮对象
  24. private SpeechRecognizer mRecognizer; // 声明一个语音识别对象
  25. private boolean isRecognizing = false; // 是否正在识别
  26. @Override
  27. protected void onCreate(Bundle savedInstanceState) {
  28. super.onCreate(savedInstanceState);
  29. setContentView(R.layout.activity_speech_recognize);
  30. tv_result = findViewById(R.id.tv_result);
  31. btn_recognize = findViewById(R.id.btn_recognize);
  32. // 检查系统是否支持原生的语音识别
  33. boolean enable = SpeechRecognizer.isRecognitionAvailable(this);
  34. if (enable) {
  35. initRecognize(); // 初始化语音识别
  36. } else {
  37. tv_result.setText("原生的语音识别服务不可用");
  38. btn_recognize.setEnabled(false);
  39. btn_recognize.setTextColor(Color.GRAY);
  40. }
  41. }
  42. // 初始化语音识别
  43. private void initRecognize() {
  44. String serviceComponent = Settings.Secure.getString(
  45. getContentResolver(), "voice_recognition_service");
  46. // 获得系统内置的语音识别服务
  47. ComponentName component = ComponentName.unflattenFromString(serviceComponent);
  48. Log.d(TAG, "getPackageName="+component.getPackageName()+",getClassName="+component.getClassName());
  49. tv_result.setText("原生的语音识别服务采用"+component.getPackageName()
  50. +"里的服务"+component.getClassName());
  51. // 创建原生的语音识别器对象
  52. mRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
  53. mRecognizer.setRecognitionListener(this); // 设置语音识别监听器
  54. btn_recognize.setOnClickListener(v -> {
  55. if (!isRecognizing) { // 未在识别
  56. Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
  57. intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
  58. intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.CHINA);
  59. intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
  60. RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
  61. intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
  62. mRecognizer.startListening(intent); // 开始语音识别
  63. } else { // 正在识别
  64. mRecognizer.stopListening(); // 停止语音识别
  65. //mRecognizer.cancel(); // 取消语音识别
  66. }
  67. isRecognizing = !isRecognizing;
  68. btn_recognize.setText(isRecognizing?"停止识别":"开始识别");
  69. });
  70. }
  71. @Override
  72. public void onReadyForSpeech(Bundle params) {}
  73. @Override
  74. public void onBeginningOfSpeech() {}
  75. @Override
  76. public void onRmsChanged(float rmsdB) {}
  77. @Override
  78. public void onBufferReceived(byte[] buffer) {}
  79. @Override
  80. public void onEndOfSpeech() {}
  81. @Override
  82. public void onError(int error) {
  83. Log.d(TAG, "Recognize error:"+error);
  84. }
  85. @Override
  86. public void onResults(Bundle results) {
  87. Log.d(TAG, "onResults Start");
  88. String desc = "";
  89. String key = SpeechRecognizer.RESULTS_RECOGNITION;
  90. try { // 百度语音分支
  91. String result = results.getString(key);
  92. Log.d(TAG, "result="+result);
  93. JSONObject object = new JSONObject(result);
  94. String recognizeResult = object.getString("recognizeResult");
  95. JSONArray recognizeArray = new JSONArray(recognizeResult);
  96. for (int i=0; i<recognizeArray.length(); i++) {
  97. JSONObject item = (JSONObject) recognizeArray.get(i);
  98. String se_query = item.getString("se_query");
  99. desc = desc + "\n" + se_query;
  100. Log.d(TAG, "desc="+desc);
  101. }
  102. } catch (Exception e) { // 讯飞语音分支
  103. e.printStackTrace();
  104. List<String> resultList = results.getStringArrayList(key);
  105. for (String str : resultList) {
  106. desc = desc + "\n" + str;
  107. Log.d(TAG, "desc="+desc);
  108. }
  109. }
  110. tv_result.setText("识别到的文字为:"+desc);
  111. Log.d(TAG, "onResults End");
  112. }
  113. @Override
  114. public void onPartialResults(Bundle partialResults) {
  115. Log.d(TAG, "onPartialResults");
  116. }
  117. @Override
  118. public void onEvent(int eventType, Bundle params) {}
  119. @Override
  120. protected void onDestroy() {
  121. super.onDestroy();
  122. if (mRecognizer != null) {
  123. mRecognizer.destroy(); // 销毁语音识别器
  124. }
  125. }
  126. }

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


本文转载自: https://blog.csdn.net/jiebaoshayebuhui/article/details/128061083
版权归原作者 showswoller 所有, 如有侵权,请联系我们删除。

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

还没有评论