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

Support MS ADPCM playback for files in Music/ game folder #710

Closed
fdelapena opened this Issue Jan 4, 2016 · 2 comments

Comments

Projects
None yet
1 participant
@fdelapena
Contributor

fdelapena commented Jan 4, 2016

SDL can play MS ADPCM WAV files, however SDL_mixer is not supporting them for music playback, however they can be played in a channel.

Because current file format detection is using SDL_Mixer to play music and files must be loaded first to detect the music type with SDL_LoadMUS_RW, mixer will return SDL_error about unknown WAVE data format. SDL_LoadWAV does not have audio type format

There is also a known double free crash bug in SDL_mixer when passing 1 value to automatically free the data source when calling SDL_LoadMUS_RW to detect the file format, which is the reason of the Yume 2kki or the game 星の海で crash as these games use MS ADPCM WAV files for music.

A simple workaround could be reading the first four bytes of the file to check WAV format before doing the bogus SDL_LoadMUS_RW detection then directly do the BGS_Play call when those first four bytes are "RIFF".

@fdelapena fdelapena added the Crash label Jan 4, 2016

@fdelapena fdelapena added this to the 0.4.1 milestone Jan 4, 2016

@fdelapena fdelapena added the Audio label Jan 4, 2016

@fdelapena

This comment has been minimized.

Contributor

fdelapena commented Jan 4, 2016

This patch allows to reproduce MS ADPCM:

diff --git a/src/platform/sdl_audio.cpp b/src/platform/sdl_audio.cpp
index c5d69f8..693b2ef 100644
--- a/src/platform/sdl_audio.cpp
+++ b/src/platform/sdl_audio.cpp
@@ -145,6 +145,21 @@ void SdlAudio::BGM_Play(std::string const& file, int volume, int /* pitch */, in
        }

        SDL_RWops *rw = SDL_RWFromFile(path.c_str(), "rb");
+
+       // SDL_mixer does not detect MS ADPCM in Mix_LoadMUS_RW
+       // and does not return the desired bgm structure to check the music type.
+       // To work around this, check valid WAV header and play BGS.
+       char header[4];
+       if (rw->read(rw, header, 4, 1) > 0) {
+               if (strncmp((char*)header, "RIFF", 4) == 0) {
+                       // SDL2_mixer bug, see above
+                       if (bgs_playing) {
+                               BGS_Stop();
+                       }
+                       BGS_Play(file, volume, 0, fadein);
+                       return;
+               }
+       }
 #if SDL_MIXER_MAJOR_VERSION>1
        bgm.reset(Mix_LoadMUS_RW(rw, 1), &Mix_FreeMusic);
 #else

However, fade out is not working properly because there is a bug in BGM_fade:

#if SDL_MAJOR_VERSION>1
    // SDL2_mixer bug, see above
    Mix_MusicType mtype = Mix_GetMusicType(bgm.get());
    if (mtype == MUS_WAV || mtype == MUS_OGG) {
        BGS_Fade(fade);
        return;
    }
#endif

Mix_GetMusicType() is getting the music type from the music special channel, which is not a normal channel. All WAV and OGG are being played from channels, if a game is not playing a WAV or an OGG in the music special channel, this bug will be hearable.

A solution would be reading again the file header from here or maybe a private class member to store the previously detected format. What do you suggest?

There is also an issue with midi playback due to this, it reports a nonsense error message:

Warning: Couldn't load [filename] BGM.
No SoundFonts have been requested

And a similar XAudio nonsense message on Win32.

@fdelapena

This comment has been minimized.

Contributor

fdelapena commented Feb 22, 2016

The crash can be worked around by passing 0 instead of 1 to SDL_LoadMUS_RW() and the free call is already done from the shared_ptr reset deleter parameter.

Warning: Couldn't load j17r BGM.
Unknown WAVE data format

Now it is easy to work around by getting the SDL_GetError() and call BGS_Play().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment