Programmēšana

Runā Java!

Kāpēc jūs vēlaties likt lietojumprogrammām runāt? Sākumā tas ir jautri un piemērots jautrām lietojumprogrammām, piemēram, spēlēm. Un tur ir daudz nopietnāka pieejamības puse. Es šeit domāju ne tikai tos, kuri dabiski ir nelabvēlīgi, izmantojot vizuālo saskarni, bet arī situācijas, kurās nav iespējams - vai pat nelikumīgi - atraut acis no tā, ko darāt.

Nesen es strādāju ar dažām tehnoloģijām, lai HTML un XML informāciju iegūtu no tīmekļa [sk. "Piekļuve pasaules lielākajai datu bāzei, izmantojot Web DataBase Connectivity" (JavaWorld, 2001. gada marts)]. Man ienāca prātā, ka es varētu savienot šo darbu un šo ideju kopā, lai izveidotu runājošu tīmekļa pārlūku. Šāds pārlūks noderētu, klausoties informācijas fragmentus no jūsu iecienītākajām vietnēm - piemēram, ziņu virsrakstus - tāpat kā klausoties radio, ejot ar suni vai braucot uz darbu. Protams, izmantojot pašreizējās tehnoloģijas, jums būs jāpārnēsā klēpjdators ar pievienotu mobilo tālruni, taču šis nepraktiskais scenārijs tuvākajā nākotnē varētu mainīties, parādoties Java viedtālruņiem, piemēram, Nokia 9210 (9290 iekšpusē). ASV).

Varbūt īstermiņā noderīgāks būtu e-pasta lasītājs, kas iespējams arī pateicoties JavaMail API. Šī lietojumprogramma periodiski pārbaudīs jūsu iesūtni, un jūsu uzmanību piesaistīs balss no nekurienes, kas paziņo: "Jums ir jauns pasts, vai vēlaties, lai es jums to izlasu?" Līdzīgā veidā apsveriet runājošu atgādinājumu, kas saistīts ar jūsu dienasgrāmatas lietojumprogrammu, kas sauc "Neaizmirstiet savu tikšanos ar priekšnieku 10 minūtēs!"

Pieņemot, ka esat pārdots par šīm idejām vai jums ir dažas labas idejas, mēs turpināsim. Sākumā es parādīšu, kā ievietot piegādāto ZIP failu, lai jūs varētu uzreiz sākt darboties un izlaist ieviešanas detaļas, ja domājat, ka tas ir pārāk smags darbs.

Pārbaudiet runas dzinēju

Lai izmantotu runas motoru, CLASSPATH jāiekļauj fails jw-0817-javatalk.zip un jāpalaiž com.lotontech.speech.Talker klases no komandrindas vai no Java programmas.

Lai to palaistu no komandrindas, ierakstiet:

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

Lai to palaistu no Java programmas, vienkārši iekļaujiet divas koda rindas:

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

Šajā brīdī jūs, iespējams, domājat par formātu "h | e | l | oo" virkne, kuru piegādājat komandrindā vai sniedzat teiksimPhoneWord (...) metodi. Ļauj man paskaidrot.

Runas motors darbojas, savienojot īsus skaņas paraugus, kas atspoguļo mazākās cilvēku - šajā gadījumā angļu - runas vienības. Tie skaņas paraugi, saukti alofoni, ir marķēti ar viena, divu vai trīs burtu identifikatoru. Daži identifikatori ir acīmredzami, un daži ne tik acīmredzami, kā jūs varat redzēt no vārda "sveiki" fonētiskā attēlojuma.

  • h - izklausās, kā jūs varētu gaidīt
  • e - izklausās, kā jūs varētu gaidīt
  • l - izklausās, kā jūs varētu sagaidīt, bet ievērojiet, ka esmu samazinājis dubulto "l" uz vienu
  • oo - vai skaņa ir "sveiki", nevis "bot" un ne "pārāk"

Šeit ir pieejamo alofonu saraksts:

  • a - kā kaķim
  • b - kā kabīnē
  • c - kā kaķī
  • d - kā pa punktam
  • e - kā derībās
  • f - kā vardē
  • g - kā vardē
  • h - kā cūkā
  • i - kā cūkai
  • j - kā džigā
  • k - kā mucā
  • l - kā kājā
  • m - kā met
  • n - kā sākumā
  • o - kā nav
  • lpp - kā katlā
  • r - kā puvi
  • s - kā sēd
  • t - kā sēd
  • u - kā likts
  • v - kā jau ir
  • w - kā slapjā
  • y - kā jau
  • z - kā zoodārzā
  • aa - kā viltus
  • ay - kā sienā
  • ee - kā bitei
  • ii - kā augstajā
  • oo - kā iet
  • bb - b variācija ar dažādu uzsvaru
  • dd - d variācija ar dažādu uzsvaru
  • ggg - g variācija ar dažādu uzsvaru
  • hh - h variācija ar dažādu uzsvaru
  • ll - l variācija ar dažādu uzsvaru
  • nn - n variācija ar dažādu uzsvaru
  • rr - r variācija ar dažādu uzsvaru
  • tt - t variācija ar dažādu uzsvaru
  • yy - y variācija ar dažādu uzsvaru
  • ar - kā mašīnā
  • aer - kā aprūpē
  • ch - kā kurā
  • ck - kā čekā
  • auss - kā alus
  • er - kā vēlāk
  • kļūdīties - kā vēlāk (garāka skaņa)
  • ng - kā barošanā
  • vai - kā likumā
  • ou - kā zoodārzā
  • ouu - kā zooloģiskajā dārzā (garāka skaņa)
  • ow - kā govī
  • oy - kā zēnā
  • sh - kā ciet
  • th - kā lietā
  • dth - kā šajā
  • uh - variācija u
  • wh - kā kur
  • zh - kā Āzijas

Cilvēka runā vārdu piķis pieaug un krīt visā teiktajā teikumā. Šī intonācija padara runu dabiskāku, emocionālāku un ļauj nošķirt jautājumus no izteikumiem. Ja esat kādreiz dzirdējis Stīvena Hokinga sintētisko balsi, jūs saprotat, par ko es runāju. Apsveriet šos divus teikumus:

  • Tas ir viltots - f | aa | k
  • Vai tas ir viltots? - f | AA | k

Kā jūs jau nojautāt, intonācijas paaugstināšanas veids ir lielo burtu izmantošana. Jums tas ir nedaudz jāeksperimentē, un mans mājiens ir tāds, ka jums vajadzētu koncentrēties uz garo patskaņu skaņām.

Tas ir viss, kas jums jāzina, lai izmantotu programmatūru, bet, ja jūs interesē tas, kas notiek zem pārsega, lasiet tālāk.

Ieviesiet runas dzinēju

Runas motoram ir nepieciešama tikai viena klase, izmantojot četras metodes. Tajā tiek izmantota Java Sound API, kas iekļauta J2SE 1.3. Es nesniegšu visaptverošu Java Sound API apmācību, bet jūs uzzināsiet ar piemēru. Jūs atradīsit, ka tajā nav daudz, un komentāri norāda, kas jums jāzina.

Šeit ir pamata definīcija Runātājs klase:

pakete com.lotontech.speech; importēt javax.sound.samples. *; importēt java.io. *; importēt java.util. *; importēt java.net. *; publiskā klase Runātājs {private SourceDataLine line = null; } 

Ja skrien Runātājs no komandrindas galvenais (...) zemāk izmantotā metode kalpos kā ieejas punkts. Tas aizņem pirmo komandrindas argumentu, ja tāds pastāv, un nodod to teiksimPhoneWord (...) metode:

/ * * Šī metode izrunā komandrindā norādīto fonētisko vārdu. * / public static void main (String args []) {Talker player = new Talker (); if (args.length> 0) player.sayPhoneWord (args [0]); System.exit (0); } 

The teiksimPhoneWord (...) metodi sauc ar galvenais (...) vai arī to var izsaukt tieši no jūsu Java lietojumprogrammas vai spraudņu atbalstītās sīklietotnes. Tas izskatās sarežģītāk, nekā tas ir. Būtībā tas vienkārši veic vārdu allophones - atdalīts ar "|"simboli ievades tekstā - un atskaņo tos pa vienam, izmantojot skaņas izvades kanālu. Lai tas izklausītos dabiskāk, es apvienoju katra skaņas parauga beigas ar nākamā sākumu:

/ * * Šī metode runā doto fonētisko vārdu. * / public void sayPhoneWord (virknes vārds) {// - iestatiet manekena baitu masīvu iepriekšējai skaņai - baits [] previousSound = null; // - sadaliet ievades virkni atsevišķos alofonos - StringTokenizer st = new StringTokenizer (word, "|", false); while (st.hasMoreTokens ()) {// - Konfigurējiet faila nosaukumu alofonam - String thisPhoneFile = st.nextToken (); thisPhoneFile = "/ allophones /" + thisPhoneFile + ". au"; // - iegūt datus no faila - baits [] thisSound = getSound (thisPhoneFile); if (previousSound! = null) {// - Apvienot iepriekšējo alofonu ar šo, ja mēs varam - int mergeCount = 0; ja (iepriekšējāSkaņas.length> = 500 && thisSound.length> = 500) mergeCount = 500; par (int i = 0; i

Beigās sayPhoneWord (), jūs redzēsiet, ka tā zvana playSound (...) lai izvadītu atsevišķu skaņas paraugu (alofonu), un tas zvana notekas (...) lai izskalotu skaņas kanālu. Šeit ir kods playSound (...):

/ * * Šī metode atskaņo skaņas paraugu. * / private void playSound (baitu [] dati) {if (datu.length> 0) rinda.write (dati, 0, data.length); } 

Un par notekas (...):

/ * * Šī metode izskalo skaņas kanālu. * / private void drain () {if (line! = null) line.drain (); izmēģiniet {Thread.sleep (100);} catch (e izņēmums) {}} 

Tagad, ja atskatāties uz teiksimPhoneWord (...) metodi, jūs redzēsiet, ka ir viena metode, kuru es vēl neesmu aplūkojis: getSound (...).

getSound (...) nolasa iepriekš ierakstītā skaņas paraugā kā baitu datus no au faila. Sakot failu, es domāju resursu, kas atrodas piegādātajā ZIP failā. Es nošķiru, jo veids, kā jūs iegūstat JAR resursu, izmantojot getResource (...) metode - notiek atšķirīgi no tā, kā jūs iegūstat failu, tas nav acīmredzams fakts.

Datu lasīšanas, skaņas formāta konvertēšanas, skaņas izvades līnijas (kāpēc viņi to sauc par SourceDataLine, Es nezinu) un apkopojot baitu datus, es atsaucos uz komentāriem kodā, kas seko:

/ * * Šī metode nolasa viena alofona failu un * izveido baitu vektoru. * / privāts baits [] getSound (virknes faila nosaukums) {mēģiniet {URL url = Talker.class.getResource (faila nosaukums); AudioInputStream straume = AudioSystem.getAudioInputStream (url); AudioFormat formāts = stream.getFormat (); // - konvertējiet ALAW / ULAW skaņu uz PCM atskaņošanai - 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); straume = AudioSystem.getAudioInputStream (tmpFormat, straume); format = tmpFormat; } DataLine.Info info = new DataLine.Info (Clip.class, format, ((int) stream.getFrameLength () * format.getFrameSize ())); if (line == null) {// - izejas līnija vēl nav instantiated - // - Vai mēs varam atrast piemērotu līnijas veidu? - DataLine.Info outInfo = jauns DataLine.Info (SourceDataLine.class, formāts); ja (! AudioSystem.isLineSupported (outInfo)) {System.out.println ("Line matching" + outInfo + "netiek atbalstīts."); mest jaunu izņēmumu ("Line matching" + outInfo + "neatbalsta".); } // - Atveriet avota datu līniju (izvades līnija) - rinda = (SourceDataLine) AudioSystem.getLine (outInfo); line.open (formāts, 50000); line.start (); } // - Daži izmēru aprēķini - int frameSizeInBytes = format.getFrameSize (); int bufferLengthInFrames = line.getBufferSize () / 8; int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes; baits [] dati = jauns baits [bufera garumsInBaitos]; // - nolasiet datu baitus un saskaitiet tos - int numBytesRead = 0; if ((numBytesRead = straume.lasīt (dati))! = -1) {int numBytesRemaining = numBytesRead; } // - saīsiniet baitu masīvu līdz pareizajam izmēram - baits [] newData = jauns baits [numBytesRead]; par (int i = 0; i

Tātad, viss. Runas sintezators aptuveni 150 koda rindiņās, ieskaitot komentārus. Bet tas vēl nav beidzies.

Teksta pārveidošana runā

Vārdu norādīšana fonētiski var šķist nedaudz nogurdinoša, tādēļ, ja jūs plānojat izveidot vienu no lietojumprogrammu piemēriem, kurus es ierosināju ievadā, jūs vēlaties sniegt parastu tekstu kā ievadāmu tekstu.

Pēc jautājuma izskatīšanas zip failā esmu nodrošinājis eksperimentālu teksta pārveidošanu runā. Kad jūs to palaižat, izvade sniegs ieskatu par to, ko tā dara.

Teksta-runas pārveidotāju var palaist ar šādu komandu:

java com.lotontech.speech.Converter "sveiki tur" 

Tas, ko redzēsiet kā izvadi, izskatās apmēram šādi:

labdien -> h | e | l | oo tur -> dth | aer 

Vai arī kā rīkoties tā:

java com.lotontech.speech.Converter "Man patīk lasīt JavaWorld" 

lai to redzētu (un dzirdētu):

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

Ja jūs domājat, kā tas darbojas, es varu pateikt, ka mana pieeja ir diezgan vienkārša, kas sastāv no teksta aizstāšanas noteikumu kopuma, kas tiek piemērots noteiktā secībā. Šeit ir daži noteikumu piemēri, kurus jūs varētu vēlēties piemērot garīgi, lai vārdiem "skudra", "gribu", "meklējamais", "nevēlamais" un "unikālais":

  1. Aizstājiet "* unikāls *" ar "| y | ou | n | ee | k |"
  2. Aizstājiet "* vēlaties *" ar "| w | o | n | t |"
  3. Aizstājiet "* a *" ar "| a |"
  4. Aizstāt "* e *" ar "| e |"
  5. Aizstāt "* d *" ar "| d |"
  6. Aizstāt "* n *" ar "| n |"
  7. Aizstājiet "* u *" ar "| u |"
  8. Aizstāt "* t *" ar "| t |"

"Nevēlamajam" secība būtu šāda:

nevēlamsun [| w | o | n | t |] red (2. noteikums) [| u |] [| n |] [| w | o | n | t |] [| e |] [| d |] (4., 5., 6., 7. noteikums) u | n | w | o | n | t | e | d (ar lieko rakstzīmju noņemšanu) 

Jums vajadzētu redzēt, kā vārdi, kas satur burtus paradis tiks runāts citādi nekā vārdi, kas satur burtus skudra. Jums vajadzētu arī redzēt, kā īpašais gadījums nosaka pilnu vārdu unikāls ir prioritāte pār citiem noteikumiem, lai šo vārdu runātu kā y | ou ... nevis u | n ....

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