Web Audio API in JavaScript
Introduction
The Web Audio API processes and plays sound in the browser with low latency—oscillators, filters, volume, and effects. It is lower level than <audio src="..."> but enables games, visualizers, and dynamic sound. This chapter builds a minimal beep and mentions user-gesture requirements.
Prerequisites
AudioContext
Browsers require user interaction before audio starts (autoplay policy):
html
<button id="play">Play tone</button>
<script>
let ctx;
document.getElementById("play").addEventListener("click", () => {
if (!ctx) ctx = new AudioContext();
playBeep(ctx);
});
function playBeep(audioCtx) {
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.frequency.value = 440;
gain.gain.value = 0.1;
osc.start();
osc.stop(audioCtx.currentTime + 0.2);
}
</script>Play an Audio File
javascript
async function playSample(audioCtx, url) {
const res = await fetch(url);
const buffer = await audioCtx.decodeAudioData(await res.arrayBuffer());
const source = audioCtx.createBufferSource();
source.buffer = buffer;
source.connect(audioCtx.destination);
source.start();
}Use royalty-free samples; large files should stream with care.
Volume Control
javascript
// GainNode as volume knob
const gain = audioCtx.createGain();
gain.gain.value = 0.5;
source.connect(gain);
gain.connect(audioCtx.destination);Fade with scheduled ramps: gain.gain.setValueAtTime(0, t).
Analyser for Visualizers
javascript
// Frequency data for canvas bars
const analyser = audioCtx.createAnalyser();
analyser.fftSize = 256;
source.connect(analyser);
analyser.connect(audioCtx.destination);
const data = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(data);
console.log(data.slice(0, 8));Pair with Canvas for bar charts.
<audio> Element vs Web Audio
| Approach | Best for |
|---|---|
<audio controls> | Podcasts, simple playback |
| Web Audio API | Games, synthesis, effects, visualizers |
Mini Example: Click Sound
javascript
function clickSound(audioCtx) {
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = "square";
osc.frequency.value = 880;
gain.gain.setValueAtTime(0.15, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.08);
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start();
osc.stop(audioCtx.currentTime + 0.08);
}FAQ
Mobile Safari quirks?
Resume AudioContext after user tap if state === "suspended".
Autoplay blocked?
Always tie first AudioContext creation to a click or keydown.
Record microphone?
navigator.mediaDevices.getUserMedia({ audio: true })—requires HTTPS and permission prompt.