From 92fdc4753b448b3db08a2d5df522b56fbbe77dce Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Wed, 27 Oct 2021 11:41:04 -0700 Subject: [PATCH] fix audio buffer stutter + add pass filter API --- src/FAudioGMS.c | 186 ++++++++++++++++++++++++++++-------------------- src/FAudioGMS.h | 3 + 2 files changed, 111 insertions(+), 78 deletions(-) diff --git a/src/FAudioGMS.c b/src/FAudioGMS.c index ec52132..4a84822 100644 --- a/src/FAudioGMS.c +++ b/src/FAudioGMS.c @@ -257,7 +257,7 @@ static const float DOPPLER_SCALE = 1.0f; static const uint32_t MINIMUM_BUFFER_CHECK = 3; #define MAX_BUFFER_QUEUE_COUNT 16 -#define STREAMING_BUFFER_SIZE 1024 * 128 * sizeof(float) /* FIXME: what should this value be? */ +#define STREAMING_BUFFER_SIZE 1024 * 8 * sizeof(float) /* FIXME: what should this value be? */ typedef struct FAudioGMS_Device { @@ -645,6 +645,16 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetLowPassFilter(FAudioGMS_SoundIns instance->lowPassFilter = lowPassFilter; } +void FAudioGMS_SoundInstance_SetLowPassFilter(double soundInstanceID, float lowPassFilter) +{ + FAudioGMS_SoundInstance *instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)soundInstanceID); + + if (instance != NULL) + { + FAudioGMS_INTERNAL_SoundInstance_SetLowPassFilter(instance, lowPassFilter); + } +} + static void FAudioGMS_INTERNAL_SoundInstance_SetHighPassFilter(FAudioGMS_SoundInstance* instance, float highPassFilter) { FAudioFilterParameters p; @@ -657,6 +667,16 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetHighPassFilter(FAudioGMS_SoundIn instance->highPassFilter = highPassFilter; } +void FAudioGMS_SoundInstance_SetHighPassFilter(double soundInstanceID, float highPassFilter) +{ + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)soundInstanceID); + + if (instance != NULL) + { + FAudioGMS_INTERNAL_SoundInstance_SetHighPassFilter(instance, highPassFilter); + } +} + static void FAudioGMS_INTERNAL_SoundInstance_SetBandPassFilter(FAudioGMS_SoundInstance* instance, float bandPassFilter) { FAudioFilterParameters p; @@ -669,6 +689,16 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetBandPassFilter(FAudioGMS_SoundIn instance->bandPassFilter = bandPassFilter; } +void FAudioGMS_SoundInstance_SetBandPassFilter(double soundInstanceID, float bandPassFilter) +{ + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)soundInstanceID); + + if (instance != NULL) + { + FAudioGMS_INTERNAL_SoundInstance_SetBandPassFilter(instance, bandPassFilter); + } +} + static void FAudioGMS_INTERNAL_SoundInstance_SetPan(FAudioGMS_SoundInstance* instance, float pan) { instance->pan = pan; @@ -713,6 +743,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetPitch(FAudioGMS_SoundInstance* i static void FAudioGMS_INTERNAL_SoundInstance_SetVolume(FAudioGMS_SoundInstance* instance, float volume) { + instance->volume = volume; FAudioVoice_SetVolume(instance->handle, volume, 0); } @@ -852,6 +883,80 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_CreateFromStati return instance; } +static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* instance) +{ + /* NOTE: this function returns samples per channel, not total samples */ + uint32_t samples = stb_vorbis_get_samples_float_interleaved( + instance->soundData.streamingSound.fileHandle, + instance->format.nChannels, + device->streamStagingBuffer, + STREAMING_BUFFER_SIZE + ); + + uint32_t sampleCount = samples * instance->format.nChannels; + uint32_t bufferLength = sampleCount * sizeof(float); + + uint8_t* nextBuffer = SDL_malloc(bufferLength); + SDL_memcpy(nextBuffer, device->streamStagingBuffer, bufferLength); + + BufferQueue_Enqueue(&instance->soundData.streamingSound.bufferQueue, nextBuffer); + + FAudioBuffer buffer; + buffer.AudioBytes = bufferLength; + buffer.pAudioData = nextBuffer; + buffer.PlayLength = + bufferLength / + instance->format.nChannels / + (instance->format.wBitsPerSample / 8); + buffer.PlayBegin = 0; + + buffer.Flags = 0; + buffer.LoopBegin = 0; + buffer.LoopCount = 0; + buffer.LoopLength = 0; + buffer.pContext = NULL; + + FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &buffer, NULL); + + /* We have reached the end of the file! */ + if (sampleCount < STREAMING_BUFFER_SIZE) + { + if (instance->loop) + { + stb_vorbis_seek_start(instance->soundData.streamingSound.fileHandle); + } + else + { + instance->soundState = SoundState_Stopped; + } + } +} + +static void FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(FAudioGMS_SoundInstance* instance) +{ + uint32_t i; + FAudioVoiceState voiceState; + + if (instance->isStatic) { return; } + + FAudioSourceVoice_GetState( + instance->handle, + &voiceState, + FAUDIO_VOICE_NOSAMPLESPLAYED + ); + + while (instance->soundData.streamingSound.bufferQueue.count > voiceState.BuffersQueued) + { + uint8_t* buffer = BufferQueue_Dequeue(&instance->soundData.streamingSound.bufferQueue); + SDL_free(buffer); + } + + for (i = MINIMUM_BUFFER_CHECK - instance->soundData.streamingSound.bufferQueue.count; i > 0; i -= 1) + { + FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); + } +} + double FAudioGMS_StreamingSound_LoadOGG(char* filePath) { int error = 0; @@ -876,6 +981,8 @@ double FAudioGMS_StreamingSound_LoadOGG(char* filePath) instance->soundData.streamingSound.info = info; BufferQueue_Init(&instance->soundData.streamingSound.bufferQueue, MAX_BUFFER_QUEUE_COUNT); + FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance); + return instance->id; } @@ -920,83 +1027,6 @@ static void FAudioGMS_INTERNAL_StaticSound_AddEmitter(FAudioGMS_SoundInstance* i FAudioGMS_INTERNAL_Apply3D(instance); } -static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* instance) -{ - /* NOTE: this function returns samples per channel, not total samples */ - uint32_t samples = stb_vorbis_get_samples_float_interleaved( - instance->soundData.streamingSound.fileHandle, - instance->format.nChannels, - device->streamStagingBuffer, - STREAMING_BUFFER_SIZE - ); - - uint32_t sampleCount = samples * instance->format.nChannels; - uint32_t bufferLength = sampleCount * sizeof(float); - - uint8_t* nextBuffer = SDL_malloc(bufferLength); - SDL_memcpy(nextBuffer, device->streamStagingBuffer, bufferLength); - - BufferQueue_Enqueue(&instance->soundData.streamingSound.bufferQueue, nextBuffer); - - if (instance->soundState != SoundState_Stopped) - { - FAudioBuffer buffer; - buffer.AudioBytes = bufferLength; - buffer.pAudioData = nextBuffer; - buffer.PlayLength = - bufferLength / - instance->format.nChannels / - (instance->format.wBitsPerSample / 8); - buffer.PlayBegin = 0; - - buffer.Flags = 0; - buffer.LoopBegin = 0; - buffer.LoopCount = 0; - buffer.LoopLength = 0; - buffer.pContext = NULL; - - FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &buffer, NULL); - } - - /* We have reached the end of the file! */ - if (sampleCount < STREAMING_BUFFER_SIZE) - { - if (instance->loop) - { - stb_vorbis_seek_start(instance->soundData.streamingSound.fileHandle); - } - else - { - instance->soundState = SoundState_Stopped; - } - } -} - -static void FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(FAudioGMS_SoundInstance* instance) -{ - uint32_t i; - FAudioVoiceState voiceState; - - if (instance->isStatic) { return; } - - FAudioSourceVoice_GetState( - instance->handle, - &voiceState, - FAUDIO_VOICE_NOSAMPLESPLAYED - ); - - while (instance->soundData.streamingSound.bufferQueue.count > voiceState.BuffersQueued) - { - uint8_t* buffer = BufferQueue_Dequeue(&instance->soundData.streamingSound.bufferQueue); - SDL_free(buffer); - } - - for (i = MINIMUM_BUFFER_CHECK - instance->soundData.streamingSound.bufferQueue.count; i > 0; i -= 1) - { - FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); - } -} - static void FAudioGMS_INTERNAL_SoundInstance_ClearBuffers(FAudioGMS_SoundInstance* instance) { uint32_t i; diff --git a/src/FAudioGMS.h b/src/FAudioGMS.h index f4eac8a..7d3d848 100644 --- a/src/FAudioGMS.h +++ b/src/FAudioGMS.h @@ -62,6 +62,9 @@ FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetReverb(double soundInstanceID, doub FAUDIOGMSAPI void FAudioGMS_SoundInstance_Set3DPosition(double soundInstanceID, double x, double y, double z); FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetTrackPosition(double soundInstanceID, double trackPositionInSeconds); FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetVolumeOverTime(double soundInstanceID, double volume, double milliseconds); +FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetLowPassFilter(double soundInstanceID, float lowPassFilter); +FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetHighPassFilter(double soundInstanceID, float highPassFilter); +FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetBandPassFilter(double soundInstanceID, float bandPassFilter); FAUDIOGMSAPI double FAudioGMS_SoundInstance_GetPitch(double soundInstanceID); FAUDIOGMSAPI double FAudioGMS_SoundInstance_GetVolume(double soundInstanceID);