Î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.
Î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.
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
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.
Î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.
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.
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.
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ă.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.
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.
Î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.