Filters
sculpting the spectrum
Additive synthesis built a sound up from pure sines. A filter does the opposite: start with a wave that already has everything, then carve frequencies away until what's left is the sound you want. Drag the cutoff. Hear the tone darken under your finger.
Sculptors don't add clay. They cut it away.
In How Synths Make Sound you built a timbre up: start from silence, stack sine waves, and a saw appears. That's additive synthesis — pour in harmonics one at a time.
There's an opposite, and historically far more common, way to make a synth sound. Start with a wave that's already harmonically rich — a buzzy sawtooth or hollow square, crammed with overtones — and then remove the frequencies you don't want. You sculpt by subtraction. This is subtractive synthesis, and the tool that does the cutting is a filter.
Almost every classic synth you've heard — a Minimoog bass, a Prophet pad, an acid 303 line — is subtractive: a rich oscillator feeding a filter you sweep with your hands. Master the filter and you've got the other half of synthesis.
Additive — last lesson
Begin at zero. Add sine waves, one harmonic at a time, until the spectrum is full. The recipe is "how much of each harmonic to pour in."
Subtractive — this lesson
Begin full — a saw has every harmonic already. Cut frequencies away with a filter. The recipe is "which frequencies to let through, and how much."
What a filter is (a gain you apply per frequency, H(f)), where the cutoff comes from, why the slope is 6 dB per octave, a saw carved by hand harmonic-by-harmonic, what resonance / Q does, high-pass and band-pass, the code in Web Audio and NumPy — and a filter you play with your finger, watching harmonics get carved off the live spectrum.
One number, for every frequency.
Forget circuits for a moment. A filter does exactly one conceptual thing: for every frequency, it decides how much of it gets through. Some frequencies pass at full strength; others come out quieter; some are killed entirely.
Collect all those "how much gets through" numbers and you have a curve — the frequency response, written H(f). It's just a gain knob that has a different setting at every frequency:
That single line is the whole secret of filtering, and it reaches straight back to the DFT lesson. There you learned that any sound has a spectrum X(f) — the amount of each frequency present. A filter takes that spectrum and multiplies it, frequency by frequency, by its response H(f). Subtractive synthesis is nothing but reshaping the spectrum you already know how to read.
A low-pass filter is the workhorse. Its rule: let low frequencies through unchanged, and progressively turn down everything above some threshold. That threshold — the frequency where the filter starts seriously cutting — is the cutoff frequency, fc.
Mathematician: H(f) is a transfer function — the spectrum out equals the spectrum in, multiplied frequency-by-frequency. Musician: H(f) is a tone control — "dark," "bright," "nasal," a hand sweeping the cutoff. Artist: H(f) is a silhouette laid over the spectrum; the harmonics poking above the curve survive, the ones below it fade. Learn to see the curve and hear the tone at once and the filter stops being mysterious.
Where it cuts, and how steeply.
The simplest real low-pass filter is a resistor and a capacitor — a one-pole RC filter. A capacitor charges slowly, so it can follow slow (low-frequency) wiggles but can't keep up with fast (high-frequency) ones; the fast ones get smoothed away. The frequency where it gives up is set entirely by the resistor and capacitor:
That's where the cut starts. The shape of the cut — how much of each frequency survives — is the magnitude of the response. For the one-pole low-pass it has a clean closed form:
Read it like a story. When f is far below fc the ratio f/fc is tiny, so |H| ≈ 1 — low frequencies pass untouched. When f is far above, the (f/fc)² term dominates and |H| ≈ fc/f — it shrinks toward zero. The interesting moment is exactly at the cutoff. Let's grind the numbers out.
f = fc the ratio is 1, so |H| = 1/√(1+1) = 1/√2 ≈ 0.707. In decibels (20·log₁₀) that's 20·log₁₀(0.707) = −3.01 dB. This is the famous −3 dB point — the agreed definition of "the cutoff." The signal isn't gone there; it's down to 71% of its amplitude (half its power).f = 2fc): |H| = 1/√(1+4) = 1/√5 ≈ 0.447 → 20·log₁₀(0.447) = −7.0 dB. So from the knee to one octave up we lost about 6 dB.f = 4fc): |H| = 1/√(1+16) ≈ 0.243 → −12.3 dB. Another ~6 dB. The pattern is locked in: every octave above the cutoff drops another 6 dB — a 6 dB/octave slope, the signature of a one-pole filter.f = 10·fc): now (f/fc)² = 100 dominates the 1, so |H| ≈ 1/√101 ≈ 0.0995 ≈ 0.1 → 20·log₁₀(0.1) = −20 dB. Ten times above the cutoff, a tenth of the amplitude survives. Tidy.So the cutoff isn't a wall — it's a gentle knee that bends the spectrum down, then keeps falling at a steady 6 dB per octave. Real synth filters stack two poles (12 dB/octave) or four (24 dB/octave) for a steeper, more dramatic cut — the famous Moog ladder is 24 dB/octave. Same idea, just a steeper slope. The instrument at the end of this lesson uses a two-pole (12 dB/octave) filter, which is why its skirt falls faster than the one-pole math above.
We measure the cut in dB for the same reason loudness lived in dB back in the synth lesson: your ear hears ratios. A 6 dB drop is "half the amplitude" no matter where it happens. Saying "−6 dB per octave" means the filter halves the amplitude every time the frequency doubles — a statement your ear can actually parse.
Darken a sawtooth, harmonic by harmonic.
Now make it concrete with the wave from the synth lesson. Take a sawtooth at f₀ = 110 Hz. From additive synthesis you know its recipe exactly: every harmonic is present, with amplitude 1/n — so harmonic n sits at frequency 110·n with amplitude 1/n.
Drop a one-pole low-pass with cutoff fc = 500 Hz in front of it. Subtractive synthesis says: the output amplitude of each harmonic is its original amplitude times |H(f)| at that harmonic's frequency. Let's carve each one with our hands, using |H(f)| = 1/√(1+(f/500)²):
| Harmonic | Freq (110·n) | Original 1/n | |H(f)| at fc=500 | Surviving amp |
|---|---|---|---|---|
| n = 1 | 110 Hz | 1.000 | 1/√(1+0.048) = 0.976 | 0.976 — barely touched |
| n = 2 | 220 Hz | 0.500 | 1/√(1+0.194) = 0.915 | 0.458 |
| n = 3 | 330 Hz | 0.333 | 1/√(1+0.436) = 0.835 | 0.278 |
| n = 4 | 440 Hz | 0.250 | 1/√(1+0.774) = 0.751 | 0.188 |
| n = 5 | 550 Hz | 0.200 | 1/√(1+1.21) = 0.673 | 0.135 — ~at cutoff |
| n = 9 | 990 Hz | 0.111 | 1/√(1+3.92) = 0.451 | 0.050 |
| n = 18 | 1980 Hz | 0.056 | 1/√(1+15.7) = 0.245 | 0.0136 — nearly gone |
Read the last column down the page. The fundamental and low harmonics walk through almost untouched — they're below the cutoff. But the high harmonics get hammered twice: once by the saw's own 1/n fade, and again by the filter's rolloff. Harmonic 18 started at 0.056 and leaves at 0.0136 — a quarter of what it was.
What does the ear make of that? The high harmonics are exactly the brightness of the tone. Strip them and the saw goes from buzzy and razor-sharp to round, dark, mellow. Sweeping the cutoff down is heard as the tone "closing" or "darkening" — the single most iconic gesture in electronic music. You just computed it by hand; in a moment you'll do it with your finger and watch those exact bars shrink.
fc = 200 Hz and re-check harmonic 5 (550 Hz): |H| = 1/√(1+(550/200)²) = 1/√(1+7.56) = 0.342. It was 0.673 at fc=500; now it's halved again. Drag the cutoff down and the brightness drains away — that's the whole feel of a low-pass sweep.Make the cutoff sing.
A plain low-pass just rolls off. But every great synth filter has a second knob: resonance, also called Q (the "quality factor"). Resonance does something delicious — instead of a smooth knee, it builds a peak right at the cutoff frequency, boosting the handful of harmonics that sit near fc before the rolloff takes over.
The two-pole filter's magnitude response makes the peak explicit:
r = 1, so the (1−r²)² term vanishes and |H(fc)| = 1/√(0 + (1/Q)²) = Q. The gain at the cutoff is exactly Q. With Q = 8 the cutoff frequency is boosted eightfold (+18 dB) while everything above it still gets cut.Q = 0.707 (the "flat" Butterworth value): |H(fc)| = 0.707 = −3 dB — no bump at all, the maximally smooth knee. That's why Q ≈ 0.7 is the natural starting point: it's the boundary between "no resonance" and "a peak."fc.Mathematician: high Q means the filter's poles sit close to the unit circle — a sharply peaked response, a system that rings. Musician: resonance is "emphasis" or "the squelch" — it makes a swept filter vocal, alive, the sound of acid house and every wobble bass. Artist: on the spectrum it's a bright spike that walks left and right as you sweep, dragging a glowing peak across the harmonics. One peak, three readings.
Cut from the bottom, or keep only a slice.
Flip the low-pass on its head and you get a high-pass filter: it kills the low frequencies and lets the highs through. Its response is the mirror image — instead of 1/√(1+(f/fc)²) it's:
High-pass is how you thin out a sound — strip the boom from a bass, make a pad airy, carve room for the kick drum. Musically it's the opposite gesture from a low-pass: open it and the sound gets thinner and brighter, not duller.
Put a high-pass and a low-pass back to back and only a band of frequencies survives between them — a band-pass filter. It keeps a slice around the cutoff and rejects everything above and below. Its peak sits at fc, and Q now controls how wide the surviving band is: high Q is a narrow, vocal, telephone-y slice; low Q is a broad swath.
Three shapes — low-pass, high-pass, band-pass — and you can build an astonishing range of timbres just by choosing which one and sweeping its cutoff. The instrument at the end lets you flip between all three on the same rich saw, so you can hear them as siblings, not strangers.
A filter is one node, or one line of NumPy.
In the browser, the whole filter is a single BiquadFilterNode — a two-pole biquad with a type, a frequency (the cutoff), and a Q. Subtractive synthesis in Web Audio is just "wire the oscillator through the filter on the way to the speakers." This is exactly the graph the instrument below builds:
const ctx = new AudioContext(); const osc = ctx.createOscillator(); osc.type = 'sawtooth'; // the rich source: every harmonic, amplitude 1/n osc.frequency.value = 110; // 110 Hz fundamental — the saw from the synth lesson const filter = ctx.createBiquadFilter(); filter.type = 'lowpass'; // 'lowpass' | 'highpass' | 'bandpass' filter.frequency.value = 500; // the cutoff f_c, in Hz filter.Q.value = 8; // resonance: peak of height ~Q at the cutoff osc.connect(filter); // source → filter filter.connect(ctx.destination); // filter → speakers osc.start(); // sweep the cutoff like a hand on the knob — the iconic "filter open" gesture filter.frequency.linearRampToValueAtTime(4000, ctx.currentTime + 2);
And the math made literal: apply the response curve |H(f)| to a spectrum and invert. Here we take a real saw, transform it with rfft, multiply every frequency bin by the one-pole low-pass gain, and transform back — subtractive synthesis as one elementwise multiply, exactly as Chapter 1 promised:
import numpy as np fs, f0, fc = 44100, 110.0, 500.0 # sample rate, saw pitch, cutoff t = np.arange(fs) / fs # a rich sawtooth: every harmonic, amplitude 1/n (additive, from last lesson) x = sum((-1)**(n+1)/n * np.sin(2*np.pi*n*f0*t) for n in range(1, 80)) X = np.fft.rfft(x) # wave → spectrum (the DFT lesson) f = np.fft.rfftfreq(len(x), 1/fs) # the frequency of each bin H = 1 / np.sqrt(1 + (f / fc)**2) # |H(f)| — the one-pole low-pass response y = np.fft.irfft(X * H) # carve the spectrum, then back to a wave # y is the darkened saw. Every high harmonic is scaled down by H at its freq — # the exact numbers you worked out by hand in Chapter 3.
def lowpass_response(f, fc, Q=0.707): r = f / fc return 1.0 / np.sqrt((1 - r**2)**2 + (r / Q)**2) # two-pole, with resonance # at f = fc this returns Q (the resonant peak); far above it falls as 1/r² lowpass_response(np.array([500.]), fc=500, Q=8) # → ~8.0, the +18 dB bump
The BiquadFilterNode runs the filter sample-by-sample in the time domain (a tiny recursive equation) for zero latency, while the NumPy version does it in the frequency domain (one multiply by H(f)). Different machinery, identical result — because filtering in time is multiplying in frequency. That equivalence is the convolution theorem, and it's the bridge into the whole Signal track.
Sweep it with your finger.
Here is everything at once, as one instrument. A rich source — your choice of saw or square — runs through a real two-pole BiquadFilterNode and out to your speakers. Drag anywhere on the pad: left↔right is the cutoff fc (on a log axis, so it feels even to the ear), up↕down is the resonance Q. Flip between low-pass, high-pass and band-pass.
Two things are drawn on the same log-frequency axis: the glowing teal curve is the filter response H(f), and the warm bars are the live post-filter spectrum — the actual harmonics surviving the carve. Drag the cutoff down and watch the high harmonics vanish under the falling curve exactly as you computed by hand. Raise Q and watch a peak rise at the cutoff — and hear it whistle.
Music (Ableton): you sweep the cutoff by hand and instantly hear the tone open and close — the filter sweep that defines electronic music. Math (Stanford): the teal curve is literally H(f), and the bars are the spectrum X(f) from the DFT lesson; what you hear is their product, frequency by frequency. Art (Nature of Code): the surviving harmonics glow above the response silhouette and fade below it, so the carve is something you watch happen. One signal — the curve, the spectrum, the sound — three readings of the same number.
And it scales straight to where this whole project is headed: swap the saw for the output of a live Lyria-class music model and the same filter becomes a real-time tone-sculpting stage over AI-generated music — the cinematic, conducted finale. Nothing in the routing changes; only the source of the rich signal does.
You can now build, and re-shape, a sound.
You've now held both halves of synthesis. Additive built a spectrum up from sines; subtractive carves a rich spectrum down with a response curve H(f). Between them you can manufacture almost any timbre.
But a filter is only the simplest sound transformation. The same idea — multiply the spectrum, or equivalently slide a little kernel along the wave — opens up delay, reverb, modulation, and the whole world of effects. And reading which frequencies are present so you know what to carve is the job of the Signal track you started in the DFT lesson. The filter is the hinge between making sound and transforming it.
Back to Reverbs — see the tracks →The curve isn't describing the filter. The curve is the filter — and the sound is the spectrum passing through it.
Xavier Serra et al., Audio Signal Processing for Music Applications (Stanford / UPF, Coursera) — filters & the frequency response. · Ableton, Learning Synths — the filter as a sweepable tone control. · MDN, BiquadFilterNode — the filter under every panel. · Daniel Shiffman, The Nature of Code — the generative visuals.