Web Audio și 3D Soundscapes Implementare

În acest tutorial vom împacheta Web Audio într-un simplu API care se concentrează pe redarea sunetelor într-un spațiu 3D de coordonate și poate fi folosit pentru aplicații interactive imersive, incluzând, dar fără a se limita la, jocuri 3D.

Acest tutorial este al doilea dintr-o serie de două părți. Dacă nu ați citit primul tutorial din serie, ar trebui să faceți acest lucru înainte de a citi acest tutorial deoarece vă prezintă diferitele elemente Web Audio pe care le vom folosi aici.

Demonstrație

Înainte de a începe, iată o mică demonstrație care utilizează API-ul simplificat pe care îl vom acoperi în acest tutorial. Sunetele (reprezentate de pătratele albe) sunt poziționate aleatoriu și redate într-un spațiu de coordonate 3D folosind funcția de transfer în legătură cu capul (HRTF) pe care Web Audio ne oferă.

Fișierele sursă pentru demonstrație sunt atașate acestui tutorial.

Prezentare generală

Deoarece API-ul simplificat (AudioPlayer) a fost deja creat pentru acest tutorial și este disponibil pentru descărcare, ceea ce vom face aici este o privire amplă asupra API-ului AudioPlayer și a codului care o execută.

Înainte de a continua acest tutorial, vă rugăm să citiți tutorialul anterior din această serie, dacă nu ați făcut-o deja și sunteți nou în lumea Web Audio.

Casetofon

Casetofon clasa conține API-ul nostru simplificat și este expus pe fereastră obiect alături de clasele Web Audio standard dacă și numai dacă Web Audio este acceptat de browserul web. Aceasta înseamnă că ar trebui să verificăm existența clasei înainte de a încerca să o folosim.

dacă (window.AudioPlayer! == undefined) audioPlayer = noul AudioPlayer ()

(Am fi încercat să creăm un nou Casetofon obiect în interiorul unui încearcă să prinzi dar o simplă verificare condițională funcționează perfect.)

În spatele scenei, casetofon creează un nou AudioContext obiect și un nou AudioGainNode obiect pentru noi, și conectează GainNode obiecte față de destinaţie nod expus de către AudioContext obiect.

var m_context = nou AudioContext () var m_gain = m_context.createGain () ... m_gain.connect (m_context.destination)

Când sunetele sunt create și redate, acestea vor fi conectate la m_gain nod, acest lucru ne permite să controlam cu ușurință volumul (amplitudinea) tuturor sunetelor.

casetofon configurează de asemenea audio ascultător, expus prin m_context, astfel încât se potrivește cu sistemul comun de coordonate 3D utilizat cu WebGL. Cei pozitivi z punctele axe la vizualizator (cu alte cuvinte, indică din ecranul 2D), pozitiv y axa puncte sus, și pozitiv X axele spre dreapta.

m_context.listener.setOrientation (0, 0, -1, 0, 1, 0)

Poziția ascultător este întotdeauna zero; acesta se află în centrul sistemului de coordonate audio.

Încărcarea sunetelor

Înainte de a putea crea sau reda sunete, trebuie să încărăm fișierele de sunet; Din fericire casetofon are grijă de toată munca grea pentru noi. Expune o sarcină(… ) funcția pe care o putem utiliza pentru a încărca sunetele și trei agenți de procesare a evenimentelor care ne permit să urmărim progresul încărcării.

audioPlayer.onloadstart = functie () ... audioPlayer.onloaderror = function () ... audioPlayer.onloadcomplete = function () ... audioPlayer.load ("sound-01.ogg" .ogg ") audioPlayer.load (" sunet-03.ogg ")

Setul de formate de sunet acceptate este dependent de browser. De exemplu, Chrome și Firefox suportă OGG Vorbis, dar Internet Explorer nu. Toate cele trei browsere suportă MP3, care este la îndemână, dar problema cu MP3 este lipsa de buclă de sunet fără sudură - format MP3 nu este pur și simplu proiectat pentru el. Cu toate acestea, OGG Vorbis este, și poate suna perfect.

Când sunați sarcină(… ) funcție de mai multe ori, casetofon va împinge cererile într-o coadă și le va încărca secvențial. Când toate sunetele de așteptare au fost încărcate (și decodificate) onloadcomplete gestionarea evenimentului va fi apelată.

În spatele scenelor, casetofon utilizează un singur XMLHttpRequest obiect pentru încărcarea sunetelor. responseType din solicitare este setată la "Arraybuffer", iar atunci când fișierul a fost încărcat, tamponul de array este trimis la m_context pentru decodificare.

// Exemplul simplificat m_loader = new XMLHttpRequest () m_queue = [] funcția încărcare () m_loader.open ("GET", m_queue [0]) m_loader.responseType = "arraybuffer" m_loader.onload = onLoad m_loader.send funcția onLoad (eveniment) var data = m_loader.response var status = m_loader.status m_loader.abort () // resetează încărcătorul dacă (status < 400)  m_context.decodeAudioData(data, onDecode)  

Dacă încărcarea și decodificarea unui fișier are succes, casetofon va încărca fie următorul fișier în coadă (dacă coada nu este goală), fie anunțați-ne că toate fișierele au fost încărcate.

Crearea sunetelor

Acum că am încărcat niște fișiere audio, putem crea și reda sunetele noastre. Mai întâi trebuie să spunem casetofon pentru a crea sunete, și acest lucru se face folosind crea(… ) funcția expusă de casetofon.

var sound1 = audioPlayer.create ("sound-01.ogg") var sound2 = audioPlayer.create ("sound-02.ogg") var sound3 = audioPlayer.create ("sound-03.ogg"

Suntem liberi să creăm cât mai multe sunete de care avem nevoie chiar dacă am încărcat doar un singur fișier de sunet.

var a = audioPlayer.create ("beep.ogg") var b = audioPlayer.create ("beep.ogg") var c = audioPlayer.create ("beep.ogg")

Calea de fișier audio a trecut la crea(… ) funcția spune pur și simplu casetofon care ar trebui să folosească sunetul creat. Dacă fișierul de sunet specificat nu a fost încărcat când crea(… ) funcția se numește, va fi aruncată o eroare de execuție.

Redarea sunetelor

Când am creat unul sau mai multe sunete, suntem liberi să jucăm acele sunete ori de câte ori avem nevoie. Pentru a reda un sunet, folosim denumirea potrivită Joaca(… ) funcția expusă de casetofon.

audioPlayer.play (sound1)

Pentru a determina dacă doriți să jucați a buclate sunet, putem, de asemenea, trece un boolean la Joaca(… ) funcţie. Dacă este booleanul Adevărat, sunetul se va bifa continuu până când se oprește.

audioPlayer.play (sound1, true)

Pentru a opri un sunet, putem folosi Stop(… ) funcţie.

audioPlayer.stop (sound1)

se joacă(… ) ne permite să știm dacă sună în prezent un sunet.

dacă (audioPlayer.isPlaying (sound1)) ...

În spatele scenei, casetofon trebuie să facă o sumă surprinzătoare de lucru pentru a obține un sunet de jucat, datorită naturii modulare a Web Audio. Ori de câte ori trebuie să fie redat un sunet,casetofon trebuie să creeze noi AudioSourceBufferNode și PannerNode obiecte, configurați și conectați-le, apoi conectați sunetul la m_gain nodul. Din fericire, Web Audio este extrem de optimizat, astfel încât crearea și configurarea noilor noduri audio rareori cauzează orice cheltuială notabilă.

sound.source = m_context.createBufferSource () sound.panner = m_context.createPanner () sound.source.buffer = sunet.buffer sound.source.loop = bucla sound.source.onended = onSoundEnded // Acesta este un pic de hack dar trebuie să facem referire la obiectul sunet // în handlerul evenimentului onSoundEnded și să facem lucrurile / / în acest fel este mai optimal decât legarea mânerului. sound.source.sound = sunet sunet.panner.panningModel = "HRTF" sound.panner.distanceModel = "liniar" sound.panner.setPosition (sound.x, sound.y, sound.z) sound.source.connect (sunet .panner) sound.panner.connect (m_gain) sound.source.start ()

Redarea sunetelor este evident utilă, dar scopul este casetofon este să redați sunete într-un sistem de coordonate 3D, așadar ar trebui să setăm pozițiile de sunet înainte de a le juca. casetofon expune câteva funcții care ne permit să facem acest lucru.

Poziționarea sunetului

  • setX (...) și getX (...) funcții expuse de casetofon poate fi folosit pentru a seta și obține poziția unui sunet de-a lungul sistemului de coordonate X axă.
  • setY (...) și getY (...) funcțiile pot fi folosite pentru a seta și obține poziția unui sunet de-a lungul sistemului de coordonate y axă.
  • setZ (...) și getZ (...) funcțiile pot fi folosite pentru a seta și obține poziția unui sunet de-a lungul sistemului de coordonate z axă.
  • În cele din urmă, de ajutor setPosition (...) funcția poate fi utilizată pentru a seta poziția unui sunet de-a lungul sistemului de coordonate X, y, și z axe.
audioPlayer.setX (sound1, 100) audioPlayer.setZ (sound1, 200) console.log (audioPlayer.getX (sound1)) // 100 console.log (audioPlayer.getZ (sound1)) // 200 audioPlayer.setPosition (sound1, 300, 0, 400) console.log (audioPlayer.getX (sound1)) // 300 console.log (audioPlayer.getZ (sound1)) // 400

Cu cât un sunet este mai departe de centrul sistemului de coordonate, cu atât va fi mai liniștit sunetul. La o distanță de 10000 (sunetul Web Audio) un sunet va fi complet silențios.

Volum

Putem controla volumul global (master) al sunetelor folosind setVolume (...) și getVolume (...) funcții expuse de casetofon.

audioPlayer.setVolume (0.5) // 50% console.log (audioPlayer.getVolume ()) // 0.5

setVolume (...) funcția are de asemenea un al doilea parametru care poate fi utilizat pentru a atenua volumul pe o perioadă de timp. De exemplu, pentru a atenua volumul la zero timp de două secunde, am putea face următoarele:

audioPlayer.setVolume (0.0, 2.0)

Demo-ul tutorial profită de acest lucru pentru a se estompeze - în sunete fără probleme.

În spatele scenei, casetofon spune pur și simplu m_gain nod pentru a schimba liniar valoarea câștigului ori de câte ori volumul trebuie schimbat.

var actualTime = m_context.currentTime var actualVolume = m_gain.gain.value m_gain.gain.cancelScheduledValues ​​(0.0) m_gain.gain.setValueAtTime (curentVolume, curentTime) m_gain.gain.linearRampToValueAtTime (volum, curentTime + timp)

casetofon aplică un timp minim de decolorare 0,01 secunde, pentru a vă asigura că modificările abrupte ale volumului nu generează clicuri sau semnale sonore.

Concluzie

În acest tutorial am aruncat o privire asupra unui mod de a înfășura Web Audio într-un simplu API care se concentrează pe redarea sunetelor într-un spațiu de coordonate 3D pentru utilizarea în jocuri 3D (printre alte aplicații).

Datorită naturii modulare a aplicației Web Audio, programele care utilizează Web Audio pot deveni complexe destul de repede, așa că sper că acest tutorial a fost de folos pentru tine. Când înțelegeți cum funcționează Web Audio și cât de puternic este, sunt sigur că veți avea parte de multă distracție.

Nu uitați că fișierele sursă AudioPlayer și demonstrative sunt disponibile pe GitHub și sunt gata pentru descărcare. Codul sursă este comentat destul de bine, deci merită să vă luați timpul pentru a vă uita rapid la el.

Dacă aveți feedback sau întrebări, vă rugăm să postați un comentariu de mai jos.

Resurse

  • W3C Web Audio Specification
  • MDN Web Audio Documentation