The Web Audio API is a criminally underused tool for generating dynamic, real-time sound. This post walks through creating a mini synth from scratch — no libraries, no UI frameworks, just pure browser-native sound generation using JavaScript. Ideal for game devs, creative coders, or anyone who wants to learn procedural audio at a low level.
Why Use Web Audio API Directly?
- No external libraries or builds needed
- Precise control over oscillators, filters, and timing
- Useful in games, interactive apps, or generative art
Step 1: Create the Audio Context and Oscillator
The AudioContext
is your entry point to the Web Audio graph:
const ctx = new (window.AudioContext || window.webkitAudioContext)();
const osc = ctx.createOscillator();
osc.type = 'sawtooth'; // Try sine, square, triangle, etc.
osc.frequency.value = 440; // A4
osc.start();
Step 2: Add Envelope Control (ADSR)
We'll use a GainNode to fade the volume in and out for each note:
const gain = ctx.createGain();
gain.gain.setValueAtTime(0, ctx.currentTime);
gain.gain.linearRampToValueAtTime(1, ctx.currentTime + 0.1); // attack
gain.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.6); // decay + release
osc.connect(gain).connect(ctx.destination);
Step 3: Wire It to a Key Press
Basic synth: play a tone on key press, release it after a fixed time:
document.addEventListener('keydown', (e) => {
const note = e.key.toUpperCase();
const freqMap = { A: 440, W: 466, S: 494, D: 523 }; // add more
if (!freqMap[note]) return;
const o = ctx.createOscillator();
const g = ctx.createGain();
o.type = 'square';
o.frequency.value = freqMap[note];
g.gain.setValueAtTime(0, ctx.currentTime);
g.gain.linearRampToValueAtTime(0.9, ctx.currentTime + 0.05);
g.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.4);
o.connect(g).connect(ctx.destination);
o.start();
o.stop(ctx.currentTime + 0.5);
});
Step 4: Add Filter for Character
A low-pass filter can shape the tone:
const filter = ctx.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.value = 800;
osc.connect(filter).connect(gain).connect(ctx.destination);
Pros and Cons
✅ Pros
- Completely free, native to every modern browser
- Fine-grained control of sound generation
- Great for games, audio toys, or learning synthesis
⚠️ Cons
- No polyphony unless manually managed
- Inconsistent latency across devices
- Touch event restrictions on mobile (needs user interaction)
🚀 Alternatives
- Tone.js — high-level abstraction of Web Audio
- Howler.js — great for sample playback, less for synths
- SuperCollider (via WebAssembly) — if you need serious sound design
Summary
With just a few lines of JavaScript and zero dependencies, you can build a surprisingly expressive browser synth. This technique is useful not just for fun, but for building educational tools, generative art, and sound-rich web experiences without ever leaving the frontend.
If this was useful, you can support me here: buymeacoffee.com/hexshift