eq.h
The parametric equaliser, as a machine.
#include <sonore/eq.h>- 1type
- Guides: Getting started, MIDI and MPE
On this page
Design notes
Biquad in dsp.h is one band. Every EQ plugin is N of them with three things around them that a model rewrites every time and gets wrong once: the band bookkeeping, the click-free response to a knob, and the curve the faceplate draws. This is those, once -- and the bands themselves are better than the cookbook's.
MATCHED, NOT BILINEAR. The RBJ cookbook maps the analogue prototype with the bilinear transform, which pins the response at Nyquist: a bell at 16 kHz sampled at 44.1 kHz is squeezed against the top of the band and comes out narrower and lopsided -- the "cramping" every analogue-matched EQ advertises fixing. Vicanek's "Matched Second Order Digital Filters" (2016) fixes it the way the name says: the POLES are mapped by the matched Z-transform (e^{sT}, so the resonance sits exactly where the analogue one does) and the ZEROS are chosen so the digital magnitude equals the analogue prototype's at three frequencies -- DC, the band's own frequency and Nyquist. That is a three-point linear solve in Vicanek's phi = sin²(w/2) form, worked out below for every band type from the prototype's magnitude, rather than his per-type closed forms copied in. The test measures a 16 kHz bell at 44.1 kHz against the prototype: matched agrees to a third of a decibel where the cookbook is off by more than one.
ZIPPER. Frequency, gain and Q are smoothed (log for frequency, since the ear hears ratios) and the coefficients recomputed every 16 samples from the smoothed values; the transposed-direct-form state carries across, so a swept knob is a sweep and not a staircase. The test drags a bell's gain 12 dB in 100 ms across a tone and asks for no step the tone did not make.
LINEAR PHASE. On request the same curve is realised as a symmetric FIR (the composite magnitude, inverse-Fourier-summed and Kaiser-windowed), with the latency half the kernel and reported. Designed offline, because a 2047-tap design is milliseconds of work: prepare() or a message thread.
Included by dsp.h.
Types 1
template <int Bands = 8> class ParametricEq
N bands, each a matched biquad, smoothed, with the curve for the faceplate. process() is per sample; the coefficients refresh every 16 samples while a band's controls are still moving.