first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
# 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.