libsdl-org / SDL_mixer

An audio mixer that supports various file formats for Simple Directmedia Layer.
zlib License
432 stars 147 forks source link

Mix_Chunk sound is buggy and broken (in Windows11) #466

Closed GabrielFrigo4 closed 1 year ago

GabrielFrigo4 commented 2 years ago

I was using version 2.0.4 of SDL_mixer and everything worked correctly, after I changed to 2.6.2 the sounds that come out when I play the mix_chunk come out all broken and buggy... but when I all a mix_music everything works correctly... edit1: In addition to these errors, which are generalized to any sound .wav file, also had 1 file .wav (Name: RetroGame.wav, is on github along with all the code) which approximately 10% of the time that started the app, the "Mix_LoadWAV" function of the error saying that "attempt to write protected memory"

I am using C#, but I am confident that this is not the problem, here is my program code:

to facilitate c# code analysis, translations of c# links have some changes such as Mix_Chunk ==> Chunk and MixChunk* ==> PChunk 
and the functions that returned MixChunk* were changed to the last argument of them to be a reference of the returned argument...
function(..., out chunck)
using SDL_Sharp.Mixer;
using System;

namespace SDL_PLUS_EXTENSIONS;
class SoundChunk
{
    PChunk chunk;
    int volume = MIX.MAX_VOLUME;

    public static SoundChunk CreateSoundChunk(string path)
    {
        return new SoundChunk(path);
    }

    SoundChunk(string path)
    {
        MIX.LoadWAV(path, out chunk);
        //Console.WriteLine(MIX.GetError());
        if (chunk.IsNull)
            throw new Exception("PChunk not create");
        MIX.VolumeChunk(chunk, volume);
    }

    public void Play(int loop)
    {
        if (MIX.PlayChannel(0, chunk, loop) == -1)
        {
            Console.WriteLine(MIX.GetError());
        }
    }

    public void SetVolume(int volume)
    {
        this.volume = volume;
        MIX.VolumeChunk(chunk, volume);
    }

    ~SoundChunk()
    {
        MIX.FreeChunk(chunk);
    }
}

class SoundMusic
{
    public Music music;
    public static SoundMusic CurrentMusic { get; private set; }

    static int volume = MIX.MAX_VOLUME;
    public static int CurrentVolume { get => volume; }

    public static SoundMusic CreateSoundMusic(string path)
    {
        return new SoundMusic(path);
    }

    SoundMusic(string path)
    {
        music = MIX.LoadMUS(path);
        if (music.IsNull)
            throw new Exception("Music not create");
    }

    public static void PlayMusic(SoundMusic music, int loop)
    {
        CurrentMusic = music;
        if (MIX.PlayMusic(music.music, loop) == -1)
        {
            Console.WriteLine(MIX.GetError());
        }
    }

    public static void SetVolume(int volume)
    {
        SoundMusic.volume = volume;
        MIX.VolumeMusic(SoundMusic.volume);
    }

    ~SoundMusic()
    {
        MIX.FreeMusic(music);
    }
}
static void Main(){
...
        SDL.Init(SdlInitFlags.Video | SdlInitFlags.Video);
        MIX.Init(MixInitFlags.Mod);
        const int audio_buffer = 4096;
        MIX.OpenAudio(MIX.DEFAULT_FREQUENCY, MIX.DEFAULT_FORMAT, MIX.DEFAULT_CHANNELS, audio_buffer);
        MIX.AllocateChannels(MIX.CHANNELS);
        //Init SDL/Image/Mixer/Ttf

        SoundMusic soundMusic = SoundMusic.CreateSoundMusic("./Files/MUSIC.wav");
        SoundMusic.SetVolume(8);
        SoundMusic.PlayMusic(soundMusic, -1);

        SoundChunk soundChunk = SoundChunk.CreateSoundChunk("./Files/RetroGame.wav");
        soundChunk.SetVolume(32);
        soundChunk.Play(3);
... loop ...
        MIX.CloseAudio();
        MIX.Quit();
}

edit2: c++ code (continues with the same error)

#include <iostream>
#include "SDL2/SDL.h"
#include "SDL2/SDL_mixer.h"

int SDL_main(int argc, char* args[]) {
    std::cout << "app start" << std::endl;

    SDL_Init(SDL_INIT_EVERYTHING);
    Mix_Init(MIX_INIT_MOD);
    std::cout << "SDL_Init && Mix_Init" << std::endl;

    const int audio_buffer = 4096;
    Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, audio_buffer);
    Mix_AllocateChannels(MIX_CHANNELS);
    std::cout << "Mixer Open" << std::endl;

    Mix_Chunk* chunk;
    chunk = Mix_LoadWAV("./MUSIC.wav");
    Mix_VolumeChunk(chunk, MIX_MAX_VOLUME);
    std::cout << "Mix_Chunk Load" << std::endl;

    Mix_PlayChannel(0, chunk, -1);

    bool loop = true;
    while (loop) { /* loop */ }

    Mix_FreeChunk(chunk);
    SDL_Quit();
    Mix_Quit();

    return 0;
}

What is wrong with this code? The complete code for this program is on github: https://github.com/GabrielFrigo4/SDL-Sharp/tree/master/Exemples/SDL_EXTENSIONS

(This is my first time I do an issue, any error or lack of information warns me that I fix)

akrieger commented 2 years ago

+1 this also manifests in broken sounds in Cataclysm-DDA (static/squeaking/buzzing). https://github.com/CleverRaven/Cataclysm-DDA/issues/61889 The issue seems related to WAV files as users have reported that reencoding the sound files as .ogg mitigates the problem. I can confirm it reproduces on Windows 10.

The relevant source is at https://github.com/CleverRaven/Cataclysm-DDA/blob/master/src/sdlsound.cpp

a-hurst commented 2 years ago

I've also run into this with PySDL2 but didn't report upstream since I couldn't be sure it wasn't a Python -> C bug. Basically WAV files get distorted and sometimes cause memory-related exceptions, but only on Windows (Windows 10 64-bit, runs fine on macOS and Linux), only for WAV files (MP3 and OGG are fine) and only if using SDL2 2.24.0 or newer along with mixer 2.6.x: if I revert to using SDL2 2.0.22 with mixer 2.6.x the issue goes away.

I tried making a minimum reproducible example script to show the bug, but WAV files that caused exceptions on load within my actual code load fine in a dedicated test script, so I'm assuming it some sort of unpredictable memory bug.

akrieger commented 2 years ago

Any updates here?

slouken commented 2 years ago

Does it work better with SDL 2.26.0?

akrieger commented 2 years ago

It may take me some time to validate because I have to figure out how to correctly rev the vcpkg port version. I'm not entirely sure why SDL 2.26.0 would make a difference if sdl-mixer didn't update though.

icculus commented 2 years ago

why SDL 2.26.0 would make a difference if sdl-mixer didn't update though.

Because SDL_mixer uses SDL's resampler, and we made fixes to SDL's resampler in 2.26.0.

a-hurst commented 2 years ago

@slouken @icculus Still having issues with SDL 2.26.0, though things seem to be a little different than with 2.24: I'm no longer getting semi-random access violations when loading WAVs into Mix_Chunks, but once loaded and played back the audio still has weird and gitchy/scratchy distortions of varying intensity throughout. If I switch the SDL2 binary back to 2.0.22 with the same 2.6.0 Mixer binary, everything plays back fine.

Actually, didn't the default sample rate on Windows change from 44100 in SDL 2.0.22 to 48000 in SDL 2.24? My WAVs are 44100 so they wouldn't have gone through the resampler before 2.24. On Linux and macOS SDL2 still seems to default to 44100 so that might be why it seems like a Windows-only issue.

The problem WAV files SDL's glitching with can be found here, if that's helpful. I already fixed the issue in my code by encoding the instruction WAVs to MP3 (which work perfectly fine with SDL >= 2.24 regardless of OS), but they might be helpful for debugging on your end.

akrieger commented 1 year ago

Could https://github.com/libsdl-org/SDL/commit/1e5e8e2fda3796e76e6f7b1c39683925a3e9fed9 resolve this?

GabrielFrigo4 commented 1 year ago

Could libsdl-org/SDL@1e5e8e2 resolve this?

I tested with the most recent view of vcpkg, which was 2.6.3, and in that verific the error persists

akrieger commented 1 year ago

sdl-mixer 2.6.3 / sdl2 2.26.3 was released two weeks prior to that commit being authored, and it does not appear to have been backported to the 2.26.x release branch. I'll try to point vcpkg at my fork and test against that commit.

icculus commented 1 year ago

The referenced commit isn't in a release of SDL yet.

akrieger commented 1 year ago

I backported libsdl-org/SDL@1e5e8e2 to the 2.26.3 release branch, created a new tag of that branch in my fork, modified my local vcpkg checkout to reference my fork and that tag, and the audio distortion did not manifest. It seems that is sufficient to (partially) resolve this (for amd64 cpus at least). Can that be cherry-picked to 2.26.x @slouken ?

icculus commented 1 year ago

It's already in the SDL2 branch, so next release will resolve this.