Android百度語音整合——文字轉語音
專案涉及文字轉語音的需求,用Android原生提供的TTS生成的語音太單調,機器聲音太明顯,故尋求第三方更好的支援,用科大訊飛的語音包收費,百度語音免費而且不限制呼叫次數,主頁鮮明說永久免費的智慧語音開放平臺,故使用百度語音來支援。
1. 地址: http://yuyin.baidu.com/,登入網址百度語音開發者平臺,建立應用(圖下方宣告免費使用和無限制)。
2. 建好應用之後就能得到AppId相關的資訊。
3.因為只需要文字轉語音的功能,下載sdk得到的DEMO是一個大雜燴,於是把文字轉語音的功能單獨扣出來自定義封一個DEMO,效果如下,當語音引擎初始化成功後,播放按鈕會變成紅色,點選就會將顯示的文字讀出來:
4. 程式碼整合首先將官網SDK的DEMO中jar包放到app的libs下,assets離線資源和jniLibs放到src/main下,離線聲音模型便來自assets中的.dat檔案,jnilibs不必多說,是需要的so庫。
5. 將SythActivity和這個Activity涉及到相關的類都從demo中提出來,刪繁就簡,官方demo中的註釋已經很好了,比如更換離線的男女聲的設定,純線上還是離線上融合(離線沒有單獨的),語速語調等等的設定,都給出了詳盡的註釋,只要換成自己專案在平臺上的appId,appKey,secretKey, 接著初始化引擎()成功後,就能正常的播報文字轉換的語音了,initialTts()是執行初始化的語句,成功的message通過handler捕捉,下面的程式碼在初始化成功後就會將按鈕的狀態從不可點選,變成可點選的狀態,並且背景色變紅:
/** * 合成demo。含線上和離線,沒有純離線功能。 * 根據網路狀況優先走線上,線上時訪問伺服器失敗後轉為離線。 */ public class SynthActivity extends AppCompatActivity implements View.OnClickListener { private EditText mInput; private Context context; // ================== 初始化引數設定開始 ========================== /** * 釋出時請替換成自己申請的appId appKey 和 secretKey。注意如果需要離線合成功能,請在您申請的應用中填寫包名。 * 本demo的包名是com.baidu.tts.sample,定義在build.gradle中。 */ protected String appId = "15041858"; protected String appKey = "nXNfmGXnKWzci52Mj8VHkzty"; protected String secretKey = "997sojh2AVtoYIYs9sqxVha6ncYMlUft"; // TtsMode.MIX; 離線上融合,線上優先; TtsMode.ONLINE 純線上; 沒有純離線 protected TtsMode ttsMode = TtsMode.MIX; // 離線發音選擇,VOICE_FEMALE即為離線女聲發音。 // assets目錄下bd_etts_common_speech_m15_mand_eng_high_am-mix_v3.0.0_20170505.dat為離線男聲模型; // assets目錄下bd_etts_common_speech_f7_mand_eng_high_am-mix_v3.0.0_20170512.dat為離線女聲模型 protected String offlineVoice = OfflineResource.VOICE_FEMALE; // ===============初始化引數設定完畢,更多合成引數請至getParams()方法中設定 ================= // 主控制類,所有合成控制方法從這個類開始 protected MySyntherizer synthesizer; protected static String DESC = "請先看完說明。之後點選“合成並播放”按鈕即可正常測試。\n" + "測試離線合成功能需要首次聯網。\n" + "純線上請修改程式碼裡ttsMode為TtsMode.ONLINE, 沒有純離線。\n" + "本Demo的預設引數設定為wifi情況下線上合成, 其它網路(包括4G)使用離線合成。 線上普通女聲發音,離線男聲發音.\n" + "合成可以多次呼叫,SDK內部有快取佇列,會依次完成。\n\n"; private static final String TAG = "SynthActivity"; protected Handler mainHandler; private Button speak; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_synth); context = SynthActivity.this; mInput = findViewById(R.id.input); speak = findViewById(R.id.speak); mainHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); handle(msg); } }; speak.setOnClickListener(this); initialTts(); // 初始化TTS引擎 } /** * 介面上的按鈕對應方法 */ @Override public void onClick(View v) { switch (v.getId()) { case R.id.speak: speak(); // 合成並播放 break; default: break; } } /** * 初始化引擎,需要的引數均在InitConfig類裡 * <p> * DEMO中提供了3個SpeechSynthesizerListener的實現 * MessageListener 僅僅用log.i記錄日誌,在logcat中可以看見 * UiMessageListener 在MessageListener的基礎上,對handler傳送訊息,實現UI的文字更新 * FileSaveListener 在UiMessageListener的基礎上,使用 onSynthesizeDataArrived回撥,獲取音訊流 */ protected void initialTts() { LoggerProxy.printable(true); // 日誌列印在logcat中 // 設定初始化引數 // 此處可以改為 含有您業務邏輯的SpeechSynthesizerListener的實現類 SpeechSynthesizerListener listener = new UiMessageListener(mainHandler); Map<String, String> params = getParams(); // appId appKey secretKey 網站上您申請的應用獲取。注意使用離線合成功能的話,需要應用中填寫您app的包名。包名在build.gradle中獲取。 InitConfig initConfig = new InitConfig(appId, appKey, secretKey, ttsMode, params, listener); // 如果您整合中出錯,請將下面一段程式碼放在和demo中相同的位置,並複製InitConfig 和 AutoCheck到您的專案中 // 上線時請刪除AutoCheck的呼叫 AutoCheck.getInstance(getApplicationContext()).check(initConfig, new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 100) { AutoCheck autoCheck = (AutoCheck) msg.obj; synchronized (autoCheck) { String message = autoCheck.obtainDebugMessage(); Log.w("AutoCheckMessage", message); } } } }); synthesizer = new NonBlockSyntherizer(this, initConfig, mainHandler); // 此處可以改為MySyntherizer 瞭解呼叫過程 } /** * 合成的引數,可以初始化時填寫,也可以在合成前設定。 * * @return */ protected Map<String, String> getParams() { Map<String, String> params = new HashMap<String, String>(); // 以下引數均為選填 // 設定線上發聲音人: 0 普通女聲(預設) 1 普通男聲 2 特別男聲 3 情感男聲<度逍遙> 4 情感兒童聲<度丫丫> params.put(SpeechSynthesizer.PARAM_SPEAKER, "0"); // 設定合成的音量,0-9 ,預設 5 params.put(SpeechSynthesizer.PARAM_VOLUME, "9"); // 設定合成的語速,0-9 ,預設 5 params.put(SpeechSynthesizer.PARAM_SPEED, "6"); // 設定合成的語調,0-9 ,預設 5 params.put(SpeechSynthesizer.PARAM_PITCH, "5"); params.put(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT); // 該引數設定為TtsMode.MIX生效。即純線上模式不生效。 // MIX_MODE_DEFAULT 預設 ,wifi狀態下使用線上,非wifi離線。線上狀態下,請求超時6s自動轉離線 // MIX_MODE_HIGH_SPEED_SYNTHESIZE_WIFI wifi狀態下使用線上,非wifi離線。線上狀態下, 請求超時1.2s自動轉離線 // MIX_MODE_HIGH_SPEED_NETWORK , 3G 4G wifi狀態下使用線上,其它狀態離線。線上狀態下,請求超時1.2s自動轉離線 // MIX_MODE_HIGH_SPEED_SYNTHESIZE, 2G 3G 4G wifi狀態下使用線上,其它狀態離線。線上狀態下,請求超時1.2s自動轉離線 // 離線資原始檔, 從assets目錄中複製到臨時目錄,需要在initTTs方法前完成 OfflineResource offlineResource = createOfflineResource(offlineVoice); // 聲學模型檔案路徑 (離線引擎使用), 請確認下面兩個檔案存在 params.put(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, offlineResource.getTextFilename()); params.put(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, offlineResource.getModelFilename()); return params; } protected OfflineResource createOfflineResource(String voiceType) { OfflineResource offlineResource = null; try { offlineResource = new OfflineResource(this, voiceType); } catch (IOException e) { // IO 錯誤自行處理 e.printStackTrace(); } return offlineResource; } /** * speak 實際上是呼叫 synthesize後,獲取音訊流,然後播放。 * 獲取音訊流的方式見SaveFileActivity及FileSaveListener * 需要合成的文字text的長度不能超過1024個GBK位元組。 */ private void speak() { String text = mInput.getText().toString(); // 合成前可以修改引數: // Map<String, String> params = getParams(); // synthesizer.setParams(params); int result = synthesizer.speak(text); } @Override protected void onDestroy() { synthesizer.release(); Log.i(TAG, "釋放資源成功"); super.onDestroy(); } protected void handle(Message msg) { switch (msg.what) { case INIT_SUCCESS: //初始化成功,按鈕可點選 speak.setClickable(true); speak.setBackgroundColor(ContextCompat.getColor(context,R.color.colorAccent)); break; default: break; } }
Demo已上傳,裡面還有一個沒用上的MainActivity,那裡面寫好了原生的語音轉文字的功能,一併打包:https://download.csdn.net/download/crystal_xing/10829418