W3docs

Web Audio API de JavaScript

Aprende la Web Audio API de JavaScript: crea un grafo de audio con AudioContext y AudioNodes, carga y reproduce sonidos, controla el volumen y genera tonos.

La Web Audio API te permite generar, cargar, procesar y reproducir sonido directamente en el navegador, sin necesidad de plugins. Esta guía te explica sus bloques fundamentales: cómo crear un contexto de audio, cargar y reproducir archivos de sonido, controlar el volumen, generar tonos con un oscilador y sortear la política de reproducción automática del navegador. Cada ejemplo es pequeño y autocontenido, para que puedas incluirlo en una página y escuchar el resultado.

Introducción a la Web Audio API

La Web Audio API es una API de JavaScript para procesar y sintetizar audio en aplicaciones web. A diferencia de un simple elemento <audio>, que se limita a reproducir un archivo de principio a fin, la Web Audio API te ofrece un grafo de nodos conectados que enrutan, mezclan y transforman el sonido en tiempo real. Eso la convierte en la herramienta adecuada para juegos, aplicaciones de música, sintetizadores y visualizadores de audio.

Pensar en grafos de audio

Todo sonido en la Web Audio API fluye a través de una cadena de nodos, desde una fuente hasta un destino:

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

Los tres conceptos que encontrarás primero:

  • AudioContext: el contenedor que posee todo el grafo y el reloj de audio. Se crea uno por página y se reutiliza.
  • AudioNode: una unidad modular de procesamiento. Los nodos de fuente producen sonido (un búfer o un oscilador), los nodos de efecto lo transforman (ganancia, filtro, panoramizador) y el nodo destination lo envía a los altavoces.
  • AudioBuffer: datos de audio decodificados en memoria, ideales para sonidos cortos (efectos, muestras) que se activan repetidamente con una sincronización precisa.

Un grafo se construye llamando a node.connect(otherNode). El audio siempre termina en audioContext.destination.

Primeros pasos con la Web Audio API

Para hacer cualquier cosa con audio, primero creas un AudioContext, que actúa como contenedor de tu grafo de audio.

Crear un AudioContext

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

Esto inicializa un nuevo AudioContext. La alternativa con prefijo webkit cubre versiones antiguas de Safari; los navegadores modernos admiten directamente AudioContext sin prefijo.

Trampa de la política de reproducción automática. Los navegadores crean el contexto en estado "suspended" y se niegan a reproducir sonido hasta que el usuario interactúa con la página (un clic o una pulsación de tecla). Reanúdalo siempre dentro de un controlador de eventos antes de reproducir:

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

Si el audio suena en silencio y no hay errores en la consola, la causa más habitual es un contexto sin reanudar.

Cargar y reproducir audio

Para reproducir un archivo de sonido, lo cargas en un AudioBuffer y luego conectas un nodo de fuente al contexto para la reproducción.

Cargar archivos de audio

Aquí se usan la Fetch API y async/await para descargar el archivo y 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 función descarga el archivo, lo lee como un ArrayBuffer sin procesar y se lo pasa a decodeAudioData, que descomprime formatos como MP3, WAV u OGG y los convierte en un AudioBuffer listo para reproducir. La decodificación se realiza fuera del hilo principal y devuelve una promesa, así que usa await.

Reproducir el audio cargado

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

Esto crea un BufferSourceNode, lo asocia al búfer decodificado, lo conecta a los altavoces (audioContext.destination) e inicia la reproducción.

Un nodo de fuente es de un solo uso. Un AudioBufferSourceNode solo puede iniciarse una vez: cuando se detiene, debes crear uno nuevo para reproducir de nuevo el mismo búfer. El AudioBuffer en sí es reutilizable, así que conserva el búfer y vuelve a crear el nodo de fuente, que es barato, cada vez:

// ❌ 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();
}

Manipular el audio

La Web Audio API brilla cuando insertas nodos de efecto entre la fuente y el destino. El más común es el nodo de ganancia para controlar el volumen.

Crear un nodo de ganancia

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

Un GainNode multiplica la señal por su valor de gain. La propiedad gain es un AudioParam, lo que significa que también puedes programar cambios suaves a lo largo del tiempo (para fundidos) en lugar de asignar un valor de forma abrupta:

// 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);

Conectar nodos para aplicar efectos de 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();
}

Esto construye un grafo de tres nodos: la fuente alimenta al nodo de ganancia y este alimenta al destino. Puedes insertar más nodos de efecto del mismo modo, por ejemplo un BiquadFilterNode para dar forma al timbre:

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);

El orden importa: la señal fluye en la dirección de tus llamadas a connect.

Un ejemplo ejecutable: un generador de tonos

Como demostración autocontenida que no necesita ningún archivo de audio, aquí tienes un generador de tonos construido con un oscilador. También gestiona la política de reproducción automática reanudando el contexto en el primer 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>

Cómo funciona:

  • Nodo oscilador: genera una onda sinusoidal pura a 440 Hz (la nota La4 que se usa para afinar). Los otros valores de type son "square", "sawtooth" y "triangle", cada uno con un timbre distinto.
  • Funciones de control: playTone reanuda el contexto e inicia el oscilador; stopTone lo detiene, lo desconecta y restablece la variable para que la próxima vez se pueda crear un oscilador nuevo.
  • ¿Por qué restablecer oscillator = null? Igual que una fuente de búfer, un oscilador es de un solo uso: una vez detenido no puede reiniciarse, así que se construye uno nuevo para el siguiente tono.

Cuándo usar la Web Audio API

Caso de usoQué usar
Reproducir una única pista de fondo o un pódcastUn simple elemento <audio>: más sencillo, menos código
Efectos de sonido en un juego con sincronización precisaWeb Audio API + AudioBuffer
Control de volumen, fundidos, filtros, panoramizaciónNodos de ganancia, filtro y panoramizador de la Web Audio API
Sintetizadores y tonos generadosOscillatorNode de la Web Audio API
Visualizadores de forma de onda y frecuencia en tiempo realAnalyserNode de la Web Audio API

Si solo necesitas iniciar y detener la reproducción, el elemento <audio> basta. Elige la Web Audio API en cuanto necesites procesamiento, sincronización o síntesis.

Conclusión

La Web Audio API convierte el navegador en una mesa de mezclas programable: conectas un grafo de nodos desde una fuente, pasando por los efectos, hasta los altavoces, y controlas cada paso en tiempo real. Ten presentes estas ideas clave:

  • Crea un solo AudioContext y reanúdalo con un gesto del usuario antes de reproducir.
  • Reutiliza los AudioBuffer, pero crea un nodo de fuente u oscilador nuevo para cada reproducción.
  • Construye efectos encadenando nodos con connect(), terminando siempre en audioContext.destination.

A partir de aquí, explora otras capacidades relacionadas del navegador, como la Web MIDI API para conectar instrumentos musicales, o la Web Animations API para sincronizar elementos visuales con tu audio.

Práctica

Práctica
¿Qué características son ciertas respecto a las capacidades de la Web Audio API?
¿Qué características son ciertas respecto a las capacidades de la Web Audio API?
Was this page helpful?