# OpenSpec Change: enterprise-audio-analysis-loudness - **Change ID**: enterprise-audio-analysis-loudness - **Package**: `@suaveplan/audio-analysis-loudness` - **Category**: universal - **Target path**: `packages/media/audio/audio-analysis-loudness` - **Status**: PROPOSED - **Date**: 2026-05-14 - **Design**: `./design.md` - **Spec delta**: `./specs/audio-analysis-loudness/spec.md` --- ## Summary Deliver `@suaveplan/audio-analysis-loudness` on the genesis branch from scratch at enterprise quality. Loudness metering plugin for the universal audio analysis framework. Measures integrated loudness (LUFS), loudness range, true peak, RMS, and DC offset per ITU-R BS.1770-4. Essential for broadcast compliance, mastering, and auto-normalization pipelines. Runs identically in browser and server via `BlockProcessor` or direct stream iteration. --- ## Current-state audit (genesis) The package does not exist on genesis yet — this is a fresh build. No prior source, no test results, no coverage data. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/audio-core` (`workspace:^`) | `AudioDocument`, `BlockProcessor`, `BlockContext` | | `@suaveplan/error` (`workspace:^`) | `AudioError` base class; `AUDIO_ANALYSIS.*` codes | | `@suaveplan/types` (`workspace:^`) | `LoggerLike` | | `@suaveplan/opentelemetry` (`workspace:^`) | OTel spans, counters, histograms | | `zod` (`catalog:forms`) | Zod schemas for option types | Dev deps: `vitest`, `@vitest/coverage-istanbul`, `fast-check`, `mitata` (all `catalog:testing`). --- ## Public API ### Core types ```ts interface LoudnessMeterOptions { blockSize?: number // default 400ms (BS.1770) overlap?: number // default 75% targetLufs?: number // default -14.0 (streaming) or -23.0 (broadcast) } interface LoudnessResult extends AnalysisResult { lufs: number // integrated loudness loudnessRange: number // LRA in LU truePeak: number // dBTP rms: number // dB peak: number // dB dcOffset: number[] // per-channel } class LoudnessMeter implements AnalysisOp { readonly name = 'loudness-meter' readonly description = 'ITU-R BS.1770-4 loudness measurement' constructor(options?: LoudnessMeterOptions) analyze(doc: AudioDocument, opts?: LoudnessMeterOptions): Promise analyzeStream(doc: AudioDocument, opts?: LoudnessMeterOptions): AsyncGenerator analyzeBlock(block: Float32Array[], ctx: BlockContext): Partial } ``` --- ## New additions for genesis 1. **BS.1770-4 compliance** — K-weighting filter, relative gate at -70 LUFS, integrated gate. 2. **True peak** — 4x oversampled peak detection using polyphase interpolation. 3. **Loudness range** — statistical loudness range (LU) per EBU Tech 3342. 4. **Streaming meters** — `analyzeStream()` yields running integrated loudness as blocks arrive. 5. **Block-level metering** — `analyzeBlock()` returns momentary loudness for real-time meters. 6. **OTel instrumentation** — span `audio.analysis.loudness`, counter, histogram. 7. **Property-based tests** — sine wave at 0 dBFS → known LUFS, silence → -∞ LUFS handled gracefully. 8. **Benchmark suite** — meter 1-minute track, meter 10-minute track. --- ## File layout ```text packages/media/audio/audio-analysis-loudness/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts meter/ loudness-meter.ts loudness-meter.md loudness-meter.types.ts loudness-meter.test.ts index.ts algorithms/ lufs.ts lufs.md lufs.test.ts true-peak.ts true-peak.md true-peak.test.ts loudness-range.ts loudness-range.md loudness-range.test.ts index.ts filters/ k-weighting.ts k-weighting.md k-weighting.test.ts index.ts __benchmarks__/ loudness.bench.ts tests/ integration.test.ts property.test.ts ``` --- ## Impact **Breaking changes**: none — fresh build, package does not yet exist on genesis. **Prerequisites**: `@suaveplan/audio-core`, `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/opentelemetry` published to Verdaccio (all already on genesis). ### Affected dependents No dependents in this batch (verified by `bunx turbo ls --filter=...@suaveplan/audio-analysis-loudness`). `@suaveplan/audio-analysis-loudness` is a leaf analysis plugin — no batch package depends on it. It is consumed at runtime by application/timeline code and by `normalize`'s LUFS mode, both of which are created against this package's spec delta, not retrofitted.