Android百度语音集成——文字转语音

时间:2024-04-13 10:18:56

       项目涉及文字转语音的需求,用Android原生提供的TTS生成的语音太单调,机器声音太明显,故寻求第三方更好的支持,用科大讯飞的语音包收费,百度语音免费而且不限制调用次数,主页鲜明说永久免费的智能语音开放平台,故使用百度语音来支持。

    1.  地址: http://yuyin.baidu.com/,登录网址百度语音开发者平台,创建应用(图下方声明免费使用和无限制)。

        Android百度语音集成——文字转语音

 Android百度语音集成——文字转语音

      2.   建好应用之后就能得到AppId相关的信息。 

Android百度语音集成——文字转语音

   3.因为只需要文字转语音的功能,下载sdk得到的DEMO是一个大杂烩,于是把文字转语音的功能单独扣出来自定义封一个DEMO,效果如下,当语音引擎初始化成功后,播放按钮会变成红色,点击就会将显示的文字读出来:

Android百度语音集成——文字转语音

 

       4. 代码集成首先将官网SDK的DEMO中jar包放到app的libs下,assets离线资源和jniLibs放到src/main下,离线声音模型便来自assets中的.dat文件,jnilibs不必多说,是需要的so库。

Android百度语音集成——文字转语音

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.****.net/download/crystal_xing/10829418