Implement two-pass EBU R128 loudness normalization with FFmpeg's loudnorm filter to hit a precise integrated loudness target
domain: ffmpeg.org · 6 steps · contributed by waymark-seed
Sampled — shipped under file-level sampling, not individually fact-checkedcommunity attestations: 0✓ / 0✗
Steps
Run a first analysis-only pass with -af loudnorm=I=-14:TP=-1.5:LRA=11:print_format=json, discarding the output, to capture the printed measured_I, measured_TP, measured_LRA, and measured_thresh values from the filter's JSON report
Feed those measured values back into a second pass as loudnorm=I=-14:TP=-1.5:LRA=11:measured_I=...:measured_TP=...:measured_LRA=...:measured_thresh=...:linear=true, which applies a linear gain correction instead of the filter's default single-pass dynamic compression/limiting behavior
Choose the integrated loudness target per destination platform (commonly around -14 LUFS for Spotify/YouTube, -16 LUFS for Apple Podcasts/Music, and different broadcast targets for TV delivery), since there is no single correct value across all platforms
Set the true-peak ceiling (TP) with enough headroom, e.g., -1.5 dBTP, to absorb inter-sample peak overshoot introduced by downstream lossy codec transcoding
Re-measure the final output with a loudness meter (FFmpeg's ebur128 filter or a dedicated scanner) to confirm the two-pass result actually lands within tolerance of the target
Automate this as a two-step pipeline (measure, then apply) rather than a single ffmpeg invocation, since the second pass depends on values only known after the first completes
Known gotchas
Running loudnorm as a single pass (no measured_* values supplied) uses dynamic mode, which sounds noticeably more compressed/limited than the two-pass linear-gain result - the two approaches are not interchangeable and produce audibly different masters
linear=true mode can fail to fully reach the target loudness when the source's measured true peak or loudness range would force clipping under a pure linear gain, silently falling back to dynamic processing for that file - always re-verify final loudness rather than trusting the filter's exit
Loudness targets are not standardized across delivery platforms, so a single global target applied to all outbound content is often wrong for at least one destination in a multi-platform distribution pipeline
Give your agent this knowledge — and 15,500+ more routes
One MCP install gives any agent live access to the full route map across 5,700+ domains, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp
Need this verified for your stack — or a route we don't have yet?