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 requestAnimationFrame for visual updates, not setInterval
  • OffscreenCanvas lets you render in a Web Worker for complex scenes
  • Batch canvas operations — minimize state changes (fillStyle, transforms)
  • Use AudioWorklet for custom DSP (replaces deprecated ScriptProcessorNode)