VOLTAlearn

Learn Volta / Write your own DSP

A biquad from the cookbook

Turn Robert Bristow-Johnson's cookbook formulas into a resonant filter.

lesson 33 of 39 · about 12 minutes

Open this lesson in the workbench →

The one-pole has one cell and a gentle slope. Two cells buy a second-order filter — a biquad — with a 12 dB slope and a resonant peak. Every DSP programmer's first reference for its coefficients is Robert Bristow-Johnson's Audio EQ Cookbook; this lesson types its lowpass into a kernel.

The cookbook computes an angle ω = 2π·f/sampleRate and α = sin ω / (2Q), then five coefficients. For the lowpass: b0 = (1 − cos ω)/2, b1 = 1 − cos ω, b2 = b0, a0 = 1 + α, a1 = −2 cos ω, a2 = 1 − α — each divided by a0.

The transposed direct form II runs a biquad on two cells: y = b0·x + s1, then s1' = b1·x − a1·y + s2 and s2' = b2·x − a2·y. With two cells the law returns [y, [s1', s2']] and the init is [0.0, 0.0].

Every coefficient depends only on f, q and sampleRate, so with constant arguments they are computed once per block; the per-sample cost is five multiplies. Put a macro on f and they are recomputed every sample instead — still correct, just dearer.

The library already has this law (import "kernels" (biquadLp)) — writing it once is how you learn to read the others. Q around 0.7 is flat; 4 and up whistles.

The starting point#

The lesson opens with this song in the editor. Every edit recompiles and plays.

-- A biquad: this bass runs through a one-pole — gentle, no resonance.
-- Replace it with the cookbook's second-order lowpass.
onePoleLp = \cut x s ->
  let a = 1.0 - exp (0.0 - 6.283185307179586 * cut / sampleRate) in
  let y = s + a * (x - s) in
  [y, y]

bass = patch {
  source = saw (freq pitch) |> process2 (onePoleLp 700.0) 0.0,
  ampEnv = adsr 2ms 250ms 0.4 90ms,
  gain   = vel * 0.2
}

groove = play bass !"a1 ~ a1 c2 ~ a1 e2 g1"

What to watch#

Push Q past 4 and watch the spectrum: a spike grows at the cutoff and the scope rings with a decaying sine after every note — the resonance you asked for.

Goals#

The workbench checks these as you work; the solution is there when you want it.

  1. Two cells of state: an init of [0.0, 0.0]
  2. Compute the cookbook's angle with cos
  3. Stretch: sweep the cutoff from a macro

Make it yours#

Write the highpass from the same page: only b0, b1, b2 change (b0 = (1 + cos ω)/2, b1 = −(1 + cos ω), b2 = b0). Then a bandpass: b0 = α, b1 = 0, b2 = −α.

Further reading#

DSP cookbook in the reference.