一. 简单介绍

在上一篇里

http://blog.csdn.net/ichliebephone/archive/2010/08/14/5811562.aspx

我们介绍了TTS可以把合成的语音直接保存为音频文件的功能。

在这篇里我们接着上一篇的内容,介绍AndroidTTS的另一个功能,为一段文本关联一个音频文件,即允许为一段文本内容指定自定义的发音。

这个功能对应的函数有两个,一个为:

publicint addSpeech ( String text, String filename)

第一个参数为要关联的文本,比如 "south_south_east" ,第二个参数为指定和文本关联的音频文件的完整路径名,比如为"/sdcard/ south_south_east .wav"。

另一个函数类似,只是指定音频文件的方式不同:

publicint addSpeech ( String text, String packagename,intresourceId)

通过指定程序中包含的包名 , 比如"com.ichliebephone",和资源ID,比如" R.raw.south_south_east ",这样的方式确定关联的音频文件。

调用上面函数对某个文本进行了关联后,再对这个文本调用speak函数时,则会播放关联的音频文件的内容,如果关联的音频文件不存在时,才对这个文本进行语音合成。

虽然Android的TTS引擎Pico会尽力为文本去合成正确的发音,但是也会碰到可能无法正确发音的时候,比如碰到 "south_south_east" 这样的连接词时,发音时就会附带连接用的"_",因此为了正确的发音,就可以提前录制"southsoutheast"这样发音的音频文件,然后用addSpeech和上面的文本进行关联。

下面我们就用这个功能完成一个Demo例子,为她的名字关联你想说的话,使你手机中她名字的发音听起来有属于你的独特性。

二. 实例分析

我们希望做的效果如下:

图1实现效果图

在上一个Demo的基础上添加了一个文本框和一个按钮。点击Associate按钮,则第三个文本框中的文本(比如jiajia)将和第二个文本框中指定的音频文件(比如/sdcard/love.wav)进行关联。然后在第一个文本框中输入关联了的文本内容(比如jiajia),点击Speak按钮后,就不会朗读"jiajia"的发音,而是播放进行了关联的"/sdcard/love.wav"这个音频文件的内容。

创建一个Android工程,工程名为AndroidTTSDemoF if th,其中SDK版本需选择1.6及以上。

其中Main.xml文件很简单,如下所示:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <EditText android:id="@+id/inputText" android:hint="Input the text here!" android:layout_width="fill_parent" android:layout_height="wrap_content"> </EditText> <Button android:text="Speak" android:id="@+id/speakBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:enabled="false" ></Button> <TextView android:id="@+id/filenameLabel" android:text="Save as:" android:layout_width="fill_parent" android:layout_height="wrap_content" ></TextView> <EditText android:id="@+id/filenameText" android:hint="Input the saving file name here!" android:layout_width="fill_parent" android:layout_height="wrap_content"> ></EditText> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" > <Button android:id="@+id/recordBtn" android:text="Record" android:layout_width="wrap_content" android:layout_height="wrap_content" ></Button> <Button android:id="@+id/playBtn" android:text="Play" android:layout_width="wrap_content" android:layout_height="wrap_content" android:enabled="false" ></Button> </LinearLayout> <TextView android:id="@+id/associateWithLabel" android:text="Associate With:" android:layout_width="fill_parent" android:layout_height="wrap_content" ></TextView> <EditText android:id="@+id/associateText" android:hint="Input the associate text here!" android:layout_width="fill_parent" android:layout_height="wrap_content"> ></EditText> <Button android:text="Associate" android:id="@+id/associateBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:enabled="false" ></Button> </LinearLayout>

Java文件的编写:

有了前面这 Demo的实例开发,这个Demo实现起来就比较简单了,程序的代码如下所示:

public class AndroidTTSDemoFifth extends Activity implements OnInitListener{ //实现初始接口 /** Called when the activity is first created. */ //定义变量 private EditText inputText = null; private Button speakBtn = null; private EditText filenameText = null; private Button recordBtn = null; private Button playBtn = null; private EditText associateText = null; private Button associateBtn = null; private TextToSpeech mTts; private static final String TAG = "TTS Demo"; private static final String loveConfession = "jia jia, I love you. "; private String loveFileName = null; private File loveFile = null; private MediaPlayer player = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //创建TextToSpeech实例,初始化完成后会调用OnInitListener(第二个参数)的回调函数 mTts = new TextToSpeech(this, this // TextToSpeech.OnInitListener ); //设置控件 inputText = (EditText)findViewById(R.id.inputText); speakBtn = (Button)findViewById(R.id.speakBtn); filenameText = (EditText)findViewById(R.id.filenameText); recordBtn = (Button)findViewById(R.id.recordBtn); playBtn = (Button)findViewById(R.id.playBtn); associateText = (EditText)findViewById(R.id.associateText); associateBtn = (Button)findViewById(R.id.associateBtn); inputText.setText(loveConfession); filenameText.setText("/sdcard/love.wav"); associateText.setText("jia jia"); speakBtn.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub //朗读输入框里的内容 mTts.speak(inputText.getText().toString(), TextToSpeech.QUEUE_ADD, null); } }); recordBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub //把TTS语音合成的结果保存为音频文件 loveFileName = filenameText.getText().toString(); loveFile = new File(loveFileName); if(loveFile.exists()) { loveFile.delete(); } //把语音合成的结果保存到文件中 if(TextToSpeech.SUCCESS == mTts.synthesizeToFile(inputText.getText().toString(), null, loveFileName)) { Toast.makeText(getBaseContext(), "sound file created!", Toast.LENGTH_SHORT).show(); playBtn.setEnabled(true); associateBtn.setEnabled(true); } else { Toast.makeText(getBaseContext(), "failed to create sound file!", Toast.LENGTH_SHORT).show(); } } }); playBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub //播放保存着的音频文件 loveFileName = filenameText.getText().toString(); try { player = new MediaPlayer(); player.setDataSource(loveFileName); player.prepare(); player.start(); } catch (Exception e) { // TODO: handle exception Toast.makeText(getBaseContext(), "failed to play sound file!", Toast.LENGTH_SHORT).show(); e.printStackTrace(); } } }); associateBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub loveFileName = filenameText.getText().toString(); mTts.addSpeech(associateText.getText().toString(), loveFileName); Toast.makeText(getBaseContext(), "Associated!", Toast.LENGTH_SHORT).show(); } }); } public void onInit(int status) { // TODO Auto-generated method stub //TTS Engine初始化完成 if(status == TextToSpeech.SUCCESS) { int result = mTts.setLanguage(Locale.US); //设置发音语言 if(result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) //判断语言是否可用 { Log.v(TAG, "Language is not available"); speakBtn.setEnabled(false); } else { speakBtn.setEnabled(true); } } } @Override protected void onDestroy() { // TODO Auto-generated method stub //释放TTS的资源 if(mTts != null) { mTts.stop(); mTts.shutdown(); } if(player != null) { player.stop(); player.release(); } super.onDestroy(); } }

和TTS相关的新的部分为 associateBtn 的onClick事件的处理, 调用函数

mTts .addSpeech( associateText . getText ().toString(), loveFileName );

把文本和音频文件进行关联。


至此,这个Demo就完成了,但是在运行前,创建 AVD 需带 SD卡 ,因为要往SD卡上保存文件 同时还需在AndroidManifest.xml文件中添加写外部存储设备的权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

接着就可以运行这个Demo了, 程序运行后,首先点击 Record的按钮,把"jiajia,Iloveyou."语音录制为"/sdcard/love.wav"这个音频文件,然后再点击Associate按钮,把这个音频文件和"jiajia"这个文本进行关联,关联成功后会弹出"Associated!"这样的提示。最后在第一个文本框中输入"jiajia",点击Speak按钮,朗读的不是原本的"jiajia"这个发音,而是"jiajia,Iloveyou."。这样,你就为她的名字关联上了你想说的话,具备了属于你的独特性。运行效果图如下所示:

图2简单效果图

除了可以关联TTS语音合成到文本形成的音频文件外,还可以关联其他的音频文件,下面就为"jiajia"关联一首梁静茹的歌“暖暖”。

首先把歌名改为"loveSong.mp3",然后上传到SD卡中,使用adbpushloveSong.mp3/sdcard/loveSong.mp3命令,如下图所示:

图3向SD卡上传音频文件

接着我就回看到SD卡上多了loveSong.mp3这个音频文件,

图4上传到SD卡上的音频文件

然后在程序中,我们把要关联的文件名改为"/sdcard/loveSong.mp3",再次点击Associate按钮进行关联,如下图所示:

图4关联新的音频文件

最后为"jiajia"点击Speak按钮,这次将会播放梁静茹的“暖暖”这首歌。

图5关联了歌曲后的效果

到这里,和 addSpeech 关联这个功能相关的Demo介绍就结束了,不过如果你喜欢梁静茹的这首歌,也可以在Android的手机里播放。Android的Home目录下有个Music可以来播放,不过目前还看不到这首歌,我们先运行下DevTools里的MediaScanner,然后就会识别SD卡上新添加的内容,如下所示:

图6扫描SD卡上的文件

最后打开Music的Songs,找到这首“暖暖”,静下心来再次好好欣赏下。

图7静听欣赏“暖暖”

三. TTS优化

最后结合上一篇和这篇用到的两个功能,简单介绍一下TTS 优化的一些思路。

1. 对多次用到的大段文本先语音合成为音频文件,然后在朗读发音时用播放音频文件来代替。因为使用TTS 相对来说是比较费资源的,而且当文本长度比较长时语音合成的速度就比较慢。

2. 对能提前知道的要用到的一些不能正确发音的文本,比如人名、地名等,可以提前录制发音接近的音频文件,然后进行关联。

3. 对长段文本可以预处理,找出知道的不能正确发音的字符串,然后用和正确发音接近的类似字符串代替,最后才把剔除了不好正确发音的预处理后文本送给TTS 引擎进行语音合成。

以上只是几个简单的思路,具体内容还需在实际应用中实际分析。

注:文章参加“ 首届Google暑期大学生博客分享大赛——2010 Andriod篇

更多相关文章

  1. Android中的音频播放(MediaPlayer和SoundPool)
  2. Android标题栏和状态栏显示与否的设置&&& Button或者ImageButton
  3. Android学习笔记-1.Android工程结构
  4. Android(安卓)获取amr音频文件时长
  5. Android调用微信扫一扫和支付宝扫一扫
  6. Android中不用Service跨Avtivity仍然可以播放音乐的一个简单方法
  7. RK3288 android 7.1.2屏蔽开机音频
  8. Android(安卓)打开PDF,PPT,WORD,EXCEL,CHM,HTML,TEXT,AUDIO,VIDE
  9. Android学习之Image操作及时间日期选择器

随机推荐

  1. SQL Server 交叉表查询 case
  2. sqlserver数据库最大Id冲突问题解决方法
  3. vs10安装之后一些列问题
  4. 如何得到数据库中所有表名 表字段及字段
  5. sqlserver常用命令行操作(启动、停止、暂
  6. sql查询点滴记录
  7. SQL事务用法begin tran,commit tran和roll
  8. sqlserver对字段的添加修改删除、以及字
  9. 动态SQL中返回数值的实现代码
  10. 利用sql函数生成不重复的订单号的代码