JavaScript Web Audio API
Aprenda a Web Audio API do JavaScript: construa um grafo de áudio com AudioContext e AudioNodes, carregue e reproduza sons, controle o volume, gere tons e gerencie a política de autoplay do navegador.
A Web Audio API permite gerar, carregar, processar e reproduzir som diretamente no navegador — sem necessidade de plugins. Este guia apresenta seus principais blocos de construção: como criar um contexto de áudio, carregar e reproduzir arquivos de som, controlar o volume, gerar tons com um oscilador e contornar a política de autoplay do navegador. Cada exemplo é pequeno e independente, para que você possa adicioná-lo a uma página e ouvir o resultado.
Introdução à Web Audio API
A Web Audio API é uma JavaScript API para processar e sintetizar áudio em aplicações web. Ao contrário de um simples elemento <audio> — que apenas reproduz um arquivo do início ao fim — a Web Audio API oferece um grafo de nós conectados que roteiam, misturam e transformam o som em tempo real. Isso a torna a ferramenta ideal para jogos, aplicativos de música, sintetizadores e visualizadores de áudio.
Pensando em grafos de áudio
Todo som na Web Audio API flui por uma cadeia de nós, de uma fonte até um destino:
source → (effects) → destination
(file, (gain, (your
oscillator) filter) speakers)Os três conceitos que você encontrará primeiro:
- AudioContext — o contêiner que possui todo o grafo e o relógio de áudio. Você cria um por página e o reutiliza.
- AudioNode — uma unidade modular de processamento. Nós de fonte produzem som (um buffer ou um oscilador), nós de efeito o transformam (gain, filtro, panner), e o nó de destino envia o som para os alto-falantes.
- AudioBuffer — dados de áudio decodificados em memória, ideal para sons curtos (efeitos, amostras) que você aciona repetidamente com temporização precisa.
Você constrói um grafo chamando node.connect(otherNode). O áudio sempre termina em audioContext.destination.
Começando com a Web Audio API
Para fazer qualquer coisa com áudio, você primeiro cria um AudioContext, que serve como contêiner para o seu grafo de áudio.
Criando um AudioContext
const audioContext = new (window.AudioContext || window.webkitAudioContext)();Isso inicializa um novo AudioContext. O fallback webkit cobre versões mais antigas do Safari; navegadores modernos suportam o AudioContext sem prefixo diretamente.
Atenção à política de autoplay. Os navegadores criam o contexto em estado
"suspended"e recusam reproduzir som até que o usuário interaja com a página (um clique ou pressionamento de tecla). Sempre retome-o dentro de um manipulador de eventos antes de reproduzir:button.addEventListener("click", async () => { if (audioContext.state === "suspended") { await audioContext.resume(); } // ...agora é seguro reproduzir });Se o áudio estiver silencioso sem erros no console, um contexto não retomado é a causa mais comum.
Carregando e Reproduzindo Áudio
Para reproduzir um arquivo de som, você o carrega em um AudioBuffer e, em seguida, conecta um nó de fonte ao contexto para reprodução.
Carregando Arquivos de Áudio
Isso usa a Fetch API e async/await para baixar o arquivo e decodificá-lo:
async function loadAudioFile(url, audioContext) {
const response = await fetch(url);
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
return audioBuffer;
}A função busca o arquivo, lê-o como um ArrayBuffer bruto e, em seguida, passa-o para decodeAudioData, que descomprime formatos como MP3, WAV ou OGG em um AudioBuffer pronto para reprodução. A decodificação ocorre fora da thread principal e retorna uma promise, então use await.
Reproduzindo o Áudio Carregado
function playAudio(audioBuffer, audioContext) {
const sourceNode = audioContext.createBufferSource();
sourceNode.buffer = audioBuffer;
sourceNode.connect(audioContext.destination);
sourceNode.start();
}Isso cria um BufferSourceNode, aponta-o para o buffer decodificado, conecta-o aos alto-falantes (audioContext.destination) e inicia a reprodução.
Um nó de fonte é de uso único. Um
AudioBufferSourceNodesó pode ser iniciado uma vez — após parar, você deve criar um novo para reproduzir o mesmo buffer novamente. O próprioAudioBufferé reutilizável, então mantenha o buffer e recrie o nó de fonte barato a 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(); }
Manipulando Áudio
A Web Audio API brilha quando você insere nós de efeito entre a fonte e o destino. O mais comum é o nó de gain para controle de volume.
Criando um Nó de Gain
function createGainNode(audioContext, volume) {
const gainNode = audioContext.createGain();
gainNode.gain.value = volume; // 1 = full volume, 0 = silent, 0.5 = half
return gainNode;
}Um GainNode multiplica o sinal pelo seu valor de gain. A propriedade gain é um AudioParam, o que significa que você também pode agendar mudanças suaves ao longo do tempo (para fades) em vez de definir um valor abruptamente:
// 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);Conectando Nós para Efeitos de Áudio
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();
}Isso constrói um grafo de três nós: a fonte alimenta o nó de gain, e o nó de gain alimenta o destino. Insira mais nós de efeito da mesma forma — por exemplo, um BiquadFilterNode para modelagem de 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);A ordem importa: o sinal flui na direção das suas chamadas connect.
Um Exemplo Executável: um Gerador de Tons
Para uma demonstração independente que não precisa de arquivo de áudio, aqui está um gerador de tons construído a partir de um oscilador. Ele também lida com a política de autoplay retomando o contexto no primeiro clique.
<!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>Como funciona:
- Nó oscilador — gera uma onda senoidal pura a 440 Hz (a nota A4 usada para afinação). Outros valores de
typesão"square","sawtooth"e"triangle", cada um com um timbre diferente. - Funções de controle —
playToneretoma o contexto e inicia o oscilador;stopToneo para, desconecta e redefine a variável para que um novo oscilador possa ser criado na próxima vez. - Por que redefinir
oscillator = null? Como um nó de fonte de buffer, um oscilador é de uso único — uma vez parado, não pode ser reiniciado, então você cria um novo para o próximo tom.
Quando Usar a Web Audio API
| Caso de uso | Utilize… |
|---|---|
| Reproduzir uma faixa de fundo ou podcast | Um simples elemento <audio> — mais simples, menos código |
| Efeitos sonoros em jogos com temporização precisa | Web Audio API + AudioBuffer |
| Controle de volume, fades, filtros, panning | Nós de gain/filtro/panner da Web Audio API |
| Sintetizadores e tons gerados | OscillatorNode da Web Audio API |
| Visualizadores de forma de onda/frequência em tempo real | AnalyserNode da Web Audio API |
Se você só precisa de reprodução com início/pausa, o elemento <audio> é suficiente. Escolha a Web Audio API no momento em que precisar de processamento, temporização ou síntese.
Conclusão
A Web Audio API transforma o navegador em um console de mixagem programável: você conecta um grafo de nós desde uma fonte, passando por efeitos, até os alto-falantes, e controla cada etapa em tempo real. Lembre-se destes pontos:
- Crie um
AudioContexte retome-o em um gesto do usuário antes de reproduzir. - Reutilize
AudioBuffers, mas crie um novo nó de fonte/oscilador para cada reprodução. - Construa efeitos encadeando nós com
connect(), sempre terminando emaudioContext.destination.
A partir daqui, explore capacidades relacionadas do navegador, como a Web MIDI API para conectar instrumentos musicais, ou a Web Animations API para sincronizar visuais com seu áudio.