The modern way to normalize audio volume from the command line is loudness normalization (EBU R128 / LUFS), not peak normalization. For a single file, ffmpeg's loudnorm filter does it in one command. For a whole music library, rsgain writes ReplayGain tags that players honor without ever touching the audio. The old mp3gain you may have read about is unmaintained; rsgain is its successor.
# Normalize one file to -16 LUFS (the loudnorm one-pass)
ffmpeg -i in.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11 out.mp3
# Tag a whole library with ReplayGain (non-destructive, recursive)
rsgain easy ~/MusicThe rest of this page is the detail: why loudness beats peak, the accurate two-pass loudnorm, what each value means, and which LUFS target to aim for.
Peak normalization is not what you want
Peak normalization scales a file so its loudest sample hits a ceiling (say 0 dBFS or -1 dB). The problem is that a quiet, even track and a punchy, compressed track can have the same peak and sound nothing alike in volume. A single loud transient pins the peak while the rest of the track stays quiet, so peak-normalized files still jump around in perceived loudness. That is exactly the "one song is twice as loud as the next" problem people are trying to fix.
Loudness normalization measures perceived loudness over the whole file (the EBU R128 / ITU BS.1770 standard, expressed in LUFS) and adjusts to a target. Two files normalized to the same LUFS sound equally loud to a human, which is the point. Streaming platforms all switched to loudness normalization years ago, so matching their model locally is the correct move.
ffmpeg loudnorm: one-pass
loudnorm is built into ffmpeg, so if you already have ffmpeg you have it. The one-pass form is a single command:
ffmpeg -i in.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11 out.mp3The three knobs:
Iis the integrated (target) loudness in LUFS.-16is a sensible default for general listening and podcasts.TPis the maximum true peak in dBTP.-1.5leaves headroom so the file does not clip after lossy re-encoding.LRAis the target loudness range. The filter's own default is7;11is a looser range that the loudnorm author uses in the canonical example, and it is fine to leave alone for general material.
One pass is fast and good enough for casual use. Its weakness is that it normalizes in a single sweep, so the integrated loudness it lands on can drift a little from the I you asked for, especially on dynamic material.
One gotcha worth knowing: to measure true peaks accurately, loudnorm upsamples internally to 192 kHz, and that sample rate carries through to the output unless you ask for the original back. Append -ar (for example -ar 44100 or -ar 48000) so you do not end up with an unexpectedly large 192 kHz file:
ffmpeg -i in.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11 -ar 44100 out.mp3ffmpeg loudnorm: two-pass (the accurate way)
For broadcast-grade accuracy, measure first, then apply the measured values. Pass one runs loudnorm in analysis mode and prints JSON instead of writing a file:
ffmpeg -i in.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11:print_format=json -f null -That prints input_i, input_tp, input_lra, input_thresh, and target_offset. Feed the four input_* numbers back into a second pass as the measured_* parameters, pass target_offset as offset, and set linear=true:
ffmpeg -i in.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11:measured_I=-19.3:measured_TP=-3.1:measured_LRA=6.4:measured_thresh=-29.8:offset=0.5:linear=true:print_format=summary out.mp3Substitute the real measured values from pass one (the numbers above are an example). The offset is the small target_offset correction the analysis pass computes; passing it back is what the loudnorm author's canonical workflow does, and you can drop it if you do not need that last fraction of a dB. With the measurements in hand, ffmpeg applies a single linear gain that hits the target precisely instead of guessing. This is the form to use when you actually care about the output landing on -16 LUFS rather than near it.
If wiring the two passes by hand is tedious, the Python wrapper ffmpeg-normalize automates exactly this two-pass loudnorm flow over one file or a batch.
rsgain: normalize a whole library without re-encoding
For a music collection, you usually do not want to rewrite every file. ReplayGain is the better model: scan each track, compute the gain needed to hit a reference loudness, and store that as a tag in the file's metadata. The audio data is untouched; any ReplayGain-aware player (foobar2000, VLC, mpv, Rhythmbox, Kodi, and most others) reads the tag and adjusts playback volume on the fly. Non-destructive, reversible, and it preserves album dynamics.
rsgain is the modern, actively maintained tool for this. Its Easy Mode points at a directory and scans recursively with sensible defaults:
# Recursively scan and tag every supported file under the directory
rsgain easy ~/Musicrsgain easy writes both track gain (each file normalized on its own) and album gain (a single gain per album so the relative loudness between tracks on a record is preserved). A player set to album mode keeps the quiet intro and the loud chorus in their intended relationship; track mode flattens every song to the same level. rsgain handles MP3, FLAC, Opus, Ogg, M4A/MP4, WAV, and more, so it is not MP3-only despite the search term.
mp3gain is dead; use rsgain
Plenty of older guides reach for mp3gain -r *.mp3. It still runs, but mp3gain is unmaintained, MP3-only, and built around the older ReplayGain 1.0 model. rsgain is its spiritual successor: ReplayGain 2.0 (which uses the same EBU R128 / LUFS loudness measurement as loudnorm), modern formats, and active development. If a tutorial tells you to install mp3gain, install rsgain instead and use rsgain easy.
Which LUFS target should I use?
Pick the target for where the audio will be heard:
| Target | LUFS | Use it for |
|---|---|---|
| General / podcasts | -16 | Apple Podcasts' recommendation; a safe all-round default |
| Music streaming | -14 | Spotify and YouTube normalize playback to about -14 LUFS |
| EBU R128 broadcast | -23 | TV and radio delivery specs |
For audio you are mastering once to play "everywhere," -14 LUFS with a true peak of about -1 dBTP satisfies Spotify and YouTube and sits inside Apple's range. For ReplayGain tagging with rsgain, the ReplayGain 2.0 reference is -18 LUFS, which rsgain easy uses by default; you do not normally override it.
One thing to keep clear: loudnorm rewrites the audio to hit a fixed level, while rsgain tags the file and the player does the adjusting. Use loudnorm when you need a single export at a known loudness (a podcast episode, a video's audio track); use rsgain when you want a library that plays evenly without altering the files. The two are not competitors, they solve different problems.
FAQ
See also
- The ffmpeg command cheat sheet: convert, crop, trim, and compress from the CLI, with every common command in one reference.
- Extract audio from a video with ffmpeg: pull the audio track to MP3, AAC, or WAV, with or without re-encoding.
- Add or replace an audio track on a video with ffmpeg: mux a normalized audio file back onto a video.
Sources
Authoritative references this article was fact-checked against.
- ffmpeg loudnorm filter (official documentation)ffmpeg.org
- rsgain: a simple, but powerful ReplayGain 2.0 tagging utility (official repo)github.com
- Loudness normalization on Spotify (official support)support.spotify.com
- loudnorm: the filter author's reference writeup (two-pass workflow and offset)k.ylo.ph
- rsgain(1) manual page (Easy Mode defaults, ReplayGain 2.0 -18 LUFS)manpages.ubuntu.com





