Android TTS学习——用五种外语说出“我爱你”
一.?简单介绍
在上一篇里
http://blog.csdn.net/ichliebephone/archive/2010/08/10/5802044.aspx
我们简单的介绍了Android里的TTS功能并实现了一个最简单的Demo例子--AndroidTTSDemoFirst,在这篇文章中我们将具体介绍用到的TTS?API,并给上一个Demo增加语言选择功能,可以使用TTS引擎支持的?English、?French?、?German?、?Italian?和?Spanish?这?5大语言来进行相应的语音合成,并用这?5?种外语向她说出“我爱你”。
二.?实例分析
我们希望做的效果如下:
?
图1?实现效果图
有了上一个例子做基础,这个Demo比较好实现,主要是增加了一个语言选择的控件Spinner,选择不同的语言,就会用对应的语言表达“我爱你”。
接下来就边实现这个Demo边讲解用到的TTS?API。也是先创建一个Android工程,工程名为AndroidTTSDemoSecond,其中SDK必须选择1.6版本及以上。
其中Main.xml文件也还是很简单,在前一个AndroidTTSDemoFirst例子的基础上增加了一个Spinner控件,?如下所示:
?
- <?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>???????????
- ????<Spinner?android:id="@+id/langSelect"???
- ????????????android:layout_width="wrap_content"???
- ????????????android:layout_height="wrap_content"??
- ????????????android:layout_gravity="center_horizontal">??
- ????????????</Spinner>??
- ????</LinearLayout>??
?
Java文件的编写:
因为这个Demo例子只是在上一个AndroidTTSDemoFirst基础上的增加,因此可以使用上一个编写的java文件,只要把class名字改为AndroidTTSDemoSecond,如下所示:
?
- public?class?AndroidTTSDemoSecond?extends?Activity?implements?OnInitListener{??
- ????/**?Called?when?the?activity?is?first?created.?*/??
- ????private?EditText?inputText?=?null;??
- ????private?Button?speakBtn?=?null;??
- ????private?static?final?int?REQ_TTS_STATUS_CHECK?=?0;??
- ????private?static?final?String?TAG?=?"TTS?Demo";??
- ????private?TextToSpeech?mTts;??
- ????@Override??
- ????public?void?onCreate(Bundle?savedInstanceState)?{??
- ????????super.onCreate(savedInstanceState);??
- ????????setContentView(R.layout.main);??
- ??????????
- ????????//检查TTS数据是否已经安装并且可用??
- ????????Intent?checkIntent?=?new?Intent();??
- ????????checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);??
- ????????startActivityForResult(checkIntent,?REQ_TTS_STATUS_CHECK);??
- ??????????
- ????????inputText?=?(EditText)findViewById(R.id.inputText);??
- ????????speakBtn?=?(Button)findViewById(R.id.speakBtn);??????????
- ????????inputText.setText("This?is?an?example?of?speech?synthesis.");??
- ????????speakBtn.setOnClickListener(new?OnClickListener()?{??
- ??????????????
- ????????????public?void?onClick(View?v)?{??
- ????????????????//?TODO?Auto-generated?method?stub??
- ????????????????mTts.speak(inputText.getText().toString(),?TextToSpeech.QUEUE_ADD,?null);??
- ????????????????//朗读输入框里的内容??
- ????????????}??
- ????????????});??
- ????}??
- ??????
- ????//实现TTS初始化接口??
- ????@Override??
- ????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??
- ????????????{??
- ????mTts.speak("This?is?an?example?of?speech?synthesis.",?TextToSpeech.QUEUE_ADD,?null);??
- ????????????????speakBtn.setEnabled(true);??
- ????????????}??
- ????????}??
- ??????????
- ????}??
- ??????
- ????protected??void?onActivityResult(int?requestCode,?int?resultCode,?Intent?data)?{??
- ????????if(requestCode?==?REQ_TTS_STATUS_CHECK)??
- ????????{??
- ????????????switch?(resultCode)?{??
- ????????????case?TextToSpeech.Engine.CHECK_VOICE_DATA_PASS:??
- ????????????????//这个返回结果表明TTS?Engine可以用??
- ????????????{??
- ????????????????mTts?=?new?TextToSpeech(this,?this);??
- ????????????????Log.v(TAG,?"TTS?Engine?is?installed!");??
- ??????????????????
- ????????????}??
- ??????????????????
- ????????????????break;??
- ????????????case?TextToSpeech.Engine.CHECK_VOICE_DATA_BAD_DATA:??
- ????????????????//需要的语音数据已损坏??
- ????????????case?TextToSpeech.Engine.CHECK_VOICE_DATA_MISSING_DATA:??
- ????????????????//缺少需要语言的语音数据??
- ????????????case?TextToSpeech.Engine.CHECK_VOICE_DATA_MISSING_VOLUME:??
- ????????????????//缺少需要语言的发音数据??
- ????????????{??
- ????????????????//这三种情况都表明数据有错,重新下载安装需要的数据??
- ????????????????Log.v(TAG,?"Need?language?stuff:"+resultCode);??
- ????????????????Intent?dataIntent?=?new?Intent();??
- ????????????????dataIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);??
- ????????????????startActivity(dataIntent);??
- ??????????????????
- ????????????}??
- ????????????????break;??
- ????????????case?TextToSpeech.Engine.CHECK_VOICE_DATA_FAIL:??
- ????????????????//检查失败??
- ????????????default:??
- ????????????????Log.v(TAG,?"Got?a?failure.?TTS?apparently?not?available");??
- ????????????????break;??
- ????????????}??
- ????????}??
- ????????else??
- ????????{??
- ????????????//其他Intent返回的结果??
- ????????}??
- ????????}??
- ??????
- ????@Override??
- ????protected?void?onPause()?{??
- ????????//?TODO?Auto-generated?method?stub??
- ????????super.onPause();??
- ????????if(mTts?!=?null)??
- ????????????//activity暂停时也停止TTS??
- ????????{??
- ????????????mTts.stop();??
- ????????}??
- ????}??
- ??????
- ????@Override??
- ????protected?void?onDestroy()?{??
- ????????//?TODO?Auto-generated?method?stub??
- ????????super.onDestroy();??
- ????????//释放TTS的资源??
- ????????mTts.shutdown();??
- ????????}??
- ????}??
?
下面简单介绍下上面代码中和TTS相关的一些API使用。
首先是实现?OnInitListener?这个接口,这个接口中只有一个抽象函数?void??onInit(?int??status),在?TextToSpeech?引擎初始化完成后调用,在这个函数里就可以根据状态?status(为TextToSpeech.SUCCESS?或者?TextToSpeech.?Error?)判断TTS?初始化成功与否进行相应的操作。
?
接着在使用TTS?时,会先启动一个?Activity?检查?TTS?引擎需要的?TTS?数据是否已经安装并且可用,checkIntent.?setAction?(?TextToSpeech?.Engine.?ACTION_CHECK_TTS_DATA?);
这个?Activity会返回如下结果之一:?CHECK_VOICE_DATA_PASS?,??CHECK_VOICE_DATA_FAIL?,?CHECK_VOICE_DATA_BAD_DATA?,??CHECK_VOICE_DATA_MISSING_DATA?,??或者CHECK_VOICE_DATA_MISSING_VOLUME?.?
只有第一个结果?CHECK_VOICE_DATA_PASS?表明?TTS数据可用,其他都是数据不可用的结果,可以启动一个?Activity?去安装需要的?TTS?数据,
dataIntent.setAction(TextToSpeech.Engine.?ACTION_INSTALL_TTS_DATA?);
?
当数据可用时,就可以创建一个TextToSpeech?实例,
public?TextToSpeech?(?Context??context,??TextToSpeech.OnInitListener??listener)
这里需要两个参数,一个是?TTS?实例运行的?Context;
另一个是初始化接口的实现,在实例的创建过程中,如果TTS?引擎没有运行的话,则会初始化?TTS?引擎,并且在初始化完成后调用其第二个参数?listener?。
?
有了?TextToSpeech实例,接下来就可以对文本进行语音合成并发音了,对应的?API为
public?int?speak?(?String??text,?int?queueMode,??HashMap?<?String?,??String?>?params)
这里需要三个参数,第一个为要合成的文本;
第二个为使用?TTS队列的方式,因为使用TTS合成语音时需要时间,TTS引擎就会把还没有轮到的部分放在其队列中排队,后来的内容有两种使用队列的方式:?QUEUE_ADD???或者???QUEUE_FLUSH,?QUEUE_ADD?表示把当前需要合成的内容添加到?TTS队列的后面,等前面的都完成了后再轮到他,QUEUE_FLUSH?表示清除队列中原有的内容,直接使?TTS引擎对当前内容进行语音合成,一般来说适合比较紧急的情况使用,但因为在?Android?中可能不止你一个程序使用?TTS?引擎,因此为了不破坏其他人的数据,建议使用?QUEUE_ADD?参数;
第三个为键值对表示的一个参数,我们后面再来介绍,目前可以使其为?null?。
?
前半部分简单的介绍了前一个Demo?用到的?API?,下半部分添加这个?Demo?中新的语言选择部分。
首先为?Spinner?控件?新增加两个变量,
?
- private?Spinner?langSelect?=?null;??
- private?String?languages[]={"English","French","German","Italian","Spanish"};??
?
接着添加?Spinner?的使用,
?
- langSelect?=?(Spinner)findViewById(R.id.langSelect);??
- ??????????
- ????????inputText.setText("I?love?you");??
- ??????????
- ????????ArrayAdapter<String>?adapter?=?new?ArrayAdapter<String>(this,?android.R.layout.simple_spinner_item,?languages);??
- ????????adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);??
- ????????langSelect.setAdapter(adapter);??
- ????????langSelect.setSelection(0);??
?
和TTS?相关的部分是?Spinner?控件的?item?selected事件的处理,
?
- ????langSelect.setOnItemSelectedListener(new?OnItemSelectedListener()?{??
- public?void?onItemSelected(AdapterView<?>?parent,?View?view,??
- ????????int?position,?long?id)?{??
- ????//?TODO?Auto-generated?method?stub??
- ????int?pos?=?langSelect.getSelectedItemPosition();??
- ????int?result?=?-1;??
- ????switch?(pos)?{??
- ????case?0:??
- ????{??
- ????????inputText.setText("I?love?you");??
- ????????result?=?mTts.setLanguage(Locale.US);??
- ????}??
- ??????????
- ????????break;??
- ????case?1:??
- ????{??
- ????????inputText.setText("Je?t'aime");??
- ????????result?=?mTts.setLanguage(Locale.FRENCH);??
- ????}??
- ????????break;??
- ????case?2:??
- ????{??
- ????????inputText.setText("Ich?liebe?dich");??
- ????????result?=?mTts.setLanguage(Locale.GERMAN);??
- ????}??
- ????????break;??
- ????case?3:??
- ????{??
- ????????inputText.setText("Ti?amo");??
- ????????result?=?mTts.setLanguage(Locale.ITALIAN);??
- ????}??
- ????????break;??
- ????case?4:??
- ????{??
- ????????inputText.setText("Te?quiero");??
- ????????result?=?mTts.setLanguage(new?Locale("spa",?"ESP"));??
- ????}??
- ????????break;??
- ????default:??
- ????????break;??
- ????}??
- ????//设置发音语言??
- ????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);??
- ????}??
- }??
- public?void?onNothingSelected(AdapterView<?>?arg)?{??
- ????//?TODO?Auto-generated?method?stub??
- ??????
- }??
- );??
?
在选择不同的?item时,为?inputText?设置不同语言“我爱你”对应的文本,并且为?TTS实例设置语言。
为TTS?引擎设置语言的?API?为
public?int?setLanguage?(?Locale??loc)?;
使用Locale?这个表示语言及国家区域的类来设置语言,目前支持?English、?French?、?German?、?Italian?和Spanish?这?5大语言,?返回的结果为
LANG_AVAILABLE?,??LANG_COUNTRY_AVAILABLE?,??LANG_COUNTRY_VAR_AVAILABLE?,?LANG_MISSING_DATA???和?LANG_NOT_SUPPORTED?。其中?LANG_MISSING_DATA???和LANG_NOT_SUPPORTED?表示无法使用当前进行设置的语言,另外的几个表示设置的语言有效。
??? 至此,增加了语言选择的新的Demo?完成了,程序运行后可以选择不同的语言说出“我爱你”,简单效果图如下所示:
??
图2??简单效果图
??? 文章对应的完整代码例子可以在这里下载:
????http://download.csdn.net/source/2611687?
?? ??注:文章参加“?首届Google暑期大学生博客分享大赛——2010 Andriod篇”