1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-28 23:48:30 +02:00

Copy rest of music code to OGG sound effects

The missing piece from sound effects was handling what to do when the
buffer ran out. Which seems to happen often when decoding from OGG,
unlike WAV. This handling involves callbacks to functions named
refillReserve and swapBuffers.

Without this code,some sound effects would be cut off early, as
documented in #953. This might also explain the division by 20 - which
I've copied too, just in case.

Now OGG sound effect tracks should be identical to music tracks (except
I've stripped the looping code out).

Fixes #953.
This commit is contained in:
Misa 2023-03-28 20:48:43 -07:00
parent c36655d5c7
commit 09c07d8ad4

View File

@ -97,6 +97,7 @@ public:
{ {
unsigned char* mem; unsigned char* mem;
size_t length; size_t length;
voice_index = -1;
FILESYSTEM_loadAssetToMemory(fileName, &mem, &length); FILESYSTEM_loadAssetToMemory(fileName, &mem, &length);
if (mem == NULL) if (mem == NULL)
@ -110,6 +111,8 @@ public:
if (length >= 4 && SDL_memcmp(mem, "OggS", 4) == 0) if (length >= 4 && SDL_memcmp(mem, "OggS", 4) == 0)
{ {
LoadOGG(fileName, mem, length); LoadOGG(fileName, mem, length);
callbacks.OnBufferStart = &SoundTrack::refillReserve;
callbacks.OnBufferEnd = &SoundTrack::swapBuffers;
} }
else else
{ {
@ -160,8 +163,10 @@ end:
format.cbSize = 0; format.cbSize = 0;
channels = format.nChannels; channels = format.nChannels;
size = format.nAvgBytesPerSec; size = format.nAvgBytesPerSec / 20;
decoded_buf_playing = (Uint8*) SDL_malloc(size); decoded_buf_playing = (Uint8*) SDL_malloc(size);
decoded_buf_reserve = (Uint8*) SDL_malloc(size);
ogg_file = mem; ogg_file = mem;
valid = true; valid = true;
@ -172,6 +177,7 @@ end:
VVV_free(wav_buffer); VVV_free(wav_buffer);
VVV_free(decoded_buf_playing); VVV_free(decoded_buf_playing);
VVV_free(decoded_buf_reserve);
VVV_freefunc(stb_vorbis_close, vorbis); VVV_freefunc(stb_vorbis_close, vorbis);
VVV_free(ogg_file); VVV_free(ogg_file);
} }
@ -192,7 +198,14 @@ end:
if (SDL_memcmp(&voice_formats[i], &format, sizeof(format)) != 0) if (SDL_memcmp(&voice_formats[i], &format, sizeof(format)) != 0)
{ {
VVV_freefunc(FAudioVoice_DestroyVoice, voices[i]); VVV_freefunc(FAudioVoice_DestroyVoice, voices[i]);
FAudio_CreateSourceVoice(faudioctx, &voices[i], &format, 0, 2.0f, NULL, NULL, NULL); if (vorbis != NULL)
{
FAudio_CreateSourceVoice(faudioctx, &voices[i], &format, 0, 2.0f, &callbacks, NULL, NULL);
}
else
{
FAudio_CreateSourceVoice(faudioctx, &voices[i], &format, 0, 2.0f, NULL, NULL, NULL);
}
voice_formats[i] = format; voice_formats[i] = format;
} }
FAudioBuffer faudio_buffer = { FAudioBuffer faudio_buffer = {
@ -217,17 +230,21 @@ end:
); );
faudio_buffer.AudioBytes = size; faudio_buffer.AudioBytes = size;
faudio_buffer.pAudioData = decoded_buf_playing; faudio_buffer.pAudioData = decoded_buf_playing;
faudio_buffer.pContext = this;
} }
if (FAudioSourceVoice_SubmitSourceBuffer(voices[i], &faudio_buffer, NULL)) if (FAudioSourceVoice_SubmitSourceBuffer(voices[i], &faudio_buffer, NULL))
{ {
vlog_error("Unable to queue sound buffer"); vlog_error("Unable to queue sound buffer");
voice_index = -1;
return; return;
} }
FAudioVoice_SetVolume(voices[i], volume, FAUDIO_COMMIT_NOW); FAudioVoice_SetVolume(voices[i], volume, FAUDIO_COMMIT_NOW);
if (FAudioSourceVoice_Start(voices[i], 0, FAUDIO_COMMIT_NOW)) if (FAudioSourceVoice_Start(voices[i], 0, FAUDIO_COMMIT_NOW))
{ {
vlog_error("Unable to start voice processing"); vlog_error("Unable to start voice processing");
voice_index = -1;
} }
voice_index = i;
return; return;
} }
} }
@ -295,15 +312,52 @@ end:
} }
} }
static void refillReserve(FAudioVoiceCallback* callback, void* ctx)
{
bool inbounds;
SoundTrack* t = (SoundTrack*) ctx;
FAudioBuffer faudio_buffer;
SDL_zero(faudio_buffer);
UNUSED(callback);
faudio_buffer.PlayLength = stb_vorbis_get_samples_float_interleaved(t->vorbis, t->channels, (float*) t->decoded_buf_reserve, t->size / sizeof(float));
faudio_buffer.AudioBytes = t->size;
faudio_buffer.pAudioData = t->decoded_buf_reserve;
faudio_buffer.pContext = t;
if (faudio_buffer.PlayLength == 0)
{
return;
}
inbounds = t->voice_index >= 0 && t->voice_index < VVV_MAX_CHANNELS;
if (!inbounds)
{
return;
}
FAudioSourceVoice_SubmitSourceBuffer(voices[t->voice_index], &faudio_buffer, NULL);
}
static void swapBuffers(FAudioVoiceCallback* callback, void* ctx)
{
SoundTrack* t = (SoundTrack*) ctx;
Uint8* tmp = t->decoded_buf_playing;
UNUSED(callback);
t->decoded_buf_playing = t->decoded_buf_reserve;
t->decoded_buf_reserve = tmp;
}
Uint8 *wav_buffer; Uint8 *wav_buffer;
Uint32 wav_length; Uint32 wav_length;
FAudioWaveFormatEx format; FAudioWaveFormatEx format;
int voice_index;
unsigned char* ogg_file; unsigned char* ogg_file;
stb_vorbis* vorbis; stb_vorbis* vorbis;
int channels; int channels;
Uint32 size; Uint32 size;
Uint8* decoded_buf_playing; Uint8* decoded_buf_playing;
Uint8* decoded_buf_reserve;
FAudioVoiceCallback callbacks;
bool valid; bool valid;