熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

讓Java說話-用Java實現語音引擎

2013-11-15 11:44:29  來源: JSP教程 

  為應用程序加上語音能力有什麼好處呢?粗略地講是為了趣味它適合所有注重趣味的應用比如游戲當然從更嚴肅的角度來講它還涉及到應用的可用性問題注意這裡我考慮的不僅是可視化界面固有的不足而且還有這樣一些情形一些時候讓雙眼離開當前的工作很不方便甚至是不合法的比如假設有一個帶語音功能的浏覽器你就可以在外出散步或開車上班的同時用聽的方式浏覽自己喜愛的網站
  
  從目前來看郵件閱讀器或許是語音技術更實際的應用在JavaMail API的幫助下這一切已經可能郵件閱讀器可以定期地檢查收件箱然後用語音You have new mail would you like me to read it to you?引起你的注意按照類似的思路我們還可以考慮一個帶語音功能的提醒器把它連接到一個日歷應用它會及時地提醒你Dont forget your meeting with the boss in minutes!
  
  也許你已經被這些主意吸引或者有了自己更好的主意現在讓我們繼續首先我將介紹如何啟用本文提供的語音引擎這樣如果你認為語音引擎的實現細節過於復雜就可以直接使用它而忽略其實現細節
  一試用語音引擎
  
  要使用這個語音引擎你必須在CLASSPATH中加入本文提供的javatalkjar文件然後從命令行運行(或者從Java程序調用)comlotontechspeechTalker類如果從命令行運行則命令為
  
  java comlotontechspeechTalker h|e|l|oo
  
  如果從Java程序調用則代碼為
  
  comlotontechspeechTalker talker=new comlotontechspeechTalker();
  
  talkersayPhoneWord(h|e|l|oo);
  
  現在對於在命令行上(或者調用sayPhoneWord()方法時)提供的h|e|l|oo字符串你或許有所不解下面我就來解釋一下
  
  語音引擎的工作原理是把細小的聲音樣本連接起來每一個樣本都是人的語言發音(英語)的一個最小單位這些聲音樣本稱為音素(allophone)每一個因素對應一個二個或者三個字母從前面hello的語音表示可以看出一些字母組合的發音顯而易見還有一些卻不是很明顯
  
  
  
  h 讀音顯而易見
  
  e 讀音顯而易見
  
  l 讀音顯而易見但注意兩個l被簡縮成了一個l
  
  OO 應該讀作hello中的讀音不應讀作bottoo中的讀音
  
  下面是一個有效音素的清單
  
  
  
  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
  
  人說話的時候語音在整個句子之內起落變化語調變化使得語音更自然更富有感染力使得問句和陳述句能夠相互區別請考慮下面兩個句子
  
  It is fake f|aa|k
  
  Is it fake? f|AA|k
  
  也許你已經猜想到提高語調的方法是使用大寫字母
  
  以上就是使用該軟件時你需要了解的東西如果你對其後台實現細節感興趣請繼續閱讀
  
  二實現語音引擎
  
  
  語音引擎的實現只包括一個類四個方法它利用了JSE 包含的Java Sound API在這裡我不准備全面地介紹這個API但你可以通過實例學習它的用法Java Sound API並不是一個特別復雜的API代碼中的注釋將告訴你必須了解的知識
  
  下面是Talker類的基本定義
  
  package comlotontechspeech;
  
  import javaxsoundsampled*;
  
  import javaio*;
  
  import javautil*;
  
  import *;
  
  public class Talker
  
  {
  
  private SourceDataLine line=null;
  
  }
  
  如果從命令行執行Talker下面的main()方法將作為入口點運行main()方法獲取第一個命令行參數然後把它傳遞給sayPhoneWord()方法
  
  /*
  
  * 讀出在命令行中指定的表示讀音的字符串
  
  */
  
  public static void main(String args[])
  
  {
  
  Talker player=new Talker();
  
  if (argslength>) playersayPhoneWord(args[]);
  
  Systemexit();
  
  }
  
  sayPhoneWord()方法既可以通過上面的main()方法調用也可以在Java程序中直接調用從表面上看sayPhoneWord()方法比較復雜其實並非如此實際上它簡單地遍歷所有單詞的語音元素(在輸入字符串中語音元素以|分隔)通過一個聲音輸出通道一個元素一個元素地播放出來為了讓聲音更自然一些我把每一個聲音樣本的結尾和下一個聲音樣本的開頭合並了起來
  
  /*
  
  * 讀出指定的語音字符串
  
  */
  
  public void sayPhoneWord(String word)
  
  {
  
  // 為上一個聲音構造的模擬byte數組
  
  byte[] previousSound=null;
  
  
  // 把輸入字符串分割成單獨的音素
  
  StringTokenizer st=new StringTokenizer(word|false);
  
  while (sthasMoreTokens())
  
  {
  
  // 為音素構造相應的文件名字
  
  String thisPhoneFile=stnextToken();
  
  thisPhoneFile=/allophones/+thisPhoneFile+au;
  
  // 從聲音文件讀取數據
  
  byte[] thisSound=getSound(thisPhoneFile);
  
  if (previousSound!=null)
  
  {
  
  // 如果可能的話把前一個音素和當前音素合並
  
  int mergeCount=;
  
  if (previousSoundlength>= && thisSoundlength>=)
  
  mergeCount=;
  
  for (int i=; i
  
  {
  
  previousSound[previousSoundlengthmergeCount+i]
  
  =(byte)((previousSound[previousSoundlength
  
  mergeCount+i]+thisSound[i])/);
  
  }
  
  // 播放前一個音素
  
  playSound(previousSound);
  
  // 把經過截短的當前音素作為前一個音素
  
  byte[] newSound=new byte[thisSoundlengthmergeCount];
  
  for (int ii=; ii
  
  newSound[ii]=thisSound[ii+mergeCount];
  
  previousSound=newSound;
  
  }
  
  else
  
  previousSound=thisSound;
  
  }
  
  // 播放最後一個音素清理聲音通道
  
  playSound(previousSound);
  
  drain();
  
  }
  在sayPhoneWord()的後面你可以看到它調用playSound()輸出單個聲音樣本(即一個音素)然後調用drain()清理聲音通道下面是playSound()的代碼
  
  
  
  /*
  
  * 該方法播放一個聲音樣本
  
  */
  
  private void playSound(byte[] data)
  
  {
  
  if (datalength>) linewrite(data datalength);
  
  }
  
  下面是drain()的代碼
  
  /*
  
  * 該方法清理聲音通道
  
  */ From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19532.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.