Files
skills/docs/media/audio/audio-analysis-loudness/src/algorithms/loudness-range.md
2026-05-29 08:20:56 +01:00

2.3 KiB
Raw Blame History

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

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.