20.5 语音合成(百度2016年2月29日发布的tts引擎)
分类:C#、Android、VS2015;
创建日期:2016-03-17
一、简介
编写手机App时,有时需要使用文字转语音(Text to Speech)的功能,比如开车时阅读收到的短信、导航语音提示、界面中比较重要的信息通过语音强调、……等。
由于Android自带的Pico TTS并不支持中文,所以要既能阅读中文文本,还能阅读英文文本,必须下载第三方提供的能说中文的语音包。
二、申请百度tts授权
本节以百度2016年2月29日发布的“离在线融合语音合成SDK_Android 2.2.3版”为例说明用C#实现语音合成的基本用法。之所以选择百度语音合成来实现,是因为据百度官网声明,该开发包是“永久免费”的。网址如下:
http://yuyin.baidu.com/tts/
由于原来已经申请过MyDemos的授权,所以再继续申请tts授权就比较简单了,申请和设置步骤如下。
1、申请授权
进入 http://yuyin.baidu.com/tts/ 的首页:

单击【立即使用】,进入“开通语音合成服务”的页面:
在下拉框中选择原来已经申请的某个应用,单击【下一步】,然后按提示操作,开通离线服务即可。
2、在BdMapV371BindingLib项目中转换JAR文件
先通过 http://yuyin.baidu.com/tts/ 首页中的【相关下载】下载对应的开发包,然后再按下面的步骤操作。
1、将示例中的com.baidu.tts_2.2.3.20160229_359d952_release.jar、galaxy-v2.0.jar添加到Jars文件夹下,如下图所示,然后将其【生成操作】属性全部设置为“EmbeddedJar”。

2、在Metadata.xml文件中添加下面的语句:
<remove-node path="/api/package[@name='com.baidu.tts.aop']/interface[@name='IProxyFactory']/method[@name='createProxied' and count(parameter)=0]" />
3、重新生成项目,此时应该无错误。
经过这3个步骤,就完成了tts的Jar包导入和转换为.cs文件的过程。
3、在MyDemos项目中添加.so文件
将tts相关的4个.so文件添加到MyDemos项目的x86文件夹下,如下图所示,然后将其【生成操作】属性全部设置为“AndroidNativeLibrary”。
4、将.dat文件添加到sd卡的BaiduTTS文件夹下
具体添加办法见【常见问题解答】,这里不再截图。
也可以先将这些文件添加到Assets文件夹下,然后通过代码将其复制到sd卡的文件夹下。为简化起见,这里通过手工直接复制了。
OK,经过上面这4步,以后就可以在MyDemos项目中的任何模块中轻松利用百度tts实现语音阅读的功能了
三、示例
1、运行截图
单击【阅读】,就会自动用女音朗读文本框中的内容,单击【批量阅读】,就会依次朗读队列中添加的文字段(主要是为了演示阅读各种不同的中英文短句)。
2、设计步骤
(1)添加ch2005Main.axml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:weightSum="4">
<Button
android:id="@+id/speak"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:lines="2"
android:text="阅读"
android:textSize="12dp" />
<Button
android:id="@+id/pause"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:lines="2"
android:text="暂停"
android:textSize="12dp" />
<Button
android:id="@+id/resume"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:lines="2"
android:text="继续"
android:textSize="12dp" />
<Button
android:id="@+id/stop"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:lines="2"
android:text="停止"
android:textSize="12dp" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:weightSum="4">
<Button
android:id="@+id/synthesize"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:lines="2"
android:text="synthesize"
android:textSize="12dp" />
<Button
android:id="@+id/play"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:lines="2"
android:text="play"
android:textSize="12dp" />
<Button
android:id="@+id/batchSpeak"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:lines="2"
android:text="批量阅读"
android:textSize="12dp" />
<Button
android:id="@+id/nextActivity"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:lines="2"
android:enabled="false"
android:text="备用"
android:textSize="12dp" />
</LinearLayout>
<EditText
android:id="@+id/input"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="input" />
<TextView
android:id="@+id/showText"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="10dp"
android:background="@android:color/darker_gray"
android:minLines="3"
android:scrollbars="vertical" />
</LinearLayout>
2、添加ch2005MainActivity.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using Android.App;
using Android.OS;
using Android.Widget;
using Com.Baidu.Tts.Client;
using Com.Baidu.Tts.Answer.Auth; namespace MyDemos.SrcDemos
{
[Activity(Label = "【例20-5】百度tts基本用法")]
public class ch2005MainActivity : Activity, ISpeechSynthesizerListener
{
private EditText mInput;
private TextView mShowText; private SpeechSynthesizer mSpeechSynthesizer; /// <summary>
/// sd卡上保存百度tts文件的路径
/// </summary>
private string mSampleDirPath; private const string SpeechFemaleModelName = "bd_etts_speech_female.dat";
private const string SpeechMaleModelName = "bd_etts_speech_male.dat";
private const string TextModelName = "bd_etts_text.dat";
private const string EnglishSpeechFemaleModelName = "bd_etts_speech_female_en.dat";
private const string EnglishSpeechMaleModelName = "bd_etts_speech_male_en.dat";
private const string EnglishTextModelName = "bd_etts_text_en.dat"; protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.ch2005Main);
mSampleDirPath = Android.OS.Environment.ExternalStorageDirectory.Path + "/baiduTTS";
Console.WriteLine("mSampleDirPath=" + mSampleDirPath);
initialView();
initialTts();
} private void initialTts()
{
mSpeechSynthesizer = SpeechSynthesizer.Instance;
mSpeechSynthesizer.SetContext(this);
mSpeechSynthesizer.SetSpeechSynthesizerListener(this);
// 文本模型文件路径 (离线引擎使用)
mSpeechSynthesizer.SetParam(SpeechSynthesizer.ParamTtsTextModelFile,
mSampleDirPath + "/" + TextModelName);
// 声学模型文件路径 (离线引擎使用)
mSpeechSynthesizer.SetParam(SpeechSynthesizer.ParamTtsSpeechModelFile,
mSampleDirPath + "/" + SpeechFemaleModelName); // 请替换为语音开发者平台上注册应用得到的App ID (离线授权)
//mSpeechSynthesizer.SetAppId("your_app_id");
mSpeechSynthesizer.SetAppId(ch.TtsAppID); // 请替换为语音开发者平台注册应用得到的apikey和secretkey (在线授权)
//this.mSpeechSynthesizer.SetApiKey("your_api_key", "your_secret_key");
this.mSpeechSynthesizer.SetApiKey(ch.TtsApiKey, ch.TtsSecretKey); // 发音人(在线引擎),可用参数为0,1,2,3。。。(服务器端会动态增加,各值含义参考文档,以文档说明为准。0--普通女声,1--普通男声,2--特别男声,3--情感男声。。。)
mSpeechSynthesizer.SetParam(SpeechSynthesizer.ParamSpeaker, "0");
// 设置Mix模式的合成策略
mSpeechSynthesizer.SetParam(SpeechSynthesizer.ParamMixMode, SpeechSynthesizer.MixModeDefault); // 授权检测接口(可以不使用,只是验证授权是否成功)
AuthInfo authInfo = this.mSpeechSynthesizer.Auth(TtsMode.Mix);
if (authInfo.IsSuccess)
{
Console.WriteLine("授权检测--授权成功(auth success)。");
}
else
{
string errorMsg = authInfo.TtsError.DetailMessage;
Console.WriteLine("授权检测--授权失败(auth failed),errorMsg=" + errorMsg);
} // 初始化tts
mSpeechSynthesizer.InitTts(TtsMode.Mix);
// 加载离线英文资源(提供离线英文合成功能)
int result = mSpeechSynthesizer.LoadEnglishModel(
mSampleDirPath +
"/" + EnglishTextModelName, mSampleDirPath +
"/" + EnglishSpeechFemaleModelName);
} private void initialView()
{
mInput = FindViewById<EditText>(Resource.Id.input);
mInput.Text = "今天阳光明媚,风和日丽!"; mShowText = FindViewById<TextView>(Resource.Id.showText); var speak = FindViewById<Button>(Resource.Id.speak);
speak.Click += delegate
{
string text = this.mInput.Text;
int result = this.mSpeechSynthesizer.Speak(text);
if (result < 0)
{
System.Diagnostics.Debug.WriteLine("出错了,错误码:{0},请检查百度tts文档中对应错误码的含义。", result);
}
}; var pause = FindViewById<Button>(Resource.Id.pause);
pause.Click += delegate
{
mSpeechSynthesizer.Pause();
}; var resume = FindViewById<Button>(Resource.Id.resume);
resume.Click += delegate
{
mSpeechSynthesizer.Resume();
}; var stop = FindViewById<Button>(Resource.Id.stop);
stop.Click += delegate
{
mSpeechSynthesizer.Stop();
}; var synthesize = FindViewById<Button>(Resource.Id.synthesize);
synthesize.Click += delegate
{
string text = this.mInput.Text;
int result = this.mSpeechSynthesizer.Synthesize(text);
if (result < 0)
{
System.Diagnostics.Debug.WriteLine("error,please look up error code in doc or URL:http://yuyin.baidu.com/docs/tts/122 ");
}
}; var play = FindViewById<Button>(Resource.Id.play);
play.Click += delegate { }; var batchSpeak = FindViewById<Button>(Resource.Id.batchSpeak);
batchSpeak.Click += delegate
{
List<SpeechSynthesizeBag> bags = new List<SpeechSynthesizeBag>();
bags.Add(GetSpeechSynthesizeBag("123456", "0"));
bags.Add(GetSpeechSynthesizeBag("你好", "1"));
bags.Add(GetSpeechSynthesizeBag("使用百度语音合成SDK", "2"));
bags.Add(GetSpeechSynthesizeBag("hello", "3"));
bags.Add(GetSpeechSynthesizeBag("这是一个demo工程", "4"));
int result = this.mSpeechSynthesizer.BatchSpeak(bags);
if (result < 0)
{
System.Diagnostics.Debug.WriteLine("error({0}),please look up error code in doc or URL:http://yuyin.baidu.com/docs/tts/122 ", result);
}
};
} protected override void OnDestroy()
{
base.OnDestroy();
} private SpeechSynthesizeBag GetSpeechSynthesizeBag(string text, string utteranceId)
{
SpeechSynthesizeBag speechSynthesizeBag = new SpeechSynthesizeBag();
speechSynthesizeBag.SetText(text);
speechSynthesizeBag.UtteranceId = utteranceId;
return speechSynthesizeBag;
} public void OnError(string utteranceId, SpeechError error)
{
Console.WriteLine("onError error=" + error.Description + "--utteranceId=" + utteranceId);
} public void OnSpeechFinish(string utteranceId)
{
Console.WriteLine("onSpeechFinish utteranceId=" + utteranceId);
} public void OnSpeechProgressChanged(string p0, int p1)
{
//Console.WriteLine("onSpeechProgressChanged");
} public void OnSpeechStart(string utteranceId)
{
Console.WriteLine("onSpeechStart utteranceId=" + utteranceId);
} public void OnSynthesizeDataArrived(string utteranceId, byte[] data, int progress)
{
Console.WriteLine("onSynthesizeDataArrived");
} public void OnSynthesizeFinish(string utteranceId)
{
Console.WriteLine("onSpeechFinish utteranceId=" + utteranceId);
} public void OnSynthesizeStart(string utteranceId)
{
Console.WriteLine("onSynthesizeStart utteranceId=" + utteranceId);
}
}
}
20.5 语音合成(百度2016年2月29日发布的tts引擎)的更多相关文章
- 2016年11月29日 星期二 --出埃及记 Exodus 20:20
		
2016年11月29日 星期二 --出埃及记 Exodus 20:20 Moses said to the people, "Do not be afraid. God has come t ...
 - 2016年12月29日 星期四 --出埃及记 Exodus 21:24
		
2016年12月29日 星期四 --出埃及记 Exodus 21:24 eye for eye, tooth for tooth, hand for hand, foot for foot,以眼还眼, ...
 - 2016年10月29日 星期六 --出埃及记 Exodus 19:14
		
2016年10月29日 星期六 --出埃及记 Exodus 19:14 After Moses had gone down the mountain to the people, he consecr ...
 - 2016年6月29日 星期三 --出埃及记 Exodus 14:26
		
2016年6月29日 星期三 --出埃及记 Exodus 14:26 Then the LORD said to Moses, "Stretch out your hand over the ...
 - Git学习(二)(2015年11月18日)(2016年1月29日)
		
2015年11月18日Git学习: .Shell 删除文件夹及其所有文件 rd/s/q 文件目录 ---------------当前为先创建本地Git库后与网上Git服务器关联------------ ...
 - WebForm控件--2016年12月29日
		
简单控件 1.Label => <span id="Label1">Label1</span> 2.Literal => Text 填 ...
 - 诚聘.NET架构师、高级开发工程师(2019年8月29日发布)
		
招聘单位是ABP架构设计交流群(134710707)群主阳铭所在的公司 公司简介 七二四科技有限公司成立于2015年,成立之初便由金茂资本按估值2亿投资2200万,进行“健康724”平台搭建,2017 ...
 - 优步UBER司机全国各地奖励政策汇总 (2月29日-3月6日)
		
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
 - [转载]Ubuntu17.04(Zesty Zapus)路线图发布:2017年4月13日发布
		
Canonical今天公布了Ubuntu 17.04(Zesty Zapus)操作系统的发布路线图,该版本于今年10月24日上线启动,toolchain已经上传且首个daily ISO镜像已经生成.面 ...
 
随机推荐
- 触发器二(DML触发器)(学习笔记)
			
DML触发器(语句触发器) 由DML语句进行触发,当用户执行了INSERT,UPDATE,DELETE操作时就会触发操作 示例一.只有在每个月的10日才允许办理,新员工入职与离职,其他时间不允许增加和 ...
 - iOS Dev (50)用代码实现图片加圆角
			
用代码实现图片加圆角: iconView.layer.masksToBounds = YES; iconView.;
 - 从Java的堆栈到Equals和==的比較
			
认识Java中堆和栈 栈与堆都是Java用来在Ram中存放数据的地方. 与C++不同.Java自己主动管理栈和堆,程序猿不能直接地设置栈或堆. Java的堆是一个执行时数据区,类的对象从中分配空间.这 ...
 - iOS自定义从底部弹上来的View
			
概述 自定义蒙层弹起View,点击一下遮罩或界面上关闭按钮,页面会自动下去(从上向下) 详细 代码下载:http://www.demodashi.com/demo/10724.html 在一些少数据没 ...
 - iOS-仿支付宝刮刮乐效果
			
概述 仿支付宝刮刮乐效果, 可以按照自己需求更改展示刮出来的效果的view(即刮开后刮刮乐效果展示) 详细 代码下载:http://www.demodashi.com/demo/10673.html ...
 - HDUOJ --2566
			
统计硬币 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
 - 浅谈软件配置管理工具(github & SVN)
			
1 配置管理名词定义 1.1 配置项 软件生存周期各个阶段活动的产物经审批后即可称之为软件配置项. 软件配置项包括: ①与合同.过程.计划和产品有关的文档和资料: ②源代码.目标代码和可执行代码: ...
 - 【LeetCode】9. Palindrome Number (2 solutions)
			
Palindrome Number Determine whether an integer is a palindrome. Do this without extra space. click t ...
 - 马老师 Linux基础入门
			
总线(Bus)是计算机各种功能部件之间传送信息的公共通信干线,它是由导线组成的传输线束, 按照计算机所传输的信息种类,计算机的总线可以划分为数据总线.地址总线和控制总线,分别用来传输数据.数据地址和控 ...
 - Java语言中的面向对象特性:封装、继承、多态,面向对象的基本思想(总结得不错)
			
Java语言中的面向对象特性(总结得不错) [课前思考] 1. 什么是对象?什么是类?什么是包?什么是接口?什么是内部类? 2. 面向对象编程的特性有哪三个?它们各自又有哪些特性? 3. 你知道jav ...