FFmpeg Loudnorm Dual-Pass Loudness Normalization
This guide provides a straightforward tutorial on how to perform
dual-pass loudness normalization using the loudnorm filter
in FFmpeg. You will learn how to run the first pass to analyze your
audio’s baseline measurements and how to apply those parameters in the
second pass to achieve precise, broadcast-compliant audio levels
according to the EBU R128 standard.
Why Dual-Pass?
While FFmpeg’s loudnorm filter can run in a single-pass
mode, it relies on dynamic estimation which can lead to compression
artifacts or inaccurate target levels. A dual-pass approach first
analyzes the entire audio file to gather precise metadata, then uses
those exact measurements in the second pass to apply linear
normalization. This results in much higher audio quality and perfect
compliance with your target parameters.
Step 1: The First Pass (Analysis)
In the first pass, you run the loudnorm filter with the
print_format=json option enabled. This analyzes the file
and outputs the measurements to your terminal without writing a new
audio file.
Run the following command:
ffmpeg -i input.wav -af loudnorm=I=-16:TP=-1.5:LRA=11:print_format=json -f null -Parameter Breakdown: * I=-16: Sets the
target integrated loudness to -16 LUFS (common for podcasts/stereo web
audio). * TP=-1.5: Sets the target true peak to -1.5 dBTP.
* LRA=11: Sets the target loudness range to 11 LU. *
-f null -: Tells FFmpeg to discard the output video/audio
stream since we only need the text readout.
Analyzing the Output
At the end of the command line output, you will see a JSON block that looks like this:
{
"input_i" : "-22.50",
"input_lra" : "14.20",
"input_tp" : "-3.10",
"input_thresh" : "-32.80",
"output_i" : "-16.10",
"output_lra" : "10.10",
"output_tp" : "-1.50",
"output_thresh" : "-26.20",
"normalization_type" : "dynamic",
"target_offset" : "0.10"
}Write down or copy the values for input_i,
input_lra, input_tp,
input_thresh, and target_offset.
Step 2: The Second Pass (Normalization)
Now, feed the measured values from the JSON output back into the
loudnorm filter. This allows FFmpeg to perform precise
linear normalization.
Using the values from the JSON example above, run the second pass command:
ffmpeg -i input.wav -af loudnorm=I=-16:TP=-1.5:LRA=11:measured_I=-22.50:measured_LRA=14.20:measured_TP=-3.10:measured_thresh=-32.80:offset=0.10 -ar 48000 output.wavKey Additions in the Second Pass: *
measured_I: Set to the input_i value
(-22.50). * measured_LRA: Set to the
input_lra value (14.20). *
measured_TP: Set to the input_tp value
(-3.10). * measured_thresh: Set to the
input_thresh value (-32.80). *
offset: Set to the target_offset value
(0.10). * -ar 48000: Explicitly sets the
output sample rate to 48 kHz (or your preferred sample rate). The
loudnorm filter internally upsamples to 192 kHz for
calculation, so defining the output sample rate prevents unexpected
sample rate changes in your final file.