The Web Audio API is more powerful than most developers realize — it's capable of running full synth engines in the browser. This article shows how to build a basic polyphonic synthesizer from scratch using raw Web Audio primitives. Great for interactive music apps, education tools, or browser-based DAWs.

What We’ll Build


  • Multiple simultaneous notes (polyphony)
  • ADSR envelope for smooth attack and release
  • Keyboard input for triggering sounds

Step 1: Create the Audio Context


Set up your Web Audio graph entry point:


const audioCtx = new (window.AudioContext || window.webkitAudioContext)();

Step 2: Define a Note Class


This encapsulates oscillator, gain (for volume), and envelope behavior:


class SynthNote {
constructor(freq) {
this.osc = audioCtx.createOscillator();
this.gain = audioCtx.createGain();
this.osc.type = 'sawtooth';
this.osc.frequency.value = freq;

this.osc.connect(this.gain);
this.gain.connect(audioCtx.destination);

const now = audioCtx.currentTime;
this.gain.gain.setValueAtTime(0, now);
this.gain.gain.linearRampToValueAtTime(0.5, now + 0.01); // attack
this.osc.start(now);

}

stop() {
const now = audioCtx.currentTime;
this.gain.gain.linearRampToValueAtTime(0, now + 0.3); // release
this.osc.stop(now + 0.3);
}
}

Step 3: Add Keyboard Controls


Trigger notes with key events and a simple mapping:


const activeNotes = {};
const keyMap = {
'a': 261.63, // C4
's': 293.66, // D4
'd': 329.63, // E4
'f': 349.23, // F4
'g': 392.00, // G4
};

document.addEventListener('keydown', e => {
const freq = keyMap[e.key];
if (freq && !activeNotes[e.key]) {
activeNotes[e.key] = new SynthNote(freq);
}
});

document.addEventListener('keyup', e => {
if (activeNotes[e.key]) {
activeNotes[e.key].stop();
delete activeNotes[e.key];
}
});

Optional: Enhance with Filters or LFO


You can easily insert filters between oscillator and destination:


const filter = audioCtx.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.value = 1000;
this.osc.connect(filter);
filter.connect(this.gain);

Pros and Cons

✅ Pros


  • Totally self-contained and fast to load
  • Works offline — no libraries or backend required
  • Foundation for more advanced synth engines

⚠️ Cons


  • No MIDI support out of the box (but possible with Web MIDI API)
  • Timing can drift slightly without clock sync
  • Requires handling audio unlock on mobile devices

🚀 Alternatives


  • Tone.js: Higher-level abstractions for synths, patterns, and effects
  • WAMs: Web Audio Modules for plugin-style architectures
  • WebAssembly DSP: For ultra-performant audio engines

Summary


This setup is a powerful base for browser-based synths and interactive audio. By keeping things native, you get instant load times and full control. Extend this with modulation, filters, or sequencing and you’ve got a full playground for web music.

If this was useful, you can support me here: buymeacoffee.com/hexshift