Strategy to play songs at same volume

Started by jllodra, January 14, 2022, 15:19:09

Previous topic - Next topic

jllodra

Hi. I have noticed that one of the things that annoy me when I play different songs (using libopenmpt), is that I need to manually adjust speaker's volume. Not all the times, but some times.

I would like to know how feasible would be to minimize this issue.

First question I have is: Is there anything in the lib itself I can use that automagically helps? Eg: Normalization? RMS calculation? ReplayGain?

If not, would be a good idea to analyze the PCM outputted by libopenmpt and do some kind of algorithm (which is unknown to me at this moment) to calculate a "replay gain" value in dB.
Or... instead of having to do any offline calculation, would a compressor and limiter help? or would that make it worse?

What is your opinion about it?

Thank you.

manx

Quote from: jllodra on January 14, 2022, 15:19:09
Hi. I have noticed that one of the things that annoy me when I play different songs (using libopenmpt), is that I need to manually adjust speaker's volume. Not all the times, but some times.

The underlying problem here is that a lot of trackers and thus their formats originally had no concept of intended playback volume and/or a precise definition of how loud the mixer is supposed to mix things. Thus what libopenmpt does is best described as a "guess the happens to work for most modules". Some formats specify the intended volume rendering precisely (or their original trackers make it easy to figure out), but even that can only guarantee that you will hear it as loud as the artist made it, which may and will differ from "every track at the same perceived volume". The same applies to any other audio format like e.g. MP3. However for MP3 (and CD), most tracks have just been brick-wall limited to 0dBfs, which makes them sound mostly equally loud.

Quote from: jllodra on January 14, 2022, 15:19:09
First question I have is: Is there anything in the lib itself I can use and automagically helps? Eg: Normalization? RMS calculation? ReplayGain?

Currently not, however there is already an issue filed as https://bugs.openmpt.org/view.php?id=1080

Quote from: jllodra on January 14, 2022, 15:19:09
If not, would be a good idea to analyze the PCM outputted by libopenmpt and do some kind of algorithm (which is unknown to me at this moment) to calculate a "replay gain" value in dB.

Yes, and that is what I would consider the proper solution. The most modern volume normalization standard would be EBU R 128, but in spirit, ReplayGain has the same goal.

I have to say that I am not a big fan of integrating a solution into libopenmpt, because that can only ever solve the problems for modules supported by libopenmpt, and not for any other format supported by any particular player. To solve that, any player would have to implement EBU R128 or ReplayGain anyway, at which point libopenmpt normalization would be superfluous.

Quote from: jllodra on January 14, 2022, 15:19:09
Or... instead of having to do any offline calculation, would a compressor and limiter help? or it would make it worse?

Yes, that would be a possible solution for live playback without having to check the whole file first. A combination of a slow moving automatic-gain-control with some kind of hard-limiter would probably yield the best results here.

jllodra

Thank you for answering and providing such good information.

I have been applying just now the "EBU R128 (ITU-R BS.1770) algorithm" to a collection of modules (different formats and styles, xm, it, chiptunes and doskpop...).
I used openmpt123 to convert into PCM and then used bs1770gain to rewrite the wav files with the applied LU (dB).
The results are extremely gratifying.

I will be exploring the automatic gain plus hard limiter too, since it can be applied in realtime, and decide.


manx

#3
Quote from: jllodra on January 14, 2022, 16:15:45
Thank you for answering and providing such good information.

You're welcome!

Quote from: jllodra on January 14, 2022, 16:15:45
I have been applying just now the "EBU R128 (ITU-R BS.1770) algorithm" to a collection of modules (different formats and styles, xm, it, chiptunes and doskpop...).
I used openmpt123 to convert into PCM and then used bs1770gain to rewrite the wav files with the applied LU (dB).
The results are extremely gratifying.

I guess we could add R128 normalization to openmpt123, however that would introduce a significant processing overhead when loading a module, which is probably not desirable in the general case. Maybe it's better to leave that to more sophisticated players that can cache loudness information in a database.
The batch processing you have done is of course fine if suitable to your use case.

Quote from: jllodra on January 14, 2022, 16:15:45
I will be exploring the automatic gain plus hard limiter too, since it can be applied in realtime, and decide.

Any automatic gain control (which basically is a slow-moving compressor) will always introduce some kind of long-term volume pumping. I would only consider that as a solution if prior offline analysis and applying R128gain is really not possible in your use case.

Saga Musix

One thing to keep in mind that applies to modules just as well as streamed albums: Sometimes it doesn't make sense to normalize all tracks to the same volume because they might be part of a set of tunes that are supposed to be played in a gapless manner. This was somewhat common especially in the heyday of the Amiga when people wanted to write longer tracks with many different samples, as a way to exceed ProTracker's limitation of 31 samples. Some musicdisks work that way. In this case, you want to normalize the whole set of tunes using the same factor. Hence there are separate ReplayGain values for single tracks and albums. Depending on what you want to achieve, this may be relevant for your module playback as well.
» No support, bug reports, feature requests via private messages - they will not be answered. Use the forums and the issue tracker so that everyone can benefit from your post.

manx

Quote from: Saga Musix on January 14, 2022, 17:37:37
One thing to keep in mind that applies to modules just as well as streamed albums: Sometimes it doesn't make sense to normalize all tracks to the same volume because they might be part of a set of tunes that are supposed to be played in a gapless manner. This was somewhat common especially in the heyday of the Amiga when people wanted to write longer tracks with many different samples, as a way to exceed ProTracker's limitation of 31 samples. Some musicdisks work that way. In this case, you want to normalize the whole set of tunes using the same factor. Hence there are separate ReplayGain values for single tracks and albums. Depending on what you want to achieve, this may be relevant for your module playback as well.

And this is also a reason why such functionality is likely better suited for a player, which can have knowledge about collections of songs that are supposed to have consistent relative volume. libopenmpt itself could only ever do that for a single module at a time. For modules with subsongs, libopenmpt could do both (individual subsongs, as well as the whole module).

Saga Musix

True, and that's why I wouldn't want to implement a complete ReplayGain or R128 normalization in libopenmpt. However, sometimes "I just want all tracks to be roughly equally loud" is a valid use case, and a user of the library may not have the possibility to cache the whole track output upfront for ReplayGain calculation, and it would be considerably more expensive to do this than a simple approximation, so I still think that an optional feature for this makes sense. It would often be better than having no such option at all.
» No support, bug reports, feature requests via private messages - they will not be answered. Use the forums and the issue tracker so that everyone can benefit from your post.

jllodra

Quote from: Saga Musix on January 14, 2022, 17:43:14
True, and that's why I wouldn't want to implement a complete ReplayGain or R128 normalization in libopenmpt. However, sometimes "I just want all tracks to be roughly equally loud" is a valid use case, and a user of the library may not have the possibility to cache the whole track output upfront for ReplayGain calculation, and it would be considerably more expensive to do this than a simple approximation, so I still think that an optional feature for this makes sense. It would often be better than having no such option at all.

The more I think about it, the more I agree with your point.

Is your normalization patch https://bugs.openmpt.org/view.php?id=1080 working for the current trunk? I am curious to see how it sounds compared to EBU or replaygain. If I understand correctly you are doing something similar, but faster.

Saga Musix

It should be applicable, maybe with minor modifications. Nothing fundamental should have changed in libopenmpt since I wrote it. I will look into it in a bit.

From my understanding ReplayGain and R128 are both more advanced and take psychoacoustics into account. My approach is a simple normalization, which will for example not care if the peak volume is held across the whole track or it's just 10 milliseconds of audio that are super loud. ReplayGain wouldn't reduce the volume of the whole track because of such a short event, as far as I understand.
» No support, bug reports, feature requests via private messages - they will not be answered. Use the forums and the issue tracker so that everyone can benefit from your post.