What Is EBU R128 Loudness Normalization?

EBU R128 is the European Broadcasting Union’s standard for audio loudness. It defines three values:

Metric Unit EBU R128 Target
Integrated Loudness (I) LUFS −23 LUFS
True Peak (TP) dBTP −1 dBTP maximum
Loudness Range (LRA) LU No target or maximum (it shows how much the loudness varies)

LUFS (Loudness Units, referenced to Full Scale) measures how loud audio sounds to people. Peak normalization looks only at the highest sample value; LUFS normalization goes by how loud the content actually sounds.

Streaming services use their own loudness targets. They measure loudness with ITU-R BS.1770, the same method that R128 and the US broadcast standard ATSC A/85 use.

Single-Pass Normalization (Quick)

The simplest way is a single pass:

ffmpeg -i input.mp3 -af loudnorm output.mp3

By default, loudnorm aims for −24 LUFS integrated loudness, −2 dBTP true peak and a 7 LU loudness range. A single pass estimates the source loudness during processing, which is good enough for many uses. Except with audio shorter than 3 seconds, it runs in dynamic mode: the gain keeps changing through the file. A single pass also upsamples the audio to 192 kHz internally. The output sample rate can therefore change, so set it yourself with -ar 48000 or similar.

Customizing Targets

ffmpeg -i input.mp3 -af "loudnorm=I=-16:TP=-1.5:LRA=11" output.mp3
Parameter Description Default
I Integrated loudness target (LUFS) −24
TP True peak ceiling (dBTP) −2
LRA Loudness range target (LU) 7

I=-16 matches Apple Podcasts, which asks for about −16 LKFS (LKFS is the same scale as LUFS). Spotify adjusts tracks to −14 LUFS. For broadcast (EBU R128), use I=-23.

Two-Pass Normalization (Accurate)

For the most accurate result, run loudnorm twice: first to measure, then to apply.

Pass 1: measure the source loudness

ffmpeg -i input.mp3 -af "loudnorm=I=-16:TP=-1.5:LRA=11:print_format=json" -f null /dev/null

-f null /dev/null means no file is written. At the end, loudnorm prints the measured values to stderr as a JSON block:

{
        "input_i" : "-27.06",
        "input_tp" : "-4.28",
        "input_lra" : "7.20",
        "input_thresh" : "-37.06",
        "output_i" : "-16.00",
        "output_tp" : "-1.50",
        "output_lra" : "7.20",
        "output_thresh" : "-26.00",
        "normalization_type" : "dynamic",
        "target_offset" : "0.00"
}

Pass 2: apply the measured values

Copy input_i, input_tp, input_lra and input_thresh from pass 1 into measured_I, measured_TP, measured_LRA and measured_thresh:

ffmpeg -i input.mp3 -af "loudnorm=I=-16:TP=-1.5:LRA=11:measured_I=-27.06:measured_TP=-4.28:measured_LRA=7.20:measured_thresh=-37.06:linear=true" output.mp3

linear=true asks for one fixed gain for the whole file, based on the measured values, instead of dynamic processing. It is the default anyway. The filter falls back to dynamic mode if any of the four measured values is missing, if the gain would push the peak above TP, or if measured_LRA is above LRA. In this example, raising −27.06 LUFS to −16 LUFS takes +11.06 dB. That would put the peak at +6.78 dBTP, above TP=-1.5, so this example actually runs in dynamic mode.

Applying to Video Files (Audio-Only Processing)

To normalize the loudness of a video without re-encoding the picture:

ffmpeg -i input.mp4 -c:v copy -af "loudnorm=I=-16:TP=-1.5:LRA=11" -ar 48000 output.mp4

-c:v copy copies the video unchanged. Only the audio is re-encoded. -ar 48000 sets the audio to 48 kHz. Without it, this command makes 96 kHz audio.

Understanding the Output Values

The JSON from pass 1 contains:

Field Meaning
input_i Measured integrated loudness (LUFS)
input_tp Measured true peak (dBTP)
input_lra Measured loudness range (LU)
input_thresh Gating threshold (quieter parts are left out of the measurement)
normalization_type linear or dynamic

Pass 1 has no measured values to work with, so its normalization_type is normally dynamic (linear for audio shorter than 3 seconds). It tells you nothing about pass 2. To see which mode pass 2 used, add print_format=json to pass 2 as well.

Common Pitfalls

Output Is Louder or Quieter Than Expected

In a single pass, loudnorm estimates the loudness while it encodes. If the loudness changes a lot through the file, the estimate can be off. Use two passes whenever the result matters.

Pass 1 Only Measures

Pass 1 (-f null /dev/null) writes no file; it only measures. Do not skip it when accuracy matters, because pass 2 needs its values.

True Peak Clipping

True peak is the highest level of the actual waveform, including peaks that fall between samples. If the source has peaks very close to 0 dBFS, turning the gain up can push samples over 0. The TP parameter caps the output true peak to prevent this. Set TP=-1 or lower.