日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > Android開發筆記(一百零八)智能語音

Android開發筆記(一百零八)智能語音

來源:程序員人生   發布時間:2016-08-22 08:30:02 閱讀次數:4695次

智能語音技術

如今愈來愈多的app用到了語音播報功能,例如地圖導航、天氣預報、文字瀏覽、口語訓練等等。語音技術主要分兩塊,1塊是語音轉文字,即語音辨認;另外一塊是文字轉語音,即語音合成。


對中文來講,和語音播報相干的1個技術是漢字轉拼音,想一想看,拼音本身就是音節拼讀的標記,每一個音節對應1段音頻,那末1句的拼音便能用1連串的音頻流合成而來。漢字轉拼音的說明參見《Android開發筆記(8103)多語言支持》。


語音合成通常也簡稱為TTS,即TextToSpeech(從文本到語言)。語音合成技術把文字智能地轉化為自然語音流,固然為了不機械合成的呆板和停頓感,語音引擎還得對語音流進行平滑處理,確保輸出的語音音律流暢、感覺自然。


TextToSpeech

Android從1.6開始,就內置了語音合成引擎,即“Pico TTS”。該引擎支持英語、法語、德語、意大利語,但不支持中文,幸虧Android從4.0開始允許接入第3方的語音引擎,因此只要我們安裝了中文引擎,就可以在代碼中使用中文語音合成服務。例如,在各大利用市場上下載并安裝科大訊飛+,然后在手機操作“系統設置”——“語言和輸入法”——“文字轉語音(TTS)輸出”,以下圖所示便可設置中文的語音引擎:



Android的語音合成控件類名是TextToSpeech,下面是該類經常使用的方法說明:
構造函數 : 第2個參數設置TTSListener對象,要重寫onInit方法(通常在這里調用setLanguage方法,由于初始化成功后才能設置語言)。第3個參數設置語音引擎,默許是系統自帶的pico,要獲得系統支持的所有引擎可調用getEngines方法。
setLanguage : 設置語言。英語為Locale.ENGLISH;法語為Locale.FRENCH;德語為Locale.GERMAN;意大利語為Locale.ITALIAN;漢語普通話為Locale.CHINA(需安裝中文引擎,如科大訊飛+)。該方法的返回值有3個,0表示正常,⑴表示缺失數據,⑵表示不支持該語言。
setSpeechRate : 設置語速。1.0正常語速;0.5慢1半的語速;2.0;快1倍的語速。
setPitch : 設置音調。1.0正常音調;低于1.0的為低音;高于1.0的為高音。
speak : 開始對指定文本進行語音朗誦。
synthesizeToFile : 把指定文本的朗誦語音輸出到文件。
stop : 停止朗誦。
shutdown : 關閉語音引擎。
isSpeaking : 判斷是不是在語音朗誦。
getLanguage : 獲得當前的語言。
getCurrentEngine : 獲得當前的語音引擎。
getEngines : 獲得系統支持的所有語音引擎。


下面是TextToSpeech處理語音合成的代碼示例:
import java.util.List; import java.util.Locale; import android.app.Activity; import android.os.Bundle; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.EngineInfo; import android.speech.tts.TextToSpeech.OnInitListener; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.Toast; import android.widget.AdapterView.OnItemSelectedListener; public class TTSActivity extends Activity implements OnClickListener { private TextToSpeech mSpeech; private EditText et_tts_resource; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_tts); et_tts_resource = (EditText) findViewById(R.id.et_tts_resource); Button btn_tts_start = (Button) findViewById(R.id.btn_tts_start); btn_tts_start.setOnClickListener(this); initLanguageSpinner(); mSpeech = new TextToSpeech(TTSActivity.this, new TTSListener()); } private void initLanguageSpinner() { ArrayAdapterstarAdapter = new ArrayAdapter(this, R.layout.spinner_item, mLangArray); starAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item); Spinner sp = (Spinner) findViewById(R.id.sp_tts_language); sp.setPrompt("請選擇語言"); sp.setAdapter(starAdapter); sp.setOnItemSelectedListener(new LanguageSelectedListener()); sp.setSelection(0); } private String[] mEngineArray; private int mEngine; private void initEngineSpinner() { mEngineArray = new String[mEngineList.size()]; for(int i=0; i arg0, View arg1, int arg2, long arg3) { mLanguage = arg2; if (mLocaleArray[mLanguage]==Locale.SIMPLIFIED_CHINESE || mLocaleArray[mLanguage]==Locale.TRADITIONAL_CHINESE) { et_tts_resource.setText(mTextCN); } else { et_tts_resource.setText(mTextEN); } if (mEngineList != null) { resetLanguage(); } } public void onNothingSelected(AdapterView arg0) { } } private class EngineSelectedListener implements OnItemSelectedListener { public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) { mEngine = arg2; recycleSpeech(); mSpeech = new TextToSpeech(TTSActivity.this, new TTSListener(), mEngineList.get(mEngine).name); } public void onNothingSelected(AdapterView arg0) { } } private void resetLanguage() { int result = mSpeech.setLanguage(mLocaleArray[mLanguage]); //如果打印為⑵,說明不支持這類語言;⑴說明缺失數據 Toast.makeText(TTSActivity.this, "您選擇的是"+mLangArray[mLanguage] +",result="+result, Toast.LENGTH_SHORT).show(); if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { } } @Override public void onClick(View v) { if (v.getId() == R.id.btn_tts_start) { String content = et_tts_resource.getText().toString(); int result = mSpeech.speak(content, TextToSpeech.QUEUE_FLUSH, null); Toast.makeText(TTSActivity.this, "speak result="+result, Toast.LENGTH_SHORT).show(); } } private ListmEngineList; private class TTSListener implements OnInitListener { @Override public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { if (mEngineList == null) { mEngineList = mSpeech.getEngines(); initEngineSpinner(); } else { resetLanguage(); } } } } }


科大訊飛語音

前面提到,只要安裝了中文引擎,便可在TextToSpeech中使用中文語音;可是我們沒法要求用戶再額外下載1個app,正確的做法是在自己app中集成語音sdk。目前中文環境常見的語音sdk主要有科大訊飛、百度語音、捷通華聲、云知聲等等,開發者可自行選擇1個。


sdk集成

科大訊飛語音sdk的集成步驟以下:
1、導入sdk包到libs目錄,包括libmsc.so、Msc.jar、Sunflower.jar;
2、到訊飛網站注冊并創建新利用,取得appid;
3、自定義1個Application類,在onCreate函數中加入下面代碼,注意appid值為第2步申請到的id:
SpeechUtility.createUtility(MainApplication.this, "appid=5763c4cf");
4、在AndroidManifest.xml中加入必要的權限,和自定義的Application類;
5、根據demo工程編寫代碼與布局文件;
6、如果使用了RecognizerDialog控件,則要把demo工程assets目錄下的文件原樣拷過來;
7、在混淆打包的時候需要添加-keep class com.iflytek.**{*;},


語音辨認

科大訊飛的語音辨認用的是SpeechRecognizer類,主要方法以下:
createRecognizer : 創建語音辨認對象。
setParameter : 設置語音辨認的參數。經常使用參數包括:
--SpeechConstant.ENGINE_TYPE : 設置聽寫引擎。TYPE_LOCAL表示本地,TYPE_CLOUD表示云端,TYPE_MIX表示混合。
--SpeechConstant.RESULT_TYPE : 設置返回結果格式。json表示json格式。
--SpeechConstant.LANGUAGE : 設置語言。zh_cn表示中文,en_us表示英文。
--SpeechConstant.ACCENT : 設置方言。mandarin表示普通話,cantonese表示粵語,henanese表示河南話。
--SpeechConstant.VAD_BOS : 設置語音前端點:靜音超時時間,即用戶多長時間不說話則當作超時處理。
--SpeechConstant.VAD_EOS : 設置語音后端點:后端點靜音檢測時間,即用戶停止說話多長時間內即認為不再輸入,自動停止錄音。
--SpeechConstant.ASR_PTT : 設置標點符號。0表示返回結果無標點,1表示返回結果有標點。
--SpeechConstant.AUDIO_FORMAT : 設置音頻的保存格式。
--SpeechConstant.ASR_AUDIO_PATH : 設置音頻的保存路徑。
--SpeechConstant.AUDIO_SOURCE : 設置音頻的來源。⑴表示音頻流,與writeAudio配合使用;⑵表示外部文件,同時設置ASR_SOURCE_PATH指定文件路徑。
--SpeechConstant.ASR_SOURCE_PATH : 設置外部音頻文件的路徑。
startListening : 開始監聽語音輸入。參數為RecognizerListener對象,該對象需重寫的方法包括:
--onBeginOfSpeech : 內部錄音機已準備好了,用戶可以開始語音輸入。
--onError : 毛病碼:10118(您沒有說話),多是錄音機權限被禁,需要提示用戶打開利用的錄音權限。
--onEndOfSpeech : 檢測到了語音的尾端點,已進入辨認進程,不再接受語音輸入。
--onResult : 辨認結束,返回結果串。
--onVolumeChanged : 語音輸入進程中的音量大小變化。
--onEvent : 事件處理,1般是業務出錯等異常。
stopListening : 結束監聽語音。
writeAudio : 把指定的音頻流作為語音輸入。
cancel : 取消監聽。
destroy : 回收語音辨認對象。


下面是科大訊飛語音辨認的運行截圖:



下面是科大訊飛語音辨認的代碼例子:
import java.util.HashMap; import java.util.LinkedHashMap; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.widget.EditText; import android.widget.Toast; import com.example.exmvoice.R; import com.example.exmvoice.SettingsActivity; import com.example.exmvoice.xunfei.util.FucUtil; import com.example.exmvoice.xunfei.util.JsonParser; import com.iflytek.cloud.ErrorCode; import com.iflytek.cloud.InitListener; import com.iflytek.cloud.RecognizerListener; import com.iflytek.cloud.RecognizerResult; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechRecognizer; import com.iflytek.cloud.ui.RecognizerDialog; import com.iflytek.cloud.ui.RecognizerDialogListener; public class XFRecognizeActivity extends Activity implements OnClickListener { private final static String TAG = XFRecognizeActivity.class.getSimpleName(); // 語音聽寫對象 private SpeechRecognizer mRecognize; // 語音聽寫UI private RecognizerDialog mRecognizeDialog; // 用HashMap存儲聽寫結果 private HashMap mRecognizeResults = new LinkedHashMap(); private EditText mResultText; private SharedPreferences mSharedPreferences; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_xunfei_recognize); mResultText = ((EditText) findViewById(R.id.xf_recognize_text)); findViewById(R.id.xf_recognize_start).setOnClickListener(this); findViewById(R.id.xf_recognize_stop).setOnClickListener(this); findViewById(R.id.xf_recognize_cancel).setOnClickListener(this); findViewById(R.id.xf_recognize_stream).setOnClickListener(this); findViewById(R.id.xf_recognize_setting).setOnClickListener(this); mSharedPreferences = getSharedPreferences(SettingsActivity.PREFER_NAME, Activity.MODE_PRIVATE); // 初始化辨認無UI辨認對象,使用SpeechRecognizer對象,可根據回調消息自定義界面; mRecognize = SpeechRecognizer.createRecognizer(this, mInitListener); // 初始化聽寫Dialog,如果只使用有UI聽寫功能,無需創建SpeechRecognizer // 使用UI聽寫功能,請將assets下文件拷貝到項目中 mRecognizeDialog = new RecognizerDialog(this, mInitListener); } @Override protected void onDestroy() { super.onDestroy(); // 退出時釋放連接 mRecognize.cancel(); mRecognize.destroy(); } @Override public void onClick(View v) { int ret = 0; // 函數調用返回值 int resid = v.getId(); if (resid == R.id.xf_recognize_setting) { // 進入參數設置頁面 Intent intent = new Intent(this, SettingsActivity.class); intent.putExtra("type", SettingsActivity.XF_RECOGNIZE); startActivity(intent); } else if (resid == R.id.xf_recognize_start) { // 開始聽寫。如何判斷1次聽寫結束:OnResult isLast=true 或 onError mResultText.setText(null);// 清空顯示內容 mRecognizeResults.clear(); // 設置參數 resetParam(); boolean isShowDialog = mSharedPreferences.getBoolean("show_dialog", true); if (isShowDialog) { // 顯示聽寫對話框 mRecognizeDialog.setListener(mRecognizeDialogListener); mRecognizeDialog.show(); showTip("請開始說話………"); } else { // 不顯示聽寫對話框 ret = mRecognize.startListening(mRecognizeListener); if (ret != ErrorCode.SUCCESS) { showTip("聽寫失敗,毛病碼:" + ret); } else { showTip("請開始說話…"); } } } else if (resid == R.id.xf_recognize_stop) { // 停止聽寫 mRecognize.stopListening(); showTip("停止聽寫"); } else if (resid == R.id.xf_recognize_cancel) { // 取消聽寫 mRecognize.cancel(); showTip("取消聽寫"); } else if (resid == R.id.xf_recognize_stream) { // 音頻流辨認 mResultText.setText(null);// 清空顯示內容 mRecognizeResults.clear(); // 設置參數 resetParam(); // 設置音頻來源為外部文件 mRecognize.setParameter(SpeechConstant.AUDIO_SOURCE, "⑴"); // 也能夠像以下這樣直接設置音頻文件路徑辨認(要求設置文件在sdcard上的全路徑): // mRecognize.setParameter(SpeechConstant.AUDIO_SOURCE, "⑵"); // mRecognize.setParameter(SpeechConstant.ASR_SOURCE_PATH, "sdcard/XXX/XXX.pcm"); ret = mRecognize.startListening(mRecognizeListener); if (ret != ErrorCode.SUCCESS) { showTip("辨認失敗,毛病碼:" + ret); } else { byte[] audioData = FucUtil.readAudioFile(this, "retcognize_est.wav"); if (null != audioData) { showTip("開始音頻流辨認"); // 1次(也能夠分屢次)寫入音頻文件數據,數據格式必須是采樣率為8KHz或16KHz(本地辨認只支持16K采樣率,云端都支持),位長16bit,單聲道的wav或pcm // 寫入8KHz采樣的音頻時,必須先調用setParameter(SpeechConstant.SAMPLE_RATE, "8000")設置正確的采樣率 // 注:當音頻太長,靜音部份時長超過VAD_EOS將致使靜音后臉部分不能辨認 mRecognize.writeAudio(audioData, 0, audioData.length); mRecognize.stopListening(); } else { mRecognize.cancel(); showTip("讀取音頻流失敗"); } } } } //初始化監聽器 private InitListener mInitListener = new InitListener() { @Override public void onInit(int code) { Log.d(TAG, "SpeechRecognizer init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失敗,毛病碼:" + code); } } }; //聽寫監聽器 private RecognizerListener mRecognizeListener = new RecognizerListener() { @Override public void onBeginOfSpeech() { // 此回調表示:sdk內部錄音機已準備好了,用戶可以開始語音輸入 showTip("開始說話"); } @Override public void onError(SpeechError error) { // 毛病碼:10118(您沒有說話),多是錄音機權限被禁,需要提示用戶打開利用的錄音權限。 // 如果使用本地功能(語記)需要提示用戶開啟語記的錄音權限。 showTip(error.getPlainDescription(true)); } @Override public void onEndOfSpeech() { // 此回調表示:檢測到了語音的尾端點,已進入辨認進程,不再接受語音輸入 showTip("結束說話"); } @Override public void onResult(RecognizerResult results, boolean isLast) { Log.d(TAG, results.getResultString()); printResult(results); if (isLast) { // TODO 最后的結果 } } @Override public void onVolumeChanged(int volume, byte[] data) { showTip("當前正在說話,音量大?。? + volume); Log.d(TAG, "返回音頻數據:"+data.length); } @Override public void onEvent(int eventType, int arg1, int arg2, Bundle obj) { // 以下代碼用于獲得與云真個會話id,當業務出錯時將會話id提供給技術支持人員,可用于查詢會話日志,定位出錯緣由 // 若使用本地能力,會話id為null // if (SpeechEvent.EVENT_SESSION_ID == eventType) { // String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID); // Log.d(TAG, "session id =" + sid); // } } }; private void printResult(RecognizerResult results) { String text = JsonParser.parseIatResult(results.getResultString()); String sn = null; try { JSONObject resultJson = new JSONObject(results.getResultString()); sn = resultJson.optString("sn"); } catch (JSONException e) { e.printStackTrace(); return; } mRecognizeResults.put(sn, text); StringBuffer resultBuffer = new StringBuffer(); for (String key : mRecognizeResults.keySet()) { resultBuffer.append(mRecognizeResults.get(key)); } mResultText.setText(resultBuffer.toString()); mResultText.setSelection(mResultText.length()); } //聽寫UI監聽器 private RecognizerDialogListener mRecognizeDialogListener = new RecognizerDialogListener() { public void onResult(RecognizerResult results, boolean isLast) { printResult(results); } //辨認回調毛病 public void onError(SpeechError error) { showTip(error.getPlainDescription(true)); } }; private void showTip(final String str) { Toast.makeText(this, str, Toast.LENGTH_LONG).show(); } //參數設置 public void resetParam() { // 清空參數 mRecognize.setParameter(SpeechConstant.PARAMS, null); // 設置聽寫引擎。TYPE_LOCAL表示本地,TYPE_CLOUD表示云端,TYPE_MIX 表示混合 mRecognize.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); // 設置返回結果格式 mRecognize.setParameter(SpeechConstant.RESULT_TYPE, "json"); String lag = mSharedPreferences.getString("recognize_language_preference", "mandarin"); if (lag.equals("en_us")) { // 設置語言 mRecognize.setParameter(SpeechConstant.LANGUAGE, "en_us"); } else { mRecognize.setParameter(SpeechConstant.LANGUAGE, "zh_cn"); // 設置語言區域 mRecognize.setParameter(SpeechConstant.ACCENT, lag); } // 設置語音前端點:靜音超時時間,即用戶多長時間不說話則當作超時處理 mRecognize.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("recognize_vadbos_preference", "4000")); // 設置語音后端點:后端點靜音檢測時間,即用戶停止說話多長時間內即認為不再輸入, 自動停止錄音 mRecognize.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("recognize_vadeos_preference", "1000")); // 設置標點符號,設置為"0"返回結果無標點,設置為"1"返回結果有標點 mRecognize.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("recognize_punc_preference", "1")); // 設置音頻保存路徑,保存音頻格式支持pcm、wav,設置路徑為sd卡請注意WRITE_EXTERNAL_STORAGE權限 // 注:AUDIO_FORMAT參數語記需要更新版本才能生效 mRecognize.setParameter(SpeechConstant.AUDIO_FORMAT, "wav"); mRecognize.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory()+"/msc/recognize.wav"); } }


語音合成

科大訊飛的語音合成用的是SpeechSynthesizer類,主要方法以下:
createSynthesizer : 創建語音合成對象。
setParameter : 設置語音合成的參數。經常使用參數包括:
--SpeechConstant.ENGINE_TYPE : 設置合成引擎。TYPE_LOCAL表示本地,TYPE_CLOUD表示云端,TYPE_MIX表示混合。
--SpeechConstant.VOICE_NAME : 設置朗誦者。默許xiaoyan(女青年,普通話)
--SpeechConstant.SPEED : 設置朗誦的語速。
--SpeechConstant.PITCH : 設置朗誦的音調。
--SpeechConstant.VOLUME : 設置朗誦的音量。
--SpeechConstant.STREAM_TYPE : 設置音頻流類型。默許是音樂。
--SpeechConstant.KEY_REQUEST_FOCUS : 設置是不是在播放合成音頻時打斷音樂播放,默許為true。
--SpeechConstant.AUDIO_FORMAT : 設置音頻的保存格式。
--SpeechConstant.TTS_AUDIO_PATH : 設置音頻的保存路徑。
startSpeaking :  開始語音朗誦。參數為SynthesizerListener對象,該對象需重寫的方法包括:
--onSpeakBegin : 朗誦開始。
--onSpeakPaused : 朗誦暫停。
--onSpeakResumed : 朗誦恢復。
--onBufferProgress : 合成進度變化。
--onSpeakProgress : 朗誦進度變化。
--onCompleted : 朗誦完成。
--onEvent : 事件處理,1般是業務出錯等異常。
synthesizeToUri : 只保存音頻不進行播放,調用該接口就不能調用startSpeaking。第1個參數是要合成的文本,第2個參數時要保存的音頻全路徑,第3個參數是SynthesizerListener回調接口。
pauseSpeaking : 暫停朗誦。
resumeSpeaking : 恢復朗誦。
stopSpeaking : 停止朗誦。
destroy : 回收語音合成對象。


下面是科大訊飛語音合成的代碼例子:
import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.widget.EditText; import android.widget.Toast; import com.example.exmvoice.R; import com.example.exmvoice.SettingsActivity; import com.iflytek.cloud.ErrorCode; import com.iflytek.cloud.InitListener; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechSynthesizer; import com.iflytek.cloud.SynthesizerListener; public class XFComposeActivity extends Activity implements OnClickListener { private static String TAG = XFComposeActivity.class.getSimpleName(); // 語音合成對象 private SpeechSynthesizer mCompose; // 默許發音人 private String voicer = "xiaoyan"; private String[] mCloudVoicersEntries; private String[] mCloudVoicersValue ; // 緩沖進度 private int mPercentForBuffering = 0; // 播放進度 private int mPercentForPlaying = 0; private EditText mResourceText; private SharedPreferences mSharedPreferences; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_xunfei_compose); mResourceText = ((EditText) findViewById(R.id.xf_compose_text)); findViewById(R.id.xf_compose_play).setOnClickListener(this); findViewById(R.id.xf_compose_cancel).setOnClickListener(this); findViewById(R.id.xf_compose_pause).setOnClickListener(this); findViewById(R.id.xf_compose_resume).setOnClickListener(this); findViewById(R.id.xf_compose_setting).setOnClickListener(this); findViewById(R.id.xf_compose_person).setOnClickListener(this); mSharedPreferences = getSharedPreferences(SettingsActivity.PREFER_NAME, MODE_PRIVATE); // 初始化合成對象 mCompose = SpeechSynthesizer.createSynthesizer(this, mComposeInitListener); // 云端發音人名稱列表 mCloudVoicersEntries = getResources().getStringArray(R.array.voicer_cloud_entries); mCloudVoicersValue = getResources().getStringArray(R.array.voicer_cloud_values); } @Override protected void onDestroy() { super.onDestroy(); // 退出時釋放連接 mCompose.stopSpeaking(); mCompose.destroy(); } @Override public void onClick(View v) { int resid = v.getId(); if (resid == R.id.xf_compose_setting) { Intent intent = new Intent(this, SettingsActivity.class); intent.putExtra("type", SettingsActivity.XF_COMPOSE); startActivity(intent); } else if (resid == R.id.xf_compose_play) { // 開始合成 //收到onCompleted 回調時,合成結束、生成合成音頻。合成的音頻格式:只支持pcm格式 String text = mResourceText.getText().toString(); // 設置參數 setParam(); int code = mCompose.startSpeaking(text, mComposeListener); if (code != ErrorCode.SUCCESS) { showTip("語音合成失敗,毛病碼: " + code); } // //只保存音頻不進行播放接口,調用此接口請注釋startSpeaking接口 // //text:要合成的文本,uri:需要保存的音頻全路徑,listener:回調接口 // String path = Environment.getExternalStorageDirectory()+"/compose.pcm"; // int code = mCompose.synthesizeToUri(text, path, mComposeListener); } else if (resid == R.id.xf_compose_cancel) { // 取消合成 mCompose.stopSpeaking(); } else if (resid == R.id.xf_compose_pause) { // 暫停播放 mCompose.pauseSpeaking(); } else if (resid == R.id.xf_compose_resume) { // 繼續播放 mCompose.resumeSpeaking(); } else if (resid == R.id.xf_compose_person) { // 選擇發音人 showPresonSelectDialog(); } } private int selectedNum = 0; //發音人選擇 private void showPresonSelectDialog() { new AlertDialog.Builder(this).setTitle("在線合成發音人選項") .setSingleChoiceItems(mCloudVoicersEntries, // 單選框有幾項,各是甚么名字 selectedNum, // 默許的選項 new DialogInterface.OnClickListener() { // 點擊單選框后的處理 public void onClick(DialogInterface dialog, int which) { // 點擊了哪1項 voicer = mCloudVoicersValue[which]; if ("catherine".equals(voicer) || "henry".equals(voicer) || "vimary".equals(voicer) || "Mariane".equals(voicer) || "Allabent".equals(voicer) || "Gabriela".equals(voicer) || "Abha".equals(voicer) || "XiaoYun".equals(voicer)) { mResourceText.setText(R.string.compose_source_en); } else { mResourceText.setText(R.string.compose_source); } selectedNum = which; dialog.dismiss(); } }).show(); } //初始化監聽 private InitListener mComposeInitListener = new InitListener() { @Override public void onInit(int code) { Log.d(TAG, "InitListener init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失敗,毛病碼:"+code); } else { // 初始化成功,以后可以調用startSpeaking方法 // 注:有的開發者在onCreate方法中創建完合成對象以后馬上就調用startSpeaking進行合成, // 正確的做法是將onCreate中的startSpeaking調用移至這里 } } }; //合成回調監聽 private SynthesizerListener mComposeListener = new SynthesizerListener() { @Override public void onSpeakBegin() { showTip("開始播放"); } @Override public void onSpeakPaused() { showTip("暫停播放"); } @Override public void onSpeakResumed() { showTip("繼續播放"); } @Override public void onBufferProgress(int percent, int beginPos, int endPos, String info) { // 合成進度 mPercentForBuffering = percent; showTip(String.format(getString(R.string.xf_compose_toast_format), mPercentForBuffering, mPercentForPlaying)); } @Override public void onSpeakProgress(int percent, int beginPos, int endPos) { // 播放進度 mPercentForPlaying = percent; showTip(String.format(getString(R.string.xf_compose_toast_format), mPercentForBuffering, mPercentForPlaying)); } @Override public void onCompleted(SpeechError error) { if (error == null) { showTip("播放完成"); } else if (error != null) { showTip(error.getPlainDescription(true)); } } @Override public void onEvent(int eventType, int arg1, int arg2, Bundle obj) { // 以下代碼用于獲得與云真個會話id,當業務出錯時將會話id提供給技術支持人員,可用于查詢會話日志,定位出錯緣由 // 若使用本地能力,會話id為null // if (SpeechEvent.EVENT_SESSION_ID == eventType) { // String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID); // Log.d(TAG, "session id =" + sid); // } } }; private void showTip(final String str) { Toast.makeText(this, str, Toast.LENGTH_LONG).show(); } //參數設置 private void setParam(){ // 清空參數 mCompose.setParameter(SpeechConstant.PARAMS, null); // 根據合成引擎設置相應參數 mCompose.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); // 設置在線合成發音人 mCompose.setParameter(SpeechConstant.VOICE_NAME, voicer); //設置合成語速 mCompose.setParameter(SpeechConstant.SPEED, mSharedPreferences.getString("speed_preference", "50")); //設置合成音調 mCompose.setParameter(SpeechConstant.PITCH, mSharedPreferences.getString("pitch_preference", "50")); //設置合成音量 mCompose.setParameter(SpeechConstant.VOLUME, mSharedPreferences.getString("volume_preference", "50")); //設置播放器音頻流類型 mCompose.setParameter(SpeechConstant.STREAM_TYPE, mSharedPreferences.getString("stream_preference", "3")); // 設置播放合成音頻打斷音樂播放,默許為true mCompose.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true"); // 設置音頻保存路徑,保存音頻格式支持pcm、wav,設置路徑為sd卡請注意WRITE_EXTERNAL_STORAGE權限 // 注:AUDIO_FORMAT參數語記需要更新版本才能生效 mCompose.setParameter(SpeechConstant.AUDIO_FORMAT, "wav"); mCompose.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory()+"/msc/compose.wav"); } }


PreferenceFragment

科大訊飛的demo工程在設置頁面使用了PreferenceActivity,看起來代碼簡練了許多,正好我們之前還沒接觸Preference的實際應用,現在就來研究研究。看最新的sdk源碼,提示PreferenceActivity的許多方法都過時了,官方建議使用PreferenceFragment來代替。


下面是PreferenceFragment的經常使用方法說明
getPreferenceManager : 取得參數管理的PreferenceManager對象。該對象主要有兩個方法:getDefaultSharedPreferences返回系統默許的同享參數對象;setSharedPreferencesName為設置指定名稱的同享參數;有關同享參數的說明參見《Android開發筆記(2109)使用SharedPreferences存取數據》。
addPreferencesFromResource : 從xml資源文件中添加參數界面。
findPreference : 從xml資源文件中獲得指定id的元素。EditTextPreference表示該項參數為文本輸入;ListPreference表示該項參數為列表選擇;CheckBoxPreference表示該項參數為復選框勾選;PreferenceScreen是xml文件的根節點。
setPreferenceScreen : 設置參數屏幕(1般不使用)。


下面是PreferenceFragment的代碼示例:
import com.example.exmvoice.R; import com.example.exmvoice.SettingsActivity; import com.example.exmvoice.xunfei.util.SettingTextWatcher; import android.os.Bundle; import android.preference.EditTextPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceFragment; //語音辨認設置界面 public class XFRecognizeSettingsFragment extends PreferenceFragment implements OnPreferenceChangeListener { private EditTextPreference mVadbosPreference; private EditTextPreference mVadeosPreference; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getPreferenceManager().setSharedPreferencesName(SettingsActivity.PREFER_NAME); addPreferencesFromResource(R.xml.xf_recognize_setting); mVadbosPreference = (EditTextPreference) findPreference("recognize_vadbos_preference"); mVadbosPreference.getEditText().addTextChangedListener( new SettingTextWatcher(getActivity(),mVadbosPreference,0,10000)); mVadeosPreference = (EditTextPreference) findPreference("recognize_vadeos_preference"); mVadeosPreference.getEditText().addTextChangedListener( new SettingTextWatcher(getActivity(),mVadeosPreference,0,10000)); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { return true; } }


下面是PreferenceFragment的布局示例:


百度語音

sdk集成

百度語音sdk的集成比較麻煩,主要步驟以下:
1、導入sdk包到libs目錄,包括語音辨認和語音合成兩種庫
語音辨認的庫有:
libbdEASRAndroid.so
libBDVoiceRecognitionClient_MFE_V1.so
VoiceRecognition⑵.0.1.jar
語音合成的庫有:
libbd_etts.so
libBDSpeechDecoder_V1.so
libbdtts.so
libgnustl_shared.so
com.baidu.tts_2.2.7.20160616_81bcb05_release.jar
galaxy-v2.0.jar
2、到百度注冊并創建新利用,取得APP_ID、API_KEY、SECRET_KEY;
3、在AndroidManifest.xml中加入必要的權限,和meta-data、service和activity設置,注意meta-data的參數值為第2步取得的APP_ID、API_KEY、SECRET_KEY。詳細的xml部份例子以下:
4、demo工程中assets目錄下的文件原樣拷過來;
5、demo工程中res目錄下的drawable、layout、raw下面的資源原樣拷過來;
6、根據demo工程編寫代碼與布局文件,注意在語音合成初始化時,setAppId和setApiKey要把第2步取得的APP_ID、API_KEY、SECRET_KEY給填進去;


下面是我在集成百度語音時遇到的幾個問題及處理辦法:
1、語音合成運行報錯,日志提示:
06⑵1 16:31:37.118: W/System.err(4595): Caused by: java.util.concurrent.ExecutionException: java.lang.Exception: #5, Other client side errors. request token failed, error: unknown, desc: unknown client id, used AK=this/this
緣由:setAppId和setApiKey方法沒有設置appkey。
2、語音合成運行報錯,日志提示:
06⑵1 16:32:57.830: W/System.err(4769): java.lang.Exception: #5, Other client side errors. The AK can only be used for demo. AK=8MAxI5o7VjKSZOKeBzS4XtxO/Ge5GXVdGQpaxOmLzc8fOM8309ATCz9Ha
緣由:setAppId和setApiKey方法設置的值不對,可能使用了demo的appkey,而不是自己申請的appkey。
3、語音合成運行報錯,日志提示:
06⑵2 11:32:00.998: W/MainActivity(31928): onError error=(⑴5)(⑴5)online synthesize get was timeout[(cause)java.util.concurrent.TimeoutException]--utteranceId=0
緣由:網絡連不上,請檢查網絡連接。如果使用摹擬器測試,最好重啟摹擬器再試試
4、調用loadEnglishModel方法加載英語模塊時,返回值是⑴1加載失?。ㄕR祷?)。
緣由:加載離線英文資源需要在初始化時采取混合模式TtsMode.MIX,不可采取在線模式TtsMode.ONLINE。


語音辨認

百度語音辨認用的是SpeechRecognizer類,主要方法以下:
createSpeechRecognizer : 創建語音辨認對象。
setRecognitionListener : 設置辨認監聽器。該監聽器需重寫的方法包括:
--onReadyForSpeech : 準備就緒,可以開始說話
--onBeginningOfSpeech : 檢測到用戶已開始說話
--onRmsChanged : 1般不用途理。
--onBufferReceived : 1般不用途理。
--onEndOfSpeech : 檢測到用戶已停止說話
--onError : 辨認出錯。
--onResults : 辨認完成,返回結果串。
--onPartialResults : 返回部份的辨認結果。
--onEvent : 事件處理,1般是業務出錯等異常。
startListening : 開始監聽語音。
stopListening : 結束監聽語音。
cancel : 取消監聽。
destroy : 回收語音辨認對象。


注意第1次辨認時要跳到com.baidu.action.RECOGNIZE_SPEECH,后面才能調用startListening方法。辨認時的參數設置是在activity跳轉時傳入的,經常使用參數包括:
--Constant.EXTRA_LANGUAGE : 說話的語言。cmn-Hans-CN表示普通話,sichuan-Hans-CN表示4川話,yue-Hans-CN表示粵語,en-GB表示英語。
--Constant.EXTRA_NLU : 是不是開啟語義解析。
--Constant.EXTRA_VAD : 語音邊界檢測。search表示適用輸入搜索關鍵字(默許值),input表示適用于輸入短信、微博等長句輸入。
--Constant.EXTRA_PROP : 語音的行業領域。


下面是百度語音辨認的運行截圖:



下面是百度語音辨認的代碼例子:
import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.speech.RecognitionListener; import android.speech.SpeechRecognizer; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.*; import com.baidu.speech.VoiceRecognitionService; import com.example.exmvoice.R; import com.example.exmvoice.SettingsActivity; import com.example.exmvoice.baidu.setting.Constant; import org.json.JSONObject; import java.util.*; public class BDRecognizeActivity extends Activity implements OnClickListener { private static final String TAG = BDRecognizeActivity.class.getSimpleName(); private static final int REQUEST_UI = 1; private TextView txtResult; private TextView txtLog; private Button btnStart; public static final int STATUS_None = 0; public static final int STATUS_WaitingReady = 2; public static final int STATUS_Ready = 3; public static final int STATUS_Speaking = 4; public static final int STATUS_Recognition = 5; private SpeechRecognizer speechRecognizer; private int status = STATUS_None; private long speechEndTime = ⑴; private static final int EVENT_ERROR = 11; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_baidu_recognize); txtResult = (TextView) findViewById(R.id.bd_recognize_text); txtLog = (TextView) findViewById(R.id.bd_recognize_log); btnStart = (Button) findViewById(R.id.bd_recognize_start); btnStart.setOnClickListener(this); findViewById(R.id.bd_recognize_setting).setOnClickListener(this); speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this, new ComponentName(this, VoiceRecognitionService.class)); speechRecognizer.setRecognitionListener(mRecognitionListener); } @Override protected void onDestroy() { speechRecognizer.destroy(); super.onDestroy(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { mRecognitionListener.onResults(data.getExtras()); } else { status = STATUS_None; btnStart.setText("開始"); } } public void bindParams(Intent intent) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); if (sp.getBoolean("tips_sound", true)) { intent.putExtra(Constant.EXTRA_SOUND_START, R.raw.bdspeech_recognition_start); intent.putExtra(Constant.EXTRA_SOUND_END, R.raw.bdspeech_speech_end); intent.putExtra(Constant.EXTRA_SOUND_SUCCESS, R.raw.bdspeech_recognition_success); intent.putExtra(Constant.EXTRA_SOUND_ERROR, R.raw.bdspeech_recognition_error); intent.putExtra(Constant.EXTRA_SOUND_CANCEL, R.raw.bdspeech_recognition_cancel); } if (sp.contains(Constant.EXTRA_INFILE)) { String tmp = sp.getString(Constant.EXTRA_INFILE, "").replaceAll(",.*", "").trim(); intent.putExtra(Constant.EXTRA_INFILE, tmp); } if (sp.getBoolean(Constant.EXTRA_OUTFILE, false)) { intent.putExtra(Constant.EXTRA_OUTFILE, "sdcard/outfile.pcm"); } if (sp.contains(Constant.EXTRA_SAMPLE)) { String tmp = sp.getString(Constant.EXTRA_SAMPLE, "").replaceAll(",.*", "").trim(); if (null != tmp && !"".equals(tmp)) { intent.putExtra(Constant.EXTRA_SAMPLE, Integer.parseInt(tmp)); } } if (sp.contains(Constant.EXTRA_LANGUAGE)) { String tmp = sp.getString(Constant.EXTRA_LANGUAGE, "").replaceAll(",.*", "").trim(); if (null != tmp && !"".equals(tmp)) { intent.putExtra(Constant.EXTRA_LANGUAGE, tmp); } } if (sp.contains(Constant.EXTRA_NLU)) { String tmp = sp.getString(Constant.EXTRA_NLU, "").replaceAll(",.*", "").trim(); if (null != tmp && !"".equals(tmp)) { intent.putExtra(Constant.EXTRA_NLU, tmp); } } if (sp.contains(Constant.EXTRA_VAD)) { String tmp = sp.getString(Constant.EXTRA_VAD, "").replaceAll(",.*", "").trim(); if (null != tmp && !"".equals(tmp)) { intent.putExtra(Constant.EXTRA_VAD, tmp); } } if (sp.contains(Constant.EXTRA_PROP)) { String tmp = sp.getString(Constant.EXTRA_PROP, "").replaceAll(",.*", "").trim(); if (null != tmp && !"".equals(tmp)) { intent.putExtra(Constant.EXTRA_PROP, Integer.parseInt(tmp)); } } } private void start() { btnStart.setText("取消"); txtLog.setText(""); status = STATUS_WaitingReady; print("點擊了“開始”"); Intent intent = new Intent(); bindParams(intent); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); { String args = sp.getString("args", ""); if (null != args) { print("參數集:" + args); intent.putExtra("args", args); } } boolean api = sp.getBoolean("api", false); if (api) { speechEndTime = ⑴; speechRecognizer.startListening(intent); } else { intent.setAction("com.baidu.action.RECOGNIZE_SPEECH"); startActivityForResult(intent, REQUEST_UI); } txtResult.setText(""); } private void stop() { speechRecognizer.stopListening(); status = STATUS_Recognition; btnStart.setText("辨認中"); print("點擊了“說完了”"); } private void cancel() { speechRecognizer.cancel(); btnStart.setText("開始"); status = STATUS_None; print("點擊了“取消”"); } private RecognitionListener mRecognitionListener = new RecognitionListener() { @Override public void onReadyForSpeech(Bundle params) { status = STATUS_Ready; print("準備就緒,可以開始說話"); } @Override public void onBeginningOfSpeech() { status = STATUS_Speaking; btnStart.setText("說完了"); print("檢測到用戶已開始說話"); } @Override public void onRmsChanged(float rmsdB) { } @Override public void onBufferReceived(byte[] buffer) { } @Override public void onEndOfSpeech() { speechEndTime = System.currentTimeMillis(); status = STATUS_Recognition; print("檢測到用戶已停止說話"); btnStart.setText("辨認中"); } @Override public void onError(int error) { status = STATUS_None; StringBuilder sb = new StringBuilder(); switch (error) { case SpeechRecognizer.ERROR_AUDIO: sb.append("音頻問題"); break; case SpeechRecognizer.ERROR_SPEECH_TIMEOUT: sb.append("沒有語音輸入"); break; case SpeechRecognizer.ERROR_CLIENT: sb.append("其它客戶端毛病"); break; case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: sb.append("權限不足"); break; case SpeechRecognizer.ERROR_NETWORK: sb.append("網絡問題"); break; case SpeechRecognizer.ERROR_NO_MATCH: sb.append("沒有匹配的辨認結果"); break; case SpeechRecognizer.ERROR_RECOGNIZER_BUSY: sb.append("引擎忙"); break; case SpeechRecognizer.ERROR_SERVER: sb.append("服務端毛病"); break; case SpeechRecognizer.ERROR_NETWORK_TIMEOUT: sb.append("連接超時"); break; } sb.append(":" + error); print("辨認失?。? + sb.toString()); btnStart.setText("開始"); } @Override public void onResults(Bundle results) { long end2finish = System.currentTimeMillis() - speechEndTime; ArrayListnbest = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); print("辨認成功:" + Arrays.toString(nbest.toArray(new String[nbest.size()]))); String json_res = results.getString("origin_result"); try { print("origin_result=\n" + new JSONObject(json_res).toString(4)); } catch (Exception e) { print("origin_result=[warning: bad json]\n" + json_res); } String strEnd2Finish = ""; if (end2finish < 60 * 1000) { strEnd2Finish = "(waited " + end2finish + "ms)"; } txtResult.setText(nbest.get(0) + strEnd2Finish); status = STATUS_None; btnStart.setText("開始"); } @Override public void onPartialResults(Bundle partialResults) { ArrayListnbest = partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); if (nbest.size() > 0) { print("~臨時辨認結果:" + Arrays.toString(nbest.toArray(new String[0]))); txtResult.setText(nbest.get(0)); } } @Override public void onEvent(int eventType, Bundle params) { switch (eventType) { case EVENT_ERROR: String reason = params.get("reason") + ""; print("EVENT_ERROR, " + reason); status = STATUS_None; btnStart.setText("開始"); break; case VoiceRecognitionService.EVENT_ENGINE_SWITCH: int type = params.getInt("engine_type"); print("*引擎切換至" + (type == 0 ? "在線" : "離線")); break; } } }; private void print(String msg) { txtLog.append(msg + "\n"); ScrollView sv = (ScrollView) txtLog.getParent(); sv.smoothScrollTo(0, 1000000); Log.d(TAG, "----" + msg); } @Override public void onClick(View v) { int resid = v.getId(); if (resid == R.id.bd_recognize_setting) { Intent intent = new Intent(this, SettingsActivity.class); intent.putExtra("type", SettingsActivity.BD_RECOGNIZE); startActivity(intent); } else if (resid == R.id.bd_recognize_start) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); boolean api = sp.getBoolean("api", false); if (api) { if (status == STATUS_None) { start(); } else if (status == STATUS_WaitingReady || status == STATUS_Ready || status == STATUS_Recognition) { cancel(); } else if (status == STATUS_Speaking) { stop(); } } else { start(); } } } }


語音合成

百度語音合成用的是SpeechSynthesizer類,主要方法以下:
getInstance : 取得語音合成的實例。
setContext : 設置語音合成的上下文。
setSpeechSynthesizerListener : 語音合成的監聽器。該監聽器需重寫的方法包括:
--onSynthesizeStart : 合成開始。
--onSynthesizeDataArrived : 1般不使用。
--onSynthesizeFinish : 合成結束。
--onSpeechStart : 朗誦開始。
--onSpeechProgressChanged : 朗誦進度變化。
--onSpeechFinish : 朗誦結束。
--onError : 處理出錯。
setAppId : 設置appid。
setApiKey : 設置apikey和secretkey。
auth : 對appid、apikey和secretkey進行鑒權。
initTts : 初始化。TtsMode.ONLINE表示在線合成,TtsMode.MIX表示混合(即在線與離線結合)。
setAudioStreamType : 設置音頻流的類型。AudioManager.STREAM_MUSIC表示音樂。
setParam : 設置語音合成的參數。經常使用參數包括:
--SpeechSynthesizer.PARAM_SPEAKER : 設置朗誦者。0表示普通女聲,1表示普通男聲,2表示特別男聲,3表示情感男聲。
--SpeechSynthesizer.PARAM_VOLUME : 設置音量。取值范圍為0⑼,默許5。
--SpeechSynthesizer.PARAM_SPEED : 設置語速。取值范圍為0⑼,默許5。
--SpeechSynthesizer.PARAM_PITCH : 設置音調。取值范圍為0⑼,默許5。
--SpeechSynthesizer.PARAM_AUDIO_ENCODE : 設置音頻的編碼類型。1般設置SpeechSynthesizer.AUDIO_ENCODE_AMR。
--SpeechSynthesizer.PARAM_AUDIO_RATE : 設置音頻的編碼速率。1般設置SpeechSynthesizer.AUDIO_BITRATE_AMR_15K85。
loadEnglishModel : 加載英語模塊。
speak : 開始合成并朗誦。
pause : 暫停朗誦。
resume : 恢復朗誦。
stop : 停止朗誦。
release : 釋放語音合成的實例。


下面是百度語音合成的代碼例子:
import java.io.File; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.media.AudioManager; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.widget.EditText; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.RadioGroup.OnCheckedChangeListener; import android.widget.Toast; import com.baidu.tts.auth.AuthInfo; import com.baidu.tts.client.SpeechError; import com.baidu.tts.client.SpeechSynthesizer; import com.baidu.tts.client.SpeechSynthesizerListener; import com.baidu.tts.client.TtsMode; import com.example.exmvoice.R; import com.example.exmvoice.SettingsActivity; import com.example.exmvoice.baidu.util.AssetsUtil; public class BDComposeActivity extends Activity implements OnClickListener,OnCheckedChangeListener { private static String TAG = BDComposeActivity.class.getSimpleName(); private SpeechSynthesizer mSpeechSynthesizer; private String mSampleDirPath; private static final String SAMPLE_DIR_NAME = "baiduTTS"; private static final String SPEECH_FEMALE_MODEL_NAME = "bd_etts_speech_female.dat"; private static final String SPEECH_MALE_MODEL_NAME = "bd_etts_speech_male.dat"; private static final String TEXT_MODEL_NAME = "bd_etts_text.dat"; private static final String LICENSE_FILE_NAME = "bd_temp_license"; private static final String ENGLISH_SPEECH_FEMALE_MODEL_NAME = "bd_etts_speech_female_en.dat"; private static final String ENGLISH_SPEECH_MALE_MODEL_NAME = "bd_etts_speech_male_en.dat"; private static final String ENGLISH_TEXT_MODEL_NAME = "bd_etts_text_en.dat"; private boolean bOnline = true; private EditText mResourceText; private SharedPreferences mSharedPreferences; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_baidu_compose); mResourceText = ((EditText) findViewById(R.id.bd_compose_text)); ((RadioGroup)findViewById(R.id.bd_compose_mode)).setOnCheckedChangeListener(this); findViewById(R.id.bd_compose_play).setOnClickListener(this); findViewById(R.id.bd_compose_cancel).setOnClickListener(this); findViewById(R.id.bd_compose_pause).setOnClickListener(this); findViewById(R.id.bd_compose_resume).setOnClickListener(this); findViewById(R.id.bd_compose_setting).setOnClickListener(this); mSharedPreferences = getSharedPreferences(SettingsActivity.PREFER_NAME, MODE_PRIVATE); initialEnv(); initialEngine(); } private void initialEnv() { if (mSampleDirPath == null) { String sdcardPath = Environment.getExternalStorageDirectory().toString(); mSampleDirPath = sdcardPath + "/" + SAMPLE_DIR_NAME; } File file = new File(mSampleDirPath); if (!file.exists()) { file.mkdirs(); } AssetsUtil.copyFromAssetsToSdcard(this, false, SPEECH_FEMALE_MODEL_NAME, mSampleDirPath + "/" + SPEECH_FEMALE_MODEL_NAME); AssetsUtil.copyFromAssetsToSdcard(this, false, SPEECH_MALE_MODEL_NAME, mSampleDirPath + "/" + SPEECH_MALE_MODEL_NAME); AssetsUtil.copyFromAssetsToSdcard(this, false, TEXT_MODEL_NAME, mSampleDirPath + "/" + TEXT_MODEL_NAME); AssetsUtil.copyFromAssetsToSdcard(this, false, LICENSE_FILE_NAME, mSampleDirPath + "/" + LICENSE_FILE_NAME); AssetsUtil.copyFromAssetsToSdcard(this, false, "english/" + ENGLISH_SPEECH_FEMALE_MODEL_NAME, mSampleDirPath + "/" + ENGLISH_SPEECH_FEMALE_MODEL_NAME); AssetsUtil.copyFromAssetsToSdcard(this, false, "english/" + ENGLISH_SPEECH_MALE_MODEL_NAME, mSampleDirPath + "/" + ENGLISH_SPEECH_MALE_MODEL_NAME); AssetsUtil.copyFromAssetsToSdcard(this, false, "english/" + ENGLISH_TEXT_MODEL_NAME, mSampleDirPath + "/" + ENGLISH_TEXT_MODEL_NAME); } private void initialEngine() { mSpeechSynthesizer = SpeechSynthesizer.getInstance(); mSpeechSynthesizer.setContext(this); mSpeechSynthesizer.setSpeechSynthesizerListener(mSpeechListener); ApplicationInfo appInfo = null; try { appInfo = this.getPackageManager().getApplicationInfo( getPackageName(), PackageManager.GET_META_DATA); String app_id = appInfo.metaData.getString("com.baidu.speech.APP_ID"); String api_key = appInfo.metaData.getString("com.baidu.speech.API_KEY"); String secret_key = appInfo.metaData.getString("com.baidu.speech.SECRET_KEY"); mSpeechSynthesizer.setAppId(app_id); mSpeechSynthesizer.setApiKey(api_key, secret_key); } catch (NameNotFoundException e) { e.printStackTrace(); showTip("獲得appid失敗"); } AuthInfo authInfo = mSpeechSynthesizer.auth(TtsMode.ONLINE); if (authInfo.isSuccess()) { showTip("auth success"); } else { String errorMsg = authInfo.getTtsError().getDetailMessage(); showTip("auth failed errorMsg=" + errorMsg); } mSpeechSynthesizer.initTts(TtsMode.MIX); bOnline = ((RadioButton) findViewById(R.id.bd_compose_online)).isChecked(); setParams(bOnline); } @Override protected void onDestroy() { // 退出時釋放連接 mSpeechSynthesizer.release(); super.onDestroy(); } @Override public void onClick(View v) { int resid = v.getId(); if (resid == R.id.bd_compose_setting) { Intent intent = new Intent(this, SettingsActivity.class); intent.putExtra("type", SettingsActivity.BD_COMPOSE); startActivity(intent); } else if (resid == R.id.bd_compose_play) { // 開始合成 speak(); } else if (resid == R.id.bd_compose_cancel) { // 取消合成 mSpeechSynthesizer.stop(); } else if (resid == R.id.bd_compose_pause) { // 暫停播放 mSpeechSynthesizer.pause(); } else if (resid == R.id.bd_compose_resume) { // 繼續播放 mSpeechSynthesizer.resume(); } } @Override public void onCheckedChanged(RadioGroup group, int checkedId) { if (checkedId == R.id.bd_compose_online) { bOnline = true; } else if (checkedId == R.id.bd_compose_offline) { bOnline = false; } Log.d(TAG, "bOnline="+bOnline); setParams(bOnline); } private void setParams(boolean online) { mSpeechSynthesizer.setAudioStreamType(AudioManager.STREAM_MUSIC); //setVolumeControlStream(AudioManager.STREAM_MUSIC); mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, mSharedPreferences.getString("bd_person_preference", "0")); //0--普通女聲,1--普通男聲,2--特別男聲,3--情感男聲 mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, mSharedPreferences.getString("bd_volume_preference", "5")); //音量,取值0⑼,默許為5中音量 mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, mSharedPreferences.getString("bd_speed_preference", "5")); //語速,取值0⑼,默許為5中語速 mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, mSharedPreferences.getString("bd_pitch_preference", "5")); //音調,取值0⑼,默許為5中腔調 mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_AUDIO_ENCODE, SpeechSynthesizer.AUDIO_ENCODE_AMR); mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_AUDIO_RATE, SpeechSynthesizer.AUDIO_BITRATE_AMR_15K85); if (online == true) { } else { // 文本模型文件路徑 (離線引擎使用) mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, mSampleDirPath + "/" + TEXT_MODEL_NAME); // 聲學模型文件路徑 (離線引擎使用) mSpeechSynthesizer.setParam(SpeechSynthesizer.PA
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 亚洲成人福利 | 欧美一级大片在线播放 | 国产精品一区二区三区四区 | 黄色免费看片 | 99久久免费看视频 | 你懂的福利 | 黄性视频 | 91久久久久 | 99精品在线观看视频 | 青草网| 国产黄av | 6699嫩草久久久精品影院 | 91麻豆精品久久久久蜜臀 | 国产精品久久久久久久久免费 | 欧美中文字幕一区二区三区亚洲 | 亚洲小视频 | 在线亚洲成人 | 国产精品6| 亚洲综合二 | 国产日韩一区二区 | 麻豆av在线免费 | 欧美精品成人 | 国产激情久久久久 | 国内av网站 | wwwav在线播放 | 福利片免费观看 | 91精品国产高清 | 伦视频 | 国产免费黄色 | 久久久网站 | 香蕉久久a毛片 | 亚洲国产高清视频 | 久久国产成人午夜av影院宅 | 91在线看免费| 久久久4久久久久8久久久久久 | 中文字幕首页 | 欧美成人精品一区二区男人看 | www精品美女久久久tv | 欧美另类视频在线 | 99精品欧美一区二区三区 | 日韩精品二区 |