initial voice refactor

remotes/1734709060101541481/main
cosmonaut 2021-11-01 12:08:36 -07:00
parent 9f4f2a50c4
commit 5a7f98944c
2 changed files with 198 additions and 108 deletions

View File

@ -149,6 +149,17 @@ typedef enum FAudioGMS_SoundState
SoundState_Stopped
} FAudioGMS_SoundState;
typedef struct FAudioGMS_Voice
{
FAudioVoice* handle;
FAudioVoiceSends sends;
uint8_t effectChainAttached;
FAudioSubmixVoice* effectVoice;
FAudioVoiceSends effectSends;
float effectGain;
} FAudioGMS_Voice;
typedef struct FAudioGMS_StaticSound
{
uint32_t id;
@ -171,7 +182,7 @@ typedef struct FAudioGMS_StreamingSound
typedef struct FAudioGMS_SoundInstance
{
uint32_t id;
FAudioSourceVoice *handle;
FAudioGMS_Voice voice;
FAudioWaveFormatEx format;
uint8_t loop; /* bool */
FAudioGMS_SoundState soundState;
@ -184,11 +195,6 @@ typedef struct FAudioGMS_SoundInstance
float highPassFilter;
float bandPassFilter;
uint8_t effectChainAttached;
FAudioSubmixVoice* effectVoice;
FAudioVoiceSends effectSends;
float effectGain;
uint8_t adjustingVolumeOverTime;
float targetVolume;
float volumeDelta;
@ -238,6 +244,8 @@ typedef struct FAudioGMS_Device
FAudioDeviceDetails deviceDetails;
FAudioMasteringVoice *masteringVoice;
FAudioGMS_Voice fauxMasteringVoice;
F3DAUDIO_LISTENER listener;
float spatialDistanceScale;
@ -386,6 +394,36 @@ void FAudioGMS_Init(double spatialDistanceScale, double timestep)
return;
}
device->fauxMasteringVoice.sends.SendCount = 1;
device->fauxMasteringVoice.sends.pSends = SDL_malloc(sizeof(FAudioSendDescriptor));
device->fauxMasteringVoice.sends.pSends[0].Flags = 0;
device->fauxMasteringVoice.sends.pSends[0].pOutputVoice = device->masteringVoice;
if (FAudio_CreateSubmixVoice(
device->handle,
&device->fauxMasteringVoice.handle,
FAUDIO_DEFAULT_CHANNELS,
FAUDIO_DEFAULT_SAMPLERATE,
0,
i,
&device->fauxMasteringVoice.sends,
NULL
) != 0)
{
Log("Failed to create faux mastering voice! Bailing!");
FAudioVoice_DestroyVoice(device->masteringVoice);
FAudio_Release(device->handle);
SDL_free(device);
device = NULL;
return;
}
device->fauxMasteringVoice.effectChainAttached = 0;
device->fauxMasteringVoice.effectGain = 0;
device->fauxMasteringVoice.effectVoice = NULL;
device->fauxMasteringVoice.effectSends.SendCount = 0;
device->fauxMasteringVoice.effectSends.pSends = NULL;
device->spatialDistanceScale = spatialDistanceScale;
F3DAudioInitialize(
@ -543,8 +581,8 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetPan(FAudioGMS_SoundInstance* ins
SetPanMatrixCoefficients(instance);
FAudioVoice_SetOutputMatrix(
instance->handle,
device->masteringVoice,
instance->voice.handle,
device->fauxMasteringVoice.handle,
instance->dspSettings.SrcChannelCount,
instance->dspSettings.DstChannelCount,
instance->dspSettings.pMatrixCoefficients,
@ -566,7 +604,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_UpdatePitch(FAudioGMS_SoundInstance
}
FAudioSourceVoice_SetFrequencyRatio(
instance->handle,
instance->voice.handle,
SDL_powf(2.0f, instance->pitch - 1) * doppler, /* FAudio expects pitch range to be -1.0 to 1.0 while GM uses 0.0 to 2.0 so we adjust here */
0
);
@ -582,7 +620,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetPitch(FAudioGMS_SoundInstance* i
static void FAudioGMS_INTERNAL_SoundInstance_SetVolume(FAudioGMS_SoundInstance* instance, float volume)
{
instance->volume = volume;
FAudioVoice_SetVolume(instance->handle, volume, 0);
FAudioVoice_SetVolume(instance->voice.handle, volume, 0);
}
static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init(
@ -592,7 +630,7 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init(
) {
FAudioGMS_SoundInstance* instance = SDL_malloc(sizeof(FAudioGMS_SoundInstance));
instance->handle = NULL;
instance->voice.handle = NULL;
instance->isStatic = isStatic;
instance->loop = 0;
@ -606,17 +644,22 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init(
instance->format.nSamplesPerSec = samplesPerSecond;
instance->format.nAvgBytesPerSec = instance->format.nBlockAlign * samplesPerSecond;
instance->voice.sends.SendCount = 1;
instance->voice.sends.pSends = SDL_malloc(sizeof(FAudioSendDescriptor));
instance->voice.sends.pSends[0].Flags = 0;
instance->voice.sends.pSends[0].pOutputVoice = device->fauxMasteringVoice.handle;
FAudio_CreateSourceVoice(
device->handle,
&instance->handle,
&instance->voice.handle,
&instance->format,
FAUDIO_VOICE_USEFILTER,
FAUDIO_DEFAULT_FREQ_RATIO,
isStatic ? NULL : &device->voiceCallbacks,
NULL,
&instance->voice.sends,
NULL);
if (instance->handle == NULL)
if (instance->voice.handle == NULL)
{
Log("SoundInstance failed to initialize!");
SDL_free(instance);
@ -631,9 +674,9 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init(
instance->dspSettings.pMatrixCoefficients = SDL_malloc(memsize);
SDL_memset(instance->dspSettings.pMatrixCoefficients, 0, memsize);
instance->effectChainAttached = 0;
instance->effectVoice = NULL;
instance->effectGain = 0;
instance->voice.effectChainAttached = 0;
instance->voice.effectVoice = NULL;
instance->voice.effectGain = 0;
instance->lowPassFilter = 0.0f;
instance->highPassFilter = 0.0f;
@ -710,7 +753,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetLowPassFilter(FAudioGMS_SoundIns
p.Frequency = SDL_max(0.0, SDL_min(1.0, lowPassFilter));
p.OneOverQ = 1.0f / Q;
FAudioVoice_SetFilterParameters(instance->handle, &p, 0);
FAudioVoice_SetFilterParameters(instance->voice.handle, &p, 0);
instance->lowPassFilter = lowPassFilter;
}
@ -732,7 +775,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetHighPassFilter(FAudioGMS_SoundIn
p.Frequency = SDL_max(0.0, SDL_min(1.0, highPassFilter));
p.OneOverQ = 1.0f / Q;
FAudioVoice_SetFilterParameters(instance->handle, &p, 0);
FAudioVoice_SetFilterParameters(instance->voice.handle, &p, 0);
instance->highPassFilter = highPassFilter;
}
@ -754,7 +797,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_SetBandPassFilter(FAudioGMS_SoundIn
p.Frequency = SDL_max(0.0, SDL_min(1.0, bandPassFilter));
p.OneOverQ = 1.0f / Q;
FAudioVoice_SetFilterParameters(instance->handle, &p, 0);
FAudioVoice_SetFilterParameters(instance->voice.handle, &p, 0);
instance->bandPassFilter = bandPassFilter;
}
@ -789,8 +832,8 @@ static void FAudioGMS_INTERNAL_Apply3D(FAudioGMS_SoundInstance* instance)
FAudioGMS_INTERNAL_SoundInstance_UpdatePitch(instance);
FAudioVoice_SetOutputMatrix(
instance->handle,
device->masteringVoice,
instance->voice.handle,
device->fauxMasteringVoice.handle,
instance->dspSettings.SrcChannelCount,
instance->dspSettings.DstChannelCount,
instance->dspSettings.pMatrixCoefficients,
@ -832,7 +875,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance*
buffer.LoopLength = 0;
buffer.pContext = instance; /* context for OnBufferEnd callback */
FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &buffer, NULL);
FAudioSourceVoice_SubmitSourceBuffer(instance->voice.handle, &buffer, NULL);
/* We have reached the end of the file! */
/* FIXME: maybe move this to a OnStreamEnd callback? */
@ -943,10 +986,10 @@ static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* insta
instance->soundData.staticSound->buffer.LoopLength = 0;
}
FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &instance->soundData.staticSound->buffer, NULL);
FAudioSourceVoice_SubmitSourceBuffer(instance->voice.handle, &instance->soundData.staticSound->buffer, NULL);
}
FAudioSourceVoice_Start(instance->handle, 0, 0);
FAudioSourceVoice_Start(instance->voice.handle, 0, 0);
instance->soundState = SoundState_Playing;
}
@ -968,7 +1011,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_Pause(FAudioGMS_SoundInstance* inst
{
if (instance->soundState == SoundState_Playing)
{
FAudioSourceVoice_Stop(instance->handle, 0, 0); /* this actually just pauses lol */
FAudioSourceVoice_Stop(instance->voice.handle, 0, 0); /* this actually just pauses lol */
instance->soundState = SoundState_Paused;
}
}
@ -991,8 +1034,8 @@ static void FAudioGMS_INTERNAL_SoundInstance_Stop(FAudioGMS_SoundInstance* insta
{
instance->soundState = SoundState_Stopped; /* set this before so flush buffers doesn't trigger buffer add callback */
FAudioSourceVoice_Stop(instance->handle, 0, 0);
FAudioSourceVoice_FlushSourceBuffers(instance->handle);
FAudioSourceVoice_Stop(instance->voice.handle, 0, 0);
FAudioSourceVoice_FlushSourceBuffers(instance->voice.handle);
if (!instance->isStatic)
{
@ -1101,8 +1144,8 @@ void FAudioGMS_SoundInstance_SetTrackPositionInSeconds(double soundInstanceID, d
FAudioGMS_SoundState currentState = instance->soundState;
if (currentState == SoundState_Playing)
{
FAudioSourceVoice_Stop(instance->handle, 0, 0);
FAudioSourceVoice_FlushSourceBuffers(instance->handle);
FAudioSourceVoice_Stop(instance->voice.handle, 0, 0);
FAudioSourceVoice_FlushSourceBuffers(instance->voice.handle);
}
if (instance->isStatic)
@ -1197,7 +1240,7 @@ double FAudioGMS_SoundInstance_GetTrackPositionInSeconds(double soundInstanceID)
if (instance != NULL)
{
uint32_t sampleFrame = instance->handle->src.curBufferOffset / sizeof(float);
uint32_t sampleFrame = instance->voice.handle->src.curBufferOffset / sizeof(float);
return sampleFrame / instance->format.nSamplesPerSec;
}
else
@ -1231,13 +1274,14 @@ static void FAudioGMS_INTERNAL_SoundInstance_Destroy(FAudioGMS_SoundInstance* in
IdStack_Push(&device->soundInstanceIndexStack, instance->id);
FAudioGMS_INTERNAL_SoundInstance_Stop(instance);
if (instance->effectChainAttached)
if (instance->voice.effectChainAttached)
{
FAudioVoice_DestroyVoice(instance->effectVoice);
SDL_free(instance->effectSends.pSends);
FAudioVoice_DestroyVoice(instance->voice.effectVoice);
SDL_free(instance->voice.effectSends.pSends);
}
FAudioVoice_DestroyVoice(instance->handle);
SDL_free(instance->voice.sends.pSends);
FAudioVoice_DestroyVoice(instance->voice.handle);
if (!instance->isStatic)
{
@ -1419,27 +1463,29 @@ void FAudioGMS_EffectChain_AddReverb(
}
}
static void FAudioGMS_INTERNAL_SoundInstance_SetEffectGain(FAudioGMS_SoundInstance *instance, float effectGain)
static void FAudioGMS_INTERNAL_Voice_SetEffectGain(FAudioGMS_Voice *voice, float effectGain)
{
if (instance->effectChainAttached)
if (voice->effectChainAttached)
{
float* outputMatrix = instance->dspSettings.pMatrixCoefficients;
float* outputMatrix = SDL_stack_alloc(float, voice->effectSends.SendCount);
outputMatrix[0] = effectGain;
if (instance->dspSettings.SrcChannelCount == 2)
if (voice->effectSends.SendCount == 2)
{
outputMatrix[1] = effectGain;
}
FAudioVoice_SetOutputMatrix(
instance->handle,
instance->effectVoice,
instance->dspSettings.SrcChannelCount,
voice->handle,
voice->effectVoice,
voice->effectSends.SendCount,
1,
outputMatrix,
0);
instance->effectGain = effectGain;
voice->effectGain = effectGain;
SDL_stack_free(outputMatrix);
}
}
@ -1450,7 +1496,7 @@ void FAudioGMS_SoundInstance_SetEffectGain(double soundInstanceID, double effect
if (instance != NULL)
{
FAudioGMS_INTERNAL_SoundInstance_SetEffectGain(instance, effectGain);
FAudioGMS_INTERNAL_Voice_SetEffectGain(&instance->voice, effectGain);
}
}
@ -1486,79 +1532,116 @@ static FAudioEffectChain* FAudioGMS_INTERNAL_CreateFAudioEffectChain(FAudioGMS_E
return fAudioEffectChain;
}
static void FAudioGMS_INTERNAL_SetEffectChain(FAudioGMS_Voice* voice, FAudioGMS_EffectChain* effectChain, float effectGain)
{
uint32_t i;
if (voice->effectChainAttached)
{
/* This frees the effect chain on the voice */
FAudioVoice_SetEffectChain(voice->effectVoice, NULL);
SDL_free(voice->effectSends.pSends);
}
else
{
voice->sends.pSends = SDL_realloc(voice->sends.pSends, 2 * sizeof(FAudioSendDescriptor));
}
FAudioEffectChain* fAudioEffectChain = FAudioGMS_INTERNAL_CreateFAudioEffectChain(effectChain);
voice->effectSends.SendCount = 1;
voice->effectSends.pSends = SDL_malloc(sizeof(FAudioSendDescriptor));
voice->effectSends.pSends[0].Flags = 0;
voice->effectSends.pSends[0].pOutputVoice = device->fauxMasteringVoice.handle;
FAudio_CreateSubmixVoice(
device->handle,
&voice->effectVoice,
1, /* FIXME: is this correct? */
device->deviceDetails.OutputFormat.Format.nSamplesPerSec,
0,
0,
&voice->effectSends,
fAudioEffectChain);
/* Copy the effect params */
for (i = 0; i < effectChain->effectCount; i += 1)
{
uint32_t parametersSize;
void* parameters;
switch (effectChain->effectTypes[i])
{
case EffectType_Reverb:
parametersSize = sizeof(FAudioFXReverbParameters);
parameters = &effectChain->effectParameters[i].reverbParameters;
break;
default:
Log("Unknown effect type! Something is very wrong!");
}
FAudioVoice_SetEffectParameters(
voice->effectVoice,
i,
parameters,
parametersSize,
0);
}
/* Set the instance voice to go through both faux mastering and effect voice for wet/dry */
voice->sends.pSends[0].Flags = 0;
voice->sends.pSends[0].pOutputVoice = device->fauxMasteringVoice.handle;
voice->sends.pSends[1].Flags = 0;
voice->sends.pSends[1].pOutputVoice = voice->effectVoice;
voice->effectChainAttached = 1;
FAudioVoice_SetOutputVoices(
voice->handle,
&voice->effectSends);
FAudioGMS_INTERNAL_Voice_SetEffectGain(voice, effectGain);
/* All the effect parameters are copied to the voice so we free here */
for (i = 0; i < effectChain->effectCount; i += 1)
{
FAPOBase_Release((FAPOBase*)fAudioEffectChain->pEffectDescriptors[i].pEffect);
}
SDL_free(fAudioEffectChain->pEffectDescriptors);
SDL_free(fAudioEffectChain);
}
void FAudioGMS_SoundInstance_SetEffectChain(double soundInstanceID, double effectChainID, double effectGain)
{
RETURN_ON_NULL_DEVICE()
FAudioGMS_SoundInstance *instance = FAudioGMS_INTERNAL_LookupSoundInstance((uint32_t)soundInstanceID);
FAudioGMS_EffectChain *effectChain = FAudioGMS_INTERNAL_LookupEffectChain((uint32_t)effectChainID);
uint32_t i;
if (instance != NULL && effectChain != NULL)
{
if (instance->effectChainAttached)
{
/* This frees the effect chain on the voice */
FAudioVoice_SetEffectChain(instance->handle, NULL);
}
FAudioGMS_INTERNAL_SetEffectChain(&instance->voice, effectChain, effectGain);
}
}
FAudioEffectChain* fAudioEffectChain = FAudioGMS_INTERNAL_CreateFAudioEffectChain(effectChain);
FAudio_CreateSubmixVoice(
device->handle,
&instance->effectVoice,
1, /* FIXME: is this correct? */
device->deviceDetails.OutputFormat.Format.nSamplesPerSec,
0,
0,
NULL,
fAudioEffectChain);
void FAudioGMS_SetMasteringEffectChain(double effectChainID, double effectGain)
{
RETURN_ON_NULL_DEVICE()
FAudioGMS_EffectChain* effectChain = FAudioGMS_INTERNAL_LookupEffectChain((uint32_t)effectChainID);
if (effectChain != NULL)
{
FAudioGMS_INTERNAL_SetEffectChain(&device->fauxMasteringVoice, effectChain, effectGain);
}
}
instance->effectSends.SendCount = 2;
instance->effectSends.pSends = SDL_malloc(2 * sizeof(FAudioSendDescriptor));
instance->effectSends.pSends[0].Flags = 0;
instance->effectSends.pSends[0].pOutputVoice = device->masteringVoice;
instance->effectSends.pSends[1].Flags = 0;
instance->effectSends.pSends[1].pOutputVoice = instance->effectVoice;
instance->effectChainAttached = 1;
for (i = 0; i < effectChain->effectCount; i += 1)
{
uint32_t parametersSize;
void *parameters;
switch (effectChain->effectTypes[i])
{
case EffectType_Reverb:
parametersSize = sizeof(FAudioFXReverbParameters);
parameters = &effectChain->effectParameters[i].reverbParameters;
break;
default:
Log("Unknown effect type! Something is very wrong!");
}
FAudioVoice_SetEffectParameters(
instance->effectVoice,
i,
parameters,
parametersSize,
0);
}
FAudioVoice_SetOutputVoices(
instance->handle,
&instance->effectSends);
FAudioGMS_INTERNAL_SoundInstance_SetEffectGain(instance, effectGain);
/* all the effect parameters are copied to the voice so we free here */
for (i = 0; i < effectChain->effectCount; i += 1)
{
FAPOBase_Release((FAPOBase*)fAudioEffectChain->pEffectDescriptors[i].pEffect);
}
SDL_free(fAudioEffectChain->pEffectDescriptors);
SDL_free(fAudioEffectChain);
void FAudioGMS_SetMasteringEffectGain(double effectGain)
{
RETURN_ON_NULL_DEVICE()
if (device->fauxMasteringVoice.effectChainAttached)
{
FAudioGMS_INTERNAL_Voice_SetEffectGain(&device->fauxMasteringVoice, effectGain);
}
}
@ -1632,7 +1715,7 @@ void FAudioGMS_Update()
if (instance->destroyOnFinish)
{
FAudioVoiceState state;
FAudioSourceVoice_GetState(instance->handle, &state, FAUDIO_VOICE_NOSAMPLESPLAYED);
FAudioSourceVoice_GetState(instance->voice.handle, &state, FAUDIO_VOICE_NOSAMPLESPLAYED);
if (state.BuffersQueued == 0)
{
@ -1706,6 +1789,10 @@ void FAudioGMS_Destroy()
FAudioGMS_INTERNAL_StaticSound_Destroy(device->staticSounds[i]);
}
/* FIXME: FAudioGMS_Voice_Destroy call */
FAudioVoice_DestroyVoice(device->fauxMasteringVoice.handle);
SDL_free(device->fauxMasteringVoice.sends.pSends);
FAudio_Release(device->handle);
SDL_free(device);
device = NULL;

View File

@ -98,6 +98,9 @@ FAUDIOGMSAPI void FAudioGMS_EffectChain_Destroy(double effectChainID);
FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetEffectChain(double soundInstanceID, double effectChainID, double effectGain);
FAUDIOGMSAPI void FAudioGMS_SoundInstance_SetEffectGain(double soundInstanceID, double effectGain);
FAUDIOGMSAPI void FAudioGMS_SetMasteringEffectChain(double effectChainID, double effectGain);
FAUDIOGMSAPI void FAudioGMS_SetMasteringEffectGain(double effectGain);
FAUDIOGMSAPI void FAudioGMS_SetListenerPosition(double x, double y, double z);
FAUDIOGMSAPI void FAudioGMS_SetListenerVelocity(double xVelocity, double yVelocity, double zVelocity);