Search guides and the APICtrl K
  1. API reference
  2. DSP

eq.h

The parametric equaliser, as a machine.

#include <sonore/eq.h>
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.

↑↓ to move↵ to openEvery public name in the headers, and every guide