浏览代码

[raudio] Fix load and unload issues with Music (#1588)

* Add MUSIC_AUDIO_NONE to MusicContextType and format fixes
- Useful to check the context type to see if the format is recognized. Defaulting to wav causes issues where formats are assumed to
be wav.

* Fix memory issues with LoadMusicStream and UnloadMusicStream
- Set ctxType and ctxData even if the format fails to load.
- Set ctxData to NULL if it fails and check for null inside UnloadMusicStream.
- Change RL_MALLOC when loading formats to RL_CALLOC to prevent undefined behavior.
- Add NULL check when unloading xm file.
pull/1589/head
Chris 4 年前
committed by GitHub
父节点
当前提交
ccb083af52
找不到此签名对应的密钥 GPG 密钥 ID: 4AEE18F83AFDEB23
共有 2 个文件被更改,包括 38 次插入35 次删除
  1. +3
    -1
      src/external/jar_xm.h
  2. +35
    -34
      src/raudio.c

+ 3
- 1
src/external/jar_xm.h 查看文件

@ -696,7 +696,9 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
} }
void jar_xm_free_context(jar_xm_context_t* ctx) { void jar_xm_free_context(jar_xm_context_t* ctx) {
JARXM_FREE(ctx->allocated_memory);
if (ctx != NULL) {
JARXM_FREE(ctx->allocated_memory);
}
} }
void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt) { void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt) {

+ 35
- 34
src/raudio.c 查看文件

@ -275,7 +275,8 @@ typedef struct tagBITMAPINFOHEADER {
// NOTE: Depends on data structure provided by the library // NOTE: Depends on data structure provided by the library
// in charge of reading the different file types // in charge of reading the different file types
typedef enum { typedef enum {
MUSIC_AUDIO_WAV = 0,
MUSIC_AUDIO_NONE = 0,
MUSIC_AUDIO_WAV,
MUSIC_AUDIO_OGG, MUSIC_AUDIO_OGG,
MUSIC_AUDIO_FLAC, MUSIC_AUDIO_FLAC,
MUSIC_AUDIO_MP3, MUSIC_AUDIO_MP3,
@ -465,7 +466,7 @@ void InitAudioDevice(void)
ma_context_uninit(&AUDIO.System.context); ma_context_uninit(&AUDIO.System.context);
return; return;
} }
// Init dummy audio buffers pool for multichannel sound playing // Init dummy audio buffers pool for multichannel sound playing
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
{ {
@ -491,7 +492,7 @@ void CloseAudioDevice(void)
{ {
// Unload dummy audio buffers pool // Unload dummy audio buffers pool
// WARNING: They can be pointing to already unloaded data // WARNING: They can be pointing to already unloaded data
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
{ {
//UnloadAudioBuffer(AUDIO.MultiChannel.pool[i]); //UnloadAudioBuffer(AUDIO.MultiChannel.pool[i]);
if (AUDIO.MultiChannel.pool[i] != NULL) if (AUDIO.MultiChannel.pool[i] != NULL)
@ -502,7 +503,7 @@ void CloseAudioDevice(void)
RL_FREE(AUDIO.MultiChannel.pool[i]); RL_FREE(AUDIO.MultiChannel.pool[i]);
} }
} }
ma_mutex_uninit(&AUDIO.System.lock); ma_mutex_uninit(&AUDIO.System.lock);
ma_device_uninit(&AUDIO.System.device); ma_device_uninit(&AUDIO.System.device);
ma_context_uninit(&AUDIO.System.context); ma_context_uninit(&AUDIO.System.context);
@ -1112,9 +1113,9 @@ float *LoadWaveSamples(Wave wave)
for (unsigned int i = 0; i < wave.sampleCount; i++) for (unsigned int i = 0; i < wave.sampleCount; i++)
{ {
if (wave.sampleSize == 8) samples[i] = (float)(((unsigned char *)wave.data)[i] - 127)/256.0f;
else if (wave.sampleSize == 16) samples[i] = (float)(((short *)wave.data)[i])/32767.0f;
else if (wave.sampleSize == 32) samples[i] = ((float *)wave.data)[i];
if (wave.sampleSize == 8) samples[i] = (float)(((unsigned char *)wave.data)[i] - 127)/256.0f;
else if (wave.sampleSize == 16) samples[i] = (float)(((short *)wave.data)[i])/32767.0f;
else if (wave.sampleSize == 32) samples[i] = ((float *)wave.data)[i];
} }
return samples; return samples;
@ -1140,14 +1141,14 @@ Music LoadMusicStream(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_WAV) #if defined(SUPPORT_FILEFORMAT_WAV)
else if (IsFileExtension(fileName, ".wav")) else if (IsFileExtension(fileName, ".wav"))
{ {
drwav *ctxWav = RL_MALLOC(sizeof(drwav));
drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
bool success = drwav_init_file(ctxWav, fileName, NULL); bool success = drwav_init_file(ctxWav, fileName, NULL);
music.ctxType = MUSIC_AUDIO_WAV;
music.ctxData = ctxWav;
if (success) if (success)
{ {
music.ctxType = MUSIC_AUDIO_WAV;
music.ctxData = ctxWav;
int sampleSize = ctxWav->bitsPerSample; int sampleSize = ctxWav->bitsPerSample;
if (ctxWav->bitsPerSample == 24) sampleSize = 16; // Forcing conversion to s16 on UpdateMusicStream() if (ctxWav->bitsPerSample == 24) sampleSize = 16; // Forcing conversion to s16 on UpdateMusicStream()
@ -1162,11 +1163,11 @@ Music LoadMusicStream(const char *fileName)
else if (IsFileExtension(fileName, ".ogg")) else if (IsFileExtension(fileName, ".ogg"))
{ {
// Open ogg audio stream // Open ogg audio stream
music.ctxType = MUSIC_AUDIO_OGG;
music.ctxData = stb_vorbis_open_filename(fileName, NULL, NULL); music.ctxData = stb_vorbis_open_filename(fileName, NULL, NULL);
if (music.ctxData != NULL) if (music.ctxData != NULL)
{ {
music.ctxType = MUSIC_AUDIO_OGG;
stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData); // Get Ogg file info stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData); // Get Ogg file info
// OGG bit rate defaults to 16 bit, it's enough for compressed format // OGG bit rate defaults to 16 bit, it's enough for compressed format
@ -1182,11 +1183,11 @@ Music LoadMusicStream(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (IsFileExtension(fileName, ".flac")) else if (IsFileExtension(fileName, ".flac"))
{ {
music.ctxType = MUSIC_AUDIO_FLAC;
music.ctxData = drflac_open_file(fileName, NULL); music.ctxData = drflac_open_file(fileName, NULL);
if (music.ctxData != NULL) if (music.ctxData != NULL)
{ {
music.ctxType = MUSIC_AUDIO_FLAC;
drflac *ctxFlac = (drflac *)music.ctxData; drflac *ctxFlac = (drflac *)music.ctxData;
music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
@ -1199,15 +1200,14 @@ Music LoadMusicStream(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
else if (IsFileExtension(fileName, ".mp3")) else if (IsFileExtension(fileName, ".mp3"))
{ {
drmp3 *ctxMp3 = RL_MALLOC(sizeof(drmp3));
music.ctxData = ctxMp3;
drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
int result = drmp3_init_file(ctxMp3, fileName, NULL); int result = drmp3_init_file(ctxMp3, fileName, NULL);
music.ctxType = MUSIC_AUDIO_MP3;
music.ctxData = ctxMp3;
if (result > 0) if (result > 0)
{ {
music.ctxType = MUSIC_AUDIO_MP3;
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels); music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
music.sampleCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels; music.sampleCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels;
music.looping = true; // Looping enabled by default music.looping = true; // Looping enabled by default
@ -1219,12 +1219,13 @@ Music LoadMusicStream(const char *fileName)
else if (IsFileExtension(fileName, ".xm")) else if (IsFileExtension(fileName, ".xm"))
{ {
jar_xm_context_t *ctxXm = NULL; jar_xm_context_t *ctxXm = NULL;
int result = jar_xm_create_context_from_file(&ctxXm, 48000, fileName); int result = jar_xm_create_context_from_file(&ctxXm, 48000, fileName);
music.ctxType = MUSIC_MODULE_XM;
music.ctxData = ctxXm;
if (result == 0) // XM AUDIO.System.context created successfully if (result == 0) // XM AUDIO.System.context created successfully
{ {
music.ctxType = MUSIC_MODULE_XM;
jar_xm_set_max_loop_count(ctxXm, 0); // Set infinite number of loops jar_xm_set_max_loop_count(ctxXm, 0); // Set infinite number of loops
// NOTE: Only stereo is supported for XM // NOTE: Only stereo is supported for XM
@ -1233,30 +1234,26 @@ Music LoadMusicStream(const char *fileName)
music.looping = true; // Looping enabled by default music.looping = true; // Looping enabled by default
jar_xm_reset(ctxXm); // make sure we start at the beginning of the song jar_xm_reset(ctxXm); // make sure we start at the beginning of the song
musicLoaded = true; musicLoaded = true;
music.ctxData = ctxXm;
} }
} }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MOD) #if defined(SUPPORT_FILEFORMAT_MOD)
else if (IsFileExtension(fileName, ".mod")) else if (IsFileExtension(fileName, ".mod"))
{ {
jar_mod_context_t *ctxMod = RL_MALLOC(sizeof(jar_mod_context_t));
jar_mod_context_t *ctxMod = RL_CALLOC(1, sizeof(jar_mod_context_t));
jar_mod_init(ctxMod); jar_mod_init(ctxMod);
int result = jar_mod_load_file(ctxMod, fileName); int result = jar_mod_load_file(ctxMod, fileName);
music.ctxType = MUSIC_MODULE_MOD;
music.ctxData = ctxMod;
if (result > 0) if (result > 0)
{ {
music.ctxType = MUSIC_MODULE_MOD;
// NOTE: Only stereo is supported for MOD // NOTE: Only stereo is supported for MOD
music.stream = InitAudioStream(48000, 16, 2); music.stream = InitAudioStream(48000, 16, 2);
music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*2; // 2 channels music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*2; // 2 channels
music.looping = true; // Looping enabled by default music.looping = true; // Looping enabled by default
musicLoaded = true; musicLoaded = true;
music.ctxData = ctxMod;
} }
} }
#endif #endif
@ -1284,6 +1281,7 @@ Music LoadMusicStream(const char *fileName)
else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); } else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); }
#endif #endif
music.ctxData = NULL;
TRACELOG(LOG_WARNING, "FILEIO: [%s] Music file could not be opened", fileName); TRACELOG(LOG_WARNING, "FILEIO: [%s] Music file could not be opened", fileName);
} }
else else
@ -1304,25 +1302,28 @@ void UnloadMusicStream(Music music)
{ {
CloseAudioStream(music.stream); CloseAudioStream(music.stream);
if (false) { }
if (music.ctxData != NULL)
{
if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV) #if defined(SUPPORT_FILEFORMAT_WAV)
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL);
else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); } else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_XM) #if defined(SUPPORT_FILEFORMAT_XM)
else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData);
else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData);
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MOD) #if defined(SUPPORT_FILEFORMAT_MOD)
else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); }
else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); }
#endif #endif
}
} }
// Start music playing (open stream) // Start music playing (open stream)

正在加载...
取消
保存