Coder Social home page Coder Social logo

regainer's Introduction

regainer is an Advanced ReplayGain scanner and tagger

I wanted a simple-to-use tool that can apply ReplayGain compatible tags to a wide variety of audio files - even mixing and matching different file types, sample rates, etc. I couldn’t find any existing tools that did the job, so I wrote regainer.

regainer writes ReplayGain tags compatible with the ReplayGain 2.0 proposed specification. The tags written by regainer are compatible with a wide variety of players, even older players. It does this by writing multiple formats of tags within the same file for file types like mp3 which have multiple ways to store ReplayGain information.

If you find a player that is not compatible with tags written by regainer, please let me know by filing an issue on Github.

Requirements

regainer is written in Python 3. It should work with Python 3.7 and any later release. In addition to Python, you will need the following:

  • mutagen, a Python library that can read and write tags from a wide variety of audio formats.
  • ffmpeg command line tools, version 4.0 or later. I use the “ebur128” filter in ffmpeg to calculate loudness levels.

Installation

Packaging is still a work in progress. But regainer is a single python script, so it's sufficient to just copy or symlink it to somewhere in your path. Some examples:

sudo cp regainer.py /usr/local/bin/regainer
# or
ln -s /path/to/regainer.py /home/username/.local/bin/regainer

Using regainer

The simplest use case is to add track (aka “radio”) ReplayGain tags to a single file:

$ regainer track.mp3

Or you can add both track and album (aka “audiophile”) ReplayGain tags to all the tracks in an album:

$ regainer Album/*.opus

You can mix and match different modes by specifying the -a and -t options. Using -a starts a new album, and using -t disables album processing for the following tracks. You can use -t if you want to add only track ReplayGain tags to several files at the same time.

$ regainer -a Album1/*.ogg \
    -t A_Single_track.mp3 A_different_single_track.opus \
    -a Another_album/*.m4a

In some cases, you might want to process gain for a complete album, but exclude certain tracks from being included in the calculated album gain value - for example, there might be some karaoke song versions, drama or interview tracks, etc. You can use the -e option to do this.

In this example, the album gain tag will be written to all 4 tracks, but only tracks 1 and 2 will be used to calculate the album gain:

$ regainer -a 01.opus 02.opus -e 03.opus 04.opus

Some additional options may also come in handy:

-n puts regainer into dry-run mode. It will calculate and print the loudness levels in the file, but it will not write the ReplayGain tags.

-f causes regainer to recalculate the loudness levels even if ReplayGain tags are already present in the files. If you have files which had loudness levels calculated using the old ReplayGain algorithm, you can use this option to recalculate using the EBU R128 algorithm.

-j N specifies the number of parallel jobs to run. By default it will use all CPUs available on the system. You can use this to reduce the amount of CPU that regainer will use.

License

regainer is released under the terms of the MIT license; see the file COPYING for the license text. This is a very simple non-copyleft license, but note that the dependencies of regainer may have different licenses.

I encourage developers of music tagging applications to reference or use regainer code to improve their support for ReplayGain tags.

Format-specific Notes

Flac

regainer does not support writing ReplayGain information to an embedded CUE file.

M4A (AAC, ALAC, etc.)

regainer uses comment tags in the com.apple.iTunes namespace. This is compatible with the tag format used by foobar2000 and many other players.

Older tags in the org.hydrogenaudio.replaygain namespace will be read and converted to the new format.

regainer does not support writing tags compatible with iTunes Sound Check.

MP3

regainer currently converts all MP3 ID3v2 tags to version 2.4. This might cause issues with some players, particularly on Windows. If you are affected, please file a Github issue and I'll look into having an option to specify the preferred tag version.

In addition to the standard TXXX ReplayGain tags, regainer also writes ID3v2 RVA2 tags as specified in the Replaygain legacy metadata formats document.

regainer does not read or write the LAME header ReplayGain tags. As far as I know, no players read this format. Or at least, if any do, they also support (and prefer) the standard tag formats.

Ogg Opus

In addition to the standard VorbisComment ReplayGain tags, regainer also writes the opus-specific R128_TRACK_GAIN and R128_ALBUM_GAIN tags specified in the Ogg Encapsulation for the Opus Audio Codec proposed standard. The correct reference level is used for these tags so that you music will play back at the same volume regardless of whether the player reads the ReplayGain or R128 tags.

Note that regainer does not modify the ID header “output gain” field in Ogg Opus files. Gain values for ReplayGain and the R128 tags are both applied in addition to the ID header output gain field. If you modify the ID header output gain field, you should re-run regainer with the -f option to recalculate the ReplayGain and R128 header values.

Additional References

I'm working on a set of ReplayGain Test Vectors for various audio formats. This is still a work in progress, but I'd be interested in hearing from you about players that don't pass the test vectors.

regainer's People

Contributors

kepstin avatar maszaa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

maszaa metzlmane

regainer's Issues

Incorrect album gain

I got incorrect album gain for Ennio Morricone - The Platinum Collection (https://www.discogs.com/Ennio-Morricone-The-Platinum-Collection/release/4291445)

2-14 - For Love One Dies- Si muore d'amore.flac
Track: I: -19.90 LUFS, Peak: -1.70 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-01 - The Mission- Gabriel's Oboe.flac
Track: I: -16.90 LUFS, Peak: -2.10 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-14 - Revolver- Inseguimento e fuga.flac
Track: I: -13.10 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-14 - I… come Icaro- La verité et le soleil.flac
Track: I: -15.40 LUFS, Peak: -2.20 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-15 - Che c'entriamo noi con la rivoluzione- Rivoluzione.flac
Track: I: -14.40 LUFS, Peak: -2.10 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-01 - Once Upon a Time in America- Deborah's Theme.flac
Track: I: -19.50 LUFS, Peak: -1.10 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-19 - Gli intoccabili- La ballata di Hank McCain.flac
Track: I: -13.50 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-05 - Once Upon a Time in the West- L'uomo dell'armonica.flac
Track: I: -15.30 LUFS, Peak: -1.70 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-07 - The Sicilian Clan- Il clan dei Siciliani.flac
Track: I: -12.90 LUFS, Peak: 0.10 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-17 - Tepepa- Viva la revolucion.flac
Track: I: -12.80 LUFS, Peak: -0.30 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-13 - Once Upon a Time in America- Cockeye's Song.flac
Track: I: -15.10 LUFS, Peak: -1.30 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-11 - Maddalena- Chi mai.flac
Track: I: -15.30 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-04 - Love Circle- Metti una sera a cena.flac
Track: I: -15.50 LUFS, Peak: 0.20 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-05 - Novecento- Romanzo.flac
Track: I: -13.70 LUFS, Peak: -1.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-19 - Joss il professionista- Il vento il grido.flac
Track: I: -13.10 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-20 - La tragedia di un uomo ridicolo- La tragedia di un uomo ridicolo.flac
Track: I: -17.40 LUFS, Peak: -2.50 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-02 - Investigation of a Citizen Above Suspicion- Indagine.flac
Track: I: -17.20 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-12 - Alzati spia- Marche en La.flac
Track: I: -15.20 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-13 - La califfa- La califfa.flac
Track: I: -16.90 LUFS, Peak: -1.80 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-10 - I crudeli- I crudeli.flac
Track: I: -16.50 LUFS, Peak: -2.40 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-07 - Questa specie d'amore- Questa specie d'amore.flac
Track: I: -17.10 LUFS, Peak: -1.90 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-12 - Peur su la ville- Paura sulla città.flac
Track: I: -16.20 LUFS, Peak: -0.30 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-20 - La ragion pura- La ragion pura.flac
Track: I: -18.60 LUFS, Peak: -0.70 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-15 - God with Us- Lontano.flac
Track: I: -16.10 LUFS, Peak: -2.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-09 - My Name is Nobody- Il mio nome è Nessuno.flac
Track: I: -13.40 LUFS, Peak: -0.60 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-02 - The Good, the Bad and the Ugly- Il buono, il brutto, il cattivo.flac
Track: I: -13.80 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-18 - Ecce Homo- Venuta dal mare.flac
Track: I: -21.30 LUFS, Peak: -3.20 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-03 - Cinema Paradiso- Maturità.flac
Track: I: -18.30 LUFS, Peak: -3.10 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-18 - Arabian Nights- Tema di Dunja.flac
Track: I: -14.70 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-16 - Libera amore mio- Estate 1943.flac
Track: I: -21.30 LUFS, Peak: -3.80 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-06 - The Secret of the Sahara- Il segreto del Sahara.flac
Track: I: -19.00 LUFS, Peak: -1.10 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-01 - A Fistul of Dynamite- Giù la testa.flac
Track: I: -13.90 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-16 - Barbablù- Barbablù.flac
Track: I: -18.30 LUFS, Peak: -2.70 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-04 - Cinema Paradiso- Dal sex-appeal al primo Fellini.flac
Track: I: -16.50 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-19 - The Most Beautiful Wife- La moglie più bella.flac
Track: I: -14.90 LUFS, Peak: -1.40 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-20 - A Fistful of Dollars- Per un pugno di dollari.flac
Track: I: -13.60 LUFS, Peak: -1.30 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-09 - La Cage aux folles- Il vizietto.flac
Track: I: -13.50 LUFS, Peak: -0.70 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-06 - The Sunday Woman- La donna della domenica.flac
Track: I: -15.40 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-17 - Crescete e moltiplicatevi- Crescete e moltiplicatevi.flac
Track: I: -15.50 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-08 - Corleone- Addio a Palermo.flac
Track: I: -14.40 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-10 - Canone inverso - making love- Tema d'amore disperato.flac
Track: I: -17.60 LUFS, Peak: -2.60 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-08 - Il federale- Titoli.flac
Track: I: -18.10 LUFS, Peak: -0.90 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-09 - Veruschka- Poesia di una donna.flac
Track: I: -16.60 LUFS, Peak: 0.10 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-04 - For a Few Dollars More- Per qualche dollaro in più.flac
Track: I: -13.70 LUFS, Peak: -0.50 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-16 - L'uomo proiettile- L'uomo proiettile.flac
Track: I: -16.50 LUFS, Peak: -0.10 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-17 - Le Casse- Tema d'amore.flac
Track: I: -13.60 LUFS, Peak: -0.30 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-03 - Once Upon a Time in the West- C'era una volta il West.flac
Track: I: -17.10 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-07 - Battle of Algiers- Algeri 1 novembre 1954.flac
Track: I: -15.30 LUFS, Peak: -5.30 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-11 - Sacco and Vanzetti- Speranze di libertà.flac
Track: I: -15.60 LUFS, Peak: -1.50 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-05 - Cinema Paradiso- Nuovo cinema Paradiso.flac
Track: I: -13.40 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
1-18 - Lovers and Liars- Viaggio con Anita.flac
Track: I: -13.00 LUFS, Peak: -1.60 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-02 - The Good, the Bad and the Ugly- L'estasi dell'oro.flac
Track: I: -13.20 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-15 - I ladri della notte- Thieves After Dark.flac
Track: I: -15.10 LUFS, Peak: -1.40 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-11 - La cosa buffa- La cosa buffa.flac
Track: I: -14.20 LUFS, Peak: 0.10 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-08 - Il giro del mondo degli innamorati di Peynet- Forse basta.flac
Track: I: -15.70 LUFS, Peak: -0.50 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-13 - Quartiere- Romanza quartiere.flac
Track: I: -15.40 LUFS, Peak: 0.10 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
3-06 - The Mission- The Falls.flac
Track: I: -18.20 LUFS, Peak: -0.30 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-03 - The Mission- The Mission.flac
Track: I: -18.50 LUFS, Peak: -1.60 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-12 - Dimenticare Palermo- Dimenticare Palermo.flac
Track: I: -15.80 LUFS, Peak: 0.00 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS
2-10 - Via mala- Via mala.flac
Track: I: -14.30 LUFS, Peak: 0.20 dBFS; Album: I: -70.00 LUFS, Peak: 0.20 dBFS

Tried to rescan with --force but it didn't help.

Invalid syntax errors with Python 3.7

Hi,

async and await were made reserved keywords in Python 3.7 which means lines like 804 and 839 throw syntax errors.

I haven't done any work with asyncio otherwise I'd submit a PR.

Russ

More deprecation warnings with python 3.7 (cut'n'paste)

Namespace(FILE=['foo.mp3'], album=deque([]), dry_run=False, exclude=deque([]), force=False, jobs=2, track=deque([]))
./regainer:725: DeprecationWarning: 'with (yield from lock)' is deprecated use 'async with lock' instead
  with (yield from self.job_sem):
./regainer:732: DeprecationWarning: 'with (yield from lock)' is deprecated use 'async with lock' instead
  with (yield from self.job_sem):
./regainer:738: DeprecationWarning: 'with (yield from lock)' is deprecated use 'async with lock' instead
  with (yield from self.job_sem):

foo.mp3
Track: I: -17.90 LUFS, Peak: -5.80 dBFS; Album: I: None, Peak: None
Rescanned loudness
Updated tags

Peak values over 1.0

Why does for example foobar2000 report that some tracks whose replay gain has been calculated with Regainer have album and/or track peaks over 1.0? The audio format is integer PCM (16 and 24 bit) so that shouldn't be technically possible. Are the gains calculated in floating point and stored in that representation?

Can regainer tag multiple albums at once?

I have my library organized like so:

Music/Aritists/Album/Tracks.flac

Would passing ~/Music as the directory argument enable album replay gain even though the Artists folder level is in between them?

misnamed .opus.webm causes stacktrace

The .opus file was downloaded from a video platform and named .opus by the script or by the browser. Yet it contains a .webm container with an opus stream. Regainer is confused about this.

Namespace(FILE=['foo.opus'], album=deque([]), dry_run=False, exclude=deque([]), force=False, jobs=2, track=deque([]))
./regainer:725: DeprecationWarning: 'with (yield from lock)' is deprecated use 'async with lock' instead
  with (yield from self.job_sem):
Traceback (most recent call last):
  File "./regainer", line 878, in <module>
    loop.run_until_complete(future)
  File "/usr/lib64/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "./regainer", line 745, in scan
    yield from self.read_tags()
  File "./regainer", line 728, in read_tags
    self.tagger.read_gain)
  File "/usr/lib64/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "./regainer", line 460, in read_gain
    if self.audio.tags is None:
AttributeError: 'NoneType' object has no attribute 'tags'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.