2.3 KiB
loudness-range
Purpose
loudness-range computes the EBU Tech 3342 loudness range (LRA, in LU) — a
statistical measure of dynamic spread. It takes short-term loudness samples
(K-weighted, channel-summed loudness over 3 s windows stepped by 1 s) and
returns the 95th-minus-10th percentile spread of the gated distribution.
LRA complements integrated loudness: two programmes can share an integrated LUFS but have wildly different listener experience if one is uniformly compressed and the other has dynamic swings. Broadcasters use LRA thresholds (e.g. EBU R128 recommends ≤ 7 LU for spoken-word programming) to flag material that needs dynamics processing before transmission.
Features
- Two-gate algorithm: absolute gate at −70 LUFS, relative gate 20 LU below the gated mean (wider than the BS.1770-4 integrated-loudness 10 LU gate).
- Linear-interpolated percentiles per Tech 3342.
- Returns
lra,low,high, andgatedCountfor downstream UIs. - Sub-window documents safely report
lra: 0instead of throwing.
Usage: Basic
import { loudnessRange } from "@suaveplan/audio-analysis-loudness/algorithms/loudness-range";
const { lra } = loudnessRange(shortTermLufsValues);
Usage: Advanced
import {
loudnessRange,
percentile,
} from "@suaveplan/audio-analysis-loudness/algorithms/loudness-range";
const result = loudnessRange(shortTermLufsValues);
console.log({
lra: result.lra,
p10: result.low,
p95: result.high,
surviving: result.gatedCount,
});
// Inspect arbitrary percentiles for diagnostic overlays.
const sorted = [...shortTermLufsValues].sort((a, b) => a - b);
const p50 = percentile(sorted, 0.5);
API Reference
LRA_RELATIVE_GATE_OFFSET_LU—-20, the Tech 3342 relative-gate offset.loudnessRange(shortTermLufs: readonly number[]) => LoudnessRangeResult.percentile(sortedAsc, q)— linear-interpolated q ∈ [0,1].
Implementation Notes
The mean used for the relative gate is computed in linear power and then
converted back to LUFS via energyToLufs, not as an arithmetic mean of LUFS
values — averaging in dB would over-weight quiet blocks. Edge cases (no
input, no survivors after the absolute gate, no survivors after the relative
gate) all map cleanly to lra: 0 with the best-available low/high so
downstream consumers never see NaN.