ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 141
Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 10
Abonament PDF

HTML5: WebAudio API

Radu Olaru
Senior Software Developer
@Small Footprint



PROGRAMARE


În acești ani aplicațiile online au împins tot mai departe limitele platformei web. Probabil cu toții am fost iritați la un moment dat de aplicațiile web. Cu toții am sperat că până la urmă lumea se va liniști, se va vedea clar că webul nu poate suporta aplicații serioase și Universul își va reveni la normal. Aplicațiile mari sunt pentru desktop, iar aplicațiile web sunt doar visele doctoranzilor entuziaști de la Google.

Dar apoi a apărut parcă de nicăieri HTML5. Și HTML5 a revoluționat nu doar web-ul aplicațiilor business, ci a deschis larg porțile web-ului aplicațiilor multimedia - în special a jocurilor.

Noutatea multimedia

HTML5 vine cu o mare surpriză pentru dezvoltatorii de aplicații multimedia. Deja știm pe de rost că există tagul audio și video. Nu vom vorbi despre ele în acest articol. O examinare superficială arată că tagul audio nu este suficient pentru aplicații serioase, fiind gândit să ascundă complexitatea redării sunetelor. Tagul asigură eventual un background muzical - excelent pentru nostalgicii site-urilor din anii "90. Pentru cei ce vor să dezvolte procesoare de sunet în timp real, HTML5 descrie o interfață specială: WebAudio.

WebAudio permite poziționarea sunetelor într-un spațiu tridimensional, mixarea surselor multiple de sunet redate simultan și rutarea lor printr-un sistem modular puternic de procesare. Efectele aplicabile includ un motor de calitate înaltă pentru reverberații și simulare completă a spațiului de audiție. De asemenea, datele audio pot fi analizate în timp real.

Aceste facilități au o țintă foarte specifică: jocurile și aplicațiile de procesare audio. Stațiile de procesare audio software au fost strict de domeniul desktopului. Niciodată nu s-a pus problema ca un artist să pornească browserul pentru a executa o performanță live. Nici nu s-a crezut că va avea vreodată sens ca o claviatură MIDI să comunice cu un browser web. Ei bine, totul s-a schimbat cu apariția WebAudio.

Infrastructură mai sofisticată

Pentru a ridica standardul multimedia în browsere atât de sus, WebAudio necesită o fundație specială. Pentru început, datele audio există într-un thread separat de restul aplicației - deci orice procesare este ferită de interferențele aplicației web. Datele audio, sursele, destinațiile sunetelor și nodurile de procesare există într-un context independent, cu un timp de sincronizare independent, asigurând păstrarea controlului asupra mai multor seturi de surse audio sincronizate.

În clipa în care se instanțiază un asemenea context, deja se pot specifica surse de sunet, destinații și se pot defini procesoare de sunet conectate în diferite configurații:

var context = new AudioContext();
var source = context.createBufferSource();
var volume = context.createGainNode();
 
source.buffer = buffer;
volume.gain.value = 0.6;
source.connect(volume);
volume.connect(context.destination);
source.start(0);

Arhitectura este de tip plugin: sunetul este încărcat într-un buffer (vom vedea mai târziu cum), buffer-ul este trimis la o sursă de date, apoi la un procesor de sunet, iar în final la o destinație. Destinația implicită a contextului audio este cea standard configurată în sistemul de operare - de obicei ieșirea "line out" a plăcii de sunet.

Dincolo de sintaxa intuitivă, procesarea sunetelor este efectuată direct de driverul audio. Dacă sistemul deține o placă de sunet profesională, driver-ul va executa instrucțiunile folosind hardware-ul dedicat al plăcii de sunet. Dacă este vorba doar de un "codec", rularea va regresa spre microprocesor. Indiferent de situație, arbitrul final este browser-ul. Modul în care browserul compilează, execută și decide rularea instrucțiunilor determină soarta datelor audio. O implementare bună însă va tinde să folosească resurse dedicate și să evite blocajele din fluxul de procesare și redare a datelor audio.

Noduri și grafuri orientate

Inițierea unui flux audio se face prin definirea unei surse de sunet. Aceasta poate fi o intrare live a plăcii de sunet (un microfon), un fișier audio existent sau un sintetizator de sunet (un oscilator). Desigur, în graf pot exista mai multe surse de sunet - fie generate, fie fișiere, fie live. Toate sursele de sunet pot fi redate simultan sau la cerere (la apăsarea unei taste de exemplu sau la primirea unui mesaj MIDI).

Mai departe sunetul poate fi trimis spre diferite noduri de procesare. Procesoarele audio includ localizare în spațiu, efecte specifice sunetelor aflate la distanță, efecte doppler, filtre, reverberații, ecouri, altele. Orice nod suportă mai multe intrări și mai multe ieșiri, permițând legături în serie și în paralel.

Există inclusiv un context audio offline, deconectat de o sursă hardware de redare a sunetelor, ce poate fi folosit pentru generarea datelor audio independent de timp. Contextul "redă" sunetele ca pachet de date, accesibil într-o funcție callback:

callback OfflineRenderSuccessCallback = void (AudioBuffer renderedData)
 
interface OfflineAudioContext : AudioContext {
   void startRendering();
   attribute OfflineRenderSuccessCallback onComplete;
}

Surse audio și conexiuni în graf

Graful de procesare audio primește informații de la surse audio. Datele care trec prin graf sunt sunete reformulate într-o formă accesibilă browserul-ui pentru procesare și redare ulterioară. Există mai multe tipuri de surse audio, în funcție de metoda de achiziție a sunetului: fișier existent pe disc, sample-uri generate în cod, oscilatoare și intrări hardware ale plăcii de sunet. După achiziția și formatarea sunetului, acesta poate fi trimis mai departe spre procesoare sau spre destinația audio.

AudioBuffer

Buffer-ele audio codifică sunetele în sample-uri, cum sunt fișierele audio. Caracteristica de bază a unui buffer audio se numește sample rate - frecvența cu care sunetul păstrat în buffer a fost analizat pentru a obține informații utile procesării audio. Aceste valori sunt specifice procesării digitale audio și intră într-un domeniu de cunoștințe mai vast, despre care nu vom vorbi aici.

Pentru a folosi un fișier audio, acesta se încarcă într-un buffer care apoi este conectat la destinația unui context audio:

var request = new XMLHttpRequest();
request.open("GET", "sound.mp3", true);
request.responseType = "arraybuffer";
	
request.onload = function() {
    audioContext.decodeAudioData(request.response, function(buffer) {
        // buffer conține un obiect de tip AudioBuffer
    });
}

Buffer-ul permite accesarea sample-urilor în mod direct:

var buffer = audioContext.createBuffer(1, 5, 44100);
var bufferData = buffer.getChannelData(0);
 
bufferData[i] = 0.3;

Codul de mai sus creează un buffer cu un singur canal audio (mono), care conține cinci sample-uri cu sample rate de 44100 Hz. Datele din buffer sunt accesibile într-un vector folosind metoda getChannelData - vector în care apoi se poate scrie. În acest mod se pot construi sunete folosind ecuații sau alte generatoare.

În fine, redarea unui buffer audio se face folosind nodul de tip AudioBufferSourceNode:

var source = audioContext.createBufferSource();
 
source.buffer = buffer;
source.connect(audioContext.destination);
source.start(0);

Oscillator

O altă sursă audio este oscilatorul. Oscilatorul codifică sunetele în funcții periodice, repetate apoi la infinit - astfel caracteristica sa de bază este funcția generatoare. Există patru tipuri de oscilatoare predefinite: sinusoidal, pătrat, triunghiular isoscel și triunghiular drept. Oscilatoarele pot fi conectate în paralel pentru a compune funcții, generând astfel sunete complexe.

var source = context.createOscillator();
 
source.type = 0;  // oscilator sinusoidal
source.connect(context.destination);
source.start(0);

De asemenea, se pot formula oscilatoare particulare prin compunerea mai multor funcții matematice într-un singur generator:

 

var first = new Float32Array(100);
var second = new Float32Array(100);
 
for (var i = 0; i < 100; i++) first[i] = Math.sin(Math.PI * i / 100);
for (var i = 0; I < 100; i++) second[i] = Math.cos(Math.PI * i / 100);
 
source.setWaveTable(context.createWaveTable(first, second));

Live

Pentru folosirea surselor audio live cum ar fi un microfon, browser-ul trebuie să obțină un flux audio de la sistemul de operare. Din acest motiv, aceste surse sunt accesibile doar din obiectul Javascript ce reprezintă browser-ul:

navigator.getUserMedia( { audio: true }, function(stream) {
    var context = new audioContext();
    var source = context.createMediaStreamSource(stream);
 
    source.connect(context.destination);
});

Fluxul audio nu poate fi alterat în mod direct cum este cazul buffer-elor sau a oscilatoarelor dar, ca și celelalte surse audio, poate fi conectat la oricare din nodurile procesoare definite în graf. Acest tip de sursă audio depinde direct de hardware și de driverele instalate, iar achiziția datelor audio poate întârzia sau poate interfera cu alte procese care să afecteze claritatea semnalului.

Browser-ul Chrome optimizează în mod special achiziția datelor audio live și permite crearea unor adevărate procesoare de sunet în timp real. Implementarea se bazează pe rutarea execuției cât mai rapid spre driverul audio. Dacă sistemul conține o placă de sunet dedicată, prelucrarea audio va avea întârzieri minime. În secțiunea Resurse există câteva link-uri ce demonstrează viteza de execuție în Chrome a platformei WebAudio.

Modificarea volumului audio

Există o serie de procesoare ale semnalului audio, fiecare cu specificele ei, dar în acest articol ne vom referi doar la modificarea volumului audio. Modificarea volumului se face conectând una sau mai multe surse audio la un nod de tip GainNode. Sursele audio pot fi cele descrise mai sus sau alte procesoare audio care primesc date audio:

var gainNode = context.createGainNode();
 
source.connect(gainNode);
gainNode.connect(context.destination);
gainNode.gain.value = 0.8;

Modificarea volumului se poate automatiza și sincroniza cu alte evenimente dependente de timp:

var envelope = context.createGainNode();
var now = context.currentTime;
 
source.connect(envelope);
envelope.connect(context.destination);
envelope.gain.setValueAtTime(0, now);
envelope.gain.linearRampToValueAtTime(1.0, now + 2.0);

În acest mod se pot stabili crossfade-uri între două surse de sunet de exemplu.

Tendințe

Situația actuală a platformei WebAudio nu este tocmai fericită. Practic ea este suportată în mod complet doar de browser-ul Chrome - și doar pe desktop. Doar ultimele versiuni de Chrome de pe platforma Android 4 suportă WebAudio, iar browser-ul implicit din Android nu este inclus aici. WebAudio mai este suportat de iOS6, de ChromeOS și de ChromeFrame.

Însă platforma este definită și acceptată în standardul HTML5, ceea ce înseamnă că viitorul nu poate fi decât strălucit pentru dezvoltatorii de soft multimedia. Deja se pot construi sintetizatoare audio și procesoare în timp real a sunetelor analogice, iar în curând Chrome va implementa comunicarea cu dispozitive MIDI, permițând compoziția audio folosind claviaturi și alte dispozitive profesionale.

Și ca o inovație, standardul WebAudio alături de WebSockets permite pentru prima dată crearea performanțelor audio în mod distribuit, pe web. Utilizatorii se pot conecta la un singur site web și pot crea împreună, simultan, piese audio de înaltă calitate - prima demonstrație a acestui tandem de tehnologii fiind site-ul jamwithchrome.

Resurse și referințe

http://dashersw.github.com/pedalboard.js/demo

http://www.jamwithchrome.com

http://kevincennis.com/mix

http://www.tenthcirclesound.com/sympyrean

http://docs.webplatform.org/wiki/apis/webaudio

http://webaudio-io2012.appspot.com

https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html

NUMĂRUL 140 - Generative AI

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • Yardi
  • Colors in projects

INTERVIURI VIDEO

Radu Olaru a mai scris