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);
        }
    }
}
时间: 2024-11-04 13:29:46

20.5 语音合成(百度2016年2月29日发布的tts引擎)的相关文章

pfSense 2.3于2016年4月12日发布

pfSense 2.3于2016年4月12日发布,pfsense 2.3基于freebsd 10.3,是目前非常优秀的防火墙,路由器开源软件. 下载地址:http://www.pfsense.org/mirror.php?section=downloads 首次使用可以下载完整安装版,目前完整安装版取消livecd模式,需要安装到存储才能正常运行.已经安装的可以在线升级,也可以下载手动升级包. 最新的pfsense咨询来自51cto网站的morehd玩家.

软考信息系统监理师:2016年4月29日作业

软考信息系统监理师:2016年4月29日作业一.信息应用系统分析设计阶段监理1.需求分析的进入条件是什么?(记)2.需求分析的目标是什么?3.需求分析阶段的成果有哪些?(记)4.软件概要设计阶段的进入条件是什么?(记,并理解:加不加概要2字,答案均相同)5.软件详细设计阶段的进入条件是什么?6.描述算法除了流程图外,还有一些别的工具,如哪3种?7.软件设计阶段的成果是什么?(记)8.软件工程化要求以软件质量保证为核心,紧紧抓住哪8个主要环节?二.信息应用系统实施阶段监理1.编码阶段进入条件是什么

2016年04月29日【EPM-易通元】最新价位公布

2016年04月29日[EPM-易通元]最新价位公布   涨了.涨了.又涨了!   我们的「EPM易通元」天天见涨!太给力了!!   2016.04.29日今天已涨0,01美金,目前已到0.35美金啦!   如果你有1000个易通元,你今天就收益10美金   如果你有10000个易通元,今天就收益100美金   如果你有100000个易通元,你今天就收益1000美金.   恭喜买到「EPM易通元」的朋友们,买到即是赚到!   买入210美金到3500美金 :1美金:6.3人民币兑换,举例买入35

2016年5月29日周总结

本周的周二时,算是重新制定了2016年目标和未来五年的职业规划情况,很可惜有不少地方无法落实到实处.比如,目标太多,涉及面太广,而平时自己的时间少,导致很多会无法完成甚至开始干都没法干. 每周周一到周六晚上会加班到十点半以后,回家再洗漱休息一下,看会书或者查点资料,就要过了零点了,接着就要睡觉休息了,第二天还要七点以前起床,七点四十到办公室.在上班的时间倒是很想看会想看的书,却发现事情太杂太多,电话一个接一个,事情一个接一个,根本没法静下心来. 很矛盾,很纠结煎熬,但是没办法,这就是工作和生活的

C++第十天笔记2016年02月29日(周一)A.M

1.把子类对象作为父类对象使用: 1.1  前提:继承方式必须公有. 1.2 将子类对象用作父类对象. 1.2.1 将子类对象赋值给父类对象. 1.2.2 将父类引用指向子类对象.(即用派生类对象初始化基类引用) 1 #include <iostream> 2 using namespace std; 3 4 class Base{ 5 public: 6 Base(){} 7 Base(int b):_b(b){} 8 void func(){cout<<"b:&quo

2016年5月29日下午(传智Bootstrap(笔记二))

一.Bootstrap 排版 1.行内文本样式 <b>.<strong>.<i>.<em>.<del>. Bootstrap 提供了一些用于强调文本的类,如下面实例所示: <small>本行内容是在标签内</small><br> <strong>本行内容是在标签内</strong><br> <em>本行内容是在标签内,字体为斜体</em><br&

Linux运维学习-5——2016年7月29日

格式说明: 操作 概念 命令 说明及举例 五 索引节点 原数据保存在inode table表中每个文件或目录都有一个独立的inode number(节点编号在一个分区中是唯一的,每个分区都有自己的inode table) ls -i 查看节点编号 硬链接 ln f1 dir/f11 为f1文件创建硬链接并放到dir文件夹下,名称为f11.跨设备跨分区不能创建. 链接数=文件名字的数量,为一个文件创建多个硬链接相当于给一个文件取了多个名字,修改任何一个文件都等于全部修改,删除其中一个硬链接,只相当

C++第四天笔记2016年01月29日(周五)A.M

1.   类的静态成员 静态局部变量: (1)    静态局部变量的空间并非在栈区. (2)    静态局部变量可以保留上一次函数调用时的计算结果,这与全局变量很相似,但是静态局部变量只能在当前函数体内可见. (3)    静态局部变量如果未进行初始化,会被编译器初始化为0. 静态变量的声明只会执行一次,以保证static静态变量只有一块空间 静态成员变量的初始化放在类定义之外单独做初始化,基本格式:类型 类名: : 静态成员变量名 例: int Employee::next_id = 0;//

第19天 树莓派3b安装kali linux~2016年9月29日 13:37:29

1.~~~~烧录系统这部很简单:系统下载地址:https://images.offensive-security.com/arm-images/kali-2.1.2-rpi2.img.xz 2.树莓派默认没有完全扩充到sd卡的所有内存.需要扩展分区 #df -hl查看系统分区,看到32G的内存卡只用到6.7G,大概还有23G的内存没有被识别· 如何让树莓派识别全部的内存: #sudo fdisk /dev/mmcblk0 按p 将看到的分区复制下来/dev/mmcblkop2的start值,12