W3docs

Web Audio API di JavaScript

Scopri la Web Audio API di JavaScript: crea un grafo audio con AudioContext e AudioNode, carica e riproduci suoni, controlla il volume e genera toni.

La Web Audio API ti permette di generare, caricare, elaborare e riprodurre suoni direttamente nel browser, senza bisogno di plugin. Questa guida ti accompagna attraverso i suoi elementi fondamentali: come creare un contesto audio, caricare e riprodurre file sonori, controllare il volume, generare toni con un oscillatore e aggirare il criterio di riproduzione automatica (autoplay policy) del browser. Ogni esempio è breve e autonomo, così puoi inserirlo in una pagina e sentire subito il risultato.

Introduzione alla Web Audio API

La Web Audio API è una API JavaScript per elaborare e sintetizzare audio nelle applicazioni web. A differenza di un semplice elemento <audio>, che si limita a riprodurre un file dall'inizio alla fine, la Web Audio API ti mette a disposizione un grafo di nodi collegati tra loro che instradano, mescolano e trasformano il suono in tempo reale. È quindi lo strumento giusto per giochi, app musicali, sintetizzatori e visualizzatori audio.

Pensare in termini di grafi audio

Ogni suono nella Web Audio API attraversa una catena di nodi, da una sorgente a una destinazione:

source  →  (effects)  →  destination
 (file,    (gain,        (your
 oscillator)  filter)     speakers)

I tre concetti che incontrerai per primi:

  • AudioContext: il contenitore che possiede l'intero grafo e il clock audio. Ne crei uno per pagina e lo riutilizzi.
  • AudioNode: un'unità modulare di elaborazione. I nodi sorgente producono suono (un buffer o un oscillatore), i nodi effetto lo trasformano (gain, filtro, panner) e il nodo destination lo invia agli altoparlanti.
  • AudioBuffer: dati audio decodificati e residenti in memoria, ideali per suoni brevi (effetti, campioni) che attivi più volte con tempi precisi.

Costruisci un grafo chiamando node.connect(otherNode). L'audio termina sempre in audioContext.destination.

Primi passi con la Web Audio API

Per fare qualsiasi cosa con l'audio, devi prima creare un AudioContext, che funge da contenitore del tuo grafo audio.

Creare un AudioContext

const audioContext = new (window.AudioContext || window.webkitAudioContext)();

Questo inizializza un nuovo AudioContext. Il fallback webkit copre le versioni più vecchie di Safari; i browser moderni supportano direttamente AudioContext senza prefisso.

Il tranello della autoplay policy. I browser creano il contesto nello stato "suspended" e si rifiutano di riprodurre suoni finché l'utente non interagisce con la pagina (un clic o la pressione di un tasto). Riattivalo sempre all'interno di un gestore di eventi prima di riprodurre:

button.addEventListener("click", async () => {
  if (audioContext.state === "suspended") {
    await audioContext.resume();
  }
  // ...now it is safe to play
});

Se l'audio è muto e nella console non compaiono errori, la causa più comune è un contesto non riattivato.

Caricare e riprodurre l'audio

Per riprodurre un file sonoro, lo carichi in un AudioBuffer e poi colleghi un nodo sorgente al contesto per la riproduzione.

Caricare i file audio

Questo codice usa la Fetch API e async/await per scaricare il file e decodificarlo:

async function loadAudioFile(url, audioContext) {
  const response = await fetch(url);
  const arrayBuffer = await response.arrayBuffer();
  const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
  return audioBuffer;
}

La funzione scarica il file, lo legge come ArrayBuffer grezzo e lo passa a decodeAudioData, che decomprime formati come MP3, WAV o OGG in un AudioBuffer pronto per la riproduzione. La decodifica avviene fuori dal thread principale e restituisce una promise, quindi usa await.

Riprodurre l'audio caricato

function playAudio(audioBuffer, audioContext) {
  const sourceNode = audioContext.createBufferSource();
  sourceNode.buffer = audioBuffer;
  sourceNode.connect(audioContext.destination);
  sourceNode.start();
}

Questo codice crea un BufferSourceNode, lo punta al buffer decodificato, lo collega agli altoparlanti (audioContext.destination) e avvia la riproduzione.

Un nodo sorgente è monouso. Un AudioBufferSourceNode può essere avviato una sola volta: dopo che si è fermato, devi crearne uno nuovo per riprodurre di nuovo lo stesso buffer. L'AudioBuffer in sé è riutilizzabile, quindi conserva il buffer e ricrea ogni volta il nodo sorgente, che è leggero:

// ❌ Throws after the first play: "cannot call start more than once"
// sourceNode.start();
// sourceNode.start();

// ✅ One fresh source node per playback
function playOnce(buffer, ctx) {
  const src = ctx.createBufferSource();
  src.buffer = buffer;
  src.connect(ctx.destination);
  src.start();
}

Manipolare l'audio

La Web Audio API dà il meglio di sé quando inserisci nodi effetto tra la sorgente e la destinazione. Il più comune è il gain node per il controllo del volume.

Creare un Gain Node

function createGainNode(audioContext, volume) {
  const gainNode = audioContext.createGain();
  gainNode.gain.value = volume; // 1 = full volume, 0 = silent, 0.5 = half
  return gainNode;
}

Un GainNode moltiplica il segnale per il valore di gain. La proprietà gain è un AudioParam, il che significa che puoi anche programmare variazioni graduali nel tempo (per le dissolvenze) invece di impostare un valore in modo brusco:

// Fade from silent to full volume over 2 seconds, avoiding clicks/pops
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
gainNode.gain.linearRampToValueAtTime(1, audioContext.currentTime + 2);

Collegare i nodi per gli effetti audio

function applyEffects(audioBuffer, volume, audioContext) {
  const sourceNode = audioContext.createBufferSource();
  sourceNode.buffer = audioBuffer;

  const gainNode = createGainNode(audioContext, volume);

  // source → gain → destination
  sourceNode.connect(gainNode);
  gainNode.connect(audioContext.destination);

  sourceNode.start();
}

Questo costruisce un grafo di tre nodi: la sorgente alimenta il gain node e il gain node alimenta la destinazione. Puoi inserire altri nodi effetto allo stesso modo, ad esempio un BiquadFilterNode per modellare il timbro:

const filter = audioContext.createBiquadFilter();
filter.type = "lowpass";      // let low frequencies through, cut highs
filter.frequency.value = 800; // cutoff in Hz

sourceNode.connect(filter);
filter.connect(gainNode);
gainNode.connect(audioContext.destination);

L'ordine conta: il segnale scorre nella direzione delle tue chiamate a connect.

Un esempio eseguibile: un generatore di toni

Per una demo autonoma che non richiede alcun file audio, ecco un generatore di toni costruito con un oscillatore. Gestisce anche la autoplay policy riattivando il contesto al primo clic.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Simple Tone Generator</title>
  </head>
  <body>
    <h1>Simple Tone Generator</h1>
    <button onclick="playTone()">Play Tone</button>
    <button onclick="stopTone()">Stop Tone</button>

    <script>
      let audioContext;
      let oscillator;

      async function playTone() {
        if (!audioContext) {
          audioContext = new (window.AudioContext ||
            window.webkitAudioContext)();
        }
        // Satisfy the autoplay policy: resume on user gesture
        if (audioContext.state === "suspended") {
          await audioContext.resume();
        }
        if (!oscillator) {
          oscillator = audioContext.createOscillator();
          oscillator.type = "sine"; // Sine wave — other values are 'square', 'sawtooth', 'triangle'
          oscillator.frequency.setValueAtTime(440, audioContext.currentTime); // A4 note, 440 Hz
          oscillator.connect(audioContext.destination);
          oscillator.start();
        }
      }

      function stopTone() {
        if (oscillator) {
          oscillator.stop();
          oscillator.disconnect();
          oscillator = null; // Reset the oscillator to allow a new one to be created next time
        }
      }
    </script>
  </body>
</html>

Come funziona:

  • Nodo oscillatore: genera un'onda sinusoidale pura a 440 Hz (la nota La4 usata per l'accordatura). Gli altri valori di type sono "square", "sawtooth" e "triangle", ciascuno con un timbro diverso.
  • Funzioni di controllo: playTone riattiva il contesto e avvia l'oscillatore; stopTone lo ferma, lo scollega e reimposta la variabile, in modo che al prossimo avvio si possa creare un nuovo oscillatore.
  • Perché reimpostare oscillator = null? Come un buffer source, un oscillatore è monouso: una volta fermato non può essere riavviato, quindi ne costruisci uno nuovo per il tono successivo.

Quando usare la Web Audio API

Caso d'usoCosa scegliere…
Riprodurre una singola traccia di sottofondo o un podcastUn semplice elemento <audio>: più semplice, meno codice
Effetti sonori in un gioco con tempi precisiWeb Audio API + AudioBuffer
Controllo del volume, dissolvenze, filtri, panningNodi gain/filter/panner della Web Audio API
Sintetizzatori e toni generatiOscillatorNode della Web Audio API
Visualizzatori di forma d'onda/frequenza in tempo realeAnalyserNode della Web Audio API

Se ti serve solo avviare e fermare la riproduzione, l'elemento <audio> è sufficiente. Scegli la Web Audio API nel momento in cui hai bisogno di elaborazione, temporizzazione o sintesi.

Conclusione

La Web Audio API trasforma il browser in una console di missaggio programmabile: colleghi un grafo di nodi da una sorgente, attraverso gli effetti, fino agli altoparlanti, e controlli ogni passaggio in tempo reale. Tieni a mente questi punti chiave:

  • Crea un solo AudioContext e riattivalo con un gesto dell'utente prima di riprodurre.
  • Riutilizza gli AudioBuffer, ma crea un nuovo nodo sorgente/oscillatore per ogni riproduzione.
  • Costruisci gli effetti concatenando i nodi con connect(), terminando sempre in audioContext.destination.

Da qui puoi esplorare altre funzionalità del browser correlate, come la Web MIDI API per collegare strumenti musicali, oppure la Web Animations API per sincronizzare gli elementi visivi con l'audio.

Practice

Pratica
Quali affermazioni sono vere riguardo alle capacità della Web Audio API?
Quali affermazioni sono vere riguardo alle capacità della Web Audio API?
Was this page helpful?