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

metering.h

Programme loudness and true peak, the way broadcast measures it.

#include <sonore/metering.h>
On this page

Design notes

ITU-R BS.1770-4 K-weighting, momentary / short-term / integrated loudness with the two-stage gate, loudness range (EBU Tech 3342), true peak by oversampling, and a stereo correlation meter. Nothing here allocates after prepare(): the integrated measurement, which in the standard needs every gating block kept until the end, is held as a HISTOGRAM instead: fixed memory, and exact to a tenth of an LU, which is finer than the display.

Included by dsp.h. The filters are Biquads from dsp.h; the coefficients are computed for the host's rate from the parameters that regenerate the standard's own 48 kHz table, rather than that table being pasted in and wrong at every other rate.

Types 4

The BS.1770 pre-filter pair: a +4 dB high shelf modelling the head's acoustic effect, then the RLB high-pass that takes the rumble out.

The standard publishes coefficients for 48 kHz only. These are the parameters (corner, gain, Q) and the bilinear design that regenerate that table to eleven digits, and because they are PARAMETERS rather than coefficients they design the same filter at 44.1, 96 or 192 kHz. The odd decimals are what makes the 48 kHz result match the published numbers to the last digit.

NOT the RBJ cookbook shelf, and this is the thing worth never re-learning: the product's own measurement harness (measure.ts) used the RBJ high-shelf formula with these same constants, and that filter is 0.26 dB LOW at 1 kHz -- close enough that nothing noticed, wrong enough that every absolute LUFS it reported was a quarter of an LU off. The first draft of this header copied it, and its unit test agreed with it perfectly, which is what agreeing with your own reference is worth. The test now checks against the standard's stated calibration instead: a full-scale 997 Hz sine reads -3.01 LKFS, i.e. the K gain at 997 Hz is the +0.691 dB the offset cancels. The shelf below reads +0.691 at 48 kHz; the RBJ version read +0.433.

template <int MaxChannels = 8> class LoudnessMeter

Momentary (400 ms), short-term (3 s) and integrated loudness in LUFS, and loudness range in LU, from any channel count up to MaxChannels.

The gate, and why the memory is a histogram

Integrated loudness is not the average of everything. BS.1770 first drops every 400 ms block under -70 LKFS (silence and fades must not drag a programme down), then computes the mean of what is left, drops every block more than 10 LU under THAT, and averages again. The second pass needs the whole distribution of blocks, so a literal implementation stores one number per 100 ms for the length of the programme -- an allocation that grows with the material, on the audio thread.

A histogram of block loudness at 0.1 LU resolution holds the same distribution in 800 counters, for ever. Each bin contributes its centre's power times its count, so the error is bounded by half a bin: 0.05 LU, a fifth of what any display resolves. Loudness range uses a second histogram of the short-term values with its own gate (-20 LU relative) and reports the spread between the 10th and 95th percentiles, per EBU Tech 3342.

Channel weights

BS.1770 weights surround channels by +1.5 dB (1.41) and ignores the LFE. The defaults follow the standard's layouts for 1, 2 and 6 channels (the 5.1 order being L R C LFE Ls Rs, the same one defaultChannelMask() uses) and weight everything else by 1.0; setChannelWeight() overrides one.

Peak level between the samples, in dBTP.

A sample peak reads the samples; a true peak reads the WAVEFORM the samples describe, which can pass between two of them higher than either -- a sine near a quarter of the rate sampled at 45 degrees reads -3 dBFS sample peak while the wave itself touches 0 dBTP. A limiter that watches sample peaks ships intersample overs to every DAC, and a loudness spec that says "-1 dBTP" means this measurement, not that one.

Four-times oversampling by a 16-tap Blackman-windowed sinc per phase, the taps computed here rather than pasted (BS.1770 Annex 2 tabulates a 48-tap filter for 48 kHz; the windowed sinc is the same design at any rate). The three interpolated phases and the sample itself are all compared, so this can never read LOWER than the sample peak.

Phase correlation between two channels, -1..+1, over a sliding window.

+1 is mono, 0 is unrelated, -1 is one channel inverted -- the reading a goniometer's needle shows, and the number that says whether a mix survives being summed to mono. Three exponential averages (L·R, L², R²) with one time constant, so the reading settles in the stated milliseconds rather than jittering per sample.

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