L'API Web Audio è un potente alleato per chiunque crei giochi JavaScript, ma con quel potere arriva la complessità. Web Audio è un sistema modulare; i nodi audio possono essere collegati insieme per formare grafici complessi per gestire qualsiasi cosa, dalla riproduzione di un singolo suono a un'applicazione di sequencing musicale completa. Questo è impressionante, per non dire altro.
Tuttavia, quando si tratta di programmare i giochi, la maggior parte degli sviluppatori desidera un'API di base che carichi e riproduca semplicemente i suoni e fornisce opzioni per la modifica di volume, altezza e pan (posizione stereo) di tali suoni. Questo tutorial fornisce una soluzione elegante avvolgendo l'API Web Audio in un modo veloce e leggero Suono
classe che gestisce tutto per te.
Nota: Questo tutorial si rivolge principalmente ai programmatori JavaScript, ma le tecniche utilizzate per combinare e manipolare l'audio nel codice possono essere applicate a quasi tutti gli ambienti di programmazione che forniscono accesso a un'API audio di basso livello.
Prima di iniziare, dai un'occhiata alla demo live di Suono
classe in azione. Puoi fare clic sui pulsanti nella demo per riprodurre i suoni:
SFX 01
è un suono a scatto singolo con impostazioni predefinite. SFX 02
è un suono a scatto singolo che ha il suo pan (posizione stereo) e il volume randomizzato ogni volta che viene riprodotto. SFX 03
è un suono in loop; facendo clic sul pulsante si accenderà e si spegnerà il suono e la posizione del puntatore del mouse all'interno del pulsante regolerà l'intonazione del suono.Nota: Se non si sente alcun suono riprodotto, il browser Web che si sta utilizzando non supporta l'audio Web Audio o gli stream audio OGG Vorbis. L'utilizzo di Chrome o Firefox dovrebbe risolvere il problema.
L'immagine seguente visualizza un grafico del nodo Web Audio di base:
Esempio visivo di un grafico del nodo Web Audio.Come puoi vedere ci sono alcuni nodi audio nel grafico per gestire la riproduzione di quattro suoni in un modo adatto ai giochi. I panner e i nodi di guadagno si occupano di panning e volume, e ci sono un paio di nodi del compressore di dinamiche in là per aiutare a prevenire eventuali artefatti udibili (clip, pop e così via) se il grafico finisce per essere sovraccaricato da un audio forte.
Essere in grado di creare grafici di nodi audio simili a quelli di JavaScript è fantastico, ma dover creare, connettere e disconnettere costantemente questi nodi può diventare un vero e proprio onere. Stiamo semplificando le cose gestendo il mixaggio e la manipolazione dell'audio a livello di codice, utilizzando un singolo nodo del processore di script.
Esempio visivo di un grafico del nodo di Web Audio semplificato.Sì, questo è sicuramente molto più semplice ed evita anche il sovraccarico di elaborazione coinvolto nella creazione, connessione e disconnessione di un carico di nodi audio ogni volta che è necessario riprodurre un suono.
Ci sono altre stranezze nell'API Web Audio che possono rendere le cose difficili. Il nodo panner, ad esempio, è progettato specificamente per i suoni posizionati nello spazio 3D, non nello spazio 2D e i nodi di sorgente del buffer audio (etichettati "suono" nell'immagine precedente) possono essere riprodotti solo una volta, quindi la necessità di creare costantemente e connetti quei tipi di nodi.
Il nodo del processore di script singolo utilizzato da Suono
la classe richiede periodicamente che campioni audio vengano trasmessi da JavaScript, e ciò rende le cose molto più semplici per noi. Possiamo mixare e manipolare campioni audio in modo molto rapido e semplice in JavaScript, per produrre le funzionalità di volume, altezza e panning di cui abbiamo bisogno per i giochi 2D.
Invece di fare il baby-step attraverso la creazione del Suono
classe, daremo un'occhiata alle parti principali del codice che sono direttamente correlate all'API Web Audio e alla manipolazione di campioni sonori. I file di origine demo includono il tutto funzionale Suono
classe, che puoi studiare e usare liberamente nei tuoi progetti.
Il Suono
la classe carica i file audio su una rete usando come buffer di array XMLHttpRequest
oggetti. I buffer dell'array vengono quindi decodificati in campioni audio grezzi da un oggetto contesto audio.
request.open ("GET", "sound.ogg"); request.onload = decodifica; request.responseType = "arraybuffer"; request.open (); function decode () if (request.response! == null) audioContext.decodeAudioData (request.response, done); function done (audioBuffer) ...
Ovviamente non c'è gestione degli errori in quel codice, ma dimostra come i file audio vengono caricati e decodificati. Il audioBuffer
passato al fatto()
la funzione contiene i campioni di suoni grezzi dal file audio caricato.
Per mixare e manipolare i campioni sonori caricati, il Suono
class attribuisce un listener a un nodo del processore di script. Questo listener verrà chiamato periodicamente per richiedere più campioni audio.
// Calcola una dimensione del buffer. // Questo produrrà un valore ragionevole che bilancia l'audio // latenza e l'utilizzo della CPU per i giochi che funzionano a 60 Hz. var v = audioContext.sampleRate / 60; var n = 0; while (v> 0) v >> = 1; n ++; v = Math.pow (2, n); // dimensione del buffer // Crea il processore di script. processor = audioContext.createScriptProcessor (v); // Allega l'ascoltatore. processor.onaudioprocess = processSamples; function processSamples (evento) ...
La frequenza con cui il processSamples ()
la funzione è chiamata varierà su diverse configurazioni hardware, ma di solito è circa 45 volte al secondo. Può sembrare molto, ma è necessario mantenere la latenza audio abbastanza bassa da essere utilizzabile nei giochi moderni che tipicamente girano a 60 frame al secondo. Se la latenza audio è troppo alta, i suoni verranno ascoltati troppo tardi per sincronizzarsi con ciò che sta accadendo sullo schermo, e questa sarebbe un'esperienza sconvolgente per chiunque giochi a un gioco.
Nonostante la frequenza con cui il processSamples ()
viene chiamata la funzione, l'utilizzo della CPU rimane basso, quindi non preoccuparti di perdere troppo tempo dalla logica di gioco e dal rendering. Sul mio hardware (Intel Core i3, 3 GHz) l'utilizzo della CPU raramente supera il 2%, anche quando vengono riprodotti molti suoni contemporaneamente.
Il processSamples ()
la funzione contiene effettivamente la carne del Suono
classe; è dove i campioni sonori vengono mixati e manipolati prima di essere trasferiti attraverso l'audio del web all'hardware. Il seguente codice mostra cosa succede all'interno della funzione:
// Prendi il campione sonoro. sampleL = samplesL [soundPosition >> 0]; sampleR = samplesR [soundPosition >> 0]; // Aumenta la posizione della testina del suono. soundPosition + = soundScale; // Applica il volume globale (influisce su tutti i suoni). sampleL * = globalVolume; sampleR * = globalVolume; // Applica il volume del suono. sampleL * = soundVolume; sampleR * = soundVolume; // Applica il pan del suono (posizione stereo). sampleL * = 1.0 - soundPan; sampleR * = 1.0 + soundPan;
Questo è più o meno tutto quello che c'è da fare. Questa è la magia: una manciata di semplici operazioni cambiano il volume, la tonalità e la posizione stereo di un suono.
Se sei un programmatore e hai familiarità con questo tipo di elaborazione del suono, potresti pensare "non può essere tutto quello che c'è da fare", e tu saresti corretto: la classe Sound deve tenere traccia delle istanze del suono, dei buffer dei campioni e fai un paio di altre cose, ma questo è tutto rude!
Il seguente codice mostra come utilizzare la classe Sound. Puoi anche scaricare i file sorgente per la demo live che accompagna questo tutorial.
// Crea un paio di oggetti Sound. var boom = new Sound ("boom.ogg"); var tick = new Sound ("tick.ogg"); // Passa facoltativamente un listener alla classe Sound. Sound.setListener (listener); // Questo caricherà qualsiasi oggetto Sound appena creato. Sound.load (); // L'ascoltatore. listener di funzioni (suono, stato) if (state === Sound.State.LOADED) if (sound === tick) setInterval (playTick, 1000); else if (audio === boom) setInterval (playBoom, 4000); else if (state === Sound.State.ERROR) console.warn ("Errore sonoro:% s", sound.getPath ()); // Riproduce il suono del tick. function playTick () tick.play (); // Riproduce il suono del braccio. function playBoom () boom.play (); // Randomizza l'intonazione e il volume del suono. boom.setScale (0.8 + 0.4 * Math.random ()); boom.setVolume (0,2 + 0.8 * Math.random ());
Bello e facile.
Una cosa da notare: non importa se l'API Web Audio non è disponibile in un browser e non importa se il browser non può riprodurre un formato audio specifico. Puoi ancora chiamare il giocare()
e Stop()
funzioni su a Suono
oggetto senza errori. Questo è intenzionale; ti consente di eseguire il tuo codice di gioco come al solito senza preoccuparti dei problemi di compatibilità del browser o di ramificare il tuo codice per gestire tali problemi. Il peggio che può succedere è il silenzio.
giocare()
Stop()
getPath ()
: Ottiene il percorso del file audio.getState ()
getPan ()
setPan (valore)
: Imposta il pan del suono (posizione stereo).getScale ()
setScale (valore)
: Imposta la scala del suono (intonazione).getVolume ()
setVolume (valore)
: Imposta il volume del suono.È in sospeso()
IsLoading ()
IsLoaded ()
isLooped ()
La classe Sound contiene anche le seguenti funzioni statiche.
caricare()
: Carica suoni appena creati.Stop()
: Interrompe tutti i suoni.getVolume ()
setVolume (valore)
: Imposta il volume globale (principale).getListener ()
setListener (valore)
: Tiene traccia dell'avanzamento del caricamento del suono ecc.canPlay (formato)
: Verifica se è possibile riprodurre vari formati audio.La documentazione può essere trovata nel codice sorgente della demo.
La riproduzione di effetti sonori in un gioco JavaScript dovrebbe essere semplice e questo tutorial lo rende avvolgente la potente API Web Audio in una classe Sound veloce e leggera che gestisce tutto per te.
Se sei interessato a saperne di più sui campioni sonori e su come manipolarli, ho scritto una serie per Tuts + che dovrebbe tenerti occupato per un po '...
I seguenti collegamenti sono relativi alle specifiche standardizzate W3C e Khronos direttamente correlate all'API Web Audio: