Hold the true-peak ceiling on delivered renditions; ffmpeg 9 in production #20
Loading…
Reference in a new issue
No description provided.
Delete branch "truepeak-limiter"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
No production rendition respected its −1 dBTP ceiling, and every file came out 1 LU louder than its target. Measured across all 11 production masters with ffmpeg 9
loudnorm; the full before/after table is indocs/data/truepeak-2026-09-28.tsv.main-v2/spotify-v3)mainAAC 128kspotifyVorbis q6Causes
level=1is the default) applies1/limitmakeup gain after limiting. That puts the ceiling back at 0 dBFS and adds +1 LU to everything.Changes
level=0:latency=1.CodecHeadroomDB(1.5 dB) below the profile ceiling.TranscodeMeasuredchecks the encoded file and re-encodes with a lower ceiling if it's still over (up to 3 times; the step doubles if the peak doesn't respond). It keeps the lowest-peak attempt.mainv1→v2 andspotifyv2→v3, so a re-transcode replaces the served files (ADR-0020 rule).deploy.shinstalls BtbN's staticffmpeg-n9.0build into/opt/ffmpeg, and the unit points there. Startup refuses ffmpeg < 9. Smoke-tested: the binary runs in the production container.loudnormsilently switches to dynamic/AGC mode, a high-pass made one file worse, and-aac_coder fastdidn't fix the worst case.Trade-off
The four
mainrenditions that needed retries land 0.6–0.9 LU under −16 LUFS. Apple and Overcast normalize at playback, so slightly quiet is harmless, whereas over 0 dBTP clips.Testing
go build,go vet,go test ./...pass.TestTranscodeHoldsTruePeakCeilingencodes a hot pink-noise master through both profiles. It fails on the old chain (+0.6/+1.0 dBTP, 1.5–2 LU too loud) and passes now.TranscodeMeasuredover all 11 production masters × both profiles: 22/22 at or under −1.0 dBTP.After merging
./deploy/deploy.sh oink kokosbananasinstalls ffmpeg 9 and restarts.main-v2/spotify-v3, then regenerate the feeds.🤖 Generated with Claude Code
No production rendition respected its -1 dBTP ceiling. Measured with ffmpeg 9 loudnorm across all 11 production masters (full table in docs/data/truepeak-2026-09-28.tsv): main AAC 128k before: -15.03..-15.07 LUFS, +0.44..+4.20 dBTP after: -16.07..-16.90 LUFS, -1.01..-2.84 dBTP spotify Vorbis q6 before: -12.98..-13.09 LUFS, +0.35..+1.25 dBTP after: -14.05..-14.29 LUFS, -1.72..-2.10 dBTP Causes: - alimiter's default auto-level (level=1) applies 1/limit makeup gain after limiting, putting the ceiling back at 0 dBFS and adding +1 LU to every file. - alimiter limits sample peaks, not true peaks. - Lossy encoders overshoot the limited signal; ffmpeg's native AAC encoder at 128k overshoots by up to ~3 dB on specific transients. Changes: - The limiter runs 4x oversampled with level=0 and latency=1. - Profiles limit CodecHeadroomDB (1.5 dB) below their ceiling, and TranscodeMeasured re-encodes with a lower ceiling (up to 3 times) if the encoded file still measures over it. - Bump main v1->v2 and spotify v2->v3 so the back catalog is re-encoded (ADR-0020 rule). - deploy.sh installs a static ffmpeg n9.0 build into /opt/ffmpeg, and startup refuses ffmpeg < 9 (production was on Debian's 5.1). - ADR-0022 and FINDINGS section 9 record the measurements and the rejected alternatives (loudnorm falls back to dynamic mode; high-pass; aac_coder fast). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>a9f5ddc870to9900b769c4View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.