openal-soft icon indicating copy to clipboard operation
openal-soft copied to clipboard

Runaway compounding volume when playing sound concurrently with WASAPI & WINMM backends

Open Gegy opened this issue 2 years ago • 6 comments

Hello! We discovered this issue while investigating MC-260604. Warning: extremely loud and distorted sounds!

https://github.com/kcat/openal-soft/assets/5172118/5060f349-f8a1-42eb-a14f-5c927aaa5271

When certain sounds are played many times concurrently, the volume slowly begins to increase with major distortion effects. This runaway compounding volume effect applies not only to the sounds played through OpenAL, but all system sounds. The effect is pretty dramatic!

This issue was introduced to Minecraft when upgrading to LWJGL 3.3.0 from 3.2.2. This version change included a bump from OpenAL Soft 1.19.1 to 1.21.1, in which time this issue seems to have started occurring.

We managed to isolate the case to certain sound files, particularly dig/wood1.ogg. We further isolated this case to a small reproduction, based on the alplay.c example:

ALuint buffer = LoadSound("wood1.ogg");
ALuint active_sources[64] = {0};
while (1)
{
    for (int i = 0; i < 64; i++)
    {
        ALuint source = active_sources[i];
        if (source)
        {
            ALuint state = 0;
            alGetSourcei(source, AL_SOURCE_STATE, &state);
            if (state != AL_PLAYING)
            {
                active_sources[i] = 0;
                alDeleteSources(1, &source);
                source = 0;
            }
        }
        if (!source)
        {
            alGenSources(1, &source);
            active_sources[i] = source;
            alSourcei(source, AL_BUFFER, (ALint)buffer);
            alSourcePlay(source);
        }
    }
}

This was tested against https://github.com/kcat/openal-soft/commit/4bfbdbf62dee4cf6c8658da9f2872f5d5e98eddb with the wasapi backend on Windows.

From here, through various struggles with Windows toolchains, we managed to bisect the issue to https://github.com/kcat/openal-soft/commit/e9b41d9b90407285dd5fc74165051af907608d7e, where the ALC_OUTPUT_LIMITER_SOFT property was changed from being on to off by default. This hints towards a very reasonable workaround on the game side, which seems to resolve the issue. However, we wanted to report this issue here too in the case that there might be something that can be discovered from it. 🙂

From investigating a bit further, we found that this issue occurs with the wasapi/winmm backends on Windows, but does not with the dsound or wave backend. It also only seems to occur when using headphones, but it's possible that this is device-specific rather than related to the type of device.

Thank you for your time, and your amazing work maintaining this library!

Gegy avatar May 25 '23 14:05 Gegy

Huh, that's interesting. It's always been my experience that Windows has a built-in gain limiter, so even with OpenAL Soft's off, the system one should kick in and keep the volume down still. Perhaps it's failing with such high amplitudes, or something else is causing it to misbehave.

Something I noticed in the waveform is the samples appear to be wrapping; as the sample amplitude rises to and reaches max, it shoots down to the minimum and continues rising (and afterward on the other side, when it goes down and reaches the minimum, it shoots back up to the max and continues going down). That's not OpenAL Soft's doing, which optionally applies its gain limiter, then either clamps samples for integer output (preventing such wrapping) or outputs the samples as-is for floating-point output (where it's up to the system to handle).

kcat avatar May 25 '23 19:05 kcat

Interestingly I'm getting a similar behavior with openal-soft version 1.22.2. (I'm using the vcpkg version, it's slightly out of date)

I also have code mostly based off of the alplay.c tutorial. I'm using the same buffer, but different sources, to play a sound every 10th of a second(100 milleseconds). When multiple start playing it starts sounding glitchy somewhat like the video sent by Gegy, unless I wait until many of the sounds are completed and then deleted.(The sound file is 6 seconds long, but half of it is silence)

It doesn't get super loud like Gegy's video, but it is distorted, and eventually there's almost no sound, it's just random clipping.

I can send the audio and my code if needed, let me know if you need any more details as well. I tested my audio file playing at the same rate with irrKlang, and it sounds perfectly fine.

Kai-Indiemade avatar Jun 22 '23 04:06 Kai-Indiemade

I decided to record the audio, as you can see it happens within just a few seconds of me starting to play the sound:

https://github.com/kcat/openal-soft/assets/29464461/25ff477e-72a1-40c7-809c-c477bc750344

I use the alplay.c tutorial code for the sound loading, but I made my own "Sound" class(in cpp) so that I can play multiple at once. I am passing in the same buffer to each Sound object, but of course making a new source for each one.

When the sound is finished playing I delete it, which in the destructor also deletes the source (with alDeleteSources(1, &source);)

Here's how I check if it's finished, similar to how it's done in the example. ` alGetSourcei(source, AL_SOURCE_STATE, &state);

alGetSourcef(source, AL_SEC_OFFSET, &offset);

if (alGetError() != AL_NO_ERROR || state != AL_PLAYING) {

finished = true;

}`

Kai-Indiemade avatar Jun 22 '23 18:06 Kai-Indiemade

That seems to be a different issue. The sound is cutting out, as if it's overloaded and underrunning with too many sources, as opposed to the original issue where it got too loud and started clipping or wrapping. It would probably be better to make a separate issue for your problem, and I'd need to see a trace log to get an idea of what's going on.

kcat avatar Jun 22 '23 18:06 kcat

Thank you, I've moved it to a new issue: https://github.com/kcat/openal-soft/issues/865

Kai-Indiemade avatar Jun 22 '23 19:06 Kai-Indiemade