@maruaudio/dsp/filters/one-pole holds the stateless pieces of a one-pole low-pass, y[n] = y[n-1] + a·(x[n] − y[n-1]): two ways to turn a cutoff into the coefficient a, and the per-sample update. The caller owns the state, a double accumulator that is never rounded to f32. The chain and @maruaudio/filters-tone both call these functions.
const a = onePoleLowpassCoefficient(5000, 48000) // once, outside the loop
let y = 0
y = onePoleLowpassTick(y, x, a) // per sampleParameters
This DSP node has no setters; cutoff and rate are passed to the coefficient functions, and state, input and coefficient to the tick.
| Function | Mapping and bounds as coded | Unit |
|---|---|---|
toneFilterCoefficient(toneHz, sampleRate) | toneHz / sampleRate, conditionally clamped to 0.001 to 1 | Hz in, coefficient out |
onePoleLowpassCoefficient(cutoffHz, sampleRate) | Exact digital −3 dB cutoff: sqrt(y² + 2y) − y with y = 2·sin²(π·fc/fs); cutoff clamped to 0 to Nyquist | Hz in, coefficient out |
onePoleLowpassTick(state, input, coefficient) | Returns the new state | sample |
Lifecycle
No instance state: derive the coefficient when cutoff or rate changes, tick once per sample keeping the return value as the state, and set it to 0 to reset.
When to use it
A gentle treble roll-off or a smoothing stage inside a larger DSP node. Use onePoleLowpassCoefficient when the cutoff must mean an actual −3 dB frequency; toneFilterCoefficient is the legacy mapping that keeps the chain's bytes.
Limits
- Mono, one sample per call; first order only.
toneFilterCoefficientuses a conditional clamp, not the@maru/math-rangepolicy, so a NaN passes through it.onePoleLowpassCoefficientreturns 0 for a non-finite cutoff or a rate that is not finite and positive, and 2·(√2 − 1) at Nyquist, which is still −3 dB rather than bypass.- The tick flushes results whose magnitude is below the smallest normal f32 (about 1.18e−38) to zero, so a decaying state never emits subnormal samples.