Web Audio API: De ce să compuneți când puteți codifica?
Publicat: 2022-03-11Prima schiță pentru un API audio web a apărut în W3C în 2011. Deși sunetul în paginile web a fost acceptat de mult timp, o modalitate adecvată de a genera audio din browserul web nu a fost disponibilă până de curând. Eu personal atribui acest lucru Google Chrome, deoarece în ceea ce privește interesul Google, browserul a început să devină cea mai importantă parte a unui computer. Vă amintiți, sfera browserului web nu a început să se schimbe prea mult până când a apărut Google Chrome. Dacă ați folosit sunet într-o pagină web în această perioadă, ar fi fost o decizie proastă de proiectare. Dar de când a apărut ideea experimentelor web, audio web a început să aibă din nou sens. Browserele web în zilele noastre sunt un alt instrument de exprimare artistică, iar videoclipurile și audio din browserul web joacă un rol vital în acest sens.
Web Audio API poate fi destul de greu de utilizat pentru anumite scopuri, deoarece este încă în curs de dezvoltare, dar există deja o serie de biblioteci JavaScript pentru a ușura lucrurile. În acest caz, vă voi arăta cum să începeți cu API-ul Web Audio folosind o bibliotecă numită Tone.js. Cu aceasta, veți putea acoperi majoritatea nevoilor de sunet ale browserului dvs. doar învățând elementele de bază.
Bună ziua Web Audio API
Noțiuni de bază
Vom începe fără a folosi biblioteca. Primul nostru experiment va implica realizarea a trei unde sinusoidale. Deoarece acesta va fi un exemplu simplu, vom crea doar un fișier numit hello.html, un fișier HTML simplu cu o cantitate mică de markup.
<!DOCTYPE html> <html> <head> <meta charset="utf‐8"> <title> Hello web audio </title> </head> <body> </body> <script> </script> </html>
Miezul API-ului Web Audio este contextul audio. Contextul audio este un obiect care va conține tot ce este legat de audio web. Nu este considerată o practică bună să aveți mai mult de un context audio într-un singur proiect. Vom începe prin a instanția un context audio urmând recomandările date de documentația Web Audio API a Mozilla.
var audioCtx = new (window.AudioContext || window.webkitAudioContext);
Realizarea unui oscilator
Cu un context audio instanțiat, aveți deja o componentă audio: audioCtx.destination. Acesta este ca difuzorul tău. Pentru a scoate un sunet, trebuie să-l conectați la audioCtx.destination. Acum, pentru a produce un sunet, să creăm un oscilator:
var sine = audioCtx.createOscillator();
Grozav, dar nu suficient. De asemenea, trebuie să fie pornit și conectat la audioCtx.destination:
sine.start(); sine.connect(audioCtx.destination);
Cu aceste patru linii, veți avea o pagină web destul de enervantă care redă un sunet sinus, dar acum înțelegeți cum modulele se pot conecta între ele. În următorul script, vor exista trei tonuri în formă de sinus, conectate la ieșire, fiecare cu un ton diferit. Codul este foarte explicit:
//create the context for the web audio var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); //create, tune, start and connect each oscillator sinea, sineb and sinec var sinea = audioCtx.createOscillator(); sinea.frequency.value = 440; sinea.type = "sine"; sinea.start(); sinea.connect(audioCtx.destination); var sineb = audioCtx.createOscillator(); sineb.frequency.value = 523.25; sineb.type = "sine"; sineb.start(); sineb.connect(audioCtx.destination); var sinec = audioCtx.createOscillator(); sinec.frequency.value = 698.46; sinec.type = "sine"; sinec.start(); sinec.connect(audioCtx.destination);
Oscilatoarele nu sunt limitate la undele sinusoidale, dar pot fi, de asemenea, triunghiuri, dinți de ferăstrău, pătrați și cu formă personalizată, așa cum se precizează în MDN.
Logica de corecție a audio Web
În continuare, vom adăuga un modul de câștig orchestrei noastre de componente Web Audio. Acest modul ne permite să schimbăm amplitudinea sunetelor noastre. Este asemănător cu un butonul de volum. Am folosit deja funcția de conectare pentru a conecta un oscilator la ieșirea audio. Putem folosi aceeași funcție de conectare pentru a conecta orice componentă audio. Dacă utilizați Firefox și aruncați o privire la consola audio web, veți vedea următoarele:
Dacă vrem să schimbăm volumul, patch-ul nostru ar trebui să arate astfel:
Ceea ce înseamnă că oscilatoarele nu mai sunt conectate la destinația audio, ci la un modul Gain, iar acel modul de câștig este conectat la destinație. Este bine să-ți imaginezi mereu că faci asta cu pedale și cabluri de chitară. Codul va arăta astfel:
var audioCtx = new (window.AudioContext || window.webkitAudioContext) // we create the gain module, named as volume, and connect it to our var volume = audioCtx.createGain(); volume.connect(audioCtx.destination); //these sines are the same, exept for the last connect statement. //Now they are connected to the volume gain module and not to the au var sinea = audioCtx.createOscillator(); sinea.frequency.value = 440; sinea.type = "sine"; sinea.start(); sinea.connect(volume); var sineb = audioCtx.createOscillator(); sineb.frequency.value = 523.25; sineb.type = "sine"; sineb.start(); sineb.connect(volume); var sinec = audioCtx.createOscillator(); sinec.frequency.value = 698.46; sinec.type = "sine"; sinec.start(); sinec.connect(volume); volume.gain.value=0.2;
Puteți găsi soluția la https://github.com/autotel/simple-webaudioapi/.
GainNode este cea mai de bază unitate de efect, dar există și o întârziere, un convolver, un filtru biquadratic, un panou stereo, un model de undă și multe altele. Puteți obține efecte noi din biblioteci precum Tone.js.
Stocarea unuia dintre aceste patch-uri de sunet în obiecte proprii vă va permite să le reutilizați după cum este necesar și să creați orchestrații mai complexe cu mai puțin cod. Acesta ar putea fi un subiect pentru o postare viitoare.
Ușurează lucrurile cu Tone.js
Acum că am aruncat o scurtă privire asupra modului în care funcționează modulele Web Audio vanilla, haideți să aruncăm o privire la minunatul cadru Web Audio: Tone.js. Cu aceasta (și NexusUI pentru componentele interfeței cu utilizatorul), putem construi foarte ușor sintetizatoare și sunete mai interesante. Pentru a încerca lucrurile, să facem un sampler și să-i aplicăm câteva efecte interactive de utilizator, apoi vom adăuga câteva controale simple pentru acest eșantion.
Tone.js Sampler
Putem începe prin a crea o structură de proiect simplă:
simpleSampler |-- js |-- nexusUI.js |-- Tone.js |-- noisecollector_hit4.wav |-- sampler.html
Bibliotecile noastre JavaScript vor locui în directorul js . În scopul acestei demonstrații, putem folosi fișierul hit4.wav al NoiseCollector, care poate fi descărcat de pe Freesound.org.

Tone.js oferă funcționalitățile sale prin obiecte Player. Capacitatea de bază a obiectului este de a încărca o probă și de a o reda fie în buclă, fie o dată. Primul nostru pas aici este să creăm un obiect player într-o variantă „sampler”, în interiorul fișierului sampler.html:
<!doctype html> <html> <head> <title> Sampler </title> <script type="text/javascript" src="js/nexusUI.js" ></script> <script type="text/javascript" src="js/Tone.js" ></script> <script> var sampler = new Tone.Player("noisecollector_hit4.wav", function() { console.log("samples loaded"); }); </script> </head> <body> </body> </html>
Rețineți că primul parametru al constructorului playerului este numele fișierului WAV, iar al doilea este o funcție de apel invers. WAV nu este singurul tip de fișier acceptat, iar compatibilitatea depinde mai mult de browser web decât de bibliotecă. Funcția de apel invers va rula când playerul a terminat de încărcat proba în memoria tampon.
De asemenea, trebuie să conectăm samplerul nostru la ieșire. Modul Tone.js de a face acest lucru este:
sampler.toMaster();
… unde sampler este un obiect Tone.Player, după linia 10. Funcția toMaster este prescurtarea pentru connect(Tone.Master).
Dacă deschideți browserul web cu consola pentru dezvoltatori deschisă, ar trebui să vedeți mesajul „eșantioane încărcate”, care indică faptul că playerul a fost creat corect. În acest moment, poate doriți să auziți eșantionul. Pentru a face acest lucru, trebuie să adăugăm un buton la pagina web și să îl programăm pentru a reda eșantionul odată apăsat. Vom folosi un buton NexusUI în corp:
<canvas nx="button"></canvas>
Ar trebui să vedeți acum un buton rotunjit fiind redat în document. Pentru a-l programa să redea proba noastră, adăugăm un ascultător NexusUI, care arată astfel:
button1.on('*',function(data) { console.log("button pressed!"); })
Ceva remarcabil la NexusUI este că creează o variabilă globală pentru fiecare element NexusUI. Puteți seta NexusUI să nu facă asta și, în schimb, să aveți aceste variabile numai în nx.widgets[] setând nx.globalWidgets la false. Aici vom crea doar câteva elemente, așa că ne vom ține de acest comportament.
La fel ca și în jQuery, putem pune aceste evenimente .on, iar primul argument va fi numele evenimentului. Aici atribuim doar o funcție la orice se face butonului. Acest lucru este scris ca „*”. Puteți afla mai multe despre evenimente pentru fiecare element din API-ul NexusUI. Pentru a reda eșantionul în loc să înregistrăm mesajele când apăsăm butonul, ar trebui să rulăm funcția de pornire a eșantionerului nostru.
nx.onload = function() { button1.on('*',function(data) { console.log("button pressed!"); sampler.start(); }); }
Observați, de asemenea, că ascultătorul intră într-un apel invers la încărcare. Elementele NexusUI sunt desenate în pânză și nu vă puteți referi la ele până când nx apelează funcția onload. La fel cum ați face cu elementele DOM în jQuery.
Evenimentul este declanșat cu mouse-ul în jos și la eliberare. Dacă doriți să fie declanșat doar la apăsare, trebuie să evaluați dacă event.press este egal cu unul.
Cu aceasta, ar trebui să aveți un buton care redă eșantionul la fiecare apăsare. Dacă setați sampler.retrigger la true, vă va permite să redați eșantionul indiferent dacă acesta este redat sau nu. În caz contrar, trebuie să așteptați până când eșantionul se termină pentru al redeclanșa.
Aplicarea efectelor
Cu Tone.js, putem crea cu ușurință o întârziere:
var delay= new Tone.FeedbackDelay("16n",0.5).toMaster();
Primul argument este timpul de întârziere, care poate fi scris în notație muzicală, așa cum se arată aici. Al doilea este nivelul umed, ceea ce înseamnă amestecul dintre sunetul original și sunetul care are efect asupra acestuia. Pentru întârzieri, de obicei, nu doriți un wet 100%, deoarece întârzierile sunt interesante în raport cu sunetul original, iar wet-ul singur nu este foarte atrăgător ca ambele împreună.
Următorul pas este să deconectați samplerul nostru de la master și să îl conectați în schimb la întârziere. Ajustați linia unde samplerul este conectat la master:
sampler.connect(delay);
Acum încercați din nou butonul și vedeți diferența.
În continuare, vom adăuga două cadrane în corpul documentului nostru:
<canvas nx="dial"></canvas> <canvas nx="dial"></canvas>
Și aplicăm valorile cadranelor efectului de întârziere folosind NexusUIlistener:
dial1.on('*',function(data) { delay.delayTime.value=data.value; }) dial2.on('*',function(data) { delay.feedback.value=data.value; })
Parametrii pe care îi puteți modifica pentru fiecare eveniment pot fi găsiți în documentațiile Tone.js. Pentru întârziere, este aici. Acum sunteți gata să încercați exemplul și să modificați parametrii de întârziere cu cadranele NexusUI. Acest proces poate fi realizat cu ușurință cu fiecare element NexusUI, nu limitat doar la efecte. De exemplu, încercați să adăugați un alt cadran și să adăugați ascultătorul acestuia, după cum urmează:
dial3.on('*',function(data) { sampler.playbackRate=data.value; })
Puteți găsi aceste fișiere la github.com/autotel/simpleSampler
Concluzie
Când am trecut prin aceste API-uri, am început să mă simt copleșită de toate posibilitățile și ideile care au început să-mi vină în minte. Marea diferență între această implementare a audio și implementările tradiționale ale audio digital nu este în audio în sine, ci în context. Nu există metode noi de realizare a sintezei aici. Mai degrabă, inovația este că producția audio și muzicală întâlnesc acum tehnologiile web.
Eu personal sunt implicat în crearea muzicii electronice, iar acest domeniu a avut întotdeauna acest paradox al ambiguității dintre interpretarea efectivă a muzicii și doar apăsarea pe redare a unei piese înregistrate. Dacă vrei să faci cu adevărat muzică electronică live, trebuie să poți crea propriile instrumente performative sau „roboți care fac muzică” pentru improvizația live. Dar dacă performanța muzicii electronice devine pur și simplu modificarea parametrilor în algoritmii de creare a muzicii pre-preparați, atunci publicul poate fi și el implicat în acest proces. Am lucrat la mici experimente cu privire la această integrare a web și audio pentru muzica crowdsourced, și poate că în curând vom participa la petreceri în care muzica vine de la public prin intermediul smartphone-urilor lor. La urma urmei, nu este atât de diferit de gemurile ritmice de care ne-am fi bucurat în epocile peșterilor.
Citiți suplimentare pe blogul Toptal Engineering:
- WebAssembly/Rust Tutorial: Procesare audio perfectă
- Tutorial MIDI: Crearea aplicațiilor audio bazate pe browser controlate de hardware MIDI