Skip to content
[archived] 2023

Synth in C++ from scratch

A polyphonic subtractive synthesizer with a custom DSP graph.

C++JUCECMake

Built a polyphonic subtractive synthesizer to understand the fundamentals of audio DSP — oscillators, filters, envelopes, and how to wire them together into something that makes sound.

Why

I’d been using software synths for years without understanding how they worked at the signal level. The only way to actually learn this was to build one.

What it does

  • 8-voice polyphony with voice stealing
  • Two oscillators per voice: sine, square, saw, triangle with pitch detune
  • 2-pole resonant low-pass filter with cutoff and resonance envelope
  • ADSR for both amplitude and filter cutoff
  • Basic LFO routable to pitch or filter cutoff
  • MIDI input via JUCE

What I learned

DSP is unforgiving about correctness in a way that most software isn’t. A subtle logic error in a filter coefficient produces not a crash or an assertion — it produces a weird sound that takes an hour to trace back to a wrong minus sign.

Audio buffers also taught me a lot about real-time constraints. The callback has to complete in under N milliseconds or you get glitches. No allocations, no locks, no blocking calls. It’s the kind of constraint I find satisfying to work within.

JUCE is a capable framework but it does a lot of things its own way. I’d probably reach for a smaller library (or write more raw code) next time.

What I’d do differently

The DSP graph implementation was ad hoc — connections between modules were hard-coded rather than configurable. A proper node graph (inputs, outputs, connection topology) would make it extendable. Might revisit.