Normalize multiple audio files to consistent LUFS levels using FFmpeg’s loudnorm filter in a two-pass process. First, measure the integrated loudness of each file to generate metadata, then apply that data during encoding to ensure uniform perceived volume across your entire library without clipping or distortion.
Understanding Loudness Normalization with FFmpeg
Loudness normalization is critical for maintaining consistent audio quality across different media sources. The loudnorm filter in FFmpeg implements the ITU-R BS.1770 standard, which measures perceived loudness rather than simple peak amplitude. This ensures that quieter tracks are boosted and louder tracks are attenuated to match a target level, typically -16 LUFS for music or -24 LUFS for broadcast content.
Unlike basic gain adjustments, the loudnorm filter performs dynamic range compression. It analyzes the audio stream to determine how much gain is needed while preserving the original dynamics as much as possible. For batch processing multiple files like Music1.mp3, Music2.mp3, and Music3.mp3, you cannot rely on a single global setting because each file has unique acoustic characteristics. Therefore, a two-pass method is required to achieve precise results.
If you need to combine these normalized tracks afterward, consider reviewing our guide on Merging Three Audio Files into One: A Tech Support Guide to understand how to chain filters effectively after normalization.
Pass 1: Measuring Loudness Metadata
The first pass does not produce an output file. Instead, it scans the input audio and calculates the necessary parameters for normalization. You must run this command separately for each file to capture its specific loudness profile.
ffmpeg -i Music1.mp3 -af loudnorm=print_format=json -f null /dev/null
This command uses the -af flag to apply the loudnorm audio filter. The print_format=json option tells FFmpeg to output the measurement data in JSON format to the console. The -f null /dev/null part discards the actual audio data since we only need the statistics. On Windows, replace /dev/null with NUL.
The output will look similar to this:
{
"input_i": "-23.5",
"input_tp": "-1.5",
"input_lra": "8.0",
"input_thresh": "-33.5",
"output_i": "-24.0",
"output_tp": "-2.0",
"output_lra": "7.5",
"output_thresh": "-34.0",
"normalization_type": "dynamic",
"target_offset": "0.0"
}
Save this JSON output to a temporary file, such as Music1.json. Repeat this process for Music2.mp3 and Music3.mp3, saving their respective outputs as Music2.json and Music3.json. Do not attempt to normalize video streams directly with this filter; it operates exclusively on audio streams.
Pass 2: Applying Normalization
In the second pass, you use the measured data from Pass 1 to adjust the audio. This ensures that the normalization is tailored to the specific dynamics of each track.
ffmpeg -i Music1.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11:measured_I=-23.5:measured_TP=-1.5:measured_LRA=8.0:measured_thresh=-33.5:linear=true -c:a libmp3lame -q:a 2 Music1_norm.mp3
Here, the I=-16 sets the target integrated loudness to -16 LUFS. The TP and LRA values set the true peak and loudness range limits. Crucially, the measured_* parameters correspond exactly to the values obtained in Pass 1. Setting linear=true applies linear scaling, which is often preferred for music to avoid excessive compression artifacts.
Repeat this step for each file, substituting the appropriate JSON values for Music2 and Music3. This ensures that all three tracks end up at the same perceived loudness level.
Bash Scripting for Batch Processing
Manually running commands for three files is tedious. For larger libraries, automate the process using a bash script. This approach reduces errors and saves time significantly.
- Create a directory containing your source MP3 files.
- Write a script that iterates through each file.
- Execute the Pass 1 command and redirect output to a temporary JSON file.
- Parses the JSON to extract the
measured_*values. - Execute the Pass 2 command using those extracted values.
- Delete the temporary JSON file to keep the workspace clean.
While automation is efficient, always verify the output of a few samples manually to ensure the filter settings align with your artistic goals. If you are interested in other audio manipulation techniques, such as selecting specific clips, see our article on Randomly Selecting MP3 Audio Files with FFmpeg.
Troubleshooting Common Issues
If the normalized audio sounds distorted, check your True Peak (TP) settings. Setting the TP too low can cause inter-sample peaks to clip during encoding. Using libmp3lame with high-quality settings (-q:a 2) helps mitigate this.
Another common issue is silence detection. If your input contains long periods of silence, the loudness calculation may be skewed. Consider trimming silence before normalization or using the silenceremove filter in conjunction with loudnorm.
Frequently Asked Questions
Can I use loudnorm on video files directly?
No, the loudnorm filter only processes audio streams. You must extract the audio track from the video file before applying normalization, or specify the audio stream index using -map 0:a:0 if your video contains multiple audio tracks.
What is the difference between linear and dynamic normalization?
Linear normalization applies a constant gain adjustment based on the measured loudness, preserving the original dynamic range more closely. Dynamic normalization adjusts the gain continuously throughout the track, which can result in a more consistent volume but may reduce overall dynamics.
Why do my normalized files still have different volumes?
This usually happens if you skip the two-pass method or reuse incorrect measured values. Each file must be measured individually, and those specific values must be passed back into the filter for that exact file during the second pass.
Is LUFS the same as dBFS?
No, LUFS (Loudness Units relative to Full Scale) measures perceived loudness over time, weighted by human hearing sensitivity. dBFS (Decibels relative to Full Scale) measures instantaneous peak amplitude. LUFS is the standard for loudness normalization, while dBFS is used for preventing clipping.
How do I handle stereo vs mono files?
The loudnorm filter automatically handles both stereo and mono inputs. However, ensure your output codec supports the channel layout you intend to use. Most modern codecs like AAC or MP3 support stereo seamlessly.