亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

讓Java說話! (轉)

發布時間:2020-08-10 04:50:11 來源:ITPUB博客 閱讀:150 作者:worldblog 欄目:編程語言
讓Java說話! (轉)[@more@]

  讓Java說話!
 為你的Java 1.3 應用程序和Applet添加說話能力
概要
這篇文章中,Tony Loton展示了不使用硬件和本地調用的,少于150行Java代碼實現一個簡單的語音引擎。此外,他提供了一個小zip文件,里面包含了使Java應用程序說話說需要的東西—僅僅用來娛樂或別的真正的應用程序。如果你剛剛接觸Java Sound api,這篇文章將是一個很好的介紹。(1800字)

作者:Tony Loton
譯者:Cocia Lin

  為什么要使你的程序說話呢?首先,為了娛樂,這很適合象游戲這樣的娛樂程序。并且還有很多嚴肅的應用領域。我想這雖然不是可視化界面的天生缺點,也是聲音可用之處-- 或者過分一點 – 可以使你的眼睛離開你正在做的事情。

  最近,我曾經應用一些技術在web上獲得HTML和XML信息的工作[請看 "Access the World's Biggest Database with Web DataBase Connectivity" (JavaWorld, March 2001)]。這讓我將那個工作和我的這個想法結合來創建一個說話的Web瀏覽器。這樣的一個瀏覽器可以使你聽到你喜歡的網站上的信息摘錄 – 新聞標題,例如 – 就象在外邊溜狗或開車上班的途中收聽收音機一樣。當然,以現在的科技水平,你必須帶上你的筆記本電腦和移動電話,但這些不切實際的設想在不久的將來,隨著應用Java技術的智能電話的出現而變成現實,例如Nokia 9210(在美國叫9290).

  也許對現在來說,能用的到的是一個eMail朗讀器,這也得謝謝JavaMail API.這樣的程序將定期的檢查你的電子郵箱,并且你的注意被一個聲音“你有新的email,你要我給你朗讀嗎?”吸引。相近的,考慮語音提醒 – 當連接到你的日常管理程序時 –- 電腦大喊“不要忘了10分鐘后你和老板的會議!”

  回到這些想法,或者你有更好的自己的想法,我們繼續。我將演示怎樣將我提供的zip文件添加的我們的工作中,這樣,如果你覺得這些東西太難了,你就可以直接安裝運行而跳過實現細節。

測試語音引擎
  為了使用這個語音引擎,你需要將jw-0817-javatalk.zip添加到你的classpath,在命令行方式或Java程序中使用com.lotontech.speech.Talker。

命令行方式,象下面這樣運行,輸入:


java com.lotontech.speech.Talker "h|e|l|oo"

在Java程序中,簡單的包含著兩行代碼:


com.lotontech.speech.Talker talker=new com.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”的
這里列出了能用到的音體變(allophone):

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 (longer sound)
ng -- 例如 feeding
or -- 例如 law
ou -- 例如 zoo
ouu -- 例如 zoo (longer sound)
ow -- 例如 cow
oy -- 例如 boy
sh -- 例如 shut
th -- 例如 thing
dth -- 例如 this
uh -- 變調 u
wh -- 例如 where
zh -- 例如 Asian
人說話的每一個句子都有單詞的升調和降調的變化。這個音調使說話聽起來自然,富有感情,并且可以從句子語調確定這是疑問句。如果你聽過Stephen Hawking的人造聲音,你就能夠理解我所說的了。考慮這兩個句子:

It is fake -- f|aa|k
Is it fake? -- f|AA|k
你也許猜想,使用升調的方法是用大寫字母。你要實際感受一下,我的提示是你要注意聽元音字母

  這是你使用這個軟件需要知道的全部了,但是如果你對引擎罩下面的東西感興趣,那么繼續往下讀。

實現語音引擎

  語音引擎僅僅需要一個類來實現,包含四個方法。它使用j2se1.3的Java Sound API。我不想提供一個全面的Java Sound API教程,你將通過例子學習。你將發現不是有很多需要你來做,并且說明能告訴你需要知道的。

這里是Talker類的基本定義:


package com.lotontech.speech;

import javax.sound.sampled.*;
import java.io.*;
import java.util.*;
import java.NET.*;

public class Talker
{
  private sourceDataLine line=null;
}

如果你從命令行運行程序,下面的main(..)方法將作為一個入口服務。它取得命令行的第一個參數,如果有一個參數,將傳遞給sayPhoneWord(…)方法:


/*
*這個方法在命令行對一個指定的單詞發音
*/
public static void main(String args[])
{
  Talker player=new Talker();
  if (args.length>0) player.sayPhoneWord(args[0]);
  System.exit(0);
}

上面,SayPhoneWord(…)方法被main(…)方法調用,或者它被Java程序或Applet直接調用。它看起來比它本身難理解。本質上,它簡單的一步一步解釋單詞的語音變位allophone – 被”|”標志分割的輸入文本 – 在把他們一個一個通過聲音輸出通道輸出。為了讓它聽起來更自然,合并每一個聲音的結尾到下一個聲音的開頭:

/*
*這個方法使輸入的單詞發音
*/
public void sayPhoneWord(String word)
{
// 為上一個聲音設置一個字節數組
  byte[] previousSound=null;

//分割輸入字符串
  StringTokenizer st=new StringTokenizer(word,"|",false);
  while (st.hasMoreTokens())
  {
 

為語音單位構造一個文件名
  String thisPhoneFile=st.nextToken();
  thisPhoneFile="/allophones/"+thisPhoneFile+".au";


  從文件中獲得數據
  byte[] thisSound=getSound(thisPhoneFile);

  if (previousSound!=null)
  {
 

  合并上一個語音和現在的這個
  int mergeCount=0;
  if (previousSound.length>=500 && thisSound.length>=500)
  mergeCount=500;
  for (int i=0; i  {
  previousSound[previousSound.length-mergeCount+i]
  =(byte)((previousSound[previousSound.length
  -mergeCount+i]+thisSound[i])/2);
  }


  播放前一個音符
  playSound(previousSound);


  切割當前的音符作為前一個音符
  byte[] newSound=new byte[thisSound.length-mergeCount];
  for (int ii=0; ii  newSound[ii]=thisSound[ii+mergeCount];
  previousSound=newSound;
  }
  else
  previousSound=thisSound;
  }


  //播放最終聲音和刷新聲音通道
  playSound(previousSound);
  drain();
}

在sayPhoneWord()結尾,你看到它調用playSound(..)來輸出單獨的聲音例子,并且調用drain(..)來刷新聲音通道。這里是playSound(..)的代碼:


/*
*播放一個聲音
*/
private void playSound(byte[] data)
{
  if (data.length>0) line.write(data, 0, data.length);
}

drain(..)的代碼:


/*
*刷新聲音通道
*/
private void drain()
{
  if (line!=null) line.drain();
  try {Thread.sleep(100);} catch (Exception e) {}
}

現在,如果你回頭看看sayPhoneWord(..)方法,你將發現還有一個方法我們還沒有提到:getSound(..).


getSound(..)從事先錄制好的au文件中讀出聲音的字節數據。當我說文件時,指的是我提供的zip文件里的資源。我強調這點差別,因為你得到JAR資源控制 – 使用getResource(..)方法 – 這不同于得到一個普通文件的控制權。

為了有一個語音一個語音的讀出數據,轉換到聲音格式,實例化一個聲音輸出行(為什么他們叫它SourceDateLine,我不知道),組合這些字節數據,我在下面代碼中提供給你說明:


/*
*這個方法從文件中讀出單獨的語音并且構造一個字節矢量
*/
private byte[] getSound(String fileName)
{
  try
  {
  URL url=Talker.class.getResource(fileName);
  AudioInputStream stream = AudioSystem.getAudioInputStream(url);

  AudioFormat format = stream.getFormat();

 

轉換一個ALAW/ULAW聲音到PCM
  if ((format.getEncoding() == AudioFormat.Encoding.ULAW) ||
  (format.getEncoding() == AudioFormat.Encoding.ALAW))
  {
  AudioFormat tmpFormat = new AudioFormat(
  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.Info info = new DataLine.Info(
  Clip.class,
  format,
  ((int) stream.getFrameLength() * format.getFrameSize()));

  if (line==null)
  {
  // -- Output line not instantiated yet –
  // -- Can we find a suitable kind of line? --
  DataLine.Info outInfo = new DataLine.Info(SourceDataLine.class,
  format);
  if (!AudioSystem.isLineSupported(outInfo))
  {
  System.out.println("Line matching " + outInfo + " not supported.");
  throw new Exception("Line matching " + outInfo + " not supported.");
  }

 

打開資源數據行(輸出行output line)
  line = (SourceDataLine) AudioSystem.getLine(outInfo);
  line.open(format, 50000);
  line.start();
  }

//一些尺寸計算
  int frameSizeInBytes = format.getFrameSize();
  int bufferLengthInFrames = line.getBufferSize() / 8;
  int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;

  byte[] data=new byte[bufferLengthInBytes];

  //讀出數據字節并計算
  int numBytesRead = 0;
  if ((numBytesRead = stream.read(data)) != -1)
  {
  int numBytesRemaining = numBytesRead;
  }

 

//裁剪字節數組到正確尺寸
  byte[] newData=new byte[numBytesRead];
  for (int i=0; i  newData[i]=data[i];

  return newData;
  }
  catch (Exception e)
  {
  return new byte[0];
  }
}

好了,就這么多。一個150行的語音合成器代碼,包括說明。但這沒有完全結束。

文本到語音(Text-to-speech)的轉換
用語音學方法表示單詞可能太乏味,所以,如果你想創建一個象我介紹一樣的應用程序,你要提供原始文本。

研究過這個題目后,我在zip文件中提供一個實驗性的文本到語音的轉換類。當你運行它后,將輸出給你你想要的語音表示。

在命令行模式,運行text-to-speech轉換器:


java com.lotontech.speech.Converter "hello there"

你看到的輸出類似下面這樣:


hello -> h|e|l|oo
there -> dth|aer

或者,象這樣運行它:


java com.lotontech.speech.Converter "I like to read JavaWorld"

看到(并且聽到)這些:


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”:

替換 "*unique*"使用 "|y|ou|n|ee|k|"
替換"*want*"使用"|w|o|n|t|"
替換"*a*"使用"|a|"
替換"*e*"使用"|e|"
替換"*d*"使用"|d|"
替換"*n*" 使用"|n|"
替換"*u*"使用"|u|"
替換"*t*" 使用"|t|"
”unwanted”的順序將是這樣:


unwanted
un[|w|o|n|t|]ed (rule 2)
[|u|][|n|][|w|o|n|t|][|e|][|d|] (rules 4, 5, 6, 7)
u|n|w|o|n|t|e|d (with surplus characters removed)

你應該看到,包含ant的want被用幾種不同的方式朗讀。你也應該看到對于unique來說的特殊情況,應該被讀為y|ou..而不是u|n….

電腦里的精靈,對你說話
這篇文章提供一個可以使用Java 1.3運行的簡便的語音引擎。如果你研究這些代碼,你可以得到一些關于JavaSound API播放音頻片斷的有用方法。要想使這個引擎真的能用,你要思考文本到語音的轉換方法,這真的是我的一個主要想法。在這個引擎中,你要想出大量的文本轉換規則,還要應用一些好的優先順序。我希望你有比我強的毅力。

最后,你可能還記得我說過的Nokia 9210。我有一部,它支持Java,我決定用Java使它說話。我也想使applet(Java2的以前版本)在瀏覽器中說話。這些技術依靠J2SE 1.3聲音引擎,現在是可用的。一個不同的方法是需要的,依靠簡單的Java AudioClip 接口。不像你想象的那樣簡單,但我在其上工作。

關于作者
Tony Loton
為他的公司工作 – LOTONTech Limited – 提供軟件解決方案,顧問,培訓和技術寫作服務。寫作的小蟲好像在這一年里始終叮咬著他,他為John Wiley & Sons 和 Wrox Press出版社寫書。

關于譯者

Cocia Lin(cocia@163.com)是程序員。它擁有學士學位,現在專攻Java相關技術,剛剛開始在計算機領域折騰。

相關資源

You'll find the speech engine and related source code in the jw-0817-javatalk.zip file:
http://www.javaworld.com/jw-08-2001/javatalk/jw-0817-javatalk.zip
Go to java.sun.com's "Java Sound API" page for documentation, DOWNLOAD information, and FAQ:
http://java.sun.com/products/java-media/sound/
To see how the speech engine will combine with Webpages to build my talking browser, read "Access the World's Biggest Database with Web Database Connectivity," Tony Loton (JavaWorld, March 2001):
db.html">http://www.javaworld.com/javaworld/jw-03-2001/jw-0316-webdb.html
In "Make an EJB from Any Java Class with Java Reflection" (JavaWorld, December 2000), Tony Loton explains how to turn any Java class into an EJB, and any single-tier Java application into an enterprise application:
http://www.javaworld.com/jw-12-2000/jw-1215-anyclass.html
"Program Multimedia with JMF," Budi Kurniawan (JavaWorld):
Part 1: Go multimedia by learning how the Java Media framework compares to your stereo system (April 2001)
Part 2: Jump into Java Media Framework's important classes and interfaces (May 2001)
"Add mp3 capabilities to Java Sound with SPI," Dan Becker (JavaWorld, November 2000):
http://www.javaworld.com/jw-11-2000/jw-1103-mp3.html
Sign up for the JavaWorld This Week free weekly email newsletter to learn what's new at JavaWorld:
http://www.idg.net/jw-subscribe
You'll find a wealth of IT-related articles from our sister publications at IDG.net
 


 


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

凌海市| 临漳县| 九龙城区| 信丰县| 建昌县| 东乌珠穆沁旗| 井研县| 白山市| 马龙县| 响水县| 若羌县| 金湖县| 景洪市| 门头沟区| 普定县| 佛坪县| 陇南市| 嘉善县| 卓尼县| 鸡泽县| 高清| 武川县| 贡山| 策勒县| 丽江市| 威信县| 盐津县| 齐河县| 建昌县| 邯郸市| 屏边| 丹凤县| 壤塘县| 江达县| 电白县| 福建省| 循化| 新宁县| 阜平县| 吉林省| 射洪县|