free audio voices properly

This commit is contained in:
Jamiras 2022-03-25 22:03:18 -06:00 committed by Autechre
parent 08c1c05f82
commit f63c11ebaf

View File

@ -183,13 +183,14 @@ struct audio_mixer_voice
unsigned type; unsigned type;
float volume; float volume;
bool repeat; bool repeat;
}; };
/* TODO/FIXME - static globals */ /* TODO/FIXME - static globals */
static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {0}; static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {0};
static unsigned s_rate = 0; static unsigned s_rate = 0;
static void audio_mixer_release(audio_mixer_voice_t* voice);
#ifdef HAVE_RWAV #ifdef HAVE_RWAV
static bool wav_to_float(const rwav_t* wav, float** pcm, size_t samples_out) static bool wav_to_float(const rwav_t* wav, float** pcm, size_t samples_out)
{ {
@ -319,7 +320,7 @@ void audio_mixer_done(void)
unsigned i; unsigned i;
for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++) for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++)
s_voices[i].type = AUDIO_MIXER_TYPE_NONE; audio_mixer_release(&s_voices[i]);
} }
audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size, audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size,
@ -562,14 +563,6 @@ static bool audio_mixer_play_ogg(
goto error; goto error;
} }
/* "system" menu sounds may reuse the same voice without freeing anything first, so do that here if needed */
if (voice->types.ogg.stream)
stb_vorbis_close(voice->types.ogg.stream);
if (voice->types.ogg.resampler && voice->types.ogg.resampler_data)
voice->types.ogg.resampler->free(voice->types.ogg.resampler_data);
if (voice->types.ogg.buffer)
memalign_free(voice->types.ogg.buffer);
voice->types.ogg.resampler = resamp; voice->types.ogg.resampler = resamp;
voice->types.ogg.resampler_data = resampler_data; voice->types.ogg.resampler_data = resampler_data;
voice->types.ogg.buffer = (float*)ogg_buffer; voice->types.ogg.buffer = (float*)ogg_buffer;
@ -585,6 +578,17 @@ error:
stb_vorbis_close(stb_vorbis); stb_vorbis_close(stb_vorbis);
return false; return false;
} }
static void audio_mixer_release_ogg(audio_mixer_voice_t* voice)
{
if (voice->types.ogg.stream)
stb_vorbis_close(voice->types.ogg.stream);
if (voice->types.ogg.resampler && voice->types.ogg.resampler_data)
voice->types.ogg.resampler->free(voice->types.ogg.resampler_data);
if (voice->types.ogg.buffer)
memalign_free(voice->types.ogg.buffer);
}
#endif #endif
#ifdef HAVE_IBXM #ifdef HAVE_IBXM
@ -642,12 +646,6 @@ static bool audio_mixer_play_mod(
goto error; goto error;
} }
/* FIXME: stopping and then starting a mod stream will crash here in dispose_replay (ASAN says struct replay is misaligned?) */
if (voice->types.mod.stream)
dispose_replay(voice->types.mod.stream);
if (voice->types.mod.buffer)
memalign_free(voice->types.mod.buffer);
voice->types.mod.buffer = (int*)mod_buffer; voice->types.mod.buffer = (int*)mod_buffer;
voice->types.mod.buf_samples = buf_samples; voice->types.mod.buf_samples = buf_samples;
voice->types.mod.stream = replay; voice->types.mod.stream = replay;
@ -664,6 +662,14 @@ error:
return false; return false;
} }
static void audio_mixer_release_mod(audio_mixer_voice_t* voice)
{
if (voice->types.mod.stream)
dispose_replay(voice->types.mod.stream);
if (voice->types.mod.buffer)
memalign_free(voice->types.mod.buffer);
}
#endif #endif
#ifdef HAVE_DR_FLAC #ifdef HAVE_DR_FLAC
@ -711,13 +717,6 @@ static bool audio_mixer_play_flac(
goto error; goto error;
} }
if (voice->types.flac.stream)
drflac_close(voice->types.flac.stream);
if (voice->types.flac.resampler && voice->types.flac.resampler_data)
voice->types.flac.resampler->free(voice->types.flac.resampler_data);
if (voice->types.flac.buffer)
memalign_free(voice->types.flac.buffer);
voice->types.flac.resampler = resamp; voice->types.flac.resampler = resamp;
voice->types.flac.resampler_data = resampler_data; voice->types.flac.resampler_data = resampler_data;
voice->types.flac.buffer = (float*)flac_buffer; voice->types.flac.buffer = (float*)flac_buffer;
@ -733,6 +732,16 @@ error:
drflac_close(dr_flac); drflac_close(dr_flac);
return false; return false;
} }
static void audio_mixer_release_flac(audio_mixer_voice_t* voice)
{
if (voice->types.flac.stream)
drflac_close(voice->types.flac.stream);
if (voice->types.flac.resampler && voice->types.flac.resampler_data)
voice->types.flac.resampler->free(voice->types.flac.resampler_data);
if (voice->types.flac.buffer)
memalign_free(voice->types.flac.buffer);
}
#endif #endif
#ifdef HAVE_DR_MP3 #ifdef HAVE_DR_MP3
@ -751,12 +760,6 @@ static bool audio_mixer_play_mp3(
const retro_resampler_t* resamp = NULL; const retro_resampler_t* resamp = NULL;
bool res; bool res;
if (voice->types.mp3.stream.pData)
{
drmp3_uninit(&voice->types.mp3.stream);
memset(&voice->types.mp3.stream, 0, sizeof(voice->types.mp3.stream));
}
res = drmp3_init_memory(&voice->types.mp3.stream, (const unsigned char*)sound->types.mp3.data, sound->types.mp3.size, NULL); res = drmp3_init_memory(&voice->types.mp3.stream, (const unsigned char*)sound->types.mp3.data, sound->types.mp3.size, NULL);
if (!res) if (!res)
@ -789,12 +792,6 @@ static bool audio_mixer_play_mp3(
goto error; goto error;
} }
/* "system" menu sounds may reuse the same voice without freeing anything first, so do that here if needed */
if (voice->types.mp3.resampler && voice->types.mp3.resampler_data)
voice->types.mp3.resampler->free(voice->types.mp3.resampler_data);
if (voice->types.mp3.buffer)
memalign_free(voice->types.mp3.buffer);
voice->types.mp3.resampler = resamp; voice->types.mp3.resampler = resamp;
voice->types.mp3.resampler_data = resampler_data; voice->types.mp3.resampler_data = resampler_data;
voice->types.mp3.buffer = (float*)mp3_buffer; voice->types.mp3.buffer = (float*)mp3_buffer;
@ -809,6 +806,17 @@ error:
drmp3_uninit(&voice->types.mp3.stream); drmp3_uninit(&voice->types.mp3.stream);
return false; return false;
} }
static void audio_mixer_release_mp3(audio_mixer_voice_t* voice)
{
if (voice->types.mp3.resampler && voice->types.mp3.resampler_data)
voice->types.mp3.resampler->free(voice->types.mp3.resampler_data);
if (voice->types.mp3.buffer)
memalign_free(voice->types.mp3.buffer);
if (voice->types.mp3.stream.pData)
drmp3_uninit(&voice->types.mp3.stream);
}
#endif #endif
audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,
@ -829,6 +837,9 @@ audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,
if (voice->type != AUDIO_MIXER_TYPE_NONE) if (voice->type != AUDIO_MIXER_TYPE_NONE)
continue; continue;
/* claim the voice, also helps with cleanup on error */
voice->type = sound->type;
switch (sound->type) switch (sound->type)
{ {
case AUDIO_MIXER_TYPE_WAV: case AUDIO_MIXER_TYPE_WAV:
@ -866,18 +877,55 @@ audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,
if (res) if (res)
{ {
voice->type = sound->type;
voice->repeat = repeat; voice->repeat = repeat;
voice->volume = volume; voice->volume = volume;
voice->sound = sound; voice->sound = sound;
voice->stop_cb = stop_cb; voice->stop_cb = stop_cb;
} }
else else
{
audio_mixer_release(voice);
voice = NULL; voice = NULL;
}
return voice; return voice;
} }
static void audio_mixer_release(audio_mixer_voice_t* voice)
{
if (!voice)
return;
switch (voice->type)
{
#ifdef HAVE_STB_VORBIS
case AUDIO_MIXER_TYPE_OGG:
audio_mixer_release_ogg(voice);
break;
#endif
#ifdef HAVE_IBXM
case AUDIO_MIXER_TYPE_MOD:
audio_mixer_release_mod(voice);
break;
#endif
#ifdef HAVE_DR_FLAC
case AUDIO_MIXER_TYPE_FLAC:
audio_mixer_release_flac(voice);
break;
#endif
#ifdef HAVE_DR_MP3
case AUDIO_MIXER_TYPE_MP3:
audio_mixer_release_mp3(voice);
break;
#endif
default:
break;
}
memset(&voice->types, 0, sizeof(voice->types));
voice->type = AUDIO_MIXER_TYPE_NONE;
}
void audio_mixer_stop(audio_mixer_voice_t* voice) void audio_mixer_stop(audio_mixer_voice_t* voice)
{ {
audio_mixer_stop_cb_t stop_cb = NULL; audio_mixer_stop_cb_t stop_cb = NULL;
@ -888,7 +936,7 @@ void audio_mixer_stop(audio_mixer_voice_t* voice)
stop_cb = voice->stop_cb; stop_cb = voice->stop_cb;
sound = voice->sound; sound = voice->sound;
voice->type = AUDIO_MIXER_TYPE_NONE; audio_mixer_release(voice);
if (stop_cb) if (stop_cb)
stop_cb(sound, AUDIO_MIXER_SOUND_STOPPED); stop_cb(sound, AUDIO_MIXER_SOUND_STOPPED);
@ -928,7 +976,7 @@ again:
if (voice->stop_cb) if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE; audio_mixer_release(voice);
} }
else else
{ {
@ -974,7 +1022,7 @@ again:
if (voice->stop_cb) if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE; audio_mixer_release(voice);
goto cleanup; goto cleanup;
} }
@ -1052,7 +1100,7 @@ again:
if (voice->stop_cb) if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE; audio_mixer_release(voice);
return; return;
} }
@ -1116,7 +1164,7 @@ again:
if (voice->stop_cb) if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE; audio_mixer_release(voice);
return; return;
} }
@ -1187,7 +1235,7 @@ again:
if (voice->stop_cb) if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED); voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE; audio_mixer_release(voice);
return; return;
} }