一. ? 簡單介紹
在上一篇里
http://blog.csdn.net/ichliebephone/archive/2010/08/13/5810370.aspx
我們介紹了TTS提供的接口 ? OnUtteranceCompletedListener ? 的使用,這個接口的作用是監(jiān)聽語音片段的朗讀,并在語音片段朗讀結(jié)束后調(diào)用其定義的回調(diào)函數(shù),在回調(diào)函數(shù)里可以進(jìn)行需要的操作。
在這一篇里我們介紹一下TTS提供的另一個有用的功能,把合成的語音以音頻文件的形式保存在系統(tǒng)里,然后就可以直接用播放音頻文件的方式來播放。
這個功能調(diào)用的函數(shù)為:
public?int? ? synthesizeToFile ? ( ? String ? ?text,? ? HashMap ? < ? String ? ,? ? String ? >?params,? String ? ?filename)
第一個參數(shù)為要進(jìn)行語音合成的文本;第二個參數(shù)我們在上一個Demo中有所介紹,是一個鍵值對形式的HashMap類型變量,可以設(shè)置語音片段的ID等;第三個參數(shù)為保存到系統(tǒng)中的文件名。
當(dāng)你想和朋友分享一份精彩的文本合成語音后的效果時,你可以使用這個功能把它保存為音頻文件發(fā)送給朋友,這樣即使朋友的手機(jī)不具備TTS功能,也可以用播放音頻的方式分享到;當(dāng)你要對同一段較長的文本多次進(jìn)行語音合成時,你可以把這段文本的語音保存為音頻文件,然后使用時播放,這樣會更省資源,運(yùn)行速度更快,因?yàn)槭褂肨TS是比較費(fèi)資源的一個過程。因此我們會在某些場合用到這個功能。
下面我們就用這個功能完成一個Demo例子,當(dāng)你害羞當(dāng)面向她表白你對她的喜歡時,讓Android幫你語音合成你想說的話,然后你就可以向她發(fā)送保存了對她喜歡的這個音頻文件。
二. ? 實(shí)例開發(fā)
?
我們希望做的效果如下:
?
圖 1? 實(shí)現(xiàn)效果圖
?
第一個文本框里可以輸入需要語音合成的文本,第二個文本框里輸入要保存成的音頻文件的文件名,點(diǎn)擊第一個 Speak ?按鈕你可以預(yù)聽一下 TTS ?語音合成的效果,點(diǎn)擊第二個 Record ?按鈕,就會以音頻文件的形式保存,然后就可以點(diǎn)擊第三個 Play ?按鈕播放保存的這個音頻文件。
創(chuàng)建一個 Android ?工程,工程名為 AndroidTTSDemoFourth ?,其中 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 = "fill_parent" ??
- ???????????????????? 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 > ?????????????????????????????
- </ LinearLayout > ??
?
?
Java ? 文件的編寫:
有了前面這些 Demo ?的實(shí)例開發(fā),這個 Demo ?實(shí)現(xiàn)起來就比較簡單了,程序的代碼如下所示:
?
- public ? class ?AndroidTTSDemoFourth? extends ?Activity? implements ?OnInitListener{??
- ???? //實(shí)現(xiàn)初始接口 ??
- ???? /**?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 ?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);??
- ???????? //創(chuàng)建TextToSpeech實(shí)例,初始化完成后會調(diào)用OnInitListener(第二個參數(shù))的回調(diào)函數(shù) ??
- ????????mTts?=? new ?TextToSpeech( this ,??
- ???????????????? this ?? //?TextToSpeech.OnInitListener ??
- ????????????????);??
- ???????? //設(shè)置控件 ??
- ????????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);??
- ????????????????
- ????????inputText.setText(loveConfession);????
- ????????filenameText.setText( "/sdcard/love.wav" );??
- ????????speakBtn.setOnClickListener( new ?OnClickListener()?{???????
- ???????????? public ? void ?onClick(View?v)?{??
- ???????????????? //?TODO?Auto-generated?method?stub ??
- ???????????????? //朗讀輸入框里的內(nèi)容 ??
- ????????????????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語音合成的結(jié)果保存為音頻文件 ??
- ????????????????loveFileName?=?filenameText.getText().toString();??
- ????????????????loveFile?=? new ?File(loveFileName);??
- ???????????????? if (loveFile.exists())??
- ????????????????{??
- ????????????????????loveFile.delete();??
- ????????????????}??
- ???????????????? //把語音合成的結(jié)果保存到文件中 ??
- ???????????????? if (TextToSpeech.SUCCESS?==?mTts.synthesizeToFile(inputText.getText().toString(),? null ,?loveFileName))??
- ????????????????{??
- ????????????????????Toast.makeText(getBaseContext(),? "sound?file?created!" ,?Toast.LENGTH_SHORT).show();??
- ????????????????????playBtn.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 ??
- ???????????????? //播放保存著的音頻文件 ??
- ???????????????? 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();??
- ????????????????}??
- ????????????}??
- ????????});??
- ????}??
- ??????
- ???? public ? void ?onInit( int ?status)?{??
- ???????? //?TODO?Auto-generated?method?stub ??
- ???????? //TTS?Engine初始化完成 ??
- ???????? if (status?==?TextToSpeech.SUCCESS)??
- ????????{??
- ???????????? int ?result?=?mTts.setLanguage(Locale.US);??
- ???????????? //設(shè)置發(fā)音語言 ??
- ???????????? 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();??
- ????????}?????
- ???????? super .onDestroy();??
- ????}??
- }??
?
?
和 TTS ?相關(guān)的新的部分為 recordBtn ?的 onClick ?事件的處理,先根據(jù)指定的文件名創(chuàng)建一個 File ?變量,來判斷文件是否已經(jīng)存在,如果已存在就先刪除。然后調(diào)用函數(shù)
mTts ? .synthesizeToFile( ? inputText ? .getText().toString(),? null ? ,? loveFileName ? )
把文本框中的內(nèi)容語音合成后保存到文件中。
另一個 playBtn ?的 onClick ?事件的處理,主要就是創(chuàng)建一個 MediaPlayer ?實(shí)例,播放上一步保存的音頻文件。
?
至此,這個 Demo ?就完成了,但是在運(yùn)行前,需創(chuàng)建一個帶 SD ?卡的 AVD ?,因?yàn)橐? SD ?卡上保存文件,如下所示:
圖 2? 必須創(chuàng)建帶 SD ?卡的 AVD
?
同時還需在 AndroidManifest.xml ?文件中添加寫外部存儲設(shè)備的權(quán)限:
< ? uses-permission ? android:name ? = ? "android.permission.WRITE_EXTERNAL_STORAGE" ? ></ uses-permission ? >
接著就可以運(yùn)行這個 Demo ?了,運(yùn)行程序后在 Eclipse ?中切換到 DDMS ?視圖,接著選擇查看 File Explorer ?,我們看到在沒有點(diǎn)擊程序的 Record ?按鈕進(jìn)行語音合成到文件保存時, sdcard ?目錄下沒有額外的文件,如下圖所示:
?
圖 3? 原始的 SD ?卡目錄
?
?
然后我們在程序中點(diǎn)擊 Record ?按鈕,讓 TTS ?把語音合成到文件,合成成功的話會彈出“ sound file created! ?”的提示,并且 Play ?按鈕變成可用。點(diǎn)擊 Play ?按鈕就會播放剛剛保存的音頻文件,和點(diǎn)擊第一個的 Speak ?按鈕朗讀的內(nèi)容是一樣的。這時,我們再來查看下 SD ?卡的目錄,會發(fā)現(xiàn)多了一個文件: love.wav ?,正是我們設(shè)定保存的文件名,如下圖所示:
?
圖 4? 語音合成到文件后的 SD ?卡目錄
?
?
并且,我們還可以使用 adb pull ?命令把這個文件從 SD ?卡上提取出來,在 CMD ?窗口中運(yùn)行 adb pull ./sdcard/love.wav? 就可以把 SD ?卡上的這個音頻文件保存的當(dāng)前目錄下,如下圖所示:
?
圖 5? 提取 SD ?卡上保存的音頻文件
最后,也可以在電腦上播放記錄了你對她的喜歡的這個音頻文件了,或者也可以把這個文件發(fā)送給你喜歡的她。
?
注:文章參加“ ?首屆Google暑期大學(xué)生博客分享大賽——2010 Andriod篇 ”
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
