|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
J2ME在手机游戏开发的作用也是无用质疑的。至于桌面程序,可能有人说java不行,界面不好看,但是请看看NetBeans和Eclipse吧,他们都是利用java开发的,而他们的界面是多么的华丽,所以界面决不是java的缺点。还有一个不得不提的优点就是大多java人员都挂在嘴边的java的跨平台性,目前这确实也是java优点之一。为使用程序加上语音才能有甚么优点呢?大略地讲,是为了兴趣,它合适一切注意兴趣的
使用,好比游戏。固然,从更严厉的角度来说,它还触及到使用的可用性成绩。注重,这
里我思索的不但是可视化界面固有的不敷,并且另有如许一些情况:一些时分,让双眼离
开以后的事情很不便利,乃至是分歧法的。好比,假定有一个带语音功效的扫瞄器,你就
能够在外出漫步或开车下班的同时,用听的体例扫瞄本人喜好的网站。
从今朝来看,邮件浏览器也许是语音手艺更实践的使用,在JavaMailAPI的匡助下,
这统统已大概。邮件浏览器能够按期地反省收件箱,然后用语音“Youhavenewmail,
wouldyoulikemetoreadittoyou?”引发你的注重。依照相似的思绪,我们还能够
思索一个带语音功效的提示器,把它毗连到一个日历使用:它会实时地提示你“Dont
forgetyourmeetingwiththebossin10minutes!”。
大概你已被这些主张吸引,大概有了本人更好的主张,如今让我们持续。起首我将
先容怎样启用本文供应的语音引擎,如许,假如你以为语音引擎的完成细节过于庞大,就
能够间接利用它而疏忽实在现细节。
1、试用语音引擎
要利用这个语音引擎,你必需在CLASSPATH中到场本文供应的javatalk.jar文件,然后从
命令交运行(大概从Java程序挪用)com.lotontech.speech.Talker类。假如从命令交运
行,则命令为:
javacom.lotontech.speech.Talker"h|e|l|oo"
假如从Java程序挪用,则代码为:
com.lotontech.speech.Talkertalker=newcom.lotontech.speech.Talker();
talker.sayPhoneWord("h|e|l|oo");
如今,关于在命令行上(大概挪用sayPhoneWord()办法时)供应的“h|e|l|oo”字符串,你
也许有所不解。上面我就来注释一下。
语音引擎的事情道理是把微小的声响样本毗连起来,每个样本都是人的言语发音(英
语)的一个最小单元。这些声响样本称为音素(allophone)。每个要素对应一个、二
个大概三个字母。夙昔面“hello”的语音暗示能够看出,一些字母组合的发音不言而喻,
另有一些却不是很分明:
h--读音不言而喻
e--读音不言而喻
l--读音不言而喻,但注重两个“l”被简缩成了一个“l”。
OO--应当读作“hello”中的读音,不该读作“bot”、“too”中的读音。
上面是一个无效音素的清单:
a:如cat
b:如cab
c:如cat
d:如dot
e:如bet
f:如frog
g:如frog
h:如hog
i:如pig
j:如jig
k:如keg
l:如leg
m:如met
n:如begin
o:如not
p:如pot
r:如rot
s:如sat
t:如sat
u:如put
v:如have
w:如wet
y:如yet
z:如zoo
aa:如fake
ay:如hay
ee:如bee
ii:如high
oo:如go
bb:b的变更情势,重音分歧
dd:d的变更情势,重音分歧
ggg:g的变更情势,重音分歧
hh:h的变更情势,重音分歧
ll:l的变更情势,重音分歧
nn:n的变更情势,重音分歧
rr:r的变更情势,重音分歧
tt:t的变更情势,重音分歧
yy:y的变更情势,重音分歧
ar:如car
aer:如care
ch:如which
ck:如check
ear:如beer
er:如later
err:如later(长音)
ng:如feeding
or:如law
ou:如zoo
ouu:如zoo(长音)
ow:如cow
oy:如boy
sh:如shut
th:如thing
dth:如this
uh:u的变更情势
wh:如where
zh:如Asian
人措辞的时分,语音在全部句子以内升降变更。腔调变更使得语音更天然、更富有传染
力,使得问句和报告句可以互相区分。请思索上面两个句子:
Itisfake--f|aa|k
Isitfake?--f|AA|k
大概你已料想到,进步腔调的办法是利用年夜写字母。
以上就是利用该软件时你必要懂得的工具。假如你对厥后台完成细节感乐趣,请持续浏览。
2、完成语音引擎
语音引擎的完成只包含一个类,四个办法。它使用了J2SE1.3包括的JavaSoundAPI。在
这里,我禁绝备周全地先容这个API,但你能够经由过程实例进修它的用法。JavaSoundAPI
并非一个出格庞大的API,代码中的正文将告知你必需懂得的常识。
上面是Talker类的基础界说:
packagecom.lotontech.speech;
importjavax.sound.sampled.*;
importjava.io.*;
importjava.util.*;
importjava.net.*;
publicclassTalker
{
privateSourceDataLineline=null;
}
假如从命令行实行Talker,上面的main()办法将作为出口点运转。main()办法猎取第一个
命令行参数,然后把它传送给sayPhoneWord()办法:
/*
*读出在命令行中指定的暗示读音的字符串
*/
publicstaticvoidmain(Stringargs[])
{
Talkerplayer=newTalker();
if(args.length>0)player.sayPhoneWord(args[0]);
System.exit(0);
}
sayPhoneWord()办法既能够经由过程下面的main()办法挪用,也能够在Java程序中间接挪用。
从外表上看,sayPhoneWord()办法对照庞大,实在并不是云云。实践上,它复杂地遍历所
有单词的语音元素(在输出字符串中语音元素以“|”分开),经由过程一个声响输入通道一个
元素一个元素地播放出来。为了让声响更天然一些,我把每个声响样本的开头和下一个
声响样本的开首兼并了起来:
/*
*读出指定的语音字符串
*/
publicvoidsayPhoneWord(Stringword)
{
//为上一个声响机关的摹拟byte数组
byte[]previousSound=null;
//把输出字符串支解成独自的音素
StringTokenizerst=newStringTokenizer(word,"|",false);
while(st.hasMoreTokens())
{
//为音素机关响应的文件名字
StringthisPhoneFile=st.nextToken();
thisPhoneFile="/allophones/"+thisPhoneFile+".au";
//从声响文件读取数据
byte[]thisSound=getSound(thisPhoneFile);
if(previousSound!=null)
{
//假如大概的话,把前一个音素和以后音素兼并
intmergeCount=0;
if(previousSound.length>=500&&thisSound.length>=500)
mergeCount=500;
for(inti=0;i
{
previousSound[previousSound.length-mergeCount+i]
=(byte)((previousSound[previousSound.length
-mergeCount+i]+thisSound[i])/2);
}
//播放前一个音素
playSound(previousSound);
//把经由截短确当前音素作为前一个音素
byte[]newSound=newbyte[thisSound.length-mergeCount];
for(intii=0;ii
newSound[ii]=thisSound[ii+mergeCount];
previousSound=newSound;
}
else
previousSound=thisSound;
}
//播放最初一个音素,清算声响通道
playSound(previousSound);
drain();
}
在sayPhoneWord()的前面,你能够看到它挪用playSound()输入单个声响样本(即一个音
素),然后挪用drain()清算声响通道。上面是playSound()的代码:
/*
*该办法播放一个声响样本
*/
privatevoidplaySound(byte[]data)
{
if(data.length>0)line.write(data,0,data.length);
}
上面是drain()的代码:
/*
*该办法清算声响通道
*/
privatevoiddrain()
{
if(line!=null)line.drain();
try{Thread.sleep(100);}catch(Exceptione){}
}
如今回过火来看sayPhoneWord(),这里另有一个办法我们没有剖析,即getSound()办法。
getSound()办法从一个au文件以字节数据的情势读进事后录制的声响样本。要懂得读取数
据、转换音频格局、初始化声响输入行(SouceDataLine)和机关字节数据的具体过
程,请参考上面代码中的正文:
/*
*该办法从文件读取一个音素,
*并把它转换成byte数组
*/
privatebyte[]getSound(StringfileName)
{
try
{
URLurl=Talker.class.getResource(fileName);
AudioInputStreamstream=AudioSystem.getAudioInputStream(url);
AudioFormatformat=stream.getFormat();
//把一个ALAW/ULAW声响转换成PCM以便回放
if((format.getEncoding()==AudioFormat.Encoding.ULAW)||
(format.getEncoding()==AudioFormat.Encoding.ALAW))
{
AudioFormattmpFormat=newAudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
format.getSampleRate(),format.getSampleSizeInBits()*2,
format.getChannels(),format.getFrameSize()*2,
format.getFrameRate(),true);
stream=AudioSystem.getAudioInputStream(tmpFormat,stream);
format=tmpFormat;
}
DataLine.Infoinfo=newDataLine.Info(
Clip.class,format,
((int)stream.getFrameLength()*format.getFrameSize()));
if(line==null)
{
//输入线还没有实例化
//是不是可以找到符合的输入线范例?
DataLine.InfooutInfo=newDataLine.Info(SourceDataLine.class,
format);
if(!AudioSystem.isLineSupported(outInfo))
{
System.out.println("不撑持婚配"+outInfo+"的输入线");
thrownewException("不撑持婚配"+outInfo+"的输入线");
}
//翻开输入线
line=(SourceDataLine)AudioSystem.getLine(outInfo);
line.open(format,50000);
line.start();
}
intframeSizeInBytes=format.getFrameSize();
intbufferLengthInFrames=line.getBufferSize()/8;
intbufferLengthInBytes=bufferLengthInFrames*frameSizeInBytes;
byte[]data=newbyte[bufferLengthInBytes];
//读取字节数据,并计数
intnumBytesRead=0;
if((numBytesRead=stream.read(data))!=-1)
{
intnumBytesRmaining=numBytesRead;
}
//把字节数据切割成符合的巨细
byte[]newData=newbyte[numBytesRead];
for(inti=0;i
newData[i]=data[i];
returnnewData;
}
catch(Exceptione)
{
returnnewbyte[0];
}
}
这就是全体的代码,包含正文在内,一个约莫150行代码的语音分解器。
3、文本-语音转换
以语音元素的格局指定待朗诵的单词仿佛过于庞大,假如要机关一个可以朗诵文本(好比
Web页面或Email)的使用,我们但愿可以间接指定原始的文本。
深切剖析这个成绩以后,我在本文前面的ZIP文件中供应了一个实验性的文本-语音转换
类。运转这个类,它将显现出剖析了局。文本-语音转换类能够从命令行实行,以下所示:
javacom.lotontech.speech.Converter"hellothere"
输入了局类如:
hello->h|e|l|oo
there->dth|aer
假如运转上面这个命令:
javacom.lotontech.speech.Converter"IliketoreadJavaWorld"
则输入了局为:
i->ii
like->l|ii|k
to->t|ouu
read->r|ee|a|d
java->j|a|v|a
world->w|err|l|d
这个转换类是怎样事情的呢?实践上,我的办法相称复杂,转换历程就是以必定的序次应
用一组文本交换划定规矩。比方关于单词“ant”、“want”、“wanted”、“unwanted”和
“unique”,则我们想要使用的交换划定规矩大概顺次为:
用“|y|ou|n|ee|k|”交换“*unique*”
用“|w|o|n|t|”交换“*want*”
用“|a|”交换“*a*”
用“|e|”交换“*e*”
用“|d|”交换“*d*”
用“|n|”交换“*n*”
用“|u|”交换“*u*”
用“|t|”交换“*t*”
关于“unwanted”,输入序列为:
unwanted
un[|w|o|n|t|]ed(划定规矩2)
[|u|][|n|][|w|o|n|t|][|e|][|d|](划定规矩4、5、6、7)
u|n|w|o|n|t|e|d(删除过剩的符以后)
你将看到包括字母“wont”的单词和包括字母“ant”的单词以分歧的体例发音,还将看到在
惯例划定规矩的感化下,“unique”作为一个完全单词优先于其他划定规矩,从而“unique”这个单词
读作“y|ou...”而不是“u|n...”。
停止语:本文供应了一个能够随时运转的、便利的语音引擎,你能够在本人的Java
1.3使用中利用它。假如细心剖析一下代码,它还为你供应了一个用JavaSoundAPI播放音
频片段的有用教程。要让它变得真正有效,你应当思索一下文本-语音转换手艺,由于对
于我后面提到的文本浏览使用来讲,这是真实的支持基本。要改良本文计划的效果,你必
须机关出一个复杂的交换划定规矩库,经心调剂使用划定规矩的优先序次。但愿你比我更有毅力!
到时我们不用学struts,不用学spring,不用学Hibernate,只要能把jsf学会了,完全可以替代所有的框架,包括AJAX,都知道AJAX并不是新技术,虽说我没深入学习jsf但我认为jsf应该已经能通过其它技术替代AJAX,实现无缝刷新。 |
|