initial streaming audio implementation
parent
9162b45fd4
commit
bb9b1fef65
528
src/FAudioGMS.c
528
src/FAudioGMS.c
|
@ -24,13 +24,17 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../lib/SDL/include/SDL.h"
|
#include "SDL.h"
|
||||||
|
|
||||||
|
#define DISABLE_XNASONG
|
||||||
|
|
||||||
#include "FAudioGMS.h"
|
#include "FAudioGMS.h"
|
||||||
#include "../lib/FAudio/include/FAPOBase.h"
|
|
||||||
#include "../lib/FAudio/include/FAudioFX.h"
|
#include "FAPOBase.h"
|
||||||
#include "../lib/FAudio/include/F3DAudio.h"
|
#include "FAudioFX.h"
|
||||||
#include "../lib/FAudio/include/FAudio.h"
|
#include "F3DAudio.h"
|
||||||
|
|
||||||
|
#include "FAudio.h"
|
||||||
|
|
||||||
#define DR_WAV_IMPLEMENTATION
|
#define DR_WAV_IMPLEMENTATION
|
||||||
#define DRWAV_MALLOC(sz) SDL_malloc((sz))
|
#define DRWAV_MALLOC(sz) SDL_malloc((sz))
|
||||||
|
@ -40,6 +44,64 @@
|
||||||
#define DRWAV_ZERO_MEMORY(p, sz) SDL_memset((p), 0, (sz))
|
#define DRWAV_ZERO_MEMORY(p, sz) SDL_memset((p), 0, (sz))
|
||||||
#include "../lib/dr_wav.h"
|
#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>
|
#include <stdio.h>
|
||||||
|
|
||||||
static inline void Log(char *string)
|
static inline void Log(char *string)
|
||||||
|
@ -80,6 +142,52 @@ 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,
|
||||||
|
@ -97,6 +205,13 @@ typedef struct FAudioGMS_StaticSound
|
||||||
uint32_t loopLength;
|
uint32_t loopLength;
|
||||||
} FAudioGMS_StaticSound;
|
} FAudioGMS_StaticSound;
|
||||||
|
|
||||||
|
typedef struct FAudioGMS_StreamingSound
|
||||||
|
{
|
||||||
|
stb_vorbis* fileHandle;
|
||||||
|
stb_vorbis_info info;
|
||||||
|
BufferQueue bufferQueue;
|
||||||
|
} FAudioGMS_StreamingSound;
|
||||||
|
|
||||||
typedef struct FAudioGMS_SoundInstance
|
typedef struct FAudioGMS_SoundInstance
|
||||||
{
|
{
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
@ -127,13 +242,17 @@ typedef struct FAudioGMS_SoundInstance
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
FAudioGMS_StaticSound *staticSound;
|
FAudioGMS_StaticSound *staticSound; /* static sounds are loaded separately, so they do not belong to the instance */
|
||||||
/* TODO: streaming */
|
FAudioGMS_StreamingSound streamingSound;
|
||||||
} parent;
|
} soundData;
|
||||||
} FAudioGMS_SoundInstance;
|
} FAudioGMS_SoundInstance;
|
||||||
|
|
||||||
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 * 128 * sizeof(float) /* FIXME: what should this value be? */
|
||||||
|
|
||||||
typedef struct FAudioGMS_Device
|
typedef struct FAudioGMS_Device
|
||||||
{
|
{
|
||||||
|
@ -153,6 +272,8 @@ typedef struct FAudioGMS_Device
|
||||||
FAudioGMS_SoundInstance **soundInstances;
|
FAudioGMS_SoundInstance **soundInstances;
|
||||||
uint32_t soundInstanceCount;
|
uint32_t soundInstanceCount;
|
||||||
IdStack soundInstanceIndexStack;
|
IdStack soundInstanceIndexStack;
|
||||||
|
|
||||||
|
float streamStagingBuffer[STREAMING_BUFFER_SIZE];
|
||||||
} FAudioGMS_Device;
|
} FAudioGMS_Device;
|
||||||
|
|
||||||
static FAudioGMS_Device* device = NULL;
|
static FAudioGMS_Device* device = NULL;
|
||||||
|
@ -291,68 +412,6 @@ void FAudioGMS_Init(double spatialDistanceScale)
|
||||||
fflush(stdout);
|
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 */
|
/* Taken from https://github.com/FNA-XNA/FNA/blob/master/src/Audio/SoundEffectInstance.cs */
|
||||||
static void SetPanMatrixCoefficients(FAudioGMS_SoundInstance *instance)
|
static void SetPanMatrixCoefficients(FAudioGMS_SoundInstance *instance)
|
||||||
{
|
{
|
||||||
|
@ -647,6 +706,18 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetVolume(FAudioGMS_SoundInstance*
|
||||||
FAudioVoice_SetVolume(instance->handle, volume, 0);
|
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)
|
static void FAudioGMS_INTERNAL_Apply3D(FAudioGMS_SoundInstance* instance)
|
||||||
{
|
{
|
||||||
F3DAUDIO_EMITTER* emitter = instance->emitter;
|
F3DAUDIO_EMITTER* emitter = instance->emitter;
|
||||||
|
@ -676,27 +747,23 @@ static void FAudioGMS_INTERNAL_Apply3D(FAudioGMS_SoundInstance* instance)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_CreateFromStaticSound(
|
static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init(
|
||||||
FAudioGMS_StaticSound *staticSound,
|
uint32_t channelCount,
|
||||||
double pan,
|
uint32_t samplesPerSecond
|
||||||
double pitch,
|
|
||||||
double volume,
|
|
||||||
double reverb
|
|
||||||
) {
|
) {
|
||||||
FAudioGMS_SoundInstance *instance = SDL_malloc(sizeof(FAudioGMS_SoundInstance));
|
FAudioGMS_SoundInstance* instance = SDL_malloc(sizeof(FAudioGMS_SoundInstance));
|
||||||
|
|
||||||
instance->handle = NULL;
|
instance->handle = NULL;
|
||||||
instance->parent.staticSound = staticSound;
|
|
||||||
instance->isStatic = 1;
|
|
||||||
instance->loop = 0;
|
instance->loop = 0;
|
||||||
instance->destroyOnFinish = 0;
|
instance->destroyOnFinish = 0;
|
||||||
|
|
||||||
instance->format.wFormatTag = 3;
|
instance->format.wFormatTag = FAUDIO_FORMAT_IEEE_FLOAT;
|
||||||
instance->format.wBitsPerSample = 32;
|
instance->format.wBitsPerSample = 32;
|
||||||
instance->format.nChannels = staticSound->channels;
|
instance->format.nChannels = channelCount;
|
||||||
instance->format.nBlockAlign = (uint16_t)(4 * staticSound->channels);
|
instance->format.nBlockAlign = (uint16_t)(4 * channelCount);
|
||||||
instance->format.nSamplesPerSec = staticSound->samplesPerSecond;
|
instance->format.nSamplesPerSec = samplesPerSecond;
|
||||||
instance->format.nAvgBytesPerSec = instance->format.nBlockAlign * staticSound->samplesPerSecond;
|
instance->format.nAvgBytesPerSec = instance->format.nBlockAlign * samplesPerSecond;
|
||||||
|
|
||||||
FAudio_CreateSourceVoice(
|
FAudio_CreateSourceVoice(
|
||||||
device->handle,
|
device->handle,
|
||||||
|
@ -716,27 +783,22 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_CreateFromStati
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->dspSettings.DopplerFactor = 1.0f;
|
instance->dspSettings.DopplerFactor = 1.0f;
|
||||||
instance->dspSettings.SrcChannelCount = staticSound->channels;
|
instance->dspSettings.SrcChannelCount = channelCount;
|
||||||
instance->dspSettings.DstChannelCount = device->deviceDetails.OutputFormat.Format.nChannels;
|
instance->dspSettings.DstChannelCount = device->deviceDetails.OutputFormat.Format.nChannels;
|
||||||
|
|
||||||
uint32_t memsize = 4 * instance->dspSettings.SrcChannelCount * instance->dspSettings.DstChannelCount;
|
uint32_t memsize = 4 * instance->dspSettings.SrcChannelCount * instance->dspSettings.DstChannelCount;
|
||||||
instance->dspSettings.pMatrixCoefficients = SDL_malloc(memsize);
|
instance->dspSettings.pMatrixCoefficients = SDL_malloc(memsize);
|
||||||
SDL_memset(instance->dspSettings.pMatrixCoefficients, 0, 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->reverbAttached = 0;
|
||||||
instance->reverb = 0.0f;
|
instance->reverb = 0.0f;
|
||||||
instance->lowPassFilter = 0.0f;
|
instance->lowPassFilter = 0.0f;
|
||||||
instance->highPassFilter = 0.0f;
|
instance->highPassFilter = 0.0f;
|
||||||
instance->bandPassFilter = 0.0f;
|
instance->bandPassFilter = 0.0f;
|
||||||
|
|
||||||
if (reverb > 0.0f)
|
FAudioGMS_INTERNAL_SoundInstance_SetPan(instance, 0);
|
||||||
{
|
FAudioGMS_INTERNAL_SoundInstance_SetPitch(instance, 1);
|
||||||
FAudioGMS_INTERNAL_SoundInstance_SetReverb(instance, reverb);
|
FAudioGMS_INTERNAL_SoundInstance_SetVolume(instance, 1);
|
||||||
}
|
|
||||||
|
|
||||||
instance->soundState = SoundState_Stopped;
|
instance->soundState = SoundState_Stopped;
|
||||||
|
|
||||||
|
@ -762,6 +824,47 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_CreateFromStati
|
||||||
return instance;
|
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)
|
static void FAudioGMS_INTERNAL_StaticSound_AddEmitter(FAudioGMS_SoundInstance* instance, float x, float y, float z)
|
||||||
{
|
{
|
||||||
instance->is3D = 1;
|
instance->is3D = 1;
|
||||||
|
@ -803,32 +906,126 @@ static void FAudioGMS_INTERNAL_StaticSound_AddEmitter(FAudioGMS_SoundInstance* i
|
||||||
FAudioGMS_INTERNAL_Apply3D(instance);
|
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;
|
||||||
|
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->isStatic)
|
|
||||||
{
|
|
||||||
if (instance->soundState == SoundState_Playing)
|
if (instance->soundState == SoundState_Playing)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instance->isStatic)
|
||||||
|
{
|
||||||
if (instance->loop)
|
if (instance->loop)
|
||||||
{
|
{
|
||||||
instance->parent.staticSound->buffer.LoopCount = FAUDIO_LOOP_INFINITE;
|
instance->soundData.staticSound->buffer.LoopCount = FAUDIO_LOOP_INFINITE;
|
||||||
instance->parent.staticSound->buffer.LoopBegin = instance->parent.staticSound->loopStart;
|
instance->soundData.staticSound->buffer.LoopBegin = instance->soundData.staticSound->loopStart;
|
||||||
instance->parent.staticSound->buffer.LoopLength = instance->parent.staticSound->loopLength;
|
instance->soundData.staticSound->buffer.LoopLength = instance->soundData.staticSound->loopLength;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
instance->parent.staticSound->buffer.LoopCount = 0;
|
instance->soundData.staticSound->buffer.LoopCount = 0;
|
||||||
instance->parent.staticSound->buffer.LoopBegin = 0;
|
instance->soundData.staticSound->buffer.LoopBegin = 0;
|
||||||
instance->parent.staticSound->buffer.LoopLength = 0;
|
instance->soundData.staticSound->buffer.LoopLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &instance->soundData.staticSound->buffer, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &instance->parent.staticSound->buffer, NULL);
|
|
||||||
FAudioSourceVoice_Start(instance->handle, 0, 0);
|
FAudioSourceVoice_Start(instance->handle, 0, 0);
|
||||||
instance->soundState = SoundState_Playing;
|
instance->soundState = SoundState_Playing;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FAudioGMS_StaticSound_PlayOneOff(double staticSoundID, double pan, double pitch, double volume, double reverb)
|
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)
|
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;
|
instance->destroyOnFinish = 1;
|
||||||
|
FAudioGMS_INTERNAL_SoundInstance_SetProperties(instance, pan, pitch, volume, reverb);
|
||||||
FAudioGMS_INTERNAL_SoundInstance_Play(instance);
|
FAudioGMS_INTERNAL_SoundInstance_Play(instance);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -853,8 +1051,9 @@ void FAudioGMS_StaticSound_PlayOneOffSpatial(double staticSoundID, double x, dou
|
||||||
|
|
||||||
if (staticSound != NULL)
|
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;
|
instance->destroyOnFinish = 1;
|
||||||
|
FAudioGMS_INTERNAL_SoundInstance_SetProperties(instance, 0, pitch, volume, reverb);
|
||||||
FAudioGMS_INTERNAL_StaticSound_AddEmitter(instance, x, y, z);
|
FAudioGMS_INTERNAL_StaticSound_AddEmitter(instance, x, y, z);
|
||||||
FAudioGMS_INTERNAL_SoundInstance_Play(instance);
|
FAudioGMS_INTERNAL_SoundInstance_Play(instance);
|
||||||
}
|
}
|
||||||
|
@ -870,8 +1069,9 @@ double FAudioGMS_StaticSound_Play(double staticSoundID, double pan, double pitch
|
||||||
|
|
||||||
if (staticSound != NULL)
|
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;
|
instance->loop = (uint8_t)loop;
|
||||||
|
FAudioGMS_INTERNAL_SoundInstance_SetProperties(instance, pan, pitch, volume, reverb);
|
||||||
FAudioGMS_INTERNAL_SoundInstance_Play(instance);
|
FAudioGMS_INTERNAL_SoundInstance_Play(instance);
|
||||||
return (double)instance->id;
|
return (double)instance->id;
|
||||||
}
|
}
|
||||||
|
@ -888,8 +1088,9 @@ double FAudioGMS_StaticSound_PlaySpatial(double staticSoundID, double x, double
|
||||||
|
|
||||||
if (staticSound != NULL)
|
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;
|
instance->loop = (uint8_t)loop;
|
||||||
|
FAudioGMS_INTERNAL_SoundInstance_SetProperties(instance, 0, pitch, volume, reverb);
|
||||||
FAudioGMS_INTERNAL_StaticSound_AddEmitter(instance, x, y, z);
|
FAudioGMS_INTERNAL_StaticSound_AddEmitter(instance, x, y, z);
|
||||||
FAudioGMS_INTERNAL_SoundInstance_Play(instance);
|
FAudioGMS_INTERNAL_SoundInstance_Play(instance);
|
||||||
return (double)instance->id;
|
return (double)instance->id;
|
||||||
|
@ -916,8 +1117,6 @@ void FAudioGMS_SoundInstance_Pause(double id)
|
||||||
FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)id);
|
FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)id);
|
||||||
|
|
||||||
if (instance != NULL)
|
if (instance != NULL)
|
||||||
{
|
|
||||||
if (instance->isStatic)
|
|
||||||
{
|
{
|
||||||
if (instance->soundState == SoundState_Playing)
|
if (instance->soundState == SoundState_Playing)
|
||||||
{
|
{
|
||||||
|
@ -925,23 +1124,22 @@ void FAudioGMS_SoundInstance_Pause(double id)
|
||||||
instance->soundState = SoundState_Paused;
|
instance->soundState = SoundState_Paused;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log("SoundInstance_Pause: Invalid sound instance ID! Did you destroy this instance?");
|
Log("SoundInstance_Pause: Invalid sound instance ID! Did you destroy this instance?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 != NULL)
|
||||||
{
|
{
|
||||||
if (instance->isStatic)
|
if (instance->isStatic)
|
||||||
{
|
{
|
||||||
FAudioSourceVoice_ExitLoop(instance->handle, 0);
|
FAudioSourceVoice_ExitLoop(instance->handle, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instance->soundState = SoundState_Stopped;
|
||||||
}
|
}
|
||||||
else
|
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)
|
void FAudioGMS_SoundInstance_Set3DPosition(double soundInstanceID, double x, double y, double z)
|
||||||
{
|
{
|
||||||
FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)soundInstanceID);
|
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;
|
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()
|
void FAudioGMS_Update()
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
@ -997,6 +1293,12 @@ void FAudioGMS_Update()
|
||||||
FAudioGMS_INTERNAL_Apply3D(instance);
|
FAudioGMS_INTERNAL_Apply3D(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
|
@ -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 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 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_Play(double id);
|
||||||
FAUDIOGMSAPI void FAudioGMS_SoundInstance_Pause(double id);
|
FAUDIOGMSAPI void FAudioGMS_SoundInstance_Pause(double id);
|
||||||
FAUDIOGMSAPI void FAudioGMS_SoundInstance_Stop(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_Set3DPosition(double soundInstanceID, double x, double y, double z);
|
||||||
FAUDIOGMSAPI void FAudioGMS_SoundInstance_Destroy(double id);
|
FAUDIOGMSAPI void FAudioGMS_SoundInstance_Destroy(double id);
|
||||||
FAUDIOGMSAPI void FAudioGMS_SoundInstance_DestroyWhenFinished(double id);
|
FAUDIOGMSAPI void FAudioGMS_SoundInstance_DestroyWhenFinished(double id);
|
||||||
|
|
|
@ -57,6 +57,10 @@
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||||
<EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
|
<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>
|
||||||
<PropertyGroup Label="Vcpkg">
|
<PropertyGroup Label="Vcpkg">
|
||||||
<VcpkgEnabled>false</VcpkgEnabled>
|
<VcpkgEnabled>false</VcpkgEnabled>
|
||||||
|
|
Loading…
Reference in New Issue