# 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`, and `gatedCount` for downstream UIs. - Sub-window documents safely report `lra: 0` instead of throwing. ## Usage: Basic ```ts import { loudnessRange } from "@suaveplan/audio-analysis-loudness/algorithms/loudness-range"; const { lra } = loudnessRange(shortTermLufsValues); ``` ## Usage: Advanced ```ts 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.