Build with this node

Start with a prompt in Studio, or copy it into your own coding agent.

Ask Studio

@maruaudio/dsp/filters/state-variable is Andrew Simper's trapezoidal-integrator (TPT) state-variable filter with seven response modes. Coefficients are g = tan(π·f/fs), k = 1/Q, a1 = 1/(1 + g(g + k)), a2 = g·a1, a3 = g·a2, and each mode is a mix m0·x + m1·v1 + m2·v2 of the input, band and low outputs. Coefficients, state and output are rounded to f32. It is adapted from Synthlet's @synthlet/state-variable-filter (MIT), whose notices live in ``.

const state = initStateVariableFilterNode(48000)
setStateVariableFilterNodeType(state, SVF_BANDPASS)
setStateVariableFilterNodeFrequency(state, 1200)
updateStateVariableFilterNodeCoefficients(state) // before the next tick
const y = stateVariableFilterNodeTick(state, x)

Parameters

SetterRange the setter enforcesDefault
setStateVariableFilterNodeTypeRounded, then 0 to 6: SVF_BYPASS, LOWPASS, BANDPASS, HIGHPASS, NOTCH, PEAK, ALLPASSLow-pass
setStateVariableFilterNodeFrequency10 Hz to 0.45 × the sample rate1000 Hz
setStateVariableFilterNodeQ0.025 to 400.7071

Lifecycle

initStateVariableFilterNode → setters → updateStateVariableFilterNodeCoefficients → stateVariableFilterNodeTick → resetStateVariableFilterNode. Setters only store values; a new state passes its input through until the coefficients are updated. The update may run once per block or per sample for audio-rate cutoff modulation. prepareStateVariableFilterNodeSampleRate sets a new rate and re-clamps the stored frequency; update the coefficients again before the next tick. Reset clears the two integrators and keeps the settings.

When to use it

A resonant synth or envelope filter whose cutoff moves, or one filter that switches between low-pass, band-pass and high-pass taps. The source allows a coefficient update per sample for audio-rate cutoff modulation.

Limits

  • Mono sample tick, second order.
  • No coefficient smoothing; changes apply at the next update.
  • Bypass still advances the integrators, so switching back to a filtered mode does not resume stale history.
  • The clamp is the kernel node's conditional clamp, not @maru/math-range.

Algorithm properties and proofs

Lean 4 checks specific properties of this algorithm’s mathematical model. Each model result applies within its stated domain and assumptions.

5 Lean 4 results: 1 proof in its stated domain; 4 proofs in exact arithmetic.

Proved in exact arithmetic.The state-variable filter's exact coefficients from g = tan(pi f / fs) and k = 1 / Q satisfy the Jury conditions for every positive g and k.exact arithmetic in any ordered field, g > 0 and k > 0
Limits and assumptions
  • Frozen settings and exact coefficients; the tangent is assumed, not proved.
Theorem
MaruLean.FilterStability.svf_jury
Recorded axioms
propext, Classical.choice, Quot.sound
Manifest reviewed
Proved in the stated domain.Two of the state-variable filter's three Jury conditions hold for any coefficients with the stated signs and bounds, rounded or not, because the sum they test has no cancellation.any coefficient values in an ordered field that satisfy the stated sign bounds
Limits and assumptions
  • Covers two of the three conditions only. That round-to-nearest keeps those signs and bounds is argued in the file, not proved about floats.
  • This record also covers MaruLean.FilterStability.svf_rounded_dMinus, MaruLean.FilterStability.svf_dPlus_identity, MaruLean.FilterStability.svf_dMinus_identity; axioms describe MaruLean.FilterStability.svf_rounded_dPlus only.
Theorem
MaruLean.FilterStability.svf_rounded_dPlus
Recorded axioms
propext, Classical.choice, Quot.sound
Manifest reviewed
Proved in exact arithmetic.At a fixed Q, the order in which the state-variable filter's cutoffs arrive does not change its state.exact arithmetic over any commutative ring, no input
Limits and assumptions
  • Exact arithmetic with no input; the rounded tick is measured in bench/modulation/time-warp-check.mjs, not proved. Nobody has listened, so it says nothing about which filter sounds better. A moving Q is not covered.
  • This record also covers MaruLean.ModulationStability.step_eq, MaruLean.ModulationStability.step_det; axioms describe MaruLean.ModulationStability.step_comm only.
Theorem
MaruLean.ModulationStability.step_comm
Recorded axioms
propext, Classical.choice, Quot.sound
Manifest reviewed
Show 2 more Lean 4 results
Proved in exact arithmetic.No cutoff and no Q can raise the state-variable filter's stored energy on any sample.exact arithmetic in an ordered commutative ring, g >= 0 and k >= 0, no input
Limits and assumptions
  • Exact arithmetic with no input; the rounded tick is measured in bench/modulation/time-warp-check.mjs, not proved. Nobody has listened, so it says nothing about which filter sounds better.
  • This record also covers MaruLean.ModulationStability.energy_identity, MaruLean.ModulationStability.lossless_set_leaves; axioms describe MaruLean.ModulationStability.energy_step only.
Theorem
MaruLean.ModulationStability.energy_step
Recorded axioms
propext, Classical.choice, Quot.sound
Manifest reviewed
Proved in exact arithmetic.With no damping, two state-variable steps are one step at the tangent sum of their g, so the ring follows the cutoff with no pitch error.exact arithmetic over any commutative ring, k = 0, no input
Limits and assumptions
  • Exact arithmetic with no input; the rounded tick is measured in bench/modulation/time-warp-check.mjs, not proved. Nobody has listened, so it says nothing about which filter sounds better.
Theorem
MaruLean.ModulationStability.step_compose_lossless
Recorded axioms
propext, Classical.choice, Quot.sound
Manifest reviewed
Explore proofs alongside performance

Parameters

ParameterTypeSetter
Type typefloatsetStateVariableFilterNodeType
Frequency frequencyfloatsetStateVariableFilterNodeFrequency
Q qfloatsetStateVariableFilterNodeQ

Ports

  • In ininput · audio · mono
  • Out outoutput · audio · mono

One sample per stateVariableFilterNodeTick call.

Dependencies

None: this node imports no other node.

Dependents

Used by