集成Android免费语音合成功能(在线、离线、离在线融合),有这一篇文章就够了(离线)

原址

集成Android免费语音合成功能(在线、离线、离在线融合),有这一篇文章就够了(在线)

集成Android免费语音合成功能(在线、离线、离在线融合),有这一篇文章就够了(离在线融合)


    上一篇是写的在线语音合成,用的是科大讯飞的SDK,因为在线是需要网络的,所以离线也是有需求的,至于为什么不直接用离在线,下一篇再告诉大家,这里先卖个关子,这一篇就写离线语音合成,用的是云知声的SDK。

首先,打开云知声开放平台


然后,注册、登录(图略)

接着打开我的应用,添加新应用,选择通用解决方案


添加新应用后,选择Android,离线语音合成,点击下载



下载完成后,解压压缩包USCDemo文件夹

打开USCDemo-->assets-->OfflineTTSModels,选择复制2个文件(离线语音合成模型到你项目中的assets资源目录下


打开USCDemo-->libs,复制jar包和.so文件到你的项目libs目录下


注意:需要在build.gradle增加如下图所示代码(注意层级),不然编译时会报错找不到.so文件(如下图左上角箭头修改项目结构为Project,然后找到在app目录下的build.gradle文件进行修改)

[html]  view plain  copy
  1. repositories {  
  2.     flatDir {  
  3.         dir 'libs'  
  4.     }  
  5. }  
[html]  view plain  copy
  1. sourceSets {  
  2.     main {  
  3.         jniLibs.srcDir 'libs'  
  4.     }  
  5. }  

做完以上准备工作,就可以开始撸代码了

    首先,AndroidManifest.xml申请权限(6.0需要动态申请权限,碍于篇幅,请自行百度)
[html]  view plain  copy
  1. <uses-permission android:name="android.permission.RECORD_AUDIO"/>  
  2. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>  
  3. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>  
  4. <uses-permission android:name="android.permission.INTERNET"/>  
  5. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  
  6. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>  
  7. <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />  
  8. <uses-permission android:name="android.permission.READ_PHONE_STATE"/>  
  9. <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />  
  10. <uses-permission android:name="android.permission.READ_CONTACTS"/>  
  11. <uses-permission android:name="android.permission.WAKE_LOCK" />  
  12. <uses-permission android:name="android.permission.VIBRATE" />  
    然后,直接封装成工具类,以供全局调用离线语音合成功能,大家可以直接复制进去用,其中APPKEY和SECRET在开放平台-->我的应用,点击你之前添加的应用可查看

[java]  view plain  copy
  1. package com.cyf.ttsdemo.utils;  
  2.   
  3. import android.content.Context;  
  4. import android.os.Environment;  
  5. import android.util.Log;  
  6.   
  7. import com.cyf.ttsdemo.MyApplication;  
  8. import com.unisound.client.SpeechConstants;  
  9. import com.unisound.client.SpeechSynthesizer;  
  10. import com.unisound.client.SpeechSynthesizerListener;  
  11.   
  12. import java.io.File;  
  13. import java.io.FileOutputStream;  
  14. import java.io.IOException;  
  15. import java.io.InputStream;  
  16.   
  17. /** 
  18.  * Created by As on 2017/8/7. 
  19.  */  
  20.   
  21. public class TTSUtils implements SpeechSynthesizerListener {  
  22.   
  23.     private static final String TAG = "TTSUtils";  
  24.     private static volatile TTSUtils instance = null;  
  25.     private boolean isInitSuccess = false;  
  26.     private SpeechSynthesizer mTTSPlayer;  
  27.   
  28.     private static final String SAMPLE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/unisound/tts/";  
  29.     private static final String FRONTEND_MODEL = "frontend_model";  
  30.     private static final String BACKEND_MODEL = "backend_lzl";  
  31.   
  32.     private static final String APPKEY = "wiouzjcsmxvqes7ibqqm5bcgqrzrvddsvtceiwa5";  
  33.     private static final String SECRET = "3e20d7aff586ffe7dce62b302e7cc378";  
  34.   
  35.     private TTSUtils() {  
  36.     }  
  37.   
  38.     public static TTSUtils getInstance() {  
  39.         if (instance == null) {  
  40.             synchronized (TTSUtils.class) {  
  41.                 if (instance == null) {  
  42.                     instance = new TTSUtils();  
  43.                 }  
  44.             }  
  45.         }  
  46.         return instance;  
  47.     }  
  48.   
  49.     public void init() {  
  50.         Context context = MyApplication.getContext();  
  51.         mTTSPlayer = new SpeechSynthesizer(context, APPKEY, SECRET);  
  52.         mTTSPlayer.setOption(SpeechConstants.TTS_SERVICE_MODE, SpeechConstants.TTS_SERVICE_MODE_LOCAL); // 设置本地合成  
  53.     File file = new File(SAMPLE_DIR);  
  54.         if (!file.exists()) {  
  55.             file.mkdirs();  
  56.         }  
  57.         File _FrontendModelFile = new File(SAMPLE_DIR + FRONTEND_MODEL);  
  58.         if (!_FrontendModelFile.exists()) {  
  59.             copyAssetsFile2SDCard(context, FRONTEND_MODEL, SAMPLE_DIR + FRONTEND_MODEL);  
  60.         }  
  61.         File _BackendModelFile = new File(SAMPLE_DIR + BACKEND_MODEL);  
  62.         if (!_BackendModelFile.exists()) {  
  63.             copyAssetsFile2SDCard(context, BACKEND_MODEL, SAMPLE_DIR + BACKEND_MODEL);  
  64.         }  
  65.         mTTSPlayer.setOption(SpeechConstants.TTS_KEY_FRONTEND_MODEL_PATH, SAMPLE_DIR + FRONTEND_MODEL);// 设置前端模型  
  66.         mTTSPlayer.setOption(SpeechConstants.TTS_KEY_BACKEND_MODEL_PATH, SAMPLE_DIR + BACKEND_MODEL);// 设置后端模型  
  67.         mTTSPlayer.setTTSListener(this);// 设置回调监听  
  68.         mTTSPlayer.init(null);// 初始化合成引擎  
  69.     }  
  70.   
  71.     public void speak(String msg) {  
  72.         if (isInitSuccess) {  
  73.             mTTSPlayer.playText(msg);  
  74.         }else {  
  75.             init();  
  76.         }  
  77.     }  
  78.   
  79.     public void stop() {  
  80.         mTTSPlayer.stop();  
  81.     }  
  82.   
  83.     public void pause() {  
  84.         mTTSPlayer.pause();  
  85.     }  
  86.   
  87.     public void resume() {  
  88.         mTTSPlayer.resume();  
  89.     }  
  90.   
  91.     public void release() {  
  92.         if (null != mTTSPlayer) {  
  93.             // 释放离线引擎  
  94.             mTTSPlayer.release(SpeechConstants.TTS_RELEASE_ENGINE, null);  
  95.         }  
  96.     }  
  97.   
  98.     @Override  
  99.     public void onEvent(int type) {  
  100.         switch (type) {  
  101.             case SpeechConstants.TTS_EVENT_INIT:  
  102.                 isInitSuccess = true;  
  103.                 break;  
  104.             case SpeechConstants.TTS_EVENT_SYNTHESIZER_START:  
  105.                 // 开始合成回调  
  106.                 Log.i(TAG, "beginSynthesizer");  
  107.                 break;  
  108.             case SpeechConstants.TTS_EVENT_SYNTHESIZER_END:  
  109.                 // 合成结束回调  
  110.                 Log.i(TAG, "endSynthesizer");  
  111.                 break;  
  112.             case SpeechConstants.TTS_EVENT_BUFFER_BEGIN:  
  113.                 // 开始缓存回调  
  114.                 Log.i(TAG, "beginBuffer");  
  115.                 break;  
  116.             case SpeechConstants.TTS_EVENT_BUFFER_READY:  
  117.                 // 缓存完毕回调  
  118.                 Log.i(TAG, "bufferReady");  
  119.                 break;  
  120.             case SpeechConstants.TTS_EVENT_PLAYING_START:  
  121.                 // 开始播放回调  
  122.                 Log.i(TAG, "onPlayBegin");  
  123.                 break;  
  124.             case SpeechConstants.TTS_EVENT_PLAYING_END:  
  125.                 // 播放完成回调  
  126.                 Log.i(TAG, "onPlayEnd");  
  127.                 break;  
  128.             case SpeechConstants.TTS_EVENT_PAUSE:  
  129.                 // 暂停回调  
  130.                 Log.i(TAG, "pause");  
  131.                 break;  
  132.             case SpeechConstants.TTS_EVENT_RESUME:  
  133.                 // 恢复回调  
  134.                 Log.i(TAG, "resume");  
  135.                 break;  
  136.             case SpeechConstants.TTS_EVENT_STOP:  
  137.                 // 停止回调  
  138.                 Log.i(TAG, "stop");  
  139.                 break;  
  140.             case SpeechConstants.TTS_EVENT_RELEASE:  
  141.                 // 释放资源回调  
  142.                 Log.i(TAG, "release");  
  143.                 break;  
  144.             default:  
  145.                 break;  
  146.         }  
  147.     }  
  148.   
  149.     @Override  
  150.     public void onError(int type, String errorMSG) {  
  151.         Log.e(TAG, "语音合成错误回调: " + errorMSG);  
  152.     }  
  153.   
  154.     public static void copyAssetsFile2SDCard(Context context, String fileName, String path) {  
  155.         try {  
  156.             InputStream is = context.getAssets().open(fileName);  
  157.             FileOutputStream fos = new FileOutputStream(new File(path));  
  158.             byte[] buffer = new byte[1024];  
  159.             int byteCount = 0;  
  160.             while ((byteCount = is.read(buffer)) != -1) {// 循环从输入流读取buffer字节  
  161.                 fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流  
  162.             }  
  163.             fos.flush();// 刷新缓冲区  
  164.             is.close();  
  165.             fos.close();  
  166.         } catch (IOException e) {  
  167.             Log.e(TAG, "copyAssetsFile2SDCard: " + e.toString());  
  168.         }  
  169.     }  
  170.   
  171. }  


    同样的需要新建MyApplication.java进行预初始化离线语音合成功能
[java]  view plain  copy
  1. package com.cyf.ttsdemo;  
  2.   
  3. import android.app.Application;  
  4. import android.content.Context;  
  5.   
  6. import com.cyf.ttsdemo.utils.TTSUtils;  
  7.   
  8. /** 
  9.  * Created by As on 2017/8/7. 
  10.  */  
  11.   
  12. public class MyApplication extends Application{  
  13.   
  14.     private static Context context;  
  15.   
  16.     @Override  
  17.     public void onCreate() {  
  18.         super.onCreate();  
  19.         context = getApplicationContext();  
  20.         TTSUtils.getInstance().init();  
  21.     }  
  22.   
  23.     public static Context getContext(){  
  24.         return context;  
  25.     }  
  26. }  
    最后,别忘了在AndroidManifest.xml文件中注册该Application
    好的,这样就大功告成了,在需要进行语音合成的地方调用TTSUtils.getInstance().speak("xxx")即可

    注意:离线语音合成因为需要复制文件到SD卡中,所以初始化是比较耗时的,这就有可能造成有一些情况:初始化还未完成,但调用了语音合成方法没有声音的情况,而我在代码中并未处理,所以有遇到类似情况的,可以自己琢磨处理一下。
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值