@maruaudio/dsp/analysis/k-weighting is the BS.1770 K-weighting filter: the published high-shelf stage followed by the RLB high-pass, as two biquads in direct form I with f64 state and an f32 output. At 48 kHz the stages use the published coefficients exactly. At other rates each stage's 48 kHz rational transfer is re-discretized through the inverse and forward bilinear transform, in polynomial form, so the high-pass zeros at DC are kept without dividing by its zero DC gain. It is the one coefficient owner shared by streaming loudness matching, the meters and Tetra's offline normalization.
Functions
| Name | Inputs | Output | Domain as coded |
|---|---|---|---|
initKWeighting | sampleRate | shelf and high-pass state | Rate clamped to 8 to 384 kHz; non-finite → 48 kHz |
prepareKWeightingSampleRate | state, sampleRate | re-derives both stages in place and clears history | Rate clamped to 8 to 192 kHz; non-finite → 48 kHz |
kWeightingTick | state, input | weighted sample, f32 | NaN, ±Infinity or \ |
resetKWeighting | state | clears both stages' history |
Lifecycle
initKWeighting(sampleRate) allocates the two stage records → kWeightingTick per sample → resetKWeighting. A Processor built at the maximum rate calls prepareKWeightingSampleRate from prepare; the result equals a filter created at that rate. Nothing allocates in tick.
When to use it
Weight a channel before summing energy for a LUFS-style reading. Use one state per channel and sum L² + R² afterwards, as @maru/analysis-loudness-meter, @maru/analysis-loudness-match and @maru/analysis-programme-meter do (loudness matching).
Limits
- Mono sample tick. The filter alone is not an R128 meter: there is no integration, gating or makeup gain.
- Away from 48 kHz the coefficients are derived, not published; the loudness design note labels them an approximation.
- Invalid input clears history rather than propagating.