Programavimas

Kalbėti Java!

Kodėl norėtumėte priversti savo programas kalbėti? Pirmiausia tai smagu ir tinka tokioms įdomioms programoms kaip žaidimai. Ir yra rimtesnė prieinamumo pusė. Aš čia galvoju ne tik apie tuos, kurie natūraliai yra nuskriausti, kai naudojatės vaizdine sąsaja, bet ir apie tas situacijas, kai neįmanoma ar net neteisėta atitraukti akis nuo to, ką darote.

Neseniai dirbau su kai kuriomis technologijomis, norėdamas perimti HTML ir XML informaciją iš žiniatinklio [žr. „Prisijunkite prie didžiausios pasaulyje duomenų bazės naudodami„ Web DataBase Connectivity “(„JavaWorld“, 2001 m. Kovo mėn.]]. Man kilo mintis, kad galėčiau prijungti tą darbą ir šią idėją, kad sukčiau kalbančią interneto naršyklę. Tokia naršyklė būtų naudinga klausantis informacijos fragmentų iš jūsų mėgstamų svetainių, pavyzdžiui, naujienų antraštės, lygiai taip pat, kaip klausantis radijo einant su šunimi ar važiuojant į darbą. Žinoma, turėdami dabartinę technologiją, turėtumėte nešiotis nešiojamąjį kompiuterį su pritvirtintu mobiliuoju telefonu, tačiau šis nepraktiškas scenarijus artimiausiu metu gali pasikeisti, kai pasirodys „Java“ palaikantys išmanieji telefonai, tokie kaip „Nokia 9210“ (9290 JAV).

Galbūt trumpuoju laikotarpiu naudingesnis būtų el. Pašto skaitytuvas, kuris taip pat įmanomas „JavaMail“ API dėka. Ši programa periodiškai tikrins jūsų gautuosius, o jūsų dėmesį pritrauks balsas iš niekur, skelbiantis: „Turite naujų laiškų, ar norėtumėte, kad jums jį perskaityčiau?“. Panašiai apsvarstykite priminimą apie pokalbį, susijusį su jūsų dienoraščio programa, kuris šaukia: „Nepamirškite susitikimo su viršininku per 10 minučių!“

Darant prielaidą, kad esate parduotas toms idėjoms ar turite gerų savo idėjų, mes eisime toliau. Pradėsiu nuo to, kaip parodysiu, kaip įdėti pateiktą ZIP failą, kad galėtumėte iškart pradėti veikti ir praleisti išsamią įgyvendinimo informaciją, jei manote, kad tai per daug sunkus darbas.

Išbandykite kalbos variklį

Norėdami naudoti kalbos variklį, turėsite įtraukti failą jw-0817-javatalk.zip į savo CLASSPATH ir paleisti com.lotontech.speech.Talker klasę iš komandinės eilutės arba iš „Java“ programos.

Norėdami paleisti jį iš komandinės eilutės, įveskite:

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

Norėdami paleisti jį iš „Java“ programos, tiesiog įtraukite dvi kodo eilutes:

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

Šiuo metu jums tikriausiai įdomu apie „h | e | l | oo“ eilutę, kurią pateikiate komandinėje eilutėje arba pateikiate „sayWhoneWord“ (...) metodas. Leisk man paaiškinti.

Kalbos variklis veikia sujungdamas trumpus garso pavyzdžius, kurie atspindi mažiausius žmogaus - šiuo atveju angliško - kalbos vienetus. Tie garso pavyzdžiai, vadinami alofonai, yra paženklinti vienos, dviejų ar trijų raidžių identifikatoriais. Kai kurie identifikatoriai yra akivaizdūs, o kiti ne tokie akivaizdūs, kaip matote iš fonetinio žodžio „labas“ pavaizdavimo.

  • h - skamba taip, kaip ir galėjai tikėtis
  • e - skamba taip, kaip ir galėjai tikėtis
  • l - skamba taip, kaip galėtumėte tikėtis, tačiau atkreipkite dėmesį, kad dvigubą „l“ sumažinau iki vieno
  • oo - ar „labas“, o ne „botas“ ir „per“ garsas

Čia pateikiamas galimų alofonų sąrašas:

  • a - kaip katėje
  • b - kaip kabinoje
  • c - kaip katėje
  • d - kaip taške
  • e - kaip lažybose
  • f - kaip varlyje
  • g - kaip varlyje
  • h - kaip kiaulėje
  • i - kaip kiaulėje
  • j - kaip jig
  • k - kaip statinėje
  • l - kaip kojoje
  • m - kaip susitikime
  • n - kaip iš pradžių
  • o - kaip ne
  • p - kaip puode
  • r - kaip puvinys
  • s - kaip sėdint
  • t - kaip sėdint
  • u - kaip sakant
  • v - kaip ir turėjo
  • w - kaip šlapiame
  • y - kaip dar
  • z - kaip zoologijos sode
  • aa - kaip netikras
  • ai - kaip šiene
  • ee - kaip bitėje
  • ii - kaip aukštumoje
  • oo - kaip ir einant
  • bb - b variantas su skirtingu akcentu
  • dd - d variantas su skirtingu akcentu
  • ggg - g variacija su skirtingu akcentu
  • hh - h variantas su skirtingu akcentu
  • ll - l variantas su skirtingu akcentu
  • nn - n variacija su skirtingu akcentu
  • rr - r variacija su skirtingu akcentu
  • tt - t variacija su skirtingu akcentu
  • yy - y variacija su skirtingu akcentu
  • ar - kaip automobilyje
  • aer - kaip ir globoje
  • ch - kaip kurioje
  • ck - kaip čekyje
  • ausis - kaip aluje
  • er - kaip ir vėliau
  • klysti - kaip vėliau (ilgesnis garsas)
  • ng - kaip maitinant
  • arba - kaip įstatyme
  • ou - kaip zoologijos sode
  • ouu - kaip zoologijos sode (ilgesnis garsas)
  • ow - kaip karvėje
  • oy - kaip berniukui
  • sh - kaip uždarytas
  • tūkst - kaip daikte
  • d - kaip šiame
  • uh - variacija u
  • Wh - kaip kur
  • zh - kaip ir Azijos

Žmogaus kalboje žodžių aukštis kyla ir krinta bet kuriame sakomame sakinyje. Dėl šios intonacijos kalba skamba natūraliau, emocingiau ir leidžia atskirti klausimus nuo teiginių. Jei kada nors girdėjote sintetinį Stepheno Hawkingo balsą, suprantate, apie ką kalbu. Apsvarstykite šiuos du sakinius:

  • Tai netikra - f | aa | k
  • Ar tai netikra? - f | AA | k

Kaip jau spėjote, intonacijos pakėlimo būdas yra didžiųjų raidžių naudojimas. Jums reikia šiek tiek tai eksperimentuoti, o mano užuomina yra ta, kad turėtumėte susitelkti ties ilgais balsių garsais.

Tai viskas, ką reikia žinoti norint naudotis programine įranga, tačiau jei jus domina tai, kas vyksta po gaubtu, skaitykite toliau.

Įdiegti kalbos variklį

Kalbos varikliui įgyvendinti reikia tik vienos klasės, naudojant keturis metodus. Jame naudojama „Java Sound“ API, įtraukta į J2SE 1.3. Aš nepateiksiu išsamios „Java Sound“ API pamokos, bet sužinosite iš pavyzdžio. Rasite, kad tai nėra daug, o komentaruose nurodoma, ką turite žinoti.

Čia pateikiamas pagrindinis Kalbėtojas klasė:

paketas com.lotontech.speech; importuoti javax.sound.samples. *; importuoti java.io. *; importuoti java.util. *; importuoti java.net. *; viešoji klasė Kalbėtojas {private SourceDataLine line = null; } 

Jei bėgsi Kalbėtojas iš komandinės eilutės, pagrindinis (...) žemiau pateiktas metodas bus įvesties taškas. Jis paima pirmąjį komandinės eilutės argumentą, jei toks yra, ir perduoda jį „sayWhoneWord“ (...) metodas:

/ * * Šis metodas taria fonetinį žodį, nurodytą komandinėje eilutėje. * / public static void main (String args []) {Kalbėtojo grotuvas = naujas Kalbėtojas (); if (args.length> 0) player.sayPhoneWord (args [0]); System.exit (0); } 

„sayWhoneWord“ (...) metodas vadinamas pagrindinis (...) aukščiau, arba jis gali būti iškviestas tiesiai iš jūsų „Java“ programos arba papildinyje palaikomos programėlės. Tai atrodo sudėtingiau nei yra. Iš esmės, tai tiesiog žingsnis per žodį alofonai - atskirti „|"simboliai įvesties tekste - ir groja juos po vieną per garso išvesties kanalą. Kad jis skambėtų natūraliau, kiekvieno garso pavyzdžio pabaigą sujungiu su kito pradžia:

/ * * Šis metodas taria duotą fonetinį žodį. * / public void sayPhoneWord (String word) {// - Nustatykite manekenio baitų masyvą ankstesniam garsui - baitas [] previousSound = null; // - Padalinkite įvesties eilutę į atskirus alofonus - StringTokenizer st = new StringTokenizer (word, "|", false); while (st.hasMoreTokens ()) {// - Sukurkite alofono failo pavadinimą - String thisPhoneFile = st.nextToken (); thisPhoneFile = "/ allophones /" + thisPhoneFile + ". au"; // - Gauti duomenis iš failo - baitas [] thisSound = getSound (thisPhoneFile); if (previousSound! = null) {// - Sujungti ankstesnį alofoną su šiuo, jei galime - int mergeCount = 0; jei (ankstesnisGarsas.length> = 500 && thisSound.length> = 500) mergeCount = 500; už (int i = 0; i

Pabaigoje „sayPhoneWord“ ()pamatysite, kad skambina Paleisti garsą(...) išleisti atskirą garso pavyzdį (alofoną), ir jis skambina nutekėti (...) praplauti garso kanalą. Štai kodas Paleisti garsą(...):

/ * * Šis metodas atkuria garso pavyzdį. * / private void playSound (baitų [] duomenys) {if (duomenų.length> 0) eilutė.write (duomenys, 0, data.length); } 

Ir už nutekėti (...):

/ * * Šis metodas praplauna garso kanalą. * / private void drain () {if (eilutė! = null) eilutė.drenažas (); pabandykite {Thread.sleep (100);} gaudyti (e išimtis) {}} 

Dabar, jei pažvelgsite atgal į „sayWhoneWord“ (...) metodo, pamatysite, kad yra vienas metodas, kurio dar neaprašiau: „getSound“ (...).

„getSound“ (...) iš anksto įrašytame garso pavyzdyje skaito kaip baitų duomenis iš au failo. Sakydamas failą, turiu omenyje šaltinį, esantį pateiktame ZIP faile. Aš darau skirtumą, nes tai, kaip jūs gaunate JAR išteklius, naudodami „getResource“ (...) metodas - vyksta kitaip nei tai, kaip jūs gaunate failą, nėra akivaizdus faktas.

Norėdami sužinoti, kaip skaityti duomenis, konvertuoti garso formatą, sukurti garso išvesties liniją (kodėl jie tai vadina SourceDataLine, Nežinau) ir kaupdamas baitų duomenis, kreipiuosi į toliau nurodyto kodo komentarus:

/ * * Šis metodas nuskaito vieno alofono failą ir * sukuria baitų vektorių. * / privatus baitas [] getSound (String fileName) {pabandykite {URL url = Talker.class.getResource (fileName); „AudioInputStream“ srautas = AudioSystem.getAudioInputStream (URL); AudioFormat format = stream.getFormat (); // - Konvertuokite ALAW / ULAW garsą į PCM atkūrimui - 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); srautas = AudioSystem.getAudioInputStream (tmpFormat, srautas); format = tmpFormat; } DataLine.Info info = new DataLine.Info (Clip.class, format, ((int) stream.getFrameLength () * format.getFrameSize ())); if (line == null) {// - Išvesties eilutė dar nėra sukurta - // - Ar galime rasti tinkamos eilutės rūšį? - DataLine.Info outInfo = naujas DataLine.Info (SourceDataLine.class, formatas); jei (! AudioSystem.isLineSupported (outInfo)) {System.out.println ("Linijos atitiktis" + outInfo + "nepalaikoma".); mesti naują išimtį („Linijos atitikimas“ + outInfo + „nepalaikoma“.); } // - atidarykite šaltinio duomenų eilutę (išvesties eilutę) - eilutė = (SourceDataLine) AudioSystem.getLine (outInfo); line.open (formatas, 50000); eilutė.pradėti (); } // - Kai kurie dydžio skaičiavimai - int frameSizeInBytes = format.getFrameSize (); int bufferLengthInFrames = line.getBufferSize () / 8; int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes; baitas [] duomenys = naujas baitas [buferisLengthInBytes]; // - perskaitykite duomenų baitus ir suskaičiuokite juos - int numBytesRead = 0; if ((numBytesRead = srautas.skaityti (duomenys))! = -1) {int numBytesRemaining = numBytesRead; } // - sutrumpinkite baitų masyvą iki tinkamo dydžio - baitas [] newData = naujas baitas [numBytesRead]; už (int i = 0; i

Taigi, viskas. Kalbos sintezatorius apie 150 kodo eilučių, įskaitant komentarus. Bet tai dar ne viskas.

Teksto į kalbą konvertavimas

Žodžių nurodymas fonetiškai gali pasirodyti šiek tiek varginantis, todėl jei ketinate sukurti vieną iš pavyzdinių programų, kurias pasiūliau įžangoje, norite pateikti paprastą tekstą kaip įvesties kalbą.

Išnagrinėjęs problemą, pateikiau eksperimentinę teksto į kalbą konvertavimo klasę ZIP faile. Kai paleisite, išvestis suteiks jums supratimą apie tai, ką ji daro.

Teksto į kalbą keitiklį galite paleisti naudodami tokią komandą:

java com.lotontech.speech.Converter "labas ten" 

Tai, ką matysite kaip išvestį, atrodo maždaug taip:

labas -> h | e | l | oo ten -> dth | aer 

Arba kaip apie tai, kaip jį paleisti:

java com.lotontech.speech.Converter "Man patinka skaityti JavaWorld" 

tai pamatyti (ir išgirsti):

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

Jei įdomu, kaip tai veikia, galiu pasakyti, kad mano požiūris yra gana paprastas, susideda iš tam tikra tvarka taikomų teksto pakeitimo taisyklių rinkinio. Štai keletas taisyklių pavyzdžių, kuriuos galbūt norėtumėte taikyti mintyse, kad žodžiai „skruzdė“, „norėčiau“, „norimas“, „nepageidaujamas“ ir „unikalus“:

  1. Pakeiskite „* unikalus *“ į „| y | ou | n | ee | k |"
  2. Pakeiskite „* want *“ į „| w | o | n | t |“
  3. Pakeiskite „* a *“ į „| a |“
  4. Pakeiskite „* e *“ į „| e |“
  5. Pakeiskite "* d *" į "| d |"
  6. Pakeiskite „* n *“ į „| n |“
  7. Pakeiskite „* u *“ į „| u |“
  8. Pakeiskite „* t *“ į „| t |“

„Nepageidaujamam“ seka būtų tokia:

nepageidaujamasun [| w | o | n | t |] red (2 taisyklė) [| u |] [| n |] [| w | o | n | t |] [| e |] [| d |] (4, 5, 6, 7 taisyklės) u | n | w | o | n | t | e | d (pašalinus simbolių perteklių) 

Turėtumėte pamatyti, kaip žodžiai, kuriuose yra raidės įpratęs bus kalbama kitaip nei žodžiai, kuriuose yra raidės skruzdė. Taip pat turėtumėte pamatyti, kaip specialus atvejis galioja visam žodžiui Unikalus turi viršenybę prieš kitas taisykles, kad šis žodis būtų sakomas kaip y | ou ... geriau nei u | n ....

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