forked from MoonsideGames/FAudioGMS
refactor effect chains to use a single voice
parent
4e1f53ce03
commit
6d8c80064c
BIN
gamemaker/extensions/FAudioGMS/FAudioGMS.dll (Stored with Git LFS)
BIN
gamemaker/extensions/FAudioGMS/FAudioGMS.dll (Stored with Git LFS)
Binary file not shown.
197
src/FAudioGMS.c
197
src/FAudioGMS.c
|
@ -155,7 +155,9 @@ typedef union FAudioGMS_EffectParameters
|
||||||
typedef struct FAudioGMS_EffectChain
|
typedef struct FAudioGMS_EffectChain
|
||||||
{
|
{
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint32_t effectCount;
|
FAudioEffectChain fAudioEffectChain;
|
||||||
|
FAudioSubmixVoice *effectVoice;
|
||||||
|
FAudioVoiceSends effectSends;
|
||||||
FAudioGMS_EffectType *effectTypes; /* length equal to effectCount */
|
FAudioGMS_EffectType *effectTypes; /* length equal to effectCount */
|
||||||
union FAudioGMS_EffectParameters *effectParameters; /* length equal to effectCount */
|
union FAudioGMS_EffectParameters *effectParameters; /* length equal to effectCount */
|
||||||
} FAudioGMS_EffectChain;
|
} FAudioGMS_EffectChain;
|
||||||
|
@ -174,8 +176,6 @@ typedef struct FAudioGMS_Voice
|
||||||
|
|
||||||
uint8_t effectChainAttached;
|
uint8_t effectChainAttached;
|
||||||
FAudioGMS_EffectChain *effectChain;
|
FAudioGMS_EffectChain *effectChain;
|
||||||
FAudioSubmixVoice *effectVoice;
|
|
||||||
FAudioVoiceSends effectSends;
|
|
||||||
float effectGain;
|
float effectGain;
|
||||||
} FAudioGMS_Voice;
|
} FAudioGMS_Voice;
|
||||||
|
|
||||||
|
@ -375,13 +375,13 @@ static void FAudioGMS_INTERNAL_OnBufferEndCallback(
|
||||||
{
|
{
|
||||||
/* this is a callback so we don't want to immediately destroy and screw up data */
|
/* this is a callback so we don't want to immediately destroy and screw up data */
|
||||||
instance->destroyTimerActive = 1;
|
instance->destroyTimerActive = 1;
|
||||||
instance->destroyTimer = 0;
|
instance->destroyTimer = 0;
|
||||||
|
|
||||||
if (instance->voice.effectChainAttached)
|
if (instance->voice.effectChainAttached)
|
||||||
{
|
{
|
||||||
/* If we have active reverb we don't want to clean up until the decay time is over
|
/* If we have active reverb we don't want to clean up until the decay time is over
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < instance->voice.effectChain->effectCount; i += 1)
|
for (i = 0; i < instance->voice.effectChain->fAudioEffectChain.EffectCount; i += 1)
|
||||||
{
|
{
|
||||||
if (instance->voice.effectChain->effectTypes[i] == EffectType_Reverb)
|
if (instance->voice.effectChain->effectTypes[i] == EffectType_Reverb)
|
||||||
{
|
{
|
||||||
|
@ -485,9 +485,6 @@ void FAudioGMS_Init(double spatialDistanceScale, double timestep)
|
||||||
|
|
||||||
device->fauxMasteringVoice.effectChainAttached = 0;
|
device->fauxMasteringVoice.effectChainAttached = 0;
|
||||||
device->fauxMasteringVoice.effectGain = 0;
|
device->fauxMasteringVoice.effectGain = 0;
|
||||||
device->fauxMasteringVoice.effectVoice = NULL;
|
|
||||||
device->fauxMasteringVoice.effectSends.SendCount = 0;
|
|
||||||
device->fauxMasteringVoice.effectSends.pSends = NULL;
|
|
||||||
|
|
||||||
device->spatialDistanceScale = spatialDistanceScale;
|
device->spatialDistanceScale = spatialDistanceScale;
|
||||||
|
|
||||||
|
@ -645,7 +642,7 @@ static void SetPanMatrixCoefficients(FAudioGMS_SoundInstance *instance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FAudioGMS_INTERNAL_SoundInstance_ApplyPan(FAudioGMS_SoundInstance* instance)
|
static void FAudioGMS_INTERNAL_SoundInstance_ApplyPan(FAudioGMS_SoundInstance* instance)
|
||||||
{
|
{
|
||||||
SetPanMatrixCoefficients(instance);
|
SetPanMatrixCoefficients(instance);
|
||||||
|
|
||||||
|
@ -760,7 +757,6 @@ static FAudioGMS_SoundInstance *FAudioGMS_INTERNAL_SoundInstance_Init(
|
||||||
|
|
||||||
instance->voice.effectChainAttached = 0;
|
instance->voice.effectChainAttached = 0;
|
||||||
instance->voice.effectChain = NULL;
|
instance->voice.effectChain = NULL;
|
||||||
instance->voice.effectVoice = NULL;
|
|
||||||
instance->voice.effectGain = 0;
|
instance->voice.effectGain = 0;
|
||||||
|
|
||||||
instance->lowPassFilter = 0.0f;
|
instance->lowPassFilter = 0.0f;
|
||||||
|
@ -1580,12 +1576,6 @@ static void FAudioGMS_INTERNAL_SoundInstance_Destroy(FAudioGMS_SoundInstance *in
|
||||||
IdStack_Push(&device->soundInstanceIndexStack, instance->id);
|
IdStack_Push(&device->soundInstanceIndexStack, instance->id);
|
||||||
FAudioGMS_INTERNAL_SoundInstance_Stop(instance);
|
FAudioGMS_INTERNAL_SoundInstance_Stop(instance);
|
||||||
|
|
||||||
if (instance->voice.effectChainAttached)
|
|
||||||
{
|
|
||||||
FAudioVoice_DestroyVoice(instance->voice.effectVoice);
|
|
||||||
SDL_free(instance->voice.effectSends.pSends);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_free(instance->voice.sends.pSends);
|
SDL_free(instance->voice.sends.pSends);
|
||||||
FAudioVoice_DestroyVoice(instance->voice.handle);
|
FAudioVoice_DestroyVoice(instance->voice.handle);
|
||||||
|
|
||||||
|
@ -1651,7 +1641,6 @@ double FAudioGMS_EffectChain_Create()
|
||||||
RETURN_ON_NULL_DEVICE(-1.0)
|
RETURN_ON_NULL_DEVICE(-1.0)
|
||||||
FAudioGMS_EffectChain *effectChain = SDL_malloc(sizeof(FAudioGMS_EffectChain));
|
FAudioGMS_EffectChain *effectChain = SDL_malloc(sizeof(FAudioGMS_EffectChain));
|
||||||
|
|
||||||
effectChain->effectCount = 0;
|
|
||||||
effectChain->effectTypes = NULL;
|
effectChain->effectTypes = NULL;
|
||||||
effectChain->effectParameters = NULL;
|
effectChain->effectParameters = NULL;
|
||||||
|
|
||||||
|
@ -1671,6 +1660,25 @@ double FAudioGMS_EffectChain_Create()
|
||||||
|
|
||||||
device->effectChains[effectChain->id] = effectChain;
|
device->effectChains[effectChain->id] = effectChain;
|
||||||
|
|
||||||
|
effectChain->fAudioEffectChain.EffectCount = 0;
|
||||||
|
effectChain->fAudioEffectChain.pEffectDescriptors = NULL;
|
||||||
|
|
||||||
|
effectChain->effectSends.SendCount = 1;
|
||||||
|
effectChain->effectSends.pSends = SDL_malloc(sizeof(FAudioSendDescriptor));
|
||||||
|
|
||||||
|
effectChain->effectSends.pSends[0].Flags = 0;
|
||||||
|
effectChain->effectSends.pSends[0].pOutputVoice = device->masteringVoice;
|
||||||
|
|
||||||
|
FAudio_CreateSubmixVoice(
|
||||||
|
device->handle,
|
||||||
|
&effectChain->effectVoice,
|
||||||
|
1, /* FIXME: is this correct? */
|
||||||
|
device->deviceDetails.OutputFormat.Format.nSamplesPerSec,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
&effectChain->effectSends,
|
||||||
|
&effectChain->fAudioEffectChain);
|
||||||
|
|
||||||
return effectChain->id;
|
return effectChain->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1678,20 +1686,53 @@ static void FAudioGMS_INTERNAL_EffectChain_AddReverb(
|
||||||
FAudioGMS_EffectChain *effectChain,
|
FAudioGMS_EffectChain *effectChain,
|
||||||
FAudioFXReverbParameters *reverbParameters)
|
FAudioFXReverbParameters *reverbParameters)
|
||||||
{
|
{
|
||||||
effectChain->effectCount += 1;
|
uint32_t effectIndex;
|
||||||
|
|
||||||
|
effectChain->fAudioEffectChain.EffectCount += 1;
|
||||||
|
|
||||||
|
effectChain->fAudioEffectChain.pEffectDescriptors = SDL_realloc(
|
||||||
|
effectChain->fAudioEffectChain.pEffectDescriptors,
|
||||||
|
effectChain->fAudioEffectChain.EffectCount * sizeof(FAudioEffectDescriptor));
|
||||||
|
|
||||||
|
effectIndex = effectChain->fAudioEffectChain.EffectCount - 1;
|
||||||
|
|
||||||
effectChain->effectTypes = SDL_realloc(
|
effectChain->effectTypes = SDL_realloc(
|
||||||
effectChain->effectTypes,
|
effectChain->effectTypes,
|
||||||
effectChain->effectCount * sizeof(FAudioGMS_EffectType));
|
effectChain->fAudioEffectChain.EffectCount * sizeof(FAudioGMS_EffectType));
|
||||||
effectChain->effectTypes[effectChain->effectCount - 1] = EffectType_Reverb;
|
|
||||||
|
effectChain->effectTypes[effectIndex] = EffectType_Reverb;
|
||||||
|
|
||||||
effectChain->effectParameters = SDL_realloc(
|
effectChain->effectParameters = SDL_realloc(
|
||||||
effectChain->effectParameters,
|
effectChain->effectParameters,
|
||||||
effectChain->effectCount * sizeof(FAudioGMS_EffectParameters));
|
effectChain->fAudioEffectChain.EffectCount * sizeof(FAudioGMS_EffectParameters));
|
||||||
|
|
||||||
SDL_memcpy(
|
SDL_memcpy(
|
||||||
&effectChain->effectParameters[effectChain->effectCount - 1],
|
&effectChain->effectParameters[effectIndex],
|
||||||
reverbParameters,
|
reverbParameters,
|
||||||
sizeof(FAudioFXReverbParameters));
|
sizeof(FAudioFXReverbParameters));
|
||||||
|
|
||||||
|
FAPO *reverb;
|
||||||
|
|
||||||
|
FAudioCreateReverb(&reverb, 0);
|
||||||
|
|
||||||
|
FAudioEffectDescriptor *reverbDescriptor =
|
||||||
|
&effectChain->fAudioEffectChain.pEffectDescriptors[effectIndex];
|
||||||
|
reverbDescriptor->InitialState = 1;
|
||||||
|
reverbDescriptor->OutputChannels =
|
||||||
|
device->deviceDetails.OutputFormat.Format.nChannels == 6 ? 6 : 1;
|
||||||
|
reverbDescriptor->pEffect = reverb;
|
||||||
|
|
||||||
|
FAudioVoice_SetEffectChain(effectChain->effectVoice, &effectChain->fAudioEffectChain);
|
||||||
|
|
||||||
|
FAudioVoice_SetEffectParameters(
|
||||||
|
effectChain->effectVoice,
|
||||||
|
effectIndex,
|
||||||
|
&effectChain->effectParameters[effectIndex].reverbParameters,
|
||||||
|
sizeof(FAudioFXReverbParameters),
|
||||||
|
0);
|
||||||
|
|
||||||
|
/* All the effect parameters are copied to the voice so we free here */
|
||||||
|
FAPOBase_Release((FAPOBase*)reverb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FAudioGMS_EffectChain_AddDefaultReverb(double effectChainID)
|
void FAudioGMS_EffectChain_AddDefaultReverb(double effectChainID)
|
||||||
|
@ -1788,7 +1829,7 @@ static void FAudioGMS_INTERNAL_Voice_SetEffectGain(FAudioGMS_Voice *voice, float
|
||||||
{
|
{
|
||||||
if (voice->effectChainAttached)
|
if (voice->effectChainAttached)
|
||||||
{
|
{
|
||||||
float *outputMatrix = SDL_stack_alloc(float, voice->effectSends.SendCount);
|
float *outputMatrix = SDL_stack_alloc(float, voice->handle->outputChannels);
|
||||||
|
|
||||||
outputMatrix[0] = effectGain;
|
outputMatrix[0] = effectGain;
|
||||||
if (voice->handle->outputChannels == 2)
|
if (voice->handle->outputChannels == 2)
|
||||||
|
@ -1798,7 +1839,7 @@ static void FAudioGMS_INTERNAL_Voice_SetEffectGain(FAudioGMS_Voice *voice, float
|
||||||
|
|
||||||
FAudioVoice_SetOutputMatrix(
|
FAudioVoice_SetOutputMatrix(
|
||||||
voice->handle,
|
voice->handle,
|
||||||
voice->effectVoice,
|
voice->effectChain->effectVoice,
|
||||||
voice->handle->outputChannels,
|
voice->handle->outputChannels,
|
||||||
1,
|
1,
|
||||||
outputMatrix,
|
outputMatrix,
|
||||||
|
@ -1822,108 +1863,17 @@ void FAudioGMS_SoundInstance_SetEffectGain(double soundInstanceID, double effect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static FAudioEffectChain *FAudioGMS_INTERNAL_CreateFAudioEffectChain(
|
|
||||||
FAudioGMS_EffectChain *effectChain)
|
|
||||||
{
|
|
||||||
FAudioEffectChain *fAudioEffectChain = SDL_malloc(sizeof(FAudioEffectChain));
|
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
fAudioEffectChain->EffectCount = effectChain->effectCount;
|
|
||||||
fAudioEffectChain->pEffectDescriptors =
|
|
||||||
SDL_malloc(fAudioEffectChain->EffectCount * sizeof(FAudioEffectDescriptor));
|
|
||||||
|
|
||||||
FAPO *reverb;
|
|
||||||
|
|
||||||
for (i = 0; i < effectChain->effectCount; i += 1)
|
|
||||||
{
|
|
||||||
switch (effectChain->effectTypes[i])
|
|
||||||
{
|
|
||||||
case EffectType_Reverb:
|
|
||||||
FAudioCreateReverb(&reverb, 0);
|
|
||||||
|
|
||||||
FAudioEffectDescriptor *reverbDescriptor = &fAudioEffectChain->pEffectDescriptors[i];
|
|
||||||
reverbDescriptor->InitialState = 1;
|
|
||||||
reverbDescriptor->OutputChannels =
|
|
||||||
device->deviceDetails.OutputFormat.Format.nChannels == 6 ? 6 : 1;
|
|
||||||
reverbDescriptor->pEffect = reverb;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Log("Unknown effect type! Something is very wrong!");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fAudioEffectChain;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void FAudioGMS_INTERNAL_SetEffectChain(
|
static void FAudioGMS_INTERNAL_SetEffectChain(
|
||||||
FAudioGMS_Voice *voice,
|
FAudioGMS_Voice *voice,
|
||||||
FAudioGMS_EffectChain *effectChain,
|
FAudioGMS_EffectChain *effectChain,
|
||||||
float effectGain)
|
float effectGain)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
if (!voice->effectChainAttached)
|
||||||
|
|
||||||
if (voice->effectChainAttached)
|
|
||||||
{
|
|
||||||
/* This frees the effect chain on the voice */
|
|
||||||
FAudioVoice_SetEffectChain(voice->effectVoice, NULL);
|
|
||||||
SDL_free(voice->effectSends.pSends);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
voice->sends.SendCount = 2;
|
voice->sends.SendCount = 2;
|
||||||
voice->sends.pSends = SDL_realloc(voice->sends.pSends, 2 * sizeof(FAudioSendDescriptor));
|
voice->sends.pSends = SDL_realloc(voice->sends.pSends, 2 * sizeof(FAudioSendDescriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
voice->effectChain = effectChain;
|
|
||||||
|
|
||||||
FAudioEffectChain *fAudioEffectChain = FAudioGMS_INTERNAL_CreateFAudioEffectChain(effectChain);
|
|
||||||
|
|
||||||
voice->effectSends.SendCount = 1;
|
|
||||||
voice->effectSends.pSends = SDL_malloc(sizeof(FAudioSendDescriptor));
|
|
||||||
|
|
||||||
voice->effectSends.pSends[0].Flags = 0;
|
|
||||||
|
|
||||||
if (voice == &device->fauxMasteringVoice)
|
|
||||||
{
|
|
||||||
voice->effectSends.pSends[0].pOutputVoice = device->masteringVoice;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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
|
/* Set the instance voice to go through both faux mastering and effect voice
|
||||||
* for wet/dry */
|
* for wet/dry */
|
||||||
voice->sends.pSends[0].Flags = 0;
|
voice->sends.pSends[0].Flags = 0;
|
||||||
|
@ -1936,21 +1886,13 @@ static void FAudioGMS_INTERNAL_SetEffectChain(
|
||||||
voice->sends.pSends[0].pOutputVoice = device->fauxMasteringVoice.handle;
|
voice->sends.pSends[0].pOutputVoice = device->fauxMasteringVoice.handle;
|
||||||
}
|
}
|
||||||
voice->sends.pSends[1].Flags = 0;
|
voice->sends.pSends[1].Flags = 0;
|
||||||
voice->sends.pSends[1].pOutputVoice = voice->effectVoice;
|
voice->sends.pSends[1].pOutputVoice = effectChain->effectVoice;
|
||||||
|
|
||||||
|
voice->effectChain = effectChain;
|
||||||
voice->effectChainAttached = 1;
|
voice->effectChainAttached = 1;
|
||||||
|
|
||||||
FAudioVoice_SetOutputVoices(voice->handle, &voice->sends);
|
FAudioVoice_SetOutputVoices(voice->handle, &voice->sends);
|
||||||
|
|
||||||
FAudioGMS_INTERNAL_Voice_SetEffectGain(voice, effectGain);
|
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(
|
void FAudioGMS_SoundInstance_SetEffectChain(
|
||||||
|
@ -2000,6 +1942,7 @@ static void FAudioGMS_INTERNAL_EffectChain_Destroy(FAudioGMS_EffectChain *effect
|
||||||
device->effectChains[effectChain->id] = NULL;
|
device->effectChains[effectChain->id] = NULL;
|
||||||
IdStack_Push(&device->effectChainIndexStack, effectChain->id);
|
IdStack_Push(&device->effectChainIndexStack, effectChain->id);
|
||||||
|
|
||||||
|
SDL_free(effectChain->fAudioEffectChain.pEffectDescriptors);
|
||||||
SDL_free(effectChain->effectParameters);
|
SDL_free(effectChain->effectParameters);
|
||||||
SDL_free(effectChain->effectTypes);
|
SDL_free(effectChain->effectTypes);
|
||||||
SDL_free(effectChain);
|
SDL_free(effectChain);
|
||||||
|
@ -2021,7 +1964,7 @@ void FAudioGMS_EffectChain_Destroy(double effectChainID)
|
||||||
void FAudioGMS_Update()
|
void FAudioGMS_Update()
|
||||||
{
|
{
|
||||||
RETURN_ON_NULL_DEVICE()
|
RETURN_ON_NULL_DEVICE()
|
||||||
uint32_t i, j;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < device->soundInstanceCount; i += 1)
|
for (i = 0; i < device->soundInstanceCount; i += 1)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue