3.3 KiB
loudness-meter
(no submodules)
Purpose
LoudnessMeter is the orchestration layer of @suaveplan/audio-analysis-loudness.
It wires the K-weighting filter, the gated-integration engine, the short-term
LUFS accumulator (for loudness range), the 4× oversampled true-peak detector,
and the RMS / sample-peak / DC-offset accumulators together behind three
entry points — full-document analyze, streaming analyzeStream, and the
real-time analyzeBlock. It is a sidecar processor (plugin slot 3) and
never participates in the render pipeline.
The class also threads OTel spans, the run counter, and per-block histograms
through every entry point, validates all options at the Zod boundary, and
propagates AbortSignal cancellation to mid-stream block boundaries.
Features
- ITU-R BS.1770-4 integrated LUFS via two-gate (absolute + relative).
- EBU Tech 3342 loudness range (LRA in LU).
- 4× oversampled true-peak in dBTP (per BS.1770-4 Annex 2).
- Sample peak in dB, RMS in dB, per-channel DC offset.
- Streaming
analyzeStreamwhose final yield equals batchanalyze. - Real-time
analyzeBlockfor live meters — synchronous, allocation-light. - Finite silence floors (no
-Infinityever leaks to consumers). AbortSignalpropagation at gating-block boundaries.- OTel span, counter, histograms — inert without an exporter.
Usage: Basic
import { LoudnessMeter } from "@suaveplan/audio-analysis-loudness";
const meter = new LoudnessMeter();
const result = await meter.analyze(doc);
console.log(result.lufs, result.truePeak, result.loudnessRange);
Usage: Advanced
import { LoudnessMeter } from "@suaveplan/audio-analysis-loudness";
const meter = new LoudnessMeter({ blockSize: 400, overlap: 0.75, targetLufs: -23 });
// Streaming integrated loudness — final yield equals batch analyze.
const ctrl = new AbortController();
for await (const partial of meter.analyzeStream(doc, { signal: ctrl.signal })) {
ui.updateLoudness(partial.lufs);
}
// Real-time block meter — call on every audio callback.
const partial = meter.analyzeBlock([left, right], {
sampleRate: 48000,
channelCount: 2,
});
console.log(partial.lufs, partial.peak, partial.rms);
API Reference
class LoudnessMeterreadonly name: "loudness-meter",readonly description: string,readonly version: string.constructor(options?: LoudnessMeterOptions).analyze(doc, opts?) => Promise<LoudnessResult>.analyzeStream(doc, opts?) => AsyncGenerator<LoudnessResult>.analyzeBlock(block, ctx) => Partial<LoudnessResult>.
LoudnessMeterOptions—blockSize,overlap,targetLufs,signal.LoudnessResultextendsAnalysisResultwithlufs,loudnessRange,truePeak,rms,peak,dcOffset[].
Implementation Notes
analyze and analyzeStream share one GatingEngine. The streaming path
yields the engine's running state after every gating block; the batch path
runs the same engine to completion. The invariant is that the last
analyzeStream yield equals the analyze result for the same document.
analyzeBlock keeps a per-instance scratch K-weighting filter so live-meter
callers do not allocate on every audio callback. The scratch filter is
re-built lazily when (sampleRate, channelCount) changes.