GitHub

mp3rgain vs mp3gain, aacgain, rsgain & ffmpeg

Nearly every tool here is a ReplayGain tool — they all measure loudness the same way in principle. What actually separates them is where the correction ends up: in a tag the player reads, in the bitstream itself, or in re-encoded samples. This page starts there, then places each tool — including mp3rgain — on the resulting map.

One measurement, three destinations

  1. Write ReplayGain tags. Measure loudness, store the result as metadata, and let the player apply it. Nothing about the audio changes. rsgain, loudgain, foobar2000 and ffmpeg -af replaygain all do this.
  2. Re-encode the audio. Decode, apply gain to the samples, encode again. Works everywhere, at the cost of a generation of lossy quality on every pass. ffmpeg loudnorm is the usual example.
  3. Rewrite the gain field inside the bitstream. MP3 and AAC frames carry a global_gain value that scales decoder output. Change it and the volume changes permanently, for every player, without decoding a single sample. mp3gain, aacgain, foobar2000 and mp3rgain do this.

1 and 3 are not rival camps. mp3gain, aacgain and mp3rgain do both: they run a ReplayGain analysis, bake the result into the bitstream, and write standard REPLAYGAIN_TRACK_GAIN / REPLAYGAIN_ALBUM_GAIN tags describing the residual, so a ReplayGain-aware player and a dumb one arrive at the same loudness. foobar2000 covers both routes too. "Tagger versus gain tool" is the wrong axis — the real question is whether a tool can touch the bitstream at all, and whether it can put it back.

Where those tags land, on MP3

"Writes ReplayGain tags" hides a detail that decides whether your player ever sees them. MP3 has two competing metadata containers, and the classic lineage picked the one modern players do not read. The gap is wider than it sounds — APEv2 ReplayGain on MP3 is not merely unpopular, it is close to unreadable:

So the two tag families mp3rgain writes have genuinely different audiences, and since 3.2.0 each one goes where its readers are:

TagContainerRead by
REPLAYGAIN_*ID3v2 TXXXPlayers. Also where foobar2000, rsgain and loudgain put theirs
MP3GAIN_UNDO, MP3GAIN_MINMAXAPEv2Nothing but the mp3gain lineage — which is exactly why -u still rolls back a library mp3gain processed

Two flags override the split when you want everything in one place:

mp3rgain -r *.mp3          # default: ReplayGain in ID3v2, undo in APEv2
mp3rgain -r -s a *.mp3     # everything in APEv2 — byte-for-byte mp3gain
mp3rgain -r -s i *.mp3     # everything in ID3v2

Reading is forgiving in both directions: -s c merges both containers and -u finds the undo tag in either, so files tagged by mp3gain, or by an older mp3rgain, still inspect and roll back correctly. Re-running the default over an APEv2-tagged file moves the ReplayGain values to ID3v2 and clears the APEv2 copies, so the two can never drift apart. MP3GAIN_ALBUM_MINMAX stays APEv2-only in every mode.

None of this affects AAC/M4A, which always uses MP4 freeform atoms that foobar2000 reads, and none of it affects the bitstream rewrite itself: the volume change is in the frames either way, so a ReplayGain-blind player is right regardless of which container won.

Upgrading from 3.1.x or earlier? Those versions put everything in APEv2. Nothing breaks — your files keep playing at the corrected volume, because that correction is baked into the frames, not the tags. Re-run mp3rgain to move the ReplayGain values where players can see them, or pass -s a to keep the old layout exactly.

Which destination do you want? If every device you use honours ReplayGain tags, stop at approach 1 — it is reversible by definition and stores track and album values side by side. If some of them do not — car stereos, older hardware players, DJ gear, cheap DAPs, many phone apps — the tags are silently ignored and approach 3 is the only lossless answer.

Where each tool sits

ToolStatusReplayGainGain applied byFormatsUndoPlatform
mp3rgainActiveRG1 default, --rg2 / --r128 opt-in — writes tagsBitstream gain field, or tags only with --tags-onlyMP3, AAC/M4A, raw ADTS .aacYesmacOS, Linux, Windows (CLI + GUI)
mp3gainUnmaintained (~2015)RG1 only — writes tagsBitstream gain fieldMP3YesWindows, Linux (aging builds)
aacgainUnmaintained (~2009)RG1 only — writes tagsBitstream gain fieldMP3, AAC/M4AYesRarely builds on modern 64-bit systems
foobar2000ActiveRG2 / R128 — the reference implementationTags, or bitstream gain fieldTags for most formats; bitstream for MP3 and AAC in MP4/MKATags yes — baked-in gain noWindows GUI only
rsgainActiveRG2 / R128 — writes tagsPlayer, from the tagsManyN/A — tags onlyCross-platform CLI
loudgainSuperseded by rsgainRG2 / R128 — writes tagsPlayer, from the tagsManyN/A — tags onlyLinux, macOS
ffmpeg loudnormActiveNo — R128 normalizer, not a taggerRe-encoded samplesEverythingNo — lossyCross-platform CLI

Two rows deserve a footnote. foobar2000 is not just another entry here: the Hydrogenaudio community around it is where the ReplayGain 2.0 specification was worked out, and its scanner is the practical reference other implementations get checked against. If you want textbook-correct ReplayGain and you are on Windows, that is the answer, and mp3rgain's --rg2 mode exists to agree with it rather than to compete with it. And the three bitstream tools at the top are also taggers — the classic mp3gain lineage has always written ReplayGain tags next to the gain it bakes in.

Why the classic tools ran out

What went unmaintained was never ReplayGain itself — foobar2000 and rsgain carry the standard forward in better shape than ever. What lapsed was the specific lineage that pairs a ReplayGain analysis with a lossless bitstream rewrite on the command line. mp3gain's upstream development stopped around 2015 and aacgain's around 2009. aacgain is the harder loss: it is the tool people reach for when a library contains M4A files, and it has become difficult to build on current 64-bit toolchains. That left two practical options for lossless AAC gain: run an ancient binary, or sit at a Windows desktop with foobar2000 — which does the job well, but only from the GUI and without an undo path.

mp3rgain exists to cover the case neither one does: one memory-safe Rust binary for both MP3 and AAC, scriptable and headless, with undo on both — which is what makes it usable in a container or a cron job where a mistake needs to be reversible. If you are at a Windows desktop, foobar2000 remains an excellent answer.

Reference levels

A recurring source of confusion when comparing tools is that they normalise to different targets, so identical inputs legitimately produce different numbers:

StandardReferenceMeasured bymp3rgain flag
ReplayGain 1.089 dBmp3gain, aacgain, mp3rgain (default)default
ReplayGain 2.0−18 LUFSfoobar2000 (reference), rsgain, loudgain--rg2
EBU R128−23 LUFSffmpeg ebur128, broadcast tooling--r128

mp3rgain defaults to ReplayGain 1.0 so re-scanning an mp3gain-processed library reproduces the same values instead of shifting everything. --rg2 and --r128 switch to ITU-R BS.1770 gated measurement when you would rather match the modern taggers — the target being foobar2000's numbers, not a separate dialect of them. In those modes mp3rgain also writes a REPLAYGAIN_ALGORITHM tag, so a library scanned in mixed modes stays legible.

Peak values on AAC

The other place identical inputs legitimately produce different numbers. On an AAC file, mp3rgain can report a noticeably higher peak than rsgain or foobar2000 while the gain values agree to 0.01 dB. Neither tool is wrong; they are not measuring the same signal.

Lossy AAC decodes to samples that can exceed full scale, and some encoders leave isolated bursts that decode well above 1.0. Decoders disagree about what to do with them. symphonia (which mp3rgain uses) and ffmpeg's native decoder pass them through; Apple's AudioToolbox decoder hard-limits at exactly 1.0. mp3rgain reports the peak of the decoded signal as it is, so a tool measuring a clamped decode necessarily reports less.

One track of a ffmpeg -c:a aac -b:a 256k encode, measured every way:

MeasurementValuedBFS
mp3rgain sample peak1.790314+5.06
ffmpeg's decoder, same frame1.790310+5.06
mp3rgain true peak (--true-peak)2.287768+7.19
ffmpeg ebur128=peak=true(7.3 print)+7.30
ideal band-limited interpolation2.310848+7.27
the same, after clamping to [−1, 1]1.321509+2.42
rsgain -t1.307024+2.33

mp3rgain lands 0.09 dB under the exact unclamped answer and rsgain 0.10 dB under the exact clamped one — the residual a 49-tap 4× oversampling filter leaves in both cases. The two tools agree with their own inputs to the same precision.

mp3rgain does not clamp because the peak should describe the file rather than whichever decoder the listener happens to use, and float playback paths (CoreAudio, WASAPI shared mode, PipeWire, most software players) really do reach the DAC with those samples. Over-reporting costs a little unnecessary attenuation; under-reporting clips.

In practice it rarely changes anything: applying each track's own gain to the unclamped peak on the album this was reported against gives a worst case of 0.84, so no player attenuates further either way. It matters only on a quiet recording carrying the same kind of burst, where peak-based clipping prevention would cap the gain differently. If you want the bursts gone at source, they come from the encoder — re-encoding with Apple's (ffmpeg -c:a aac_at) dropped that track from 1.790314 to 1.276827. The full investigation is in issue #350.

Migrating from mp3gain or aacgain

The CLI flags, the TSV output layout, and the APEv2 mp3gain_undo tag are all mp3gain-compatible. For most setups migration is a single substitution:

sed -i 's/\bmp3gain\b/mp3rgain/g' your_script.sh

Existing undo tags written by mp3gain remain valid, so a library that mp3gain already processed can be rolled back with mp3rgain -u. One default is intentionally inverted: mp3gain applies from stored tags unless you pass -s r, while mp3rgain re-analyses unless you pass -s R (v3.4+), which applies from stored tags and rescans only files whose tags are missing. The full flag-equivalence table, Dockerfile substitution patterns and the intentional behavioural differences are documented in the migration guide, and the bit-level verification against the original mp3gain is in the compatibility report.

When not to use mp3rgain

An honest boundary is more useful than a feature list:

Next