Programiranje

Talking Java!

Zakaj bi radi, da vaše aplikacije govorijo? Za začetek je zabaven in primeren za zabavne aplikacije, kot so igre. In obstaja bolj resna stran dostopnosti. Tu mislim ne samo na tiste, ki so naravno prikrajšani pri uporabi vizualnega vmesnika, ampak tudi na tiste situacije, ko je nemogoče - ali celo nezakonito - odvrniti pogled od tega, kar počnete.

V zadnjem času delam z nekaterimi tehnologijami za pridobivanje informacij HTML in XML iz spleta [glejte "Dostop do največje svetovne zbirke podatkov s povezljivostjo spletnih podatkovnih baz" (JavaWorld, Marec 2001)]. Zdelo se mi je, da bi lahko to delo in to idejo povezal za izgradnjo govornega spletnega brskalnika. Tak brskalnik bi se izkazal za koristnega za poslušanje delčkov informacij z vaših najljubših spletnih mest - na primer naslovov novic - tako kot poslušanje radia med sprehajanjem psa ali vožnjo v službo. Seveda bi morali s trenutno tehnologijo po prenosnem računalniku nositi priklopljen mobilni telefon, toda ta nepraktični scenarij bi se lahko v bližnji prihodnosti zelo spremenil s prihodom pametnih telefonov, ki podpirajo Javo, kot je Nokia 9210 (9290 v ZDA).

Morda bi bil kratkoročno bolj koristen bralnik e-pošte, ki je možen tudi zahvaljujoč API-ju JavaMail. Ta aplikacija bi občasno preverjala vašo mapo »Prejeto«, vašo pozornost pa bi pritegnil glas od nikoder, ki bi razglasil: «Imate novo pošto, ali bi jo rad prebral?« Podobno razmislite tudi o govornem opomniku, ki je povezan z vašo aplikacijo iz dnevnika, ki kriči "Ne pozabite na sestanek s šefom v 10 minutah!"

Če predpostavimo, da ste prodani za te ideje ali imate nekaj dobrih idej, bomo nadaljevali. Začel bom s prikazom, kako naj moja priložena zip datoteka deluje, tako da boste lahko takoj začeli delovati in preskočili podrobnosti o izvedbi, če menite, da je to preveč trdo delo.

Testna vožnja z govornim mehanizmom

Če želite uporabljati govorni mehanizem, morate v svoj CLASSPATH vključiti datoteko jw-0817-javatalk.zip in zagnati com.lotontech.speech.Talker razreda iz ukazne vrstice ali znotraj programa Java.

Če ga želite zagnati iz ukazne vrstice, vnesite:

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

Če ga želite zagnati iz programa Java, preprosto vključite dve vrstici kode:

com.lotontech.speech.Talker talker = novo com.lotontech.speech.Talker (); talker.sayPhoneWord ("h | e | l | oo"); 

Na tej točki se verjetno sprašujete o obliki "h | e | l | oo" niz, ki ga vnesete v ukazno vrstico ali ga posredujete recimoPhoneWord (...) metoda. Naj pojasnim.

Govorni mehanizem deluje tako, da združuje kratke zvočne vzorce, ki predstavljajo najmanjše enote človeškega - v tem primeru angleškega - govora. Ti zvočni vzorci, imenovani alofoni, so označeni z eno-, dvo- ali tričrkovnim identifikatorjem. Nekateri identifikatorji so očitni, nekateri pa ne tako očitni, kot lahko vidite iz fonetične predstavitve besede "zdravo".

  • h - zveni, kot bi pričakovali
  • e - zveni, kot bi pričakovali
  • l - se sliši, kot bi pričakovali, toda opazite, da sem dvojni "l" zmanjšal na enega samega
  • oo - je zvok za "zdravo", ne za "bot" in ne za "preveč"

Tu je seznam razpoložljivih alofonov:

  • a - kot pri mački
  • b - kot v kabini
  • c - kot pri mački
  • d - kot v piki
  • e - kot pri stavi
  • f - kot pri žabi
  • g - kot pri žabi
  • h - kot pri prašiču
  • jaz - kot pri prašiču
  • j - kot v jigu
  • k - kot v sodu
  • l - kot v nogi
  • m - kot v met
  • n - kot v začetku
  • o - kot ne
  • str - kot v loncu
  • r - kot pri gnitju
  • s - kot v soboto
  • t - kot v soboto
  • u - kot rečeno
  • v - kot v imeti
  • w - kot v mokrem
  • y - kot v še
  • z - kot v živalskem vrtu
  • aa - kot pri ponaredku
  • aj - kot na senu
  • ee - kot pri čebeli
  • ii - kot v visoki
  • oo - kot v go
  • bb - variacija b z drugačnim poudarkom
  • dd - variacija d z drugačnim poudarkom
  • ggg - sprememba g z drugačnim poudarkom
  • hh - variacija h z drugačnim poudarkom
  • ll - variacija l z drugačnim poudarkom
  • št - variacija n z drugačnim poudarkom
  • rr - variacija r z drugačnim poudarkom
  • tt - variacija t z drugačnim poudarkom
  • yy - variacija y z drugačnim poudarkom
  • ar - kot v avtu
  • aer - kot v negi
  • pogl - kot v kateri
  • ck - kot pri preverjanju
  • uho - kot pri pivu
  • hja - kot kasneje
  • napaka - kot kasneje (daljši zvok)
  • ng - kot pri hranjenju
  • ali - kot v zakonu
  • ou - kot v živalskem vrtu
  • ouu - kot v živalskem vrtu (daljši zvok)
  • last - kot pri kravi
  • oj - kot pri fantu
  • sh - kot v zaprtem
  • th - kot pri stvari
  • dth - kot v tem
  • uh - sprememba u
  • wh - kot kje
  • zh - kot v azijski

V človeškem govoru se višina besed v katerem koli izgovorjenem stavku dviguje in pada. Zaradi te intonacije je govor bolj naraven, bolj čustven in omogoča ločevanje vprašanj od izjav. Če ste že kdaj slišali sintetični glas Stephena Hawkinga, razumete, o čem govorim. Razmislite o teh dveh stavkih:

  • Je ponaredek - f | aa | k
  • Je ponaredek? - f | AA | k

Kot ste že slutili, je način dvigovanja intonacije uporaba velikih črk. S tem morate malo eksperimentirati in moj namig je, da bi se morali osredotočiti na dolge samoglasnike.

To je vse, kar morate vedeti za uporabo programske opreme, če pa vas zanima, kaj se dogaja pod pokrovom, preberite.

Izvedite govorni mehanizem

Za izvajanje govornega mehanizma je potreben le en razred s štirimi metodami. Uporablja Java Sound API, vključen v J2SE 1.3. Ne bom zagotovil izčrpne vadnice Java Sound API, vendar se boste naučili z zgledom. Ugotovili boste, da ni veliko, komentarji pa vam povedo, kaj morate vedeti.

Tu je osnovna opredelitev Govornik razred:

paket com.lotontech.speech; uvoz javax.sound.sampled. *; uvoz java.io. *; uvoz java.util. *; uvoz java.net. *; javni razred Talker {private SourceDataLine line = null; } 

Če tečeš Govornik iz ukazne vrstice, glavni (...) spodnja metoda bo služila kot vstopna točka. Vzame prvi argument ukazne vrstice, če obstaja, in ga posreduje recimoPhoneWord (...) metoda:

/ * * Ta metoda govori fonetično besedo, določeno v ukazni vrstici. * / public static void main (String args []) {Predvajalnik Talker = nov Talker (); if (args.length> 0) player.sayPhoneWord (args [0]); System.exit (0); } 

The recimoPhoneWord (...) metodo pokliče glavni (...) zgoraj, ali pa ga lahko pokličete neposredno iz aplikacije Java ali vtičnika, ki je podprt. Videti je bolj zapleteno, kot je. V bistvu preprosto stopi skozi besedo alofoni - ločeno z "|"v vhodnem besedilu - in jih predvaja enega za drugim skozi izhodni zvočni kanal. Da bo bolj naravno, združim konec vsakega zvočnega vzorca z začetkom naslednjega:

/ * * Ta metoda govori dano fonetično besedo. * / public void sayPhoneWord (besedna beseda) {// - nastavite navidezno bajtno matriko za prejšnji zvok - bajt [] previousSound = null; // - razdelimo vhodni niz na ločene alofone - StringTokenizer st = new StringTokenizer (beseda, "|", false); while (st.hasMoreTokens ()) {// - Izdelajte ime datoteke za alofon - String thisPhoneFile = st.nextToken (); thisPhoneFile = "/ allophones /" + thisPhoneFile + ". au"; // - Pridobi podatke iz datoteke - bajt [] thisSound = getSound (thisPhoneFile); if (previousSound! = null) {// - Spoji prejšnji alofon s tem, če lahko - int mergeCount = 0; če je (previousSound.length> = 500 && thisSound.length> = 500) mergeCount = 500; za (int i = 0; i

Konec leta recimoPhoneWord (), boste videli, da kliče playSound (...) za izhod posameznega vzorca zvoka (alofon) in pokliče odtok (...) za izpiranje zvočnega kanala. Tu je koda za playSound (...):

/ * * Ta metoda predvaja zvočni vzorec. * / private void playSound (bajt [] podatki) {if (data.length> 0) line.write (data, 0, data.length); } 

In za odtok (...):

/ * * Ta metoda odstrani zvočni kanal. * / private void drain () {if (line! = null) line.drain (); poskusite {Thread.sleep (100);} catch (izjema e) {}} 

Zdaj, če se ozrete nazaj na recimoPhoneWord (...) boste videli eno metodo, ki je še nisem obravnaval: getSound (...).

getSound (...) bere v predhodno posnetem vzorcu zvoka kot bajtne podatke iz datoteke au. Ko rečem datoteka, mislim na vir v priloženi zip datoteki. Razlikovam med seboj, ker način, kako pridete do vira JAR - z uporabo getResource (...) metoda - nadaljuje se drugače kot način, kako pridete do datoteke, kar ni očitno dejstvo.

Za podroben opis branja podatkov, pretvorbe zvočnega formata, instanciranja zvočne izhodne črte (zakaj temu pravijo SourceDataLine, Ne vem) in pri zbiranju bajtnih podatkov vas napotim na komentarje v kodi, ki sledi:

/ * * Ta metoda prebere datoteko za en alofon in * izdela bajtni vektor. * / zasebni bajt [] getSound (niz datotekeName) {poskusite {URL url = Talker.class.getResource (ime datoteke); AudioInputStream stream = AudioSystem.getAudioInputStream (url); AudioFormat format = stream.getFormat (); // - Pretvorite zvok ALAW / ULAW v PCM za predvajanje - če ((format.getEncoding () == AudioFormat.Encoding.ULAW) || (format.getEncoding () == AudioFormat.Encoding.ALAW)) { AudioFormat tmpFormat = novo 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) {// - Izhodna vrstica še ni instantirana - // - Ali lahko najdemo primerno vrsto vrstice? - DataLine.Info outInfo = nova DataLine.Info (SourceDataLine.class, format); če (! AudioSystem.isLineSupported (outInfo)) {System.out.println ("Ujemanje vrstic" + outInfo + "ni podprto."); vrzi novo izjemo ("Ujemanje vrstic" + outInfo + "ni podprto."); } // - Odprite izvorno podatkovno vrstico (izhodna vrstica) - line = (SourceDataLine) AudioSystem.getLine (outInfo); line.open (format, 50000); line.start (); } // - Nekateri izračuni velikosti - int frameSizeInBytes = format.getFrameSize (); int bufferLengthInFrames = line.getBufferSize () / 8; int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes; bajt [] podatki = nov bajt [bufferLengthInBytes]; // - preberite bajte podatkov in jih preštejte - int numBytesRead = 0; if ((numBytesRead = stream.read (data))! = -1) {int numBytesRemaining = numBytesRead; } // - Skrajšaj bajtno matriko na pravilno velikost - bajt [] newData = nov bajt [numBytesRead]; za (int i = 0; i

Torej, to je to. Sintetizator govora v približno 150 vrsticah kode, vključno s komentarji. Ampak še ni povsem konec.

Pretvorba besedila v govor

Navajanje besed fonetično se lahko zdi nekoliko dolgočasno, tako da, če nameravate zgraditi eno od primerov aplikacij, ki sem jih predlagal v uvodu, želite navesti navadno besedilo kot vhod za govor.

Po preučitvi težave sem v datoteki zip zagotovil poskusni razred pretvorbe besedila v govor. Ko ga zaženete, boste dobili vpogled v to, kaj počne.

Pretvornik besedila v govor lahko zaženete z ukazom, kot je ta:

java com.lotontech.speech.Converter "zdravo tam" 

Izpis bo videti nekako takole:

zdravo -> h | e | l | oo tam -> dth | aer 

Ali pa kako bi ga zagnali takole:

java com.lotontech.speech.Converter "Rad berem JavaWorld" 

da vidim (in slišim) to:

i -> ii všeč -> l | ii | k do -> t | ouu read -> r | ee | a | d java -> j | a | v | a world -> w | err | l | d 

Če se sprašujete, kako to deluje, vam lahko rečem, da je moj pristop dokaj preprost in je sestavljen iz nabora pravil za zamenjavo besedila, ki se uporabljajo v določenem vrstnem redu. Tu je nekaj primerov pravil, ki bi jih morda radi mentalno uporabili za besede "mrav", "želim", "želel", "neželen" in "edinstven":

  1. Zamenjajte "* unique *" z "| y | ou | n | ee | k |"
  2. Zamenjajte "* želim *" z "| w | o | n | t |"
  3. Zamenjajte "* a *" z "| a |"
  4. Zamenjajte "* e *" z "| e |"
  5. Zamenjajte "* d *" z "| d |"
  6. Zamenjajte "* n *" z "| n |"
  7. Zamenjajte "* u *" z "| u |"
  8. Zamenjajte "* t *" z "| t |"

Za "neželeno" bi bilo zaporedje tako:

nezaželenaun [| w | o | n | t |] izd (pravilo 2) [| u |] [| n |] [| w | o | n | t |] [| e |] [| d |] (pravila 4, 5, 6, 7) u | n | w | o | n | t | e | d (z odstranjenimi presežki znakov) 

Morali bi videti, kako besede, ki vsebujejo črke navada se govori drugače kot besede, ki vsebujejo črke Mravlja. Prav tako bi morali videti, kako pravilo velja za celotno besedo v posebnem primeru edinstven ima prednost pred drugimi pravili, tako da je ta beseda izgovorjena kot y | ou ... raje kot u | n ....

$config[zx-auto] not found$config[zx-overlay] not found