Web Audio & Canvas
The Web Audio API and Canvas API let you build rich interactive experiences — synthesizers, visualizers, and creative tools — right in the browser.
Web Audio API Basics
// Create audio context (one per application)
const ctx = new AudioContext();
// Simple oscillator
function playTone(frequency, duration = 0.5) {
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = 'sine'; // sine, square, sawtooth, triangle
osc.frequency.value = frequency;
gain.gain.setValueAtTime(0.3, ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + duration);
osc.connect(gain).connect(ctx.destination);
osc.start();
osc.stop(ctx.currentTime + duration);
}
// Play a C major chord
playTone(261.63); // C4
playTone(329.63); // E4
playTone(392.00); // G4
Audio Signal Chain
Web Audio uses a node-based graph:
Oscillator → Filter → Gain → Analyser → Destination (speakers)
const osc = ctx.createOscillator();
const filter = ctx.createBiquadFilter();
const gain = ctx.createGain();
const analyser = ctx.createAnalyser();
filter.type = 'lowpass';
filter.frequency.value = 1000;
osc.connect(filter)
.connect(gain)
.connect(analyser)
.connect(ctx.destination);
Canvas Visualization
Draw audio data in real-time with Canvas:
const canvas = document.querySelector('#visualizer');
const canvasCtx = canvas.getContext('2d');
const analyser = ctx.createAnalyser();
analyser.fftSize = 256;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
function draw() {
requestAnimationFrame(draw);
analyser.getByteFrequencyData(dataArray);
canvasCtx.fillStyle = '#1e1e2e';
canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
const barWidth = canvas.width / bufferLength;
dataArray.forEach((value, i) => {
const height = (value / 255) * canvas.height;
const hue = (i / bufferLength) * 360;
canvasCtx.fillStyle = `hsl(${hue}, 70%, 60%)`;
canvasCtx.fillRect(i * barWidth, canvas.height - height, barWidth - 1, height);
});
}
draw();
Performance Tips
- Reuse nodes where possible — creating/destroying is expensive
- Use
requestAnimationFramefor visual updates, notsetInterval OffscreenCanvaslets you render in a Web Worker for complex scenes- Batch canvas operations — minimize state changes (fillStyle, transforms)
- Use
AudioWorkletfor custom DSP (replaces deprecated ScriptProcessorNode)