change streaming to use OnBufferEnded callback
parent
d1a7ddcb9f
commit
9069f34b7f
149
src/FAudioGMS.c
149
src/FAudioGMS.c
|
@ -142,52 +142,6 @@ static inline uint32_t IdStack_Pop(IdStack* stack)
|
||||||
return stack->array[stack->count];
|
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
|
typedef enum FAudioGMS_SoundState
|
||||||
{
|
{
|
||||||
SoundState_Playing,
|
SoundState_Playing,
|
||||||
|
@ -210,7 +164,6 @@ typedef struct FAudioGMS_StreamingSound
|
||||||
{
|
{
|
||||||
stb_vorbis* fileHandle;
|
stb_vorbis* fileHandle;
|
||||||
stb_vorbis_info info;
|
stb_vorbis_info info;
|
||||||
BufferQueue bufferQueue;
|
|
||||||
} FAudioGMS_StreamingSound;
|
} FAudioGMS_StreamingSound;
|
||||||
|
|
||||||
typedef struct FAudioGMS_SoundInstance
|
typedef struct FAudioGMS_SoundInstance
|
||||||
|
@ -272,10 +225,8 @@ typedef struct FAudioGMS_EffectChain
|
||||||
|
|
||||||
static const float SPEED_OF_SOUND = 343.5f;
|
static const float SPEED_OF_SOUND = 343.5f;
|
||||||
static const float DOPPLER_SCALE = 1.0f;
|
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 * 16 * 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
|
typedef struct FAudioGMS_Device
|
||||||
{
|
{
|
||||||
|
@ -288,6 +239,8 @@ typedef struct FAudioGMS_Device
|
||||||
F3DAUDIO_LISTENER listener;
|
F3DAUDIO_LISTENER listener;
|
||||||
float spatialDistanceScale;
|
float spatialDistanceScale;
|
||||||
|
|
||||||
|
FAudioVoiceCallback voiceCallbacks;
|
||||||
|
|
||||||
FAudioGMS_StaticSound **staticSounds;
|
FAudioGMS_StaticSound **staticSounds;
|
||||||
uint32_t staticSoundCount;
|
uint32_t staticSoundCount;
|
||||||
IdStack staticSoundIndexStack;
|
IdStack staticSoundIndexStack;
|
||||||
|
@ -348,6 +301,17 @@ static inline FAudioGMS_EffectChain* FAudioGMS_INTERNAL_LookupEffectChain(uint32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Forward declare this to avoid annoying BS */
|
||||||
|
static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* instance);
|
||||||
|
|
||||||
|
static void FAudioGMS_INTERNAL_StreamingBufferEndCallback(FAudioVoiceCallback* callback, FAudioGMS_SoundInstance *instance)
|
||||||
|
{
|
||||||
|
if (instance->soundState == SoundState_Playing)
|
||||||
|
{
|
||||||
|
FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FAudioGMS_Init(double spatialDistanceScale, double timestep)
|
void FAudioGMS_Init(double spatialDistanceScale, double timestep)
|
||||||
{
|
{
|
||||||
device = SDL_malloc(sizeof(FAudioGMS_Device));
|
device = SDL_malloc(sizeof(FAudioGMS_Device));
|
||||||
|
@ -443,6 +407,14 @@ void FAudioGMS_Init(double spatialDistanceScale, double timestep)
|
||||||
device->listener.Velocity.z = 0;
|
device->listener.Velocity.z = 0;
|
||||||
device->listener.pCone = NULL;
|
device->listener.pCone = NULL;
|
||||||
|
|
||||||
|
device->voiceCallbacks.OnBufferEnd = FAudioGMS_INTERNAL_StreamingBufferEndCallback;
|
||||||
|
device->voiceCallbacks.OnBufferStart = NULL;
|
||||||
|
device->voiceCallbacks.OnLoopEnd = NULL;
|
||||||
|
device->voiceCallbacks.OnStreamEnd = NULL;
|
||||||
|
device->voiceCallbacks.OnVoiceError = NULL;
|
||||||
|
device->voiceCallbacks.OnVoiceProcessingPassEnd = NULL;
|
||||||
|
device->voiceCallbacks.OnVoiceProcessingPassStart = NULL;
|
||||||
|
|
||||||
device->staticSounds = NULL;
|
device->staticSounds = NULL;
|
||||||
device->staticSoundCount = 0;
|
device->staticSoundCount = 0;
|
||||||
IdStack_Init(&device->staticSoundIndexStack);
|
IdStack_Init(&device->staticSoundIndexStack);
|
||||||
|
@ -458,7 +430,7 @@ void FAudioGMS_Init(double spatialDistanceScale, double timestep)
|
||||||
device->timestep = timestep;
|
device->timestep = timestep;
|
||||||
|
|
||||||
Log("FAudio initialized successfully!");
|
Log("FAudio initialized successfully!");
|
||||||
printf("Device: %ls", device->deviceDetails.DisplayName);
|
printf("Device: %ls\n", device->deviceDetails.DisplayName);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -716,12 +688,14 @@ static void FAudioGMS_INTERNAL_Apply3D(FAudioGMS_SoundInstance* instance)
|
||||||
|
|
||||||
static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init(
|
static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init(
|
||||||
uint32_t channelCount,
|
uint32_t channelCount,
|
||||||
uint32_t samplesPerSecond
|
uint32_t samplesPerSecond,
|
||||||
|
uint8_t isStatic
|
||||||
) {
|
) {
|
||||||
FAudioGMS_SoundInstance* instance = SDL_malloc(sizeof(FAudioGMS_SoundInstance));
|
FAudioGMS_SoundInstance* instance = SDL_malloc(sizeof(FAudioGMS_SoundInstance));
|
||||||
|
|
||||||
instance->handle = NULL;
|
instance->handle = NULL;
|
||||||
|
|
||||||
|
instance->isStatic = isStatic;
|
||||||
instance->loop = 0;
|
instance->loop = 0;
|
||||||
instance->destroyOnFinish = 0;
|
instance->destroyOnFinish = 0;
|
||||||
|
|
||||||
|
@ -738,7 +712,7 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init(
|
||||||
&instance->format,
|
&instance->format,
|
||||||
FAUDIO_VOICE_USEFILTER,
|
FAUDIO_VOICE_USEFILTER,
|
||||||
FAUDIO_DEFAULT_FREQ_RATIO,
|
FAUDIO_DEFAULT_FREQ_RATIO,
|
||||||
NULL,
|
isStatic ? NULL : &device->voiceCallbacks,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
@ -802,7 +776,8 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_CreateFromStati
|
||||||
) {
|
) {
|
||||||
FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_Init(
|
FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_Init(
|
||||||
staticSound->channels,
|
staticSound->channels,
|
||||||
staticSound->samplesPerSecond
|
staticSound->samplesPerSecond,
|
||||||
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
instance->isStatic = 1;
|
instance->isStatic = 1;
|
||||||
|
@ -827,8 +802,6 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance*
|
||||||
uint8_t* nextBuffer = SDL_malloc(bufferLength);
|
uint8_t* nextBuffer = SDL_malloc(bufferLength);
|
||||||
SDL_memcpy(nextBuffer, device->streamStagingBuffer, bufferLength);
|
SDL_memcpy(nextBuffer, device->streamStagingBuffer, bufferLength);
|
||||||
|
|
||||||
BufferQueue_Enqueue(&instance->soundData.streamingSound.bufferQueue, nextBuffer);
|
|
||||||
|
|
||||||
FAudioBuffer buffer;
|
FAudioBuffer buffer;
|
||||||
buffer.AudioBytes = bufferLength;
|
buffer.AudioBytes = bufferLength;
|
||||||
buffer.pAudioData = nextBuffer;
|
buffer.pAudioData = nextBuffer;
|
||||||
|
@ -842,7 +815,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance*
|
||||||
buffer.LoopBegin = 0;
|
buffer.LoopBegin = 0;
|
||||||
buffer.LoopCount = 0;
|
buffer.LoopCount = 0;
|
||||||
buffer.LoopLength = 0;
|
buffer.LoopLength = 0;
|
||||||
buffer.pContext = NULL;
|
buffer.pContext = instance; /* context for OnBufferEnd callback */
|
||||||
|
|
||||||
FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &buffer, NULL);
|
FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &buffer, NULL);
|
||||||
|
|
||||||
|
@ -860,31 +833,6 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
double FAudioGMS_StreamingSound_LoadOGG(char* filePath)
|
||||||
{
|
{
|
||||||
RETURN_ON_NULL_DEVICE(-1.0)
|
RETURN_ON_NULL_DEVICE(-1.0)
|
||||||
|
@ -902,15 +850,14 @@ double FAudioGMS_StreamingSound_LoadOGG(char* filePath)
|
||||||
|
|
||||||
FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_Init(
|
FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_Init(
|
||||||
info.channels,
|
info.channels,
|
||||||
info.sample_rate
|
info.sample_rate,
|
||||||
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
instance->isStatic = 0;
|
|
||||||
instance->soundData.streamingSound.fileHandle = fileHandle;
|
instance->soundData.streamingSound.fileHandle = fileHandle;
|
||||||
instance->soundData.streamingSound.info = info;
|
instance->soundData.streamingSound.info = info;
|
||||||
BufferQueue_Init(&instance->soundData.streamingSound.bufferQueue, MAX_BUFFER_QUEUE_COUNT);
|
|
||||||
|
|
||||||
FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance);
|
FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance);
|
||||||
|
|
||||||
return instance->id;
|
return instance->id;
|
||||||
}
|
}
|
||||||
|
@ -956,18 +903,6 @@ static void FAudioGMS_INTERNAL_StaticSound_AddEmitter(FAudioGMS_SoundInstance* i
|
||||||
FAudioGMS_INTERNAL_Apply3D(instance);
|
FAudioGMS_INTERNAL_Apply3D(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)
|
static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* instance)
|
||||||
{
|
{
|
||||||
if (instance->soundState == SoundState_Playing)
|
if (instance->soundState == SoundState_Playing)
|
||||||
|
@ -992,10 +927,6 @@ static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* insta
|
||||||
|
|
||||||
FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &instance->soundData.staticSound->buffer, NULL);
|
FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &instance->soundData.staticSound->buffer, NULL);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
FAudioSourceVoice_Start(instance->handle, 0, 0);
|
FAudioSourceVoice_Start(instance->handle, 0, 0);
|
||||||
instance->soundState = SoundState_Playing;
|
instance->soundState = SoundState_Playing;
|
||||||
|
@ -1114,17 +1045,16 @@ static void FAudioGMS_INTERNAL_SoundInstance_Stop(FAudioGMS_SoundInstance* insta
|
||||||
{
|
{
|
||||||
if (instance != NULL)
|
if (instance != NULL)
|
||||||
{
|
{
|
||||||
|
instance->soundState = SoundState_Stopped; /* set this before so flush buffers doesn't trigger buffer add callback */
|
||||||
|
|
||||||
FAudioSourceVoice_Stop(instance->handle, 0, 0);
|
FAudioSourceVoice_Stop(instance->handle, 0, 0);
|
||||||
FAudioSourceVoice_FlushSourceBuffers(instance->handle);
|
FAudioSourceVoice_FlushSourceBuffers(instance->handle);
|
||||||
|
|
||||||
if (!instance->isStatic)
|
if (!instance->isStatic)
|
||||||
{
|
{
|
||||||
FAudioGMS_INTERNAL_SoundInstance_ClearBuffers(instance);
|
|
||||||
stb_vorbis_seek_start(instance->soundData.streamingSound.fileHandle); /* back to the start */
|
stb_vorbis_seek_start(instance->soundData.streamingSound.fileHandle); /* back to the start */
|
||||||
FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance); /* preload so we dont stutter on play */
|
FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); /* preload so we dont stutter on play */
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->soundState = SoundState_Stopped;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1317,7 +1247,6 @@ static void FAudioGMS_INTERNAL_SoundInstance_Destroy(FAudioGMS_SoundInstance* in
|
||||||
FAudioVoice_DestroyVoice(instance->handle);
|
FAudioVoice_DestroyVoice(instance->handle);
|
||||||
if (!instance->isStatic)
|
if (!instance->isStatic)
|
||||||
{
|
{
|
||||||
SDL_free(instance->soundData.streamingSound.bufferQueue.buffers);
|
|
||||||
stb_vorbis_close(instance->soundData.streamingSound.fileHandle);
|
stb_vorbis_close(instance->soundData.streamingSound.fileHandle);
|
||||||
}
|
}
|
||||||
if (instance->is3D)
|
if (instance->is3D)
|
||||||
|
@ -1667,12 +1596,6 @@ void FAudioGMS_Update()
|
||||||
FAudioGMS_INTERNAL_SoundInstance_SetVolume(instance, volume);
|
FAudioGMS_INTERNAL_SoundInstance_SetVolume(instance, volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update streaming instance */
|
|
||||||
if (!instance->isStatic && instance->soundState == SoundState_Playing)
|
|
||||||
{
|
|
||||||
FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instance->destroyOnFinish)
|
if (instance->destroyOnFinish)
|
||||||
{
|
{
|
||||||
FAudioVoiceState state;
|
FAudioVoiceState state;
|
||||||
|
|
Loading…
Reference in New Issue