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: R128_{TRACK,ALBUM}_GAIN in Opus #2557

Closed
autrimpo opened this issue May 11, 2017 · 5 comments
Closed

replaygain: R128_{TRACK,ALBUM}_GAIN in Opus #2557

autrimpo opened this issue May 11, 2017 · 5 comments
Labels
feature features we would like to implement

Comments

@autrimpo
Copy link
Contributor

The replaygain plugin using the bs1770gain backend with EBU method produces four REPLAYGAIN_ tags with Opus files. This is wrong, as it should only add two tags, R128_TRACK_GAIN and R128_ALBUM_GAIN, as described in the RFC. For example MPD only looks for the track gain tag and ignores any REPLAYGAIN_ tags (as it should). This obviously makes the replaygain plugin broken when used with Opus.

@autrimpo autrimpo changed the title R128_{TRACK,ALBUM}_GAIN in Opus replaygain: R128_{TRACK,ALBUM}_GAIN in Opus May 11, 2017
@sampsyo sampsyo added the needinfo We need more details or follow-up from the filer before this can be tagged "bug" or "feature." label May 12, 2017
@sampsyo
Copy link
Member

sampsyo commented May 12, 2017

Hi! That plugin in meant to work in a backend-agnostic way: it computes gain adjustments using any analysis tool and stores normalization results in a common format. I guess I don't quite understand why the Ogg Opus encapsulation standard's recommendation forbids other gain formats working also—is there a general reference for that idea aside from the MPD behavior?

If it make sense, we could consider using the R128 name too to maximize compatibility.

@autrimpo
Copy link
Contributor Author

To quote the linked RFC:

To avoid confusion with multiple normalization schemes, an Opus
comment header SHOULD NOT contain any of the REPLAYGAIN_TRACK_GAIN,
REPLAYGAIN_TRACK_PEAK, REPLAYGAIN_ALBUM_GAIN, or
REPLAYGAIN_ALBUM_PEAK tags, unless they are only to be used in some
context where there is guaranteed to be no such confusion.
[EBU-R128] normalization is preferred to the earlier REPLAYGAIN
schemes because of its clear definition and adoption by industry.
Peak normalizations are difficult to calculate reliably for lossy
codecs because of variation in excursion heights due to decoder
differences. In the authors' investigations, they were not applied
consistently or broadly enough to merit inclusion here.

There's also this message on the mailing list:

I can't remember if it's been said on the list before, but "true peak" is a meaningless concept for a lossy format with a non-bit-exact decoder specification, like Opus. The variation in the true peak calculation depending on your decoder implementation is theoretically unbounded. So you're guaranteed the value going into this tag is garbage.

When we first drafted this spec, we also conducted a survey of all open-source software we could find that supported ReplayGain tags. Exactly 0 programs did anything sensible with the peak tags. The most sensible thing anyone did was ignore them, which fortunately was the majority of them. By leaving them out entirely, we're making it easy for people to do the right thing.

I'm not sure if you mean adding both for every format or just Opus. I think the R128_ tags are Opus specific (again taking MPD as a reference and some light research) and thus make no sense in any other format. On the other hand adding both to Opus could potentially confuse badly written players (or just not following the spec) that accept both tags (as warned in the RFC).

@sampsyo
Copy link
Member

sampsyo commented May 12, 2017

Ah; thank you for pulling out both of those!

About dealing with this specific recommendation: Our tagging formats don't currently have any sensitivity to the underlying audio codec. That is, anything that uses Vorbis Comments gets tagged the same way. I get the sense that this would preclude implementing the right RFC-recommended policy here, yes?

It's also worth considering tools that do support REPLAYGAIN_* tags but not R128_* tags (i.e., the opposite of MPD). If we had a special case just for Opus, maybe this would be fine: we could hypothesize that any tool modern enough to support playing Opus will also support the new tags. But it would be worth validating that assumption a little bit.

Finally, the plugin can use multiple backends to compute normalization values. Would we be breaking the spec if we used mp3gain, for example, as our backend and then stuffed the results into R128_* tags?

@autrimpo
Copy link
Contributor Author

Again, quote from the RFC:

First, an optional gain for track normalization:
R128_TRACK_GAIN=-573
representing the volume shift needed to normalize the track's volume
during isolated playback, in random shuffle, and so on. The gain is
a Q7.8 fixed-point number in dB, as in the ID header's 'output gain'
field. This tag is similar to the REPLAYGAIN_TRACK_GAIN tag in
Vorbis [REPLAY-GAIN], except that the normal volume reference is the
[EBU-R128] standard.

which leads me to believe that using a replaygain backend and the values it produces indeed breaks the spec.

It is also worth noting that the R128_ tags have different format and semantics and a simple tag "renaming" is therefore not enough.

This is a gain to be applied when decoding. It is 20*log10 of
the factor by which to scale the decoder output to achieve the
desired playback volume, stored in a 16-bit, signed, two's
complement fixed-point value with 8 fractional bits (i.e.,
Q7.8 [Q-NOTATION]).
To apply the gain, an implementation could use the following:
sample *= pow(10, output_gain/(20.0*256))
where 'output_gain' is the raw 16-bit value from the header.

An Ogg Opus stream MUST NOT have more than one of each of these tags,
and, if present, their values MUST be an integer from -32768 to
32767, inclusive, represented in ASCII as a base 10 number with no
whitespace. A leading '+' or '-' character is valid. Leading zeros
are also permitted, but the value MUST be represented by no more than
6 characters. Other non-digit characters MUST NOT be present.

I do not know how other popular players besides MPD handle the Opus tags, but seeing as they are a fairly recent addition to the spec I'd expect at least some of the players to support REPLAYGAIN_ and not R128_, contrary to the spec.

Maybe a solution would be to create a new r128gain plugin, since that's quite a lot of "special case branches" just for Opus, and allow both of the plugins to have white/blacklists, if not by audio codec then at least by extension, so they could be used simultaneously with the auto option set and multiformat library. Then, if another codec pops up using the Opus-style gain tags, it's a simple addition to the default whitelist.

@sampsyo
Copy link
Member

sampsyo commented May 13, 2017

Got it; thanks! This really clarifies what we should do.

In general, I think we should probably pay closer attention in the plugin to the various standards and their corresponding tag storage formats. If this means separating the RG tags from new R128 tags everywhere in the beets interface, we should do that—and code choose which they want to fill.

I lean toward accomplishing this in one plugin, since I imagine that most of the infrastructure will be shared… but I definitely see why the two-plugin arrangement might make sense too, given the mounting stack of special cases.

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

2 participants