科大讯飞离线语音合成


转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


离线语音合成(离线资源包)

讯飞的语音合成有三种方式

  1. 在线语音合成(免费)
  2. 离线使用语记语音合成(免费,需要本地装一个语记App并且下载离线资源)
  3. 使用讯飞离线语音包(付费)

这里使用离线资源包实现离线语音合成,因为正式版是要付费的,所以这里使用试用的离线包(35天试用期、3个装机量)。

效果图

效果图

源码

下载地址(Android Studio工程):http://download.csdn.net/detail/q4878802/9063779

开通服务,下载SDK

之前已经介绍过,地址:http://blog.csdn.net/q4878802/article/details/47762169#t8

将SDK里提供的jar包、so库、离线资源都拷贝到我们的工程(Android Studio工程)

创建的工程默认可能没有jniLibs和assets目录,我们要自己在main下创建这两个目录

导入SDK

初始化

在清单文件中application标签下添加name属性

1
android:name=".InitApplication"

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.example.kongqw.kqwspeechcompounddemo;
import android.app.Application;
import android.widget.Toast;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechUtility;
/**
* Created by kongqw on 2015/8/29.
*/
public class InitApplication extends Application {
@Override
public void onCreate() {
Toast.makeText(this, "InitApplication", Toast.LENGTH_LONG).show();
// 应用程序入口处调用,避免手机内存过小,杀死后台进程后通过历史intent进入Activity造成SpeechUtility对象为null
// 如在Application中调用初始化,需要在Mainifest中注册该Applicaiton
// 注意:此接口在非主进程调用会返回null对象,如需在非主进程使用语音功能,请增加参数:SpeechConstant.FORCE_LOGIN+"=true"
// 参数间使用“,”分隔。
// 设置你申请的应用appid
StringBuffer param = new StringBuffer();
param.append("appid=55d33f09");
param.append(",");
param.append(SpeechConstant.ENGINE_MODE + "=" + SpeechConstant.MODE_MSC);
// param.append(",");
// param.append(SpeechConstant.FORCE_LOGIN + "=true");
SpeechUtility.createUtility(InitApplication.this, param.toString());
super.onCreate();
}
}

语音合成工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package com.example.kongqw.kqwspeechcompounddemo.engine;
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;
import com.iflytek.cloud.util.ResourceUtil;
import com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
/**
* 语音合成器
*
* @author kongqw
*/
public class KqwSpeechSynthesizer {
// Log标签
private static final String TAG = "KqwSpeechSynthesizer";
private Context mContext;
// 语音合成对象
private SpeechSynthesizer mTts;
public KqwSpeechSynthesizer(Context context) {
mContext = context;
// 初始化合成对象
mTts = SpeechSynthesizer.createSynthesizer(context, new InitListener() {
@Override
public void onInit(int code) {
Log.d(TAG, "InitListener init() code = " + code);
if (code != ErrorCode.SUCCESS) {
Toast.makeText(mContext, "初始化失败,错误码:" + code, Toast.LENGTH_SHORT).show();
}
}
});
}
/**
* 开始语音合成
*
* @param text
*/
public void start(String text) {
// 设置参数
setParam();
int code = mTts.startSpeaking(text, mTtsListener);
if (code != ErrorCode.SUCCESS) {
Toast.makeText(mContext, "语音合成失败,错误码: " + code, Toast.LENGTH_SHORT).show();
}
}
/**
* 合成回调监听。
*/
private SynthesizerListener mTtsListener = new SynthesizerListener() {
@Override
public void onSpeakBegin() {
Log.i(TAG, "开始合成");
}
@Override
public void onSpeakPaused() {
Log.i(TAG, "暂停合成");
}
@Override
public void onSpeakResumed() {
Log.i(TAG, "继续合成");
}
@Override
public void onBufferProgress(int percent, int beginPos, int endPos, String info) {
Log.i(TAG, "传冲进度 :" + percent);
}
@Override
public void onSpeakProgress(int percent, int beginPos, int endPos) {
Log.i(TAG, "合成进度 : " + percent);
}
@Override
public void onCompleted(SpeechError error) {
if (error == null) {
Log.i(TAG, "合成完成");
} else if (error != null) {
Log.i(TAG, "error : " + error.toString());
}
}
@Override
public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
// TODO Auto-generated method stub
}
};
/**
* 参数设置
*
* @return
*/
private void setParam() {
// 清空参数
mTts.setParameter(SpeechConstant.PARAMS, null);
// 设置使用本地引擎
mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
// 设置发音人资源路径
mTts.setParameter(ResourceUtil.TTS_RES_PATH, getResourcePath());
// 设置发音人
mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");
// 设置语速
mTts.setParameter(SpeechConstant.SPEED, "50");
// 设置音调
mTts.setParameter(SpeechConstant.PITCH, "50");
// 设置音量
mTts.setParameter(SpeechConstant.VOLUME, "50");
// 设置播放器音频流类型
mTts.setParameter(SpeechConstant.STREAM_TYPE, "3");
}
// 获取发音人资源路径
private String getResourcePath() {
StringBuffer tempBuffer = new StringBuffer();
// 合成通用资源
tempBuffer.append(ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.assets, "tts/common.jet"));
tempBuffer.append(";");
// 发音人资源
tempBuffer.append(ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.assets, "tts/xiaoyan.jet"));
return tempBuffer.toString();
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.example.kongqw.kqwspeechcompounddemo;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.example.kongqw.kqwspeechcompounddemo.engine.KqwSpeechSynthesizer;
public class MainActivity extends Activity {
private EditText mEtText;
private KqwSpeechSynthesizer mKqwSpeechSynthesizer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEtText = (EditText) findViewById(R.id.et_text);
// 初始化语音合成对象
mKqwSpeechSynthesizer = new KqwSpeechSynthesizer(this);
}
/**
* 开始合成
*
* @param view
*/
public void start(View view) {
Toast.makeText(this, "开始合成 : " + mEtText.getText().toString().trim(), Toast.LENGTH_SHORT).show();
mKqwSpeechSynthesizer.start(mEtText.getText().toString().trim());
}
}

XML页面布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<EditText
android:id="@+id/et_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="语音合成的内容"
android:textSize="20dp" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/et_text"
android:gravity="center"
android:onClick="start"
android:text="语音合成"
android:textSize="20dp" />
</RelativeLayout>

说明

因为我用的是离线资源包,试用期是有35天并且只有3个装机量,所以如果直接使用我的demo可能会有问题,如果要自己再创建一个工程,千万不要忘记替换APPID、库、离线资源。

坚持原创技术分享,您的支持将鼓励我继续创作!