Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replaygain: Add a loudgain backend #3368

Open
Moonbase59 opened this issue Sep 14, 2019 · 14 comments
Open

replaygain: Add a loudgain backend #3368

Moonbase59 opened this issue Sep 14, 2019 · 14 comments
Labels
feature features we would like to implement

Comments

@Moonbase59
Copy link

Moonbase59 commented Sep 14, 2019

Use case

As the current developer of loudgain, a ReplayGain 2.0 tagging tool for many file formats, I’d much like to see loudgain being supported by beets as an official ReplayGain backend.

Solution

I assume integration shouldn’t be too complicated, since loudgain uses an enhanced version of the well-known mp3gain commandline syntax.

Let me know how I could help getting this going.
Any testing results from beets users and feedback on loudgain’s issue tracker welcome!

More info

loudgain on GitHub
loudgain in the Hydrogenaudio wiki

@sampsyo sampsyo added the feature features we would like to implement label Sep 14, 2019
@sampsyo sampsyo changed the title Support loudgain as official ReplayGain backend? replaygain: Add a loudgain backend Sep 14, 2019
@sampsyo
Copy link
Member

sampsyo commented Sep 14, 2019

Looks cool! I am really not an expert in this space, so is there any chance you could expand a little on the advantages of your new tool vs. using FFmpeg's gain scanning module?

@Moonbase59
Copy link
Author

Moonbase59 commented Sep 14, 2019

Good question, I never much used the FFmpeg gain scanner, albeit I do use the FFmpeg libraries to be able to easily read and decode many file types. In loudgain, RG2 calculation is done purely by using libebur128 to get at correct gain and true peak values, as well as (optional) dynamic range. It also allows clipping prevention according to the EBU R128 recommendation (at -1 dBTP), and other options like writing upper- or lowercase RG tags, this unfortunately still being a problem with many players (i.e. KODI requiring lower case, VLC requiring uppercase and so on).

Oh well, and it uses an enhanced version of the mp3gain commandline syntax, never changes audio data (it only writes tags), and handles a lot of commonly used file types, using the same piece of software and commandline options.

Don’t want to make this an ad—much more tech details can be found on loudgain’s GitHub page. :-)

N.B.: The many loudgain options might require some extra beets settings somewhere, like

  • does the user wish to store upper- or lowercase RG tags?
  • does the user wish to add clipping prevention (reduce gain to compensate for clipping)?
  • does the user wish to strip "foreign" tags from files?
  • should RG tags be written to the audio files or just calculated for storage into beets’ database (the -O option might come in handy)?

EDIT: Re "loudgain vs. FFmpeg gain" – I distinctly remember it wasn’t easy to set up a good filter chain with FFmpeg to do oversampling. libebur128 has a custom polyphase FIR filter to oversample up to 4x (at 192 kHz) to calculate near-perfect true peak values, taking inter-sample peak into account. These values are also used by loudgain in case clipping prevention is enabled.

EDIT 2: It might be worthwhile to compare loudgain’s reults to the method beets uses (FFmpeg?) and desbma’s r128gain, especially since he’s switched back from true peak to sample_peak. See discussion on Hydrogenaudio.

@sampsyo
Copy link
Member

sampsyo commented Sep 15, 2019

Got it. One thing you should know is that beets ReplayGain backends do not write anything to files; beets itself takes care of all the metadata. So we would not use the tagging features of loudgain, including format-specific casing and stripping existing metadata.

The ReplayGain plugin already has a noclip setting (for the mp3gain backend), so we could provide that option to the tool. For the FFmpeg backend, we also already have a true vs. sample peak config option.

EDIT: Re "loudgain vs. FFmpeg gain" – I distinctly remember it wasn’t easy to set up a good filter chain with FFmpeg to do oversampling. libebur128 has a custom polyphase FIR filter to oversample up to 4x (at 192 kHz) to calculate near-perfect true peak values, taking inter-sample peak into account. These values are also used by loudgain in case clipping prevention is enabled.

I'm slightly confused here—FFmpeg uses libebur128, AFAIK, so I don't think this counts as a difference between the two backends. Unless this filter you're describing is disabled in the way FFmpeg uses the library?

EDIT 2: It might be worthwhile to compare loudgain’s reults to the method beets uses (FFmpeg?) and desbma’s r128gain, especially since he’s switched back from true peak to sample_peak. See discussion on Hydrogenaudio.

Yes, but it's also probably worth pointing out that r128gain uses FFmpeg too.

@Moonbase59
Copy link
Author

Moonbase59 commented Sep 15, 2019

Ah, okay. Maybe I based this on wrong assumptions—too be honest, I haven’t been using beets for a while now. I’d have to check the current FFmpeg possibilities and how you’re using it.

So, if I understand correctly, you’re saying the ReplayGain backends just calculate RG and peak values and you just store these in the beets database? Since beets can write tags to files, would there be any case where it actually does write the ReplayGain/peak values to the files?

Another question: If it turned out that loudgain should be a possible RG backend, would it help to add a JSON output to loudgain?

I’ll surely set up a beets testing environment and have a peek at the current code in the next days.

@sampsyo
Copy link
Member

sampsyo commented Sep 15, 2019

So, if I understand correctly, you’re saying the ReplayGain backends just calculate RG and peak values and you just store these in the beets database? Since beets can write tags to files, would there be any case where it actually does write the ReplayGain/peak values to the files?

Yep! Except that beets itself writes these to the files—this is a part of "core beets," so all the plugin needs to do is calculate the values and put them in the database.

Another question: If it turned out that loudgain should be a possible RG backend, would it help to add a JSON output to loudgain?

Absolutely! That would be awesome. Or CSV, if that's easier?

@Moonbase59
Copy link
Author

Moonbase59 commented Sep 15, 2019

CSV is already in there (tab-delimited to stdout), just use the -O (capital letter "O") option.

Regarding JSON: The idea would be to output JSON data for all files given on the commandline, including an entry for "Album" if album mode was specified. Does beets ask the RG backend for complete albums, a number of files, or just one file each?

@sampsyo
Copy link
Member

sampsyo commented Sep 15, 2019

Oh nice, that's cool! CSV seems just as easy to manage as JSON from Python, so maybe the JSON mode isn't necessary after all.

The plugin does indeed ask the tool to analyze entire albums (when used in album mode).

@Moonbase59
Copy link
Author

I just did a "quick one" using the same file:

$ ffmpeg -i 01\ -\ Blind\ Faith.aiff -af loudnorm=I=-18:TP=-1:LRA=11:print_format=summary -f null -
…
[Parsed_loudnorm_0 @ 0x3085300] 
Input Integrated:    -15.2 LUFS
Input True Peak:      -0.3 dBTP
Input LRA:             4.7 LU
Input Threshold:     -25.4 LUFS

Output Integrated:   -17.1 LUFS
Output True Peak:     -1.0 dBTP
Output LRA:            3.6 LU
Output Threshold:    -27.3 LUFS

Normalization Type:   Dynamic
Target Offset:        -0.9 LU
$ loudgain -k 01\ -\ Blind\ Faith.aiff 
[✔] Scanning '01 - Blind Faith.aiff' ...
[✔] Container: Audio IFF [aiff]
[✔] Stream #0: PCM signed 16-bit big-endian, 16 bit, 44100 Hz, 2 ch, stereo
 100% [========================================================================]

Track: 01 - Blind Faith.aiff
 Loudness:   -15.16 LUFS
 Range:        4.75 dB
 Peak:     0.963379 (-0.32 dBTP)
 Gain:        -2.84 dB
$ loudgain -O -k 01\ -\ Blind\ Faith.aiff 
[✔] Scanning '01 - Blind Faith.aiff' ...
[✔] Container: Audio IFF [aiff]
[✔] Stream #0: PCM signed 16-bit big-endian, 16 bit, 44100 Hz, 2 ch, stereo
File	Loudness	Range	True_Peak	True_Peak_dBTP	Reference	Will_clip	Clip_prevent	Gain	New_Peak	New_Peak_dBTP
01 - Blind Faith.aiff	-15.16 LUFS	4.75 dB	0.963379	-0.32 dBTP	-18.00 LUFS	N	N	-2.84 dB	0.695024	-3.16 dBTP

So it seems both FFmpeg and loudgain arrive at nearly identical data (expected) but FFmpeg uses the "official" notation with just 1 decimal whereas loudgain follows the RG2 spec with 2 decimals.

@Moonbase59
Copy link
Author

Moonbase59 commented Sep 15, 2019

So what’s to be gained using loudgain (pun not intended)?

  • a little more precision
  • an alternative in case the distro’s ffmpeg has no ebur128 or loudnorm filter

Then again, loudgain requires

  • the FFmpeg libraries
  • libebur128
  • TagLib (libtag1 or equivalent)

Self-critical question: Would that justify adding loudgain as a RG backend?

@dgaus
Copy link

dgaus commented Jul 8, 2020

I'm trying to switch to Opus as my library format but replaygain support is holding me back. bs1770gain crashes on Archlinux with no fix in the foreseeable future, so I'm interested in implementing either a loudgain or r128gain backend. I haven't investigated both libraries in detail to have any preference, so I'm wondering if a) the beets devs have any particular preference and b) if a MR would be accepted to add support to the replaygain plugin.

I also see there is an open MR that adds new fields, wondering if someone could take a look at it. Thanks!

@sampsyo
Copy link
Member

sampsyo commented Jul 8, 2020

That PR for the new fields seems cool, although I've lost context here. Maybe you can help by weighing in on that thread about whether it makes sense to add those fields now, even if there is no MediaFile support for them nor any RG backend that makes use of them? (Or perhaps there is?) Some commentary on that thread to help us understand what needs to be done would be super helpful.

There's no particular objection to new backends, but have you tried the recently added FFmpeg backend? (Both loudgain and r128gain use FFmpeg under the hood, IIRC.)

@dgaus
Copy link

dgaus commented Jul 8, 2020

Oh, I wasn't aware there was an ffmpeg backend. I see the commits are almost a year old, but there has been no release since. I will try master and report back, are there any plans to do a release soon?

I guess those extra fields only make sense if there is / will be a plugin backend that reports them, otherwise it's no use.

@sampsyo
Copy link
Member

sampsyo commented Jul 8, 2020

Yes, we are super behind on doing a release and hope to do that real soon now. :(

@dgaus
Copy link

dgaus commented Jul 8, 2020

No worries :) Just tried the ffmpeg backend on master and it seems to work fine, R128_ALBUM_GAIN and R128_TRACK_GAIN tags are present in the resulting files, so yeah, I'm not sure adding support for another replaygain backend is warranted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature features we would like to implement
Projects
None yet
Development

No branches or pull requests

3 participants