Prima dell'elemento <audio>
HTML5, era necessario Flash o un altro plug-in
per rompere il silenzio del web. Quando l'audio sul web non è più
richiede un plug-in, il tag audio presenta
e implementare applicazioni interattive e giochi sofisticati.
L'API Web Audio è un'API JavaScript di alto livello per l'elaborazione e sintetizzando audio nelle applicazioni web. L'obiettivo di questa API è che includono funzionalità presenti nei moderni motori audio dei giochi e alcuni dei le attività di combinazione, elaborazione e filtro presenti nella versione desktop moderna applicazioni di produzione audio. Segue una breve introduzione utilizzando questa potente API.
Introduzione ad AudioContext
Un AudioContext consente di gestire e riprodurre tutti i suoni. Per produrre
un suono utilizzando l'API Web Audio, crea una o più sorgenti sonore
e collegarli alla destinazione audio fornita da AudioContext
in esecuzione in un'istanza Compute Engine. Questa connessione non deve essere diretta e può passare
un numero qualsiasi di AudioNodes intermedi che fungono da elaborazione
per il segnale audio. Questo routing è descritto in maggiore dettaglio
nella specifica di Web Audio.
Una singola istanza di AudioContext
può supportare più input audio
e grafici audio complessi, perciò avremo bisogno di uno solo di questi
l'applicazione audio che creiamo.
Il seguente snippet crea un AudioContext
:
var context;
window.addEventListener('load', init, false);
function init() {
try {
context = new AudioContext();
}
catch(e) {
alert('Web Audio API is not supported in this browser');
}
}
Per i browser meno recenti basati su WebKit, utilizza il prefisso webkit
, come per
webkitAudioContext
.
Molte delle interessanti funzionalità dell'API Web Audio, come la creazione
AudioNodi e decodifica dei dati dei file audio sono metodi di AudioContext
.
Caricamento suoni in corso...
L'API Web Audio utilizza un AudioBuffer per video di breve e media durata i suoni. L'approccio di base consiste nell'utilizzare XMLHttpRequest per recuperare i file audio.
L'API supporta il caricamento dei dati dei file audio in più formati, come WAV, MP3, AAC, OGG e altri. Supporto del browser per i formati audio variano.
Il seguente snippet mostra il caricamento di un campione audio:
var dogBarkingBuffer = null;
var context = new AudioContext();
function loadDogSound(url) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function() {
context.decodeAudioData(request.response, function(buffer) {
dogBarkingBuffer = buffer;
}, onError);
}
request.send();
}
I dati del file audio sono binari (non testo), quindi impostiamo responseType
della richiesta a 'arraybuffer'
. Per ulteriori informazioni
ArrayBuffers
, consulta questo articolo su XHR2.
Una volta ricevuti i dati del file audio (non decodificati), puoi conservarli
per la decodifica in un secondo momento oppure può essere decodificato subito utilizzando
Metodo decodeAudioData()
AudioContext. Questo metodo utilizza
ArrayBuffer
di dati dei file audio memorizzati in request.response
e
la decodifica in modo asincrono (non bloccando l'esecuzione principale del codice JavaScript)
thread).
Al termine decodeAudioData()
, viene chiamata una funzione di callback che
fornisce i dati audio PCM decodificati sotto forma di AudioBuffer
.
Riproduzione di suoni
Puoi iniziare a giocare dopo aver caricato uno o più AudioBuffers
i suoni. Supponiamo di aver caricato un AudioBuffer
con l'audio
di un cane che abbaia e che il caricamento è terminato. Poi possiamo giocare
questo buffer con il seguente codice.
var context = new AudioContext();
function playSound(buffer) {
var source = context.createBufferSource(); // creates a sound source
source.buffer = buffer; // tell the source which sound to play
source.connect(context.destination); // connect the source to the context's destination (the speakers)
source.noteOn(0); // play the source now
}
Questa funzione playSound()
può essere chiamata ogni volta che qualcuno preme un tasto o
fa clic su qualcosa con il mouse.
La funzione noteOn(time)
semplifica la programmazione di un suono preciso
per i giochi e altre applicazioni urgenti. Tuttavia, per ottenere
questa programmazione funziona correttamente, assicurati che i sound buffer siano
sono precaricati.
Estrazione dell'API Web Audio
Naturalmente, sarebbe meglio creare un sistema di caricamento più generico che non è hardcoded per caricare questo suono specifico. Esistono molti per gestire i molti suoni di breve e media durata che un'applicazione o un gioco audio utilizzerebbe un gioco o un'applicazione audio. Ecco un modo per utilizzare un BufferLoader (che non fa parte dello standard web).
Di seguito è riportato un esempio di come utilizzare la classe BufferLoader
.
Creiamo due AudioBuffers
: e, non appena vengono caricati,
riproducili contemporaneamente.
window.onload = init;
var context;
var bufferLoader;
function init() {
context = new AudioContext();
bufferLoader = new BufferLoader(
context,
[
'../sounds/hyper-reality/br-jam-loop.wav',
'../sounds/hyper-reality/laughter.wav',
],
finishedLoading
);
bufferLoader.load();
}
function finishedLoading(bufferList) {
// Create two sources and play them both together.
var source1 = context.createBufferSource();
var source2 = context.createBufferSource();
source1.buffer = bufferList[0];
source2.buffer = bufferList[1];
source1.connect(context.destination);
source2.connect(context.destination);
source1.noteOn(0);
source2.noteOn(0);
}
Gestire il tempo: suonare i suoni seguendo il ritmo
L'API Web Audio consente agli sviluppatori di programmare con precisione la riproduzione. A dimostrare questo, impostiamo una traccia ritmica semplice. Probabilmente la pattern di drumkit più noto è il seguente:
in cui viene suonato un hihat ogni ottava nota, mentre il tasto kick e rullante sono giocate in modo alternato ogni trimestre, in 4/4.
Supponendo di aver caricato i buffer kick
, snare
e hihat
,
per farlo è semplice:
for (var bar = 0; bar < 2; bar++) {
var time = startTime + bar * 8 * eighthNoteTime;
// Play the bass (kick) drum on beats 1, 5
playSound(kick, time);
playSound(kick, time + 4 * eighthNoteTime);
// Play the snare drum on beats 3, 7
playSound(snare, time + 2 * eighthNoteTime);
playSound(snare, time + 6 * eighthNoteTime);
// Play the hi-hat every eighth note.
for (var i = 0; i < 8; ++i) {
playSound(hihat, time + i * eighthNoteTime);
}
}
Qui facciamo una sola ripetizione invece del loop illimitato che vediamo
gli spartiti. La funzione playSound
è un metodo che riproduce un
buffer in un determinato momento, come segue:
function playSound(buffer, time) {
var source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
source.noteOn(time);
}
Regolare il volume di un suono
Una delle operazioni più basilari che potresti eseguire su un suono è regolare il volume. Utilizzando l'API Web Audio, possiamo indirizzare la nostra sorgente a la sua destinazione attraverso un AudioGainNode al fine di manipolare volume:
Questa configurazione di connessione può essere eseguita nel seguente modo:
// Create a gain node.
var gainNode = context.createGainNode();
// Connect the source to the gain node.
source.connect(gainNode);
// Connect the gain node to the destination.
gainNode.connect(context.destination);
Dopo aver configurato il grafico, puoi modificare in modo programmatico il valore
manipolando gainNode.gain.value
come segue:
// Reduce the volume.
gainNode.gain.value = 0.5;
Dissolvenza incrociata tra due suoni
Supponiamo ora di avere uno scenario leggermente più complesso, in cui riproducendo più suoni ma con una dissolvenza incrociata tra i suoni. Si tratta di un caso comune in un'applicazione simile a quella da DJ, in cui abbiamo due giradischi e vuoi poter eseguire la panoramica da una sorgente audio all'altra.
Per farlo, puoi utilizzare il seguente grafico audio:
Per configurarlo, basta creare due AudioGainNodes e connettere ciascuna sorgente attraverso i nodi, utilizzando una funzione simile a questa:
function createSource(buffer) {
var source = context.createBufferSource();
// Create a gain node.
var gainNode = context.createGainNode();
source.buffer = buffer;
// Turn on looping.
source.loop = true;
// Connect source to gain.
source.connect(gainNode);
// Connect gain to destination.
gainNode.connect(context.destination);
return {
source: source,
gainNode: gainNode
};
}
Dissolvenza incrociata a potenza uguale
Un approccio ingenuo a dissolvenza incrociata lineare mostra un calo del volume durante la panoramica tra i campioni.
Per risolvere questo problema, utilizziamo una curva di potenza di parità, in cui le curve di guadagno corrispondenti non sono lineari e si intersecano a un di ampiezza. In questo modo vengono ridotti al minimo i cali di volume tra le regioni dell'audio, in una dissolvenza incrociata più uniforme tra regioni che potrebbero essere di livello diverso.
Dissolvenza incrociata della playlist
Un'altra applicazione crossfader comune è quella di un lettore musicale.
Quando un brano cambia, vogliamo applicare una dissolvenza alla traccia corrente e
per evitare una transizione sgradevole. A questo scopo, pianifica
una dissolvenza incrociata nel futuro. Per farlo potremmo utilizzare setTimeout
pianificazione, questo dato non è preciso. Con l'API Web Audio,
puoi utilizzare l'interfaccia AudioParam per pianificare valori futuri per
come il valore di guadagno di AudioGainNode
.
Di conseguenza, data una playlist, possiamo passare da una traccia all'altra programmando una diminuisci il guadagno sulla traccia attualmente in riproduzione e un aumento del guadagno sulle quella successiva, entrambe leggermente prima del termine della riproduzione della traccia corrente:
function playHelper(bufferNow, bufferLater) {
var playNow = createSource(bufferNow);
var source = playNow.source;
var gainNode = playNow.gainNode;
var duration = bufferNow.duration;
var currTime = context.currentTime;
// Fade the playNow track in.
gainNode.gain.linearRampToValueAtTime(0, currTime);
gainNode.gain.linearRampToValueAtTime(1, currTime + ctx.FADE_TIME);
// Play the playNow track.
source.noteOn(0);
// At the end of the track, fade it out.
gainNode.gain.linearRampToValueAtTime(1, currTime + duration-ctx.FADE_TIME);
gainNode.gain.linearRampToValueAtTime(0, currTime + duration);
// Schedule a recursive track change with the tracks swapped.
var recurse = arguments.callee;
ctx.timer = setTimeout(function() {
recurse(bufferLater, bufferNow);
}, (duration - ctx.FADE_TIME) - 1000);
}
L'API Web Audio offre un pratico insieme di metodi RampToValue
per
modificare gradualmente il valore di un parametro,
linearRampToValueAtTime
e exponentialRampToValueAtTime
.
La funzione di tempo di transizione può essere scelta dalla funzione
e esponenziali (come sopra), puoi anche specificare il tuo valore
della curva tramite un array di valori utilizzando la funzione setValueCurveAtTime
.
Applicare un semplice effetto filtro a un suono
L'API Web Audio consente di trasmettere l'audio da un nodo audio all'altro, creando una catena di processori potenzialmente complessa per aggiungere effetti sonori alle tue forme sonore.
Un modo per farlo è inserire BiquadFilterNode tra il suono sorgente e destinazione. Questo tipo di nodo audio può svolgere filtri di ordine inferiore che possono essere utilizzati per creare equalizzatori grafici e perfino più complessi, legati principalmente alla selezione delle parti lo spettro di frequenza di un suono da enfatizzare e da sottomettere.
I tipi di filtri supportati includono:
- Filtro passa basso
- Filtro superamento pass
- Filtro passa banda
- Filtro barra delle app in basso
- Filtro sezione superiore
- Filtro picco
- Filtro tacca
- Filtro tutte le tessere
Tutti i filtri includono parametri per specificare una certa quantità guadagno, la frequenza con cui applicare il filtro e un fattore di qualità. Il filtro passa basso mantiene l'intervallo di frequenza più basso, ma ignora i valori elevati di frequenza cardiaca. Il punto di interruzione è determinato dal valore della frequenza, mentre il fattore Q è senza unità e determina la forma del grafico. Il guadagno interessa solo alcuni filtri, come lo scaffale basso e filtri di picco e non questo filtro passa basso.
Impostiamo un semplice filtro passa-basso per estrarre solo le basi da una esempio audio:
// Create the filter
var filter = context.createBiquadFilter();
// Create the audio graph.
source.connect(filter);
filter.connect(context.destination);
// Create and specify parameters for the low-pass filter.
filter.type = 0; // Low-pass filter. See BiquadFilterNode docs
filter.frequency.value = 440; // Set cutoff to 440 HZ
// Playback the sound.
source.noteOn(0);
In generale, i controlli della frequenza devono essere modificati per funzionare
scala logaritmica, poiché l'udito umano si basa sullo stesso principio
(ovvero, A4 è 440 Hz, e A5 è 880 Hz). Per ulteriori dettagli, consulta
FilterSample.changeFrequency
nel link del codice sorgente riportato sopra.
Infine, tieni presente che il codice campione ti consente di collegare e scollegare
che modifica dinamicamente il grafico AudioContext. Possiamo scollegare
AudioNodi dal grafico chiamando node.disconnect(outputNumber)
.
Ad esempio, per reindirizzare il grafico da un filtro a una
connessione diretta, possiamo fare quanto segue:
// Disconnect the source and filter.
source.disconnect(0);
filter.disconnect(0);
// Connect the source directly.
source.connect(context.destination);
Maggiore ascolto
Abbiamo esaminato le nozioni di base dell'API, tra cui il caricamento e la riproduzione di audio i campioni. Abbiamo creato grafici audio con nodi e filtri di guadagno. suoni programmati e modifiche dei parametri audio per consentire alcuni suoni comuni e gli effetti sonori. A questo punto, sei pronto per creare un sito web applicazioni audio.
Se sei in cerca di ispirazione, molti sviluppatori hanno già creato un ottimo lavoro con l'utilizzo dell'API Web Audio. Alcune delle mie preferite include:
- AudioJedit, uno strumento di giunzione audio integrato nel browser che utilizza permalink SoundCloud.
- ToneCraft, un sequencer di suoni in cui i suoni vengono creati impilare blocchi 3D.
- Plink, un gioco collaborativo per la creazione di musica che utilizza Web Audio e Web Socket.