Skip to main content

Playground · app-grounded instrument

DSP · Audio

Biquad Filter Calculator

Hear a cascade, not just see a curve. Design 1–4 biquads in series, watch the exact magnitude + phase of the total chain, and preview live on real audio — white noise, oscillator, or mic — using the same DF2T core Biquadia ships.

Cascade

The whole cascade is encoded in the URL — send the link, get the same filters.

Frequency response (total cascade)

Mag dBPhase °

Current chain coefficients (normalized, a0=1)

Live audio preview — Biquadia-style

Uses Web Audio IIRFilterNode with the exact coefficients above. Pick a source, hit play, toggle bypass to hear the chain.

stoppedGain

DF2T — JavaScript

// Direct Form II Transposed — one biquad stage
// y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]
// State: z1 = b1*x[n-1]+b2*x[n-2]-a1*y[n-1]-a2*y[n-2], z2 = b2*x[n-1]-a2*y[n-1]
function biquadProcess(x, b0,b1,b2,a1,a2, state){
  const y = b0*x + state[0];
  state[0] = b1*x - a1*y + state[1];
  state[1] = b2*x - a2*y;
  return y;
}
// Cascade: for (const stage of cascade) x = biquadProcess(x, ...stage.coeffs, stage.state);

Reference implementation for your own code — the designer above computes frequency response, not this time-domain recurrence.

DF2T — Swift (Biquadia)

// Swift — same DF2T, stereo-safe
struct Biquad {
  var b0,b1,b2,a1,a2: Double
  var z1: Double = 0, z2: Double = 0
  mutating func process(_ x: Double) -> Double {
    let y = b0 * x + z1
    z1 = b1 * x - a1 * y + z2
    z2 = b2 * x - a2 * y
    return y
  }
}

Swift port for your own project.

Anatomy of the designer

Every knob and curve above answers to the RBJ cookbook below. Here is what each piece is actually doing.

The cascade builder and response plot

  1. 01

    Stage cards. Each card is one biquad. Type selects the RBJ formula branch, freq sets w0 = 2πf0/Fs, and gain only affects peaking/shelf types. Q sets alpha = sin(w0)/(2Q) for every type except the two shelves, which fix the slope at S = 1 exactly as Web Audio’s BiquadFilterNode does — their Q input is disabled rather than left to look live. Removing a stage splices the chain — the remaining stages recompute and redraw instantly.

  2. 02

    Magnitude + phase plot. For each frequency from 20 Hz to 20 kHz (log-spaced, 400 steps), the script evaluates every stage's transfer function H(e^jω) on the unit circle via exact complex arithmetic, then multiplies all Hk for the cascade. dB is 20 log10|H_total|. Phase is the sum of arg(Hk), wrapped to [-180°, 180°]. The plot is not a visual approximation — those curves are the literal mathematical response of the coefficients you see.

  3. 03

    Coefficient readout. The real-time b0,b1,b2,a1,a2 for every stage, normalized to a0=1. These are the exact numbers fed to Web Audio's IIRFilterNode and the same format Biquadia's Metal kernel expects. Copy them into any DF2T implementation and the filter is identical.

Audio pipeline and interaction

  1. 01

    Web Audio chain. Source → IIRFilterNode × N → Gain → destination. Each IIRFilterNode is constructed from the current biquad coefficients with feedforward [b0,b1,b2] and feedback [1,a1,a2]. Changing any parameter tears down and rebuilds the chain — new IIR nodes, clean state, no pops.

  2. 04

    Noise generators. White noise is Math.random() × 2 − 1. Pink noise uses the Voss-McCartney algorithm (seven white noise sources at octave intervals) producing −3 dB/octave rolloff — flatter to the ear. Sine is a standard OscillatorNode at 440 Hz. The sweep does an exponential ramp from 20 Hz to 20 kHz over 8 seconds.

  3. 05

    Bypass toggle. Disconnects the IIR chain and reconnects source directly to gain — zero added latency, direct A/B. The coefficients stay live in the readout, so the plot still shows what you are not hearing. Toggling bypass back rebuilds the chain from the same coefficients.

What the render loop evaluates per pixel

Htotal(ejω)=k=1Nb0,k+b1,kejω+b2,kej2ω1+a1,kejω+a2,kej2ωH_{\text{total}}(e^{j\omega}) = \prod_{k=1}^{N} \frac{b_{0,k} + b_{1,k}e^{-j\omega} + b_{2,k}e^{-j2\omega}}{1 + a_{1,k}e^{-j\omega} + a_{2,k}e^{-j2\omega}}

This is computed 400 times per plot redraw — once per log-spaced frequency bin. Each evaluation unpacks to a complex division: real/imag numerator divided by real/imag denominator. The cascade multiplies complex numbers, not dB — the dB display is the final step.

Gear behind this build

Biquadia stack · 15 picks

Audio & DSP hardware15

More gear across every app: the full Gear list →

Two gotchas worth knowing

RBJ α inversion

LLMs love writing α=Qsinw0\alpha = Q \sin w_0 (inverted). The correct formula is α=sinw0/(2Q)\alpha = \sin w_0 / (2Q). A high-Q filter with inverted α shifts the cutoff by an octave and changes the shape entirely. This page uses the real RBJ — check the α line in the script if you are porting it to your own codebase.

Cascade phase pile-up

Each biquad adds its phase shift to the total. Four stages can easily exceed ±360° of total phase at Nyquist. That is not a bug — it is real group delay. If you stack four high-Q peaking filters, you will hear audible pre-ringing on transients. Phase-wrapping the plot to ±180° hides this, but your ears and an oscilloscope will not be fooled.

Already know the corner you want? 248 designs are solved in advance →Eight types at every third-octave centre from 20 Hz to 20 kHz, each with coefficients at eight sample rates, pole radii solved from the quadratic, and the word length it stops working at.

Frequently asked questions

Is DF2T better than Direct Form 1?

DF2T uses two state variables per biquad instead of four. Fewer state variables mean less memory and less quantization noise because you only round once per sample instead of twice. The transposed topology also eliminates the feed-forward delay line. The trade-off is that the internal node can clip at high Q if not guarded with saturation — Biquadia clamps z1/z2 after every sample for exactly this reason.

Why do the coefficients change when I switch sample rates?

The RBJ cookbook formulas compute w0 = 2π f0 / Fs. Changing Fs changes w0, which cascades through every cos/sin computation and alpha. A 1 kHz lowpass at 48 kHz and 44.1 kHz needs different b0–a2 to hit the same f0. The frequency response recalculates automatically, but if you are switching rates mid-audio-stream in a real app, you must recompute all coefficients at the new Fs before the next buffer.

Can I implement more than four biquads on a microcontroller?

Yes — on a 180 MHz Cortex-M4 with a CMSIS-DSP biquad cascade, you can run 30–60 biquads at 48 kHz before hitting the real-time deadline. Each DF2T stage costs 5 MACs per sample. At 48 kHz, 60 stages is 14.4 MMAC/s — well within budget. Q format (Q1.31 fixed-point) matters more than stage count. See the MPU9250 field note for Biquadia's fixed-point DF2T ARM implementation used on-device.

Why does a high-Q peaking filter ring even after the impulse stops?

High Q means poles are close to the unit circle — near |z| = 1. The impulse response is an exponentially-decaying sinusoid where decay rate = ln(r) per sample. At Q = 10 and f0 = 1 kHz, r ≈ 0.96, so it takes about 100 samples (~2 ms) to decay to 10%. That ringing is not a bug — it is what makes a resonant filter sound like an instrument body or a room mode.

How does Biquadia run hundreds of these on Metal?

Biquadia serializes cascade coefficients into a Metal buffer, then dispatches one compute kernel per audio channel. Each thread processes a DFT block (512–4096 samples), pulling coefficients from the buffer and applying DF2T in an unrolled loop. The GPU's SIMD lanes handle stereo pairs in parallel. The same kernel verified via Accelerate vDSP on CPU for bit-exact cross-check. The Metal path adds ~0.3 ms latency at 512-sample blocks.

Shareable still

The instrument, captured—not illustrated.

This 16:9 frame is rendered from the real browser instrument above. It is the page's canonical preview for image search, link unfurls, and posts that need to show what the tool actually does.

Download 1280 × 720 JPEG
Biquad Filter Designer — live MakerPortal instrument screenshot
Canonical capture · real UI · no generated scientific artwork