From bb9b1fef65a51e705ca035fac23be98b43a86783 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 25 Oct 2021 00:27:38 -0700 Subject: [PATCH] initial streaming audio implementation --- src/FAudioGMS.c | 546 +++++++++++++++++++++++++++++--------- src/FAudioGMS.h | 3 + visualc/FAudioGMS.vcxproj | 4 + 3 files changed, 431 insertions(+), 122 deletions(-) diff --git a/src/FAudioGMS.c b/src/FAudioGMS.c index d8ab510..f737fa2 100644 --- a/src/FAudioGMS.c +++ b/src/FAudioGMS.c @@ -24,13 +24,17 @@ * */ -#include "../lib/SDL/include/SDL.h" +#include "SDL.h" + +#define DISABLE_XNASONG #include "FAudioGMS.h" -#include "../lib/FAudio/include/FAPOBase.h" -#include "../lib/FAudio/include/FAudioFX.h" -#include "../lib/FAudio/include/F3DAudio.h" -#include "../lib/FAudio/include/FAudio.h" + +#include "FAPOBase.h" +#include "FAudioFX.h" +#include "F3DAudio.h" + +#include "FAudio.h" #define DR_WAV_IMPLEMENTATION #define DRWAV_MALLOC(sz) SDL_malloc((sz)) @@ -40,6 +44,64 @@ #define DRWAV_ZERO_MEMORY(p, sz) SDL_memset((p), 0, (sz)) #include "../lib/dr_wav.h" +/* stb vorbis defines. this is kind of a mess but oh well */ + +#include "../lib/FAudio/src/FAudio_internal.h" + +#define malloc FAudio_malloc +#define realloc FAudio_realloc +#define free FAudio_free +#ifdef memset /* Thanks, Apple! */ +#undef memset +#endif +#define memset SDL_memset +#ifdef memcpy /* Thanks, Apple! */ +#undef memcpy +#endif +#define memcpy SDL_memcpy +#define memcmp FAudio_memcmp + +#define pow FAudio_pow +#define log(x) FAudio_log(x) +#define sin(x) FAudio_sin(x) +#define cos(x) FAudio_cos(x) +#define floor FAudio_floor +#define abs(x) FAudio_abs(x) +#define ldexp(v, e) FAudio_ldexp((v), (e)) +#define exp(x) FAudio_exp(x) + +#define qsort FAudio_qsort + +#ifdef assert +#undef assert +#endif + +#define assert FAudio_assert + +#define FILE FAudioIOStream +#ifdef SEEK_SET +#undef SEEK_SET +#endif +#ifdef SEEK_END +#undef SEEK_END +#endif +#ifdef EOF +#undef EOF +#endif +#define SEEK_SET FAUDIO_SEEK_SET +#define SEEK_END FAUDIO_SEEK_END +#define EOF FAUDIO_EOF +#define fopen(path, mode) FAudio_fopen(path) +#define fopen_s(io, path, mode) (!(*io = FAudio_fopen(path))) +#define fclose(io) FAudio_close(io) +#define fread(dst, size, count, io) io->read(io->data, dst, size, count) +#define fseek(io, offset, whence) io->seek(io->data, offset, whence) +#define ftell(io) io->seek(io->data, 0, FAUDIO_SEEK_CUR) + +#define STB_VORBIS_NO_PUSHDATA_API 1 +#define STB_VORBIS_NO_INTEGER_CONVERSION 1 +#include "../lib/FAudio/src/stb_vorbis.h" + #include static inline void Log(char *string) @@ -80,6 +142,52 @@ static inline uint32_t IdStack_Pop(IdStack* stack) return stack->array[stack->count]; } +typedef struct BufferQueue +{ + uint32_t head; + uint32_t tail; + uint32_t size; /* DO NOT MUTATE */ + uint32_t count; /* number of currently enqueued elements */ + uint8_t** buffers; +} BufferQueue; + +static inline void BufferQueue_Init(BufferQueue* queue, uint32_t size) +{ + queue->head = 0; + queue->tail = 0; + queue->size = size; + queue->count = 0; + queue->buffers = SDL_malloc(size * sizeof(uint8_t*)); +} + +static inline uint8_t* BufferQueue_Dequeue(BufferQueue *queue) +{ + if (queue->tail == queue->head) + { + return NULL; + } + + uint8_t* buffer = queue->buffers[queue->tail]; + queue->buffers[queue->tail] = NULL; + queue->tail = (queue->tail + 1) % queue->size; + + queue->count -= 1; + return buffer; +} + +static inline void BufferQueue_Enqueue(BufferQueue *queue, uint8_t* buffer) +{ + if (((queue->head + 1) % queue->size) == queue->tail) + { + return; + } + + queue->buffers[queue->head] = buffer; + queue->head = (queue->head + 1) % queue->size; + + queue->count += 1; +} + typedef enum FAudioGMS_SoundState { SoundState_Playing, @@ -97,6 +205,13 @@ typedef struct FAudioGMS_StaticSound uint32_t loopLength; } FAudioGMS_StaticSound; +typedef struct FAudioGMS_StreamingSound +{ + stb_vorbis* fileHandle; + stb_vorbis_info info; + BufferQueue bufferQueue; +} FAudioGMS_StreamingSound; + typedef struct FAudioGMS_SoundInstance { uint32_t id; @@ -127,13 +242,17 @@ typedef struct FAudioGMS_SoundInstance union { - FAudioGMS_StaticSound *staticSound; - /* TODO: streaming */ - } parent; + FAudioGMS_StaticSound *staticSound; /* static sounds are loaded separately, so they do not belong to the instance */ + FAudioGMS_StreamingSound streamingSound; + } soundData; } FAudioGMS_SoundInstance; static const float SPEED_OF_SOUND = 343.5f; 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? */ typedef struct FAudioGMS_Device { @@ -153,6 +272,8 @@ typedef struct FAudioGMS_Device FAudioGMS_SoundInstance **soundInstances; uint32_t soundInstanceCount; IdStack soundInstanceIndexStack; + + float streamStagingBuffer[STREAMING_BUFFER_SIZE]; } FAudioGMS_Device; static FAudioGMS_Device* device = NULL; @@ -291,68 +412,6 @@ void FAudioGMS_Init(double spatialDistanceScale) fflush(stdout); } -static void FAudioGMS_INTERNAL_SoundInstance_Destroy(FAudioGMS_SoundInstance* instance) -{ - if (instance != NULL) - { - device->soundInstances[instance->id] = NULL; - IdStack_Push(&device->soundInstanceIndexStack, instance->id); - FAudioSourceVoice_Stop(instance->handle, 0, 0); - FAudioSourceVoice_FlushSourceBuffers(instance->handle); - FAudioVoice_DestroyVoice(instance->handle); - if (instance->is3D) - { - SDL_free(instance->emitter); - } - SDL_free(instance->dspSettings.pMatrixCoefficients); - SDL_free(instance); - } -} - -void FAudioGMS_SoundInstance_Destroy(double id) -{ - FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)id); - - if (instance != NULL) - { - FAudioGMS_INTERNAL_SoundInstance_Destroy(instance); - } -} - -void FAudioGMS_SoundInstance_DestroyWhenFinished(double id) -{ - FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)id); - - if (instance != NULL) - { - instance->destroyOnFinish = 1; - } -} - -/* FIXME: this will die horribly if a sound is playing */ -static void FAudioGMS_INTERNAL_StaticSound_Destroy(FAudioGMS_StaticSound* sound) -{ - if (sound != NULL) - { - device->staticSounds[sound->id] = NULL; - IdStack_Push(&device->staticSoundIndexStack, sound->id); - SDL_free((void*)sound->buffer.pAudioData); - SDL_free(sound); - } -} - -void FAudioGMS_StaticSound_Destroy(double id) -{ - if (id >= 0 && id < device->staticSoundCount) - { - FAudioGMS_INTERNAL_StaticSound_Destroy(device->staticSounds[(uint32_t)id]); - } - else - { - Log("Invalid ID for destroy!"); - } -} - /* Taken from https://github.com/FNA-XNA/FNA/blob/master/src/Audio/SoundEffectInstance.cs */ static void SetPanMatrixCoefficients(FAudioGMS_SoundInstance *instance) { @@ -647,6 +706,18 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetVolume(FAudioGMS_SoundInstance* FAudioVoice_SetVolume(instance->handle, volume, 0); } +static void FAudioGMS_INTERNAL_SoundInstance_SetProperties(FAudioGMS_SoundInstance* instance, double pan, double pitch, double volume, double reverb) +{ + FAudioGMS_INTERNAL_SoundInstance_SetPan(instance, pan); + FAudioGMS_INTERNAL_SoundInstance_SetPitch(instance, pitch); + FAudioGMS_INTERNAL_SoundInstance_SetVolume(instance, volume); + + if (reverb > 0.0f) + { + FAudioGMS_INTERNAL_SoundInstance_SetReverb(instance, reverb); + } +} + static void FAudioGMS_INTERNAL_Apply3D(FAudioGMS_SoundInstance* instance) { F3DAUDIO_EMITTER* emitter = instance->emitter; @@ -676,27 +747,23 @@ static void FAudioGMS_INTERNAL_Apply3D(FAudioGMS_SoundInstance* instance) ); } -static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound( - FAudioGMS_StaticSound *staticSound, - double pan, - double pitch, - double volume, - double reverb +static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init( + uint32_t channelCount, + uint32_t samplesPerSecond ) { - FAudioGMS_SoundInstance *instance = SDL_malloc(sizeof(FAudioGMS_SoundInstance)); + FAudioGMS_SoundInstance* instance = SDL_malloc(sizeof(FAudioGMS_SoundInstance)); instance->handle = NULL; - instance->parent.staticSound = staticSound; - instance->isStatic = 1; + instance->loop = 0; instance->destroyOnFinish = 0; - instance->format.wFormatTag = 3; + instance->format.wFormatTag = FAUDIO_FORMAT_IEEE_FLOAT; instance->format.wBitsPerSample = 32; - instance->format.nChannels = staticSound->channels; - instance->format.nBlockAlign = (uint16_t)(4 * staticSound->channels); - instance->format.nSamplesPerSec = staticSound->samplesPerSecond; - instance->format.nAvgBytesPerSec = instance->format.nBlockAlign * staticSound->samplesPerSecond; + instance->format.nChannels = channelCount; + instance->format.nBlockAlign = (uint16_t)(4 * channelCount); + instance->format.nSamplesPerSec = samplesPerSecond; + instance->format.nAvgBytesPerSec = instance->format.nBlockAlign * samplesPerSecond; FAudio_CreateSourceVoice( device->handle, @@ -716,27 +783,22 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_CreateFromStati } instance->dspSettings.DopplerFactor = 1.0f; - instance->dspSettings.SrcChannelCount = staticSound->channels; + instance->dspSettings.SrcChannelCount = channelCount; instance->dspSettings.DstChannelCount = device->deviceDetails.OutputFormat.Format.nChannels; uint32_t memsize = 4 * instance->dspSettings.SrcChannelCount * instance->dspSettings.DstChannelCount; instance->dspSettings.pMatrixCoefficients = SDL_malloc(memsize); SDL_memset(instance->dspSettings.pMatrixCoefficients, 0, memsize); - FAudioGMS_INTERNAL_SoundInstance_SetPan(instance, pan); - FAudioGMS_INTERNAL_SoundInstance_SetPitch(instance, pitch); - FAudioGMS_INTERNAL_SoundInstance_SetVolume(instance, volume); - instance->reverbAttached = 0; instance->reverb = 0.0f; instance->lowPassFilter = 0.0f; instance->highPassFilter = 0.0f; instance->bandPassFilter = 0.0f; - if (reverb > 0.0f) - { - FAudioGMS_INTERNAL_SoundInstance_SetReverb(instance, reverb); - } + FAudioGMS_INTERNAL_SoundInstance_SetPan(instance, 0); + FAudioGMS_INTERNAL_SoundInstance_SetPitch(instance, 1); + FAudioGMS_INTERNAL_SoundInstance_SetVolume(instance, 1); instance->soundState = SoundState_Stopped; @@ -762,6 +824,47 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_CreateFromStati return instance; } +static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound( + FAudioGMS_StaticSound *staticSound +) { + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_Init( + staticSound->channels, + staticSound->samplesPerSecond + ); + + instance->isStatic = 1; + instance->soundData.staticSound = staticSound; + + return instance; +} + +double FAudioGMS_StreamingSound_LoadOGG(char* filePath) +{ + int error = -1; + stb_vorbis *fileHandle = stb_vorbis_open_filename(filePath, &error, NULL); + + if (error != 0) + { + Log("Error opening OGG file!"); + Log(filePath); + return -1; + } + + stb_vorbis_info info = stb_vorbis_get_info(fileHandle); + + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_Init( + info.channels, + info.sample_rate + ); + + instance->isStatic = 0; + instance->soundData.streamingSound.fileHandle = fileHandle; + instance->soundData.streamingSound.info = info; + BufferQueue_Init(&instance->soundData.streamingSound.bufferQueue, MAX_BUFFER_QUEUE_COUNT); + + return instance->id; +} + static void FAudioGMS_INTERNAL_StaticSound_AddEmitter(FAudioGMS_SoundInstance* instance, float x, float y, float z) { instance->is3D = 1; @@ -803,32 +906,126 @@ static void FAudioGMS_INTERNAL_StaticSound_AddEmitter(FAudioGMS_SoundInstance* i FAudioGMS_INTERNAL_Apply3D(instance); } -static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* instance) +static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* instance) { - if (instance->isStatic) - { - if (instance->soundState == SoundState_Playing) - { - return; - } + /* 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) { - instance->parent.staticSound->buffer.LoopCount = FAUDIO_LOOP_INFINITE; - instance->parent.staticSound->buffer.LoopBegin = instance->parent.staticSound->loopStart; - instance->parent.staticSound->buffer.LoopLength = instance->parent.staticSound->loopLength; + stb_vorbis_seek_start(instance->soundData.streamingSound.fileHandle); } else { - instance->parent.staticSound->buffer.LoopCount = 0; - instance->parent.staticSound->buffer.LoopBegin = 0; - instance->parent.staticSound->buffer.LoopLength = 0; + 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; + uint32_t bufferCount = instance->soundData.streamingSound.bufferQueue.count; + + for (i = 0; i < bufferCount; i += 1) + { + uint8_t* buffer = BufferQueue_Dequeue(&instance->soundData.streamingSound.bufferQueue); + SDL_free(buffer); + } +} + +static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* instance) +{ + if (instance->soundState == SoundState_Playing) + { + return; + } + + if (instance->isStatic) + { + if (instance->loop) + { + instance->soundData.staticSound->buffer.LoopCount = FAUDIO_LOOP_INFINITE; + instance->soundData.staticSound->buffer.LoopBegin = instance->soundData.staticSound->loopStart; + instance->soundData.staticSound->buffer.LoopLength = instance->soundData.staticSound->loopLength; + } + else + { + instance->soundData.staticSound->buffer.LoopCount = 0; + instance->soundData.staticSound->buffer.LoopBegin = 0; + instance->soundData.staticSound->buffer.LoopLength = 0; } - FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &instance->parent.staticSound->buffer, NULL); - FAudioSourceVoice_Start(instance->handle, 0, 0); - instance->soundState = SoundState_Playing; + FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &instance->soundData.staticSound->buffer, NULL); } + else + { + FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance); + } + + FAudioSourceVoice_Start(instance->handle, 0, 0); + instance->soundState = SoundState_Playing; } void FAudioGMS_StaticSound_PlayOneOff(double staticSoundID, double pan, double pitch, double volume, double reverb) @@ -837,8 +1034,9 @@ void FAudioGMS_StaticSound_PlayOneOff(double staticSoundID, double pan, double p if (staticSound != NULL) { - FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound(staticSound, pan, pitch, volume, reverb); + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound(staticSound); instance->destroyOnFinish = 1; + FAudioGMS_INTERNAL_SoundInstance_SetProperties(instance, pan, pitch, volume, reverb); FAudioGMS_INTERNAL_SoundInstance_Play(instance); } else @@ -853,8 +1051,9 @@ void FAudioGMS_StaticSound_PlayOneOffSpatial(double staticSoundID, double x, dou if (staticSound != NULL) { - FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound(staticSound, 0, pitch, volume, reverb); + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound(staticSound); instance->destroyOnFinish = 1; + FAudioGMS_INTERNAL_SoundInstance_SetProperties(instance, 0, pitch, volume, reverb); FAudioGMS_INTERNAL_StaticSound_AddEmitter(instance, x, y, z); FAudioGMS_INTERNAL_SoundInstance_Play(instance); } @@ -870,8 +1069,9 @@ double FAudioGMS_StaticSound_Play(double staticSoundID, double pan, double pitch if (staticSound != NULL) { - FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound(staticSound, pan, pitch, volume, reverb); + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound(staticSound); instance->loop = (uint8_t)loop; + FAudioGMS_INTERNAL_SoundInstance_SetProperties(instance, pan, pitch, volume, reverb); FAudioGMS_INTERNAL_SoundInstance_Play(instance); return (double)instance->id; } @@ -888,8 +1088,9 @@ double FAudioGMS_StaticSound_PlaySpatial(double staticSoundID, double x, double if (staticSound != NULL) { - FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound(staticSound, 0, pitch, volume, reverb); + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound(staticSound); instance->loop = (uint8_t)loop; + FAudioGMS_INTERNAL_SoundInstance_SetProperties(instance, 0, pitch, volume, reverb); FAudioGMS_INTERNAL_StaticSound_AddEmitter(instance, x, y, z); FAudioGMS_INTERNAL_SoundInstance_Play(instance); return (double)instance->id; @@ -917,13 +1118,10 @@ void FAudioGMS_SoundInstance_Pause(double id) if (instance != NULL) { - if (instance->isStatic) + if (instance->soundState == SoundState_Playing) { - if (instance->soundState == SoundState_Playing) - { - FAudioSourceVoice_Stop(instance->handle, 0, 0); - instance->soundState = SoundState_Paused; - } + FAudioSourceVoice_Stop(instance->handle, 0, 0); + instance->soundState = SoundState_Paused; } } else @@ -932,16 +1130,16 @@ void FAudioGMS_SoundInstance_Pause(double id) } } -void FAudioGMS_SoundInstance_Stop(double id) +static void FAudioGMS_INTERNAL_SoundInstance_Stop(FAudioGMS_SoundInstance* instance) { - FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)id); - if (instance != NULL) { if (instance->isStatic) { FAudioSourceVoice_ExitLoop(instance->handle, 0); } + + instance->soundState = SoundState_Stopped; } else { @@ -949,6 +1147,38 @@ void FAudioGMS_SoundInstance_Stop(double id) } } +void FAudioGMS_SoundInstance_Stop(double id) +{ + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)id); + FAudioGMS_INTERNAL_SoundInstance_Stop(instance); +} + +static void FAudioGMS_INTERNAL_SoundInstance_StopImmediate(FAudioGMS_SoundInstance* instance) +{ + if (instance != NULL) + { + FAudioSourceVoice_Stop(instance->handle, 0, 0); + FAudioSourceVoice_FlushSourceBuffers(instance->handle); + + if (!instance->isStatic) + { + FAudioGMS_INTERNAL_SoundInstance_ClearBuffers(instance); + } + + instance->soundState = SoundState_Stopped; + } + else + { + Log("SoundInstance_Stop: Invalid sound instance ID! Did you destroy this instance?"); + } +} + +void FAudioGMS_SoundInstance_StopImmediate(double id) +{ + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)id); + FAudioGMS_INTERNAL_SoundInstance_StopImmediate(instance); +} + void FAudioGMS_SoundInstance_Set3DPosition(double soundInstanceID, double x, double y, double z) { FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)soundInstanceID); @@ -982,6 +1212,72 @@ void FAudioGMS_SetListenerPosition(double x, double y, double z) device->listener.Position.z = z; } +static void FAudioGMS_INTERNAL_SoundInstance_Destroy(FAudioGMS_SoundInstance* instance) +{ + if (instance != NULL) + { + device->soundInstances[instance->id] = NULL; + IdStack_Push(&device->soundInstanceIndexStack, instance->id); + FAudioGMS_INTERNAL_SoundInstance_StopImmediate(instance); + FAudioVoice_DestroyVoice(instance->handle); + if (!instance->isStatic) + { + SDL_free(instance->soundData.streamingSound.bufferQueue.buffers); + stb_vorbis_close(instance->soundData.streamingSound.fileHandle); + } + if (instance->is3D) + { + SDL_free(instance->emitter); + } + SDL_free(instance->dspSettings.pMatrixCoefficients); + SDL_free(instance); + } +} + +void FAudioGMS_SoundInstance_Destroy(double id) +{ + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)id); + + if (instance != NULL) + { + FAudioGMS_INTERNAL_SoundInstance_Destroy(instance); + } +} + +void FAudioGMS_SoundInstance_DestroyWhenFinished(double id) +{ + FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)id); + + if (instance != NULL) + { + instance->destroyOnFinish = 1; + } +} + +/* FIXME: this will die horribly if a sound is playing */ +static void FAudioGMS_INTERNAL_StaticSound_Destroy(FAudioGMS_StaticSound* sound) +{ + if (sound != NULL) + { + device->staticSounds[sound->id] = NULL; + IdStack_Push(&device->staticSoundIndexStack, sound->id); + SDL_free((void*)sound->buffer.pAudioData); + SDL_free(sound); + } +} + +void FAudioGMS_StaticSound_Destroy(double id) +{ + if (id >= 0 && id < device->staticSoundCount) + { + FAudioGMS_INTERNAL_StaticSound_Destroy(device->staticSounds[(uint32_t)id]); + } + else + { + Log("Invalid ID for destroy!"); + } +} + void FAudioGMS_Update() { uint32_t i; @@ -997,6 +1293,12 @@ void FAudioGMS_Update() FAudioGMS_INTERNAL_Apply3D(instance); } + /* Update streaming instance */ + if (!instance->isStatic && instance->soundState == SoundState_Playing) + { + FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance); + } + if (instance->destroyOnFinish) { FAudioVoiceState state; diff --git a/src/FAudioGMS.h b/src/FAudioGMS.h index 306bda6..70c9138 100644 --- a/src/FAudioGMS.h +++ b/src/FAudioGMS.h @@ -48,9 +48,12 @@ FAUDIOGMSAPI double FAudioGMS_StaticSound_Play(double staticSoundID, double pan, FAUDIOGMSAPI double FAudioGMS_StaticSound_PlaySpatial(double staticSoundID, double x, double y, double z, double pitch, double volume, double reverb, double loop); /* returns a sound instance ID. must be freed! */ FAUDIOGMSAPI void FAudioGMS_StaticSound_Destroy(double id); +FAUDIOGMSAPI double FAudioGMS_StreamingSound_LoadOGG(char* filepath); /* returns a sound instance */ + FAUDIOGMSAPI void FAudioGMS_SoundInstance_Play(double id); FAUDIOGMSAPI void FAudioGMS_SoundInstance_Pause(double id); FAUDIOGMSAPI void FAudioGMS_SoundInstance_Stop(double id); +FAUDIOGMSAPI void FAudioGMS_SoundInstance_StopImmediate(double id); FAUDIOGMSAPI void FAudioGMS_SoundInstance_Set3DPosition(double soundInstanceID, double x, double y, double z); FAUDIOGMSAPI void FAudioGMS_SoundInstance_Destroy(double id); FAUDIOGMSAPI void FAudioGMS_SoundInstance_DestroyWhenFinished(double id); diff --git a/visualc/FAudioGMS.vcxproj b/visualc/FAudioGMS.vcxproj index 10a7b15..82dd8c5 100644 --- a/visualc/FAudioGMS.vcxproj +++ b/visualc/FAudioGMS.vcxproj @@ -57,6 +57,10 @@ true true + ../lib/SDL/include;../lib/FAudio/include;$(IncludePath) + + + ../lib/FAudio/include;../lib/SDL/include;$(IncludePath) false