1. 程式人生 > >Android百度語音整合——文字轉語音

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