diff --git a/src/FAudioGMS.c b/src/FAudioGMS.c index 052b488..aa9c6ed 100644 --- a/src/FAudioGMS.c +++ b/src/FAudioGMS.c @@ -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; diff --git a/src/FAudioGMS.h b/src/FAudioGMS.h index 8c118b5..51eced7 100644 --- a/src/FAudioGMS.h +++ b/src/FAudioGMS.h @@ -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);