Ohjelmointi

Java puhuu!

Miksi haluaisit saada sovelluksesi puhumaan? Aluksi se on hauskaa ja sopii hauskoihin sovelluksiin, kuten peleihin. Ja siellä on vakavampi esteettömyyspuoli. Ajattelen täällä paitsi niitä, jotka ovat luonnollisesti epäedullisessa asemassa, kun käytät visuaalista käyttöliittymää, mutta myös tilanteita, joissa on mahdotonta - tai jopa laitonta - poistaa silmäsi tekemästäsi.

Viime aikoina olen työskennellyt joidenkin tekniikoiden kanssa ottaaksesi HTML- ja XML-tietoja verkosta [katso "Pääsy maailman suurimpaan tietokantaan Web DataBase -yhteyksien avulla" (JavaWorld, Maaliskuuta 2001]. Ajattelin, että voisin liittää työn ja tämän idean yhteen rakentaakseni puhuvan verkkoselaimen. Tällainen selain osoittautuu hyödylliseksi kuunnellessasi katkelmia suosikkisivustoistasi - esimerkiksi uutisotsikoista - aivan kuten radion kuunteleminen koiran kävelemisen tai töihin ajamisen aikana. Tietysti nykyisen tekniikan avulla sinun on kannettava kannettavaa tietokonetta matkapuhelimen ollessa liitettynä, mutta epäkäytännöllinen skenaario voi hyvinkin muuttua lähitulevaisuudessa, kun saapuvat Java-yhteensopivat älypuhelimet, kuten Nokia 9210 (9290 vuonna MEILLE).

Ehkä hyödyllisempi lyhyellä aikavälillä olisi sähköpostinlukija, mahdollista myös JavaMail-sovellusliittymän ansiosta. Tämä sovellus tarkastaisi postilaatikkosi säännöllisesti, ja huomiosi houkuttelisi äänestä mistä tahansa, joka julisti "Sinulla on uusi posti, haluaisitko minun lukevan sen sinulle?" Harkitse samalla tavalla päiväkirjahakemukseesi liittyvää puhuttavaa muistutusta, joka huutaa "Älä unohda tapaamistasi pomon kanssa 10 minuutissa!"

Olettaen, että olet myynyt näitä ideoita tai sinulla on hyviä ideoita, siirrymme eteenpäin. Aloitan näyttämällä, kuinka toimitan toimitetun zip-tiedoston toimimaan, jotta voit päästä heti käyntiin ja ohittaa toteutuksen yksityiskohdat, jos luulet, että se on liian kovaa työtä.

Testaa puhekone

Puhemoottorin käyttämiseksi sinun on sisällytettävä jw-0817-javatalk.zip-tiedosto CLASSPATH-tiedostoon ja suoritettava com.lotontech.speech.Talker luokan komentoriviltä tai Java-ohjelmasta.

Suorita se komentoriviltä kirjoittamalla:

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

Jos haluat suorittaa sen Java-ohjelmasta, sisällytä vain kaksi koodiriviä:

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

Tässä vaiheessa luultavasti ihmettelet "h | e | l | oo" merkkijono, jonka annat komentoriville tai annat sayPhoneWord (...) menetelmä. Anna minun selittää.

Puhekone toimii liittämällä lyhyitä ääninäytteitä, jotka edustavat pienimpiä ihmisen - tässä tapauksessa englanninkielisen - puheen yksiköitä. Ne ääninäytteet, kutsutaan allofonit, on merkitty yhden, kahden tai kolmen kirjaimen tunnisteella. Jotkut tunnisteet ovat ilmeisiä ja toiset eivät niin ilmeisiä, kuten sanan "hei" foneettisesta esityksestä voi nähdä.

  • h - kuulostaa kuten voit odottaa
  • e - kuulostaa kuten voit odottaa
  • l - kuulostaa odotetulta, mutta huomaa, että olen kaksinkertaistanut "l": n yhdeksi
  • oo - on ääni "hei", ei "bot" eikä "liian"

Tässä on luettelo käytettävissä olevista allofoneista:

  • a - kuten kissassa
  • b - kuten ohjaamossa
  • c - kuten kissassa
  • d - kuten pisteessä
  • e - kuten vedonlyönnissä
  • f - kuten sammakossa
  • g - kuten sammakossa
  • h - kuten sianlihassa
  • i - kuten sialla
  • j - kuten jigissä
  • k - kuten tynnyrissä
  • l - kuten jalka
  • m - kuten tapasi
  • n - kuten alussa
  • o - kuten ei
  • s - kuten potissa
  • r - kuten mätää
  • s - kuten ist
  • t - kuten ist
  • u - kuten sanotaan
  • v - kuten on
  • w - kuten märällä
  • y - kuten vielä
  • z - kuten eläintarhassa
  • aa - kuin väärennös
  • ay - kuten heinässä
  • ee - kuten mehiläisessä
  • ii - kuten korkealla
  • oo - kuten menossa
  • bb - b: n variaatio eri painotuksella
  • dd - d: n vaihtelu eri painotuksella
  • ggg - g: n vaihtelu eri painotuksella
  • HH - h: n vaihtelu eri painotuksella
  • ll - l: n vaihtelu eri painotuksella
  • nn - n: n vaihtelu eri painotuksella
  • rr - r: n vaihtelu eri painotuksella
  • tt - t: n vaihtelu eri painotuksella
  • yy - y: n vaihtelu eri painotuksella
  • ar - kuten autossa
  • aer - kuten hoidossa
  • ch - kuten missä
  • ck - kuten sekissä
  • korva - kuten oluessa
  • er - kuten myöhemmin
  • virhe - kuten myöhemmin (pidempi ääni)
  • ng - kuten ruokinnassa
  • tai - kuten laissa
  • ou - kuten eläintarhassa
  • ouu - kuten eläintarhassa (pidempi ääni)
  • ow - kuten lehmällä
  • oy - kuten pojalla
  • sh - kuten suljettuna
  • th - kuten asia
  • dth - kuten tässä
  • uh - vaihtelu u
  • wh - kuten missä
  • zh - kuten aasialaisissa

Ihmisen puheessa sanojen sävelkorkeus nousee ja laskee minkä tahansa lausutun lauseen aikana. Tämä intonaatio tekee puheesta luonnollisemman, tunteellisemman ja antaa mahdollisuuden erottaa kysymykset lausunnoista. Jos olet koskaan kuullut Stephen Hawkingin synteettistä ääntä, ymmärrät mistä puhun. Harkitse näitä kahta lausetta:

  • Se on väärennös - f | aa | k
  • Onko se väärennös? - f | AA | k

Kuten olet ehkä arvannut, tapa lisätä intonaatio on käyttää isoja kirjaimia. Sinun täytyy kokeilla tätä vähän, ja vihjeni on, että sinun tulisi keskittyä pitkiin vokaalien ääniin.

Se on kaikki mitä sinun on tiedettävä, jotta voit käyttää ohjelmistoa, mutta jos olet kiinnostunut siitä, mitä hupun alla tapahtuu, lue lisää.

Ota käyttöön puhekone

Puhemoottori vaatii vain yhden luokan toteuttamisen neljällä menetelmällä. Se käyttää J2SE 1.3: n mukana toimitettua Java Sound -sovellusliittymää. En tarjoa kattavaa opasta Java Sound -sovellusliittymästä, mutta opit esimerkillä. Löydät, että siinä ei ole paljon, ja kommentit kertovat sinulle, mitä sinun tarvitsee tietää.

Tässä on Puhuja luokka:

paketti com.lotontech.speech; tuo javax.sound.sampling. *; tuo java.io. *; tuo java.util. *; tuo java.net. *; julkinen luokka Talker {private SourceDataLine line = null; } 

Jos juokset Puhuja komentoriviltä, tärkein (...) alla oleva menetelmä toimii lähtökohtana. Se vie ensimmäisen komentoriviargumentin, jos sellainen on olemassa, ja välittää sen sayPhoneWord (...) menetelmä:

/ * * Tämä menetelmä puhuu komentorivillä määritetyn foneettisen sanan. * / public static void main (String args []) {Puhujasoitin = uusi puhuja (); if (args.pituus> 0) player.sayPhoneWord (args [0]); System.exit (0); } 

sayPhoneWord (...) menetelmää kutsutaan tärkein (...) tai sitä voidaan kutsua suoraan Java-sovelluksestasi tai laajennuksia tukevasta sovelmasta. Se näyttää monimutkaisemmalta kuin on. Pohjimmiltaan se yksinkertaisesti astuu sana allofonit - erotettu "|"symbolit syöttötekstissä - ja toistavat ne yksitellen äänen ulostulokanavan kautta. Jotta se kuulostaisi luonnollisemmalta, yhdistän jokaisen ääninäytteen lopun seuraavan alkuun:

/ * * Tämä menetelmä puhuu annetun foneettisen sanan. * / public void sayPhoneWord (merkkijono) {// - Määritä nuken tavutaulukko edelliselle äänelle - tavu [] previousSound = null; // - Jaa syötemerkkijono erillisiin allofoneihin - StringTokenizer st = new StringTokenizer (sana, "|", väärä); while (st.hasMoreTokens ()) {// - Rakenna tiedostonimi allofonille - String thisPhoneFile = st.nextToken (); thisPhoneFile = "/ allophones /" + thisPhoneFile + ". au"; // - Hae tiedot tiedostosta - tavu [] thisSound = getSound (thisPhoneFile); if (previousSound! = null) {// - Yhdistä edellinen allofoni tähän, jos voimme - int mergeCount = 0; if (edellinenSound.length> = 500 && thisSound.length> = 500) mergeCount = 500; varten (int i = 0; i

Lopussa sayPhoneWord (), näet sen soittavan soita ääni(...) tuottaa yksittäisen ääninäytteen (allofoni), ja se kutsuu valua(...) huuhtele äänikanava. Tässä on koodi soita ääni(...):

/ * * Tämä menetelmä toistaa ääninäytteen. * / private void playSound (tavu [] data) {if (data.pituus> 0) line.write (data, 0, data.length); } 

Ja varten valua(...):

/ * * Tämä menetelmä huuhtelee äänikanavan. * / private void drain () {if (rivi! = tyhjä) line.drain (); kokeile {Thread.sleep (100);} catch (Poikkeus e) {}} 

Jos nyt katsot taaksepäin sayPhoneWord (...) menetelmä, näet yhden menetelmän, jota en ole vielä käsitellyt: getSound (...).

getSound (...) lukee ennalta äänitetyn ääninäytteen tavutiedoina au-tiedostosta. Kun sanon tiedoston, tarkoitan toimitetussa zip-tiedostossa olevaa resurssia. Teen eron, koska tapa, jolla saat hallussasi JAR-resurssin - käyttämällä getResource (...) menetelmä - etenee eri tavalla kuin tapaa saada tiedosto hallussasi, ei selvä tosiasia.

Tietojen lukemisen, äänimuodon muuntamisen, äänen ulostulolinjan (miksi he kutsuvat sitä SourceDataLine, En tiedä) ja kooten tavutiedot, viittaan seuraavan koodin kommentteihin:

/ * * Tämä menetelmä lukee yhden allofonin tiedoston ja * rakentaa tavuvektorin. * / yksityinen tavu [] getSound (String fileName) {kokeile {URL url = Talker.class.getResource (fileName); AudioInputStream-virta = AudioSystem.getAudioInputStream (url); AudioFormat-muoto = stream.getFormat (); // - Muunna ALAW / ULAW-ääni PCM: ksi toistoa varten - if ((format.getEncoding () == AudioFormat.Encoding.ULAW) || (format.getEncoding () == AudioFormat.Encoding.ALAW)) { AudioFormat tmpFormat = uusi AudioFormat (AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate (), format.getSampleSizeInBits () * 2, format.getChannels (), format.getFrameSize () * 2, format.getFrameRate (), true); stream = AudioSystem.getAudioInputStream (tmpFormat, virta); format = tmpFormat; } DataLine.Info info = new DataLine.Info (Clip.class, format, ((int) stream.getFrameLength () * format.getFrameSize ())); if (rivi == null) {// - Lähtöriviä ei ole vielä instantoitu - // - Voimmeko löytää sopivan tyyppisen rivin? - DataLine.Info outInfo = uusi DataLine.Info (SourceDataLine.class, muoto); if (! AudioSystem.isLineSupported (outInfo)) {System.out.println ("Linjavastaus" + outInfo + "ei tueta."); heittää uusi poikkeus ("Line matching" + outInfo + "ei tueta."); } // - Avaa lähdetietorivi (lähtörivi) - rivi = (SourceDataLine) AudioSystem.getLine (outInfo); line.open (muoto, 50000); line.start (); } // - Joitakin kokolaskelmia - int frameSizeInBytes = format.getFrameSize (); int bufferLengthInFrames = line.getBufferSize () / 8; int bufferLengthInBytes = puskuriLengthInFrames * frameSizeInBytes; tavu [] data = uusi tavu [puskuriPituusTietoja]; // - Lue datatavut ja laske ne - int numBytesRead = 0; if ((numBytesRead = stream.read (data))! = -1) {int numBytesRemaining = numBytesRead; } // - Katkaise tavutaulukko oikeaan kokoon - tavu [] newData = uusi tavu [numBytesRead]; varten (int i = 0; i

Joten se siitä. Puhesyntetisaattori noin 150 rivillä koodia, mukaan lukien kommentit. Mutta se ei ole aivan ohi.

Tekstistä puheeksi -muunnos

Sanojen määrittely foneettisesti saattaa tuntua hieman tylsältä, joten jos aiot rakentaa yhden johdannossa ehdottamistani esimerkkisovelluksista, haluat antaa tavallisen tekstin puhuttavaksi syötteeksi.

Tutkittuani asiaa olen toimittanut kokeellisen tekstistä puheeksi -muunnosluokan zip-tiedostoon. Kun suoritat sen, lähtö antaa sinulle käsityksen siitä, mitä se tekee.

Voit suorittaa teksti puheeksi -muuntimen tällaisella komennolla:

java com.lotontech.speech.Converter "hei siellä" 

Tuloksena näkemäsi näyttää tältä:

hei -> h | e | l | oo siellä -> dth | aer 

Tai miten ajaa se kuten:

java com.lotontech.speech.Converter "Tykkään lukea JavaWorldia" 

nähdä (ja kuulla) tämän:

i -> ii kuten -> l | ii | k to -> t | ouu read -> r | ee | a | d java -> j | a | v | a world -> w | err | l | d 

Jos mietit kuinka se toimii, voin kertoa teille, että lähestymistapani on melko yksinkertainen ja koostuu joukosta tekstin korvaussääntöjä, joita sovelletaan tietyssä järjestyksessä. Tässä on joitain esimerkkisääntöjä, joita haluat ehkä soveltaa henkisesti järjestyksessä sanoille "muurahainen", "halua", "etsitty", "ei-toivottu" ja "ainutlaatuinen":

  1. Korvaa "* ainutlaatuinen *" sanoilla "| y | ou | n | ee | k |"
  2. Korvaa "* want *" sanoilla "| w | o | n | t |"
  3. Korvaa "* a *" sanalla "| a |"
  4. Korvaa "* e *" sanalla "| e |"
  5. Korvaa "* d *" sanoilla "| d |"
  6. Korvaa "* n *" sanalla "| n |"
  7. Korvaa "* u *" sanoilla "| u |"
  8. Korvaa "* t *" sanalla "| t |"

"Ei-toivottujen" kohdalla sekvenssi olisi näin:

ei toivottuun [| w | o | n | t |] toim (sääntö 2) [| u |] [| n |] [| w | o | n | t |] [| e |] [| d |] (säännöt 4, 5, 6, 7) u | n | w | o | n | t | e | d (ylimääräiset merkit poistettu) 

Sinun pitäisi nähdä, kuinka sanat sisältävät kirjaimet tapa puhutaan eri tavalla kuin kirjaimia sisältävät sanat muurahainen. Sinun pitäisi myös nähdä, miten koko sanan erityistapaussääntö ainutlaatuinen on etusijalla muihin sääntöihin nähden, joten tämä sana puhutaan nimellä y | ou ... mielummin kuin u | n ....

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