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
