initial streaming audio implementation
							parent
							
								
									9162b45fd4
								
							
						
					
					
						commit
						bb9b1fef65
					
				
							
								
								
									
										546
									
								
								src/FAudioGMS.c
								
								
								
								
							
							
						
						
									
										546
									
								
								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 <stdio.h> | ||||
| 
 | ||||
| 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; | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -57,6 +57,10 @@ | |||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | ||||
|     <RunCodeAnalysis>true</RunCodeAnalysis> | ||||
|     <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> | ||||
|     <IncludePath>../lib/SDL/include;../lib/FAudio/include;$(IncludePath)</IncludePath> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | ||||
|     <IncludePath>../lib/FAudio/include;../lib/SDL/include;$(IncludePath)</IncludePath> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Label="Vcpkg"> | ||||
|     <VcpkgEnabled>false</VcpkgEnabled> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue