語音聽寫與合成--(訊飛語音識別與合成&&百度語音識別)

目前比較厲害的國內免費開源的語音識別庫主要就是:訊飛和百度,本篇博客也是關於這兩家SDK的使用。

訊飛語音開放平臺:http://doc.xfyun.cn/msc_android/299547

訊飛平臺下載的sdk有doc文件夾,其中有html結尾的API文件,需要的去官網可以下載

本篇博客Demo地址:http://download.csdn.net/download/g_ying_jie/9895905


訊飛語音聽寫功能:

第一步、集成SDK,配置權限文檔已經介紹的很清楚了,Demo也可以下下來直接運行。類似於以下目錄結構



第二步、實例化語音聽寫對象和UI。該dialog資源需要用到assets的資源

    // 語音聽寫對象
    private SpeechRecognizer mIat = SpeechRecognizer.createRecognizer(VoiToTxtActivity.this, mInitListener);
    // 語音聽寫UI
    private RecognizerDialog mIatDialog = new RecognizerDialog(VoiToTxtActivity.this, mInitListener);

/**
     * 初始化監聽器。
     */
    private InitListener mInitListener = new InitListener() {

        @Override
        public void onInit(int code) {
            Log.d(TAG, "SpeechRecognizer init() code = " + code);
            if (code != ErrorCode.SUCCESS) {
                showTip("初始化失敗,錯誤碼:" + code);
            }
        }
    };


第三步、設置參數

/**
     * 參數設置
     */
    public void setParam() {
        // 清空參數
        mIat.setParameter(SpeechConstant.PARAMS, null);

        // 設置聽寫引擎
        mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
        // 設置返回結果格式
        mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");

        // 設置語言
        mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        // 設置語言區域
        mIat.setParameter(SpeechConstant.ACCENT, "mandarin");

        // 設置語音前端點:靜音超時時間,即用戶多長時間不說話則當做超時處理
        mIat.setParameter(SpeechConstant.VAD_BOS, "5000");

        // 設置語音後端點:後端點靜音檢測時間,即用戶停止說話多長時間內即認爲不再輸入, 自動停止錄音
        mIat.setParameter(SpeechConstant.VAD_EOS, "1800");

        // 設置標點符號,設置爲"0"返回結果無標點,設置爲"1"返回結果有標點
        mIat.setParameter(SpeechConstant.ASR_PTT, "1");

        // 設置音頻保存路徑,保存音頻格式支持pcm、wav,設置路徑爲sd卡請注意WRITE_EXTERNAL_STORAGE權限
        //mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        //mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav");
    }

第四步、開始聽寫識別

	// 顯示聽寫對話框
	mIatDialog.setListener(mRecognizerDialogListener);
	mIatDialog.show();
	/**
     	* 聽寫UI監聽器
     	*/
    private RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
        public void onResult(RecognizerResult results, boolean isLast) {
            printResult(results);
        }

        /**
         * 識別回調錯誤.
         */
        public void onError(SpeechError error) {
            showTip(error.getPlainDescription(true));
        }

    };
	//解析返回的識別結果
    private void printResult(RecognizerResult results) {
        String text = JsonParser.parseIatResult(results.getResultString());

        String sn = null;
        // 讀取json結果中的sn字段
        try {
            JSONObject resultJson = new JSONObject(results.getResultString());
            sn = resultJson.optString("sn");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        mIatResults.put(sn, text);

        StringBuffer resultBuffer = new StringBuffer();
        for (String key : mIatResults.keySet()) {
            resultBuffer.append(mIatResults.get(key));
        }

        mResultText.setText(resultBuffer.toString());
        mResultText.setSelection(mResultText.length());
    }
注意:這裏用HashMap來存儲聽寫結果

	// 用HashMap存儲聽寫結果
    private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();


最後、在onDestroy中做好回收工作

 @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != mIat) {
            // 退出時釋放連接
            mIat.cancel();
            mIat.destroy();
        }
    }

訊飛針對詞組優化提供了上傳聯繫人和詞表的方法

①上傳聯繫人並使用mResultText展示給用戶

    ContactManager mgr = ContactManager.createManager(VoiToTxtActivity.this, mContactListener);
    mgr.asyncQueryAllContactsName();

    /**
     * 獲取聯繫人監聽器。
     */
    private ContactListener mContactListener = new ContactListener() {

        @Override
        public void onContactQueryFinish(final String contactInfos, boolean changeFlag) {
            // 注:實際應用中除第一次上傳之外,之後應該通過changeFlag判斷是否需要上傳,否則會造成不必要的流量.
            // 每當聯繫人發生變化,該接口都將會被回調,可通過ContactManager.destroy()銷燬對象,解除回調。
            // if(changeFlag) {
            // 指定引擎類型
            runOnUiThread(new Runnable() {
                public void run() {
                    mResultText.setText(contactInfos);
                }
            });

            mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
            mIat.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
            ret = mIat.updateLexicon("contact", contactInfos, mLexiconListener);
            if (ret != ErrorCode.SUCCESS) {
                showTip("上傳聯繫人失敗:" + ret);
            }
        }
    };

②上傳用戶詞組

String contents = FucUtil.readFile(VoiToTxtActivity.this, "userwords","utf-8");
mResultText.setText(contents);
// 指定引擎類型
mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
mIat.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
ret = mIat.updateLexicon("userword", contents, mLexiconListener);
if (ret != ErrorCode.SUCCESS)
showTip("上傳熱詞失敗,錯誤碼:" + ret);
/**
     * 上傳聯繫人/詞表監聽器。
     */
    private LexiconListener mLexiconListener = new LexiconListener() {

        @Override
        public void onLexiconUpdated(String lexiconId, SpeechError error) {
            if (error != null) {
                showTip(error.toString());
            } else {
                showTip("上傳成功");
            }
        }
    };

訊飛語音合成:

第一步,實例化語音合成對象和雲端發音人列表

// 語音合成對象
private SpeechSynthesizer mTts = SpeechSynthesizer.createSynthesizer(TxtToVoiActivity.this, mTtsInitListener);
// 默認發音人
private String voicer = "xiaoyan";
private String[] mCloudVoicersEntries = getResources().getStringArray(R.array.voicer_cloud_entries);
private String[] mCloudVoicersValue = getResources().getStringArray(R.array.voicer_cloud_values);

/**
  * 初始化監聽。
  */
private InitListener mTtsInitListener = new InitListener() {
        @Override
        public void onInit(int code) {
            if (code != ErrorCode.SUCCESS) {
                showTip("初始化失敗,錯誤碼:" + code);
            } else {
                // 初始化成功,之後可以調用startSpeaking方法
                // 注:有的開發者在onCreate方法中創建完合成對象之後馬上就調用startSpeaking進行合成,
                // 正確的做法是將onCreate中的startSpeaking調用移至這裏
            }
        }
};
res文件夾下的Strings配置如下

<string-array name="voicer_cloud_entries">
        <item>小燕—女青、中英、普通話</item>
        <item>小宇—男青、中英、普通話</item>
        <item>小研—女青、中英、普通話</item>
        <item>小琪—女青、中英、普通話</item>
        <item>小峯—男青、中英、普通話</item>
        <item>小梅—女青、中英、粵語</item>
        <item>小莉—女青、中英、臺灣普通話</item>
</string-array>

<string-array name="voicer_cloud_values">
        <item>xiaoyan</item>
        <item>xiaoyu</item>
        <item>vixy</item>
        <item>xiaoqi</item>
        <item>vixf</item>
        <item>vixm</item>
        <item>vixl</item>
</string-array>

第二步,設置識別參數

private int selectedNum = 0;

/**
* 發音人選擇。
*/
private void showPersonSelectDialog() {
        new AlertDialog.Builder(this)
                .setTitle("在線合成發音人選項")
                /*
                *   CharSequence[] 單選框有幾項,各是什麼名字
                *   checkedItem 默認的選項
                *   listener 點擊單選框後的回調
                * */
                .setSingleChoiceItems(mCloudVoicersEntries, selectedNum, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        // 點擊了哪一項
                        voicer = mCloudVoicersValue[which];
                        selectedNum = which;
                        dialog.dismiss();
                    }
                }).show();
}

/**
  * 參數設置
  */
private void setParam() {
        // 清空參數
        mTts.setParameter(SpeechConstant.PARAMS, null);
        // 根據合成引擎設置相應參數
        mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
        // 設置在線合成發音人
        mTts.setParameter(SpeechConstant.VOICE_NAME, voicer);
        //設置合成語速
        mTts.setParameter(SpeechConstant.SPEED, "50");
        //設置合成音調
        mTts.setParameter(SpeechConstant.PITCH, "50");
        //設置合成音量
        mTts.setParameter(SpeechConstant.VOLUME, "50");
        //設置播放器音頻流類型 值範圍:android.media.AudioManager支持的流類型值
        mTts.setParameter(SpeechConstant.STREAM_TYPE, "3");
        // 設置播放合成音頻打斷音樂播放,默認爲true
        mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");

        // 設置音頻保存路徑,保存音頻格式支持pcm、wav,設置路徑爲sd卡請注意WRITE_EXTERNAL_STORAGE權限
        // 注:AUDIO_FORMAT參數語記需要更新版本才能生效
        mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/tts.wav");
}
第三步,獲取待合成的文字內容,開始合成語音

String text = ((EditText) findViewById(R.id.tts_text)).getText().toString();
/*
*   只保存音頻不調用播放接口時請註釋startSpeaking接口
*   text:要合成的文本
*   listener:回調接口
*   uri:需要保存的音頻全路徑
*/
//String path = Environment.getExternalStorageDirectory()+"/tts.pcm";
//int code = mTts.synthesizeToUri(text, path, mTtsListener);

int code = mTts.startSpeaking(text, mTtsListener);
if (code != ErrorCode.SUCCESS) {
        showTip("語音合成失敗,錯誤碼: " + code);
}

/**
* 合成回調監聽。
*/
private SynthesizerListener mTtsListener = 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("緩衝進度爲%d%%,播放進度爲%d%%", mPercentForBuffering, mPercentForPlaying));
        }

        @Override
        public void onSpeakProgress(int percent, int beginPos, int endPos) {
            // 播放進度
            mPercentForPlaying = percent;
            showTip(String.format("緩衝進度爲%d%%,播放進度爲%d%%", 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);
            //	}
        }
};

其他的比較有用的方法:

// 取消合成
mTts.stopSpeaking();
// 暫停播放
mTts.pauseSpeaking();
// 繼續播放
mTts.resumeSpeaking();

好了到此訊飛在線語音就介紹完了,詳細的使用可以下載我上傳的Demo。這裏爲什麼強調在線呢?因爲訊飛的離線語音識別服務需要下載語記APP以及對應的離線數據包,而且離線識別只能適用於安卓平臺,因此只是嘗試了沒有深入研究就不貼出來了。


百度語音篇

百度語音基礎視頻介紹:https://chuanke.baidu.com/v7867982-208144-1278714.html

百度語音識別API對接視頻:https://chuanke.baidu.com/v7867982-209753-1294636.html

百度語音文檔中心:http://ai.baidu.com/docs#/ASR-Android-SDK/top

本篇博客Demo:http://download.csdn.net/detail/g_ying_jie/9890613

百度的SDK是離在線融合的(可是沒研究出來離線識別,需要開通離線授權,巴拉巴拉。。。委屈。如果有哪位大神弄出來了,希望也能夠共享出來)

百度自定義了一個語音識別組件,所以基本一句話就可以實現語音識別的流程

第一步、開始識別

private void start() {
        Intent recognizerIntent = new Intent(MainActivity.this, BaiduASRDigitalDialog.class);
        //採樣率
        recognizerIntent.putExtra(Constant.EXTRA_SAMPLE, 16000);
        //識別語種
        recognizerIntent.putExtra(Constant.EXTRA_LANGUAGE, "cmn-Hans-CN");
        //設置語言活動模式   input輸入模式search搜索模式
        recognizerIntent.putExtra(Constant.EXTRA_VAD, "input");

        /*//說話開始的提示音
        recognizerIntent.putExtra(Constant.EXTRA_SOUND_START, R.raw.bdspeech_recognition_start);
        //說話結束的提示音
        recognizerIntent.putExtra(Constant.EXTRA_SOUND_END, R.raw.bdspeech_speech_end);
        //識別成功的提示音
        recognizerIntent.putExtra(Constant.EXTRA_SOUND_SUCCESS, R.raw.bdspeech_recognition_success);
        //識別出錯的提示音
        recognizerIntent.putExtra(Constant.EXTRA_SOUND_ERROR, R.raw.bdspeech_recognition_error);
        //識別取消的提示音
        recognizerIntent.putExtra(Constant.EXTRA_SOUND_CANCEL, R.raw.bdspeech_recognition_cancel);
        //語義識別
        recognizerIntent.putExtra(Constant.EXTRA_NLU, "enable");*/


        startActivityForResult(recognizerIntent, 1);
    }

第二步、處理識別結果

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            textView.setText(data.getExtras().getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION).get(0));
        }
    }

注意:BaiduASRDigitalDialog需要與之配套的res資源,而且該資源都是放於drawable文件夾下,不能粗暴的將圖片資源複製到mipmap中,使用Android studio的開發者一定要注意(樓主已經入坑)


Demo都上傳到了csdn上面,有需要的可以下載運行,不需要積分。有問題或者建議歡迎在評論區留言




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章