Ahmed Doghri Logo Image
Ahmed Doghri

loudnessgate

Loudness is a delivery contract. The podcast demo measures -18.4 LUFS, identifies a 2.4 dB correction, and preserves peak headroom.

loudnessgate audio mastering and normalization gate
loudnessgate working browser demo

A Clean Mix Can Still Fail Delivery

Streaming, podcast, and broadcast targets differ. Turning a file up by ear can miss integrated loudness, loudness range, or true-peak limits and create a second rejected export.

loudnessgate wraps FFmpeg's loudnorm measurement and two-pass normalization with named broadcast, podcast, and music-streaming profiles.

Make Mastering Checkable

The JSON report records integrated LUFS, true peak, loudness range, every pass or fail decision, and required gain. The same engine powers the CLI, API, workbench, integration test, and container.

The Demo

The podcast fixture measures -18.4 LUFS against a -16 target and needs 2.4 dB of gain. Its -2.1 dBTP peak and 6.2 LU range already pass, so the report explains exactly why the file fails.

Two-pass normalization is deterministic for the measured file. Codec overshoot, downstream processing, platform-specific policies, and listening quality still require final review.

The API Would Run FFmpeg On Whatever You Told It To

The JSON endpoint was built to accept two shapes of input: pre-measured loudness values, or a file path to measure itself. The problem is that second shape didn't check who was asking. POST /api/analyze forwarded the raw request body straight into the measurement function, which would run FFmpeg against whatever local path showed up in the JSON — no matter who sent the request or where on the server's filesystem that path pointed.

Verified against a live instance: sending {"path": "/etc/hosts"} made the server actually invoke FFmpeg on /etc/hosts and echo its error output, including the exact path, straight back in the response. That's an unauthenticated file-existence oracle at a minimum, and full loudness data extraction from any media file on the box at worst — from anyone who can reach the endpoint, no credentials required.

Fixed by rejecting any request carrying a path field before it reaches the measurement code. The network API now only accepts pre-measured values; touching the local filesystem stays a CLI-only operation, where the person running the command already has legitimate access to their own files. Nothing about the CLI or the measurement engine itself changed — only the boundary where untrusted network input meets local file access.

Standards Basis

The measurement model is grounded in EBU R128, while the binary path uses FFmpeg's documented loudnorm filter.

Read the EBU R128 loudness recommendation.

Tools Used

Python
FFmpeg
EBU R128
LUFS
True Peak
Audio DSP
API Security
Docker