diff options
-rw-r--r-- | Alc/ALu.c | 117 | ||||
-rw-r--r-- | OpenAL32/Include/alAuxEffectSlot.h | 9 | ||||
-rw-r--r-- | OpenAL32/alAuxEffectSlot.c | 65 |
3 files changed, 165 insertions, 26 deletions
@@ -311,6 +311,12 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, //2. Calculate distance attenuation Distance = aluSqrt(aluDotproduct(Position, Position)); + if(ALSource->Send[0].Slot && !ALSource->Send[0].Slot->AuxSendAuto) + { + if(ALSource->Send[0].Slot->effect.type == AL_EFFECT_REVERB) + RoomRolloff = ALSource->Send[0].Slot->effect.Reverb.RoomRolloffFactor; + } + flAttenuation = 1.0f; RoomAttenuation = 1.0f; switch (ALContext->DistanceModel) @@ -371,14 +377,11 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, DryMix = SourceVolume * flAttenuation; DryMix = __min(DryMix,MaxVolume); DryMix = __max(DryMix,MinVolume); - if(ALSource->Send[0].Slot) - { - WetMix = SourceVolume * ((ALSource->WetGainAuto && - ALSource->Send[0].Slot->AuxSendAuto) ? - RoomAttenuation : 1.0f); - WetMix = __min(WetMix,MaxVolume); - WetMix = __max(WetMix,MinVolume); - } + + WetMix = SourceVolume * (ALSource->WetGainAuto ? + RoomAttenuation : 1.0f); + WetMix = __min(WetMix,MaxVolume); + WetMix = __max(WetMix,MinVolume); //3. Apply directional soundcones SourceToListener[0] = -Position[0]; @@ -473,6 +476,18 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, DryGainHF *= pow(ALSource->AirAbsorptionFactor * AIRABSORBGAINHF, Distance * MetersPerUnit); + if(ALSource->Send[0].Slot) + { + WetMix *= ALSource->Send[0].Slot->Gain; + + if(ALSource->Send[0].Slot->effect.type == AL_EFFECT_REVERB) + { + WetGainHF *= ALSource->Send[0].Slot->effect.Reverb.GainHF; + WetGainHF *= pow(ALSource->Send[0].Slot->effect.Reverb.AirAbsorptionGainHF, + Distance * MetersPerUnit); + } + } + //7. Convert normalized position into pannings, then into channel volumes aluNormalize(Position); switch(aluChannelsFromFormat(OutputFormat)) @@ -482,7 +497,6 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, drysend[FRONT_RIGHT] = ConeVolume * ListenerGain * DryMix * aluSqrt(1.0f); //Direct if(ALSource->Send[0].Slot) { - WetMix *= ALSource->Send[0].Slot->Gain; wetsend[FRONT_LEFT] = ListenerGain * WetMix * aluSqrt(1.0f); //Room wetsend[FRONT_RIGHT] = ListenerGain * WetMix * aluSqrt(1.0f); //Room } @@ -499,7 +513,6 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, drysend[FRONT_RIGHT] = ConeVolume * ListenerGain * DryMix * aluSqrt( PanningLR); //R Direct if(ALSource->Send[0].Slot) { - WetMix *= ALSource->Send[0].Slot->Gain; wetsend[FRONT_LEFT] = ListenerGain * WetMix * aluSqrt(1.0f-PanningLR); //L Room wetsend[FRONT_RIGHT] = ListenerGain * WetMix * aluSqrt( PanningLR); //R Room } @@ -526,7 +539,6 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, drysend[BACK_RIGHT] = ConeVolume * ListenerGain * DryMix * aluSqrt(( PanningLR)*( PanningFB)); if(ALSource->Send[0].Slot) { - WetMix *= ALSource->Send[0].Slot->Gain; wetsend[FRONT_LEFT] = ListenerGain * WetMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB)); wetsend[FRONT_RIGHT] = ListenerGain * WetMix * aluSqrt(( PanningLR)*(1.0f-PanningFB)); wetsend[BACK_LEFT] = ListenerGain * WetMix * aluSqrt((1.0f-PanningLR)*( PanningFB)); @@ -559,7 +571,6 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, drysend[FRONT_RIGHT] = 0.0f; if(ALSource->Send[0].Slot) { - WetMix *= ALSource->Send[0].Slot->Gain; wetsend[BACK_LEFT] = ListenerGain * WetMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB)); wetsend[BACK_RIGHT] = ListenerGain * WetMix * aluSqrt(( PanningLR)*(1.0f-PanningFB)); wetsend[SIDE_LEFT] = ListenerGain * WetMix * aluSqrt((1.0f-PanningLR)*( PanningFB)); @@ -588,7 +599,6 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, drysend[BACK_RIGHT] = 0.0f; if(ALSource->Send[0].Slot) { - WetMix *= ALSource->Send[0].Slot->Gain; wetsend[FRONT_LEFT] = ListenerGain * WetMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB)); wetsend[FRONT_RIGHT] = ListenerGain * WetMix * aluSqrt(( PanningLR)*(1.0f-PanningFB)); wetsend[SIDE_LEFT] = ListenerGain * WetMix * aluSqrt((1.0f-PanningLR)*( PanningFB)); @@ -660,6 +670,7 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma { static float DryBuffer[BUFFERSIZE][OUTPUTCHANNELS]; static float WetBuffer[BUFFERSIZE][OUTPUTCHANNELS]; + static float ReverbBuffer[BUFFERSIZE]; ALfloat DrySend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; ALfloat WetSend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; ALfloat DryGainHF = 0.0f; @@ -667,12 +678,14 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma ALuint BlockAlign,BufferSize; ALuint DataSize=0,DataPosInt=0,DataPosFrac=0; ALuint Channels,Frequency,ulExtraSamples; + ALboolean doReverb; ALfloat Pitch; ALint Looping,increment,State; ALuint Buffer,fraction; ALuint SamplesToDo; ALsource *ALSource; ALbuffer *ALBuffer; + ALeffectslot *ALEffectSlot; ALfloat value; ALshort *Data; ALuint i,j,k; @@ -698,12 +711,18 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma //Clear mixing buffer memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat)); memset(WetBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat)); + memset(ReverbBuffer, 0, SamplesToDo*sizeof(ALfloat)); //Actual mixing loop while(ALSource) { j = 0; State = ALSource->state; + + doReverb = ((ALSource->Send[0].Slot && + ALSource->Send[0].Slot->effect.type == AL_EFFECT_REVERB) ? + AL_TRUE : AL_FALSE); + while(State == AL_PLAYING && j < SamplesToDo) { DataSize = 0; @@ -798,12 +817,17 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; //Room path final mix buffer and panning value = aluComputeWetSample(ALSource, WetGainHF, sample); - WetBuffer[j][FRONT_LEFT] += value*WetSend[FRONT_LEFT]; - WetBuffer[j][FRONT_RIGHT] += value*WetSend[FRONT_RIGHT]; - WetBuffer[j][SIDE_LEFT] += value*WetSend[SIDE_LEFT]; - WetBuffer[j][SIDE_RIGHT] += value*WetSend[SIDE_RIGHT]; - WetBuffer[j][BACK_LEFT] += value*WetSend[BACK_LEFT]; - WetBuffer[j][BACK_RIGHT] += value*WetSend[BACK_RIGHT]; + if(doReverb) + ReverbBuffer[j] += value; + else + { + WetBuffer[j][FRONT_LEFT] += value*WetSend[FRONT_LEFT]; + WetBuffer[j][FRONT_RIGHT] += value*WetSend[FRONT_RIGHT]; + WetBuffer[j][SIDE_LEFT] += value*WetSend[SIDE_LEFT]; + WetBuffer[j][SIDE_RIGHT] += value*WetSend[SIDE_RIGHT]; + WetBuffer[j][BACK_LEFT] += value*WetSend[BACK_LEFT]; + WetBuffer[j][BACK_RIGHT] += value*WetSend[BACK_RIGHT]; + } } else { @@ -945,6 +969,61 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma ALSource = ALSource->next; } + ALEffectSlot = (ALContext ? ALContext->AuxiliaryEffectSlot : NULL); + while(ALEffectSlot) + { + if(ALEffectSlot->effect.type == AL_EFFECT_REVERB) + { + ALfloat *DelayBuffer = ALEffectSlot->ReverbBuffer; + ALuint Pos = ALEffectSlot->ReverbPos; + ALuint LatePos = ALEffectSlot->ReverbLatePos; + ALuint ReflectPos = ALEffectSlot->ReverbReflectPos; + ALuint Length = ALEffectSlot->ReverbLength; + ALfloat DecayGain = ALEffectSlot->ReverbDecayGain; + ALfloat DecayHFRatio = ALEffectSlot->effect.Reverb.DecayHFRatio; + ALfloat Gain = ALEffectSlot->effect.Reverb.Gain; + ALfloat ReflectGain = ALEffectSlot->effect.Reverb.ReflectionsGain; + ALfloat LateReverbGain = ALEffectSlot->effect.Reverb.LateReverbGain; + ALfloat LastDecaySample = ALEffectSlot->LastDecaySample; + ALfloat sample; + + for(i = 0;i < SamplesToDo;i++) + { + DelayBuffer[Pos] = ReverbBuffer[i] * Gain; + + sample = DelayBuffer[ReflectPos] * ReflectGain; + + DelayBuffer[LatePos] *= LateReverbGain; + + Pos = (Pos+1) % Length; + DelayBuffer[Pos] *= DecayHFRatio; + DelayBuffer[Pos] += LastDecaySample * (1.0f-DecayHFRatio); + LastDecaySample = DelayBuffer[Pos]; + DelayBuffer[Pos] *= DecayGain; + + DelayBuffer[LatePos] += DelayBuffer[Pos]; + + sample += DelayBuffer[LatePos]; + + WetBuffer[i][FRONT_LEFT] += sample; + WetBuffer[i][FRONT_RIGHT] += sample; + WetBuffer[i][SIDE_LEFT] += sample; + WetBuffer[i][SIDE_RIGHT] += sample; + WetBuffer[i][BACK_LEFT] += sample; + WetBuffer[i][BACK_RIGHT] += sample; + + LatePos = (LatePos+1) % Length; + ReflectPos = (ReflectPos+1) % Length; + } + + ALEffectSlot->ReverbPos = Pos; + ALEffectSlot->ReverbLatePos = LatePos; + ALEffectSlot->ReverbReflectPos = ReflectPos; + ALEffectSlot->LastDecaySample = LastDecaySample; + } + ALEffectSlot = ALEffectSlot->next; + } + //Post processing loop switch(format) { diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 66b3ba20..d4cb0d11 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -21,6 +21,15 @@ typedef struct ALeffectslot ALfloat Gain; ALboolean AuxSendAuto; + ALfloat *ReverbBuffer; + // in frames! + ALuint ReverbLength; + ALuint ReverbPos; + ALuint ReverbReflectPos; + ALuint ReverbLatePos; + ALfloat ReverbDecayGain; + ALfloat LastDecaySample; + ALuint refcount; // Index to itself diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 3ce845ce..41ea6c72 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -21,6 +21,7 @@ #include "config.h" #include <stdlib.h> +#include <math.h> #include "AL/al.h" #include "AL/alc.h" @@ -30,6 +31,9 @@ #include "alError.h" +static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect); + + AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) { ALCcontext *Context; @@ -144,6 +148,8 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effect *list = (*list)->next; ALTHUNK_REMOVEENTRY(ALAuxiliaryEffectSlot->effectslot); + free(ALAuxiliaryEffectSlot->ReverbBuffer); + memset(ALAuxiliaryEffectSlot, 0, sizeof(ALeffectslot)); free(ALAuxiliaryEffectSlot); @@ -202,13 +208,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param if(alIsEffect(iValue)) { ALeffect *effect = (ALeffect*)ALTHUNK_LOOKUPENTRY(iValue); - if(!effect) - { - ALEffectSlot->effect.type = AL_EFFECT_NULL; - ALEffectSlot->effect.effect = 0; - } - else - memcpy(&ALEffectSlot->effect, effect, sizeof(*effect)); + InitializeEffect(Context, ALEffectSlot, effect); } else alSetError(AL_INVALID_VALUE); @@ -465,6 +465,55 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p } +static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect) +{ + ALfloat *ptr = NULL; + + if(!effect) + { + memset(&ALEffectSlot->effect, 0, sizeof(ALEffectSlot->effect)); + goto done; + } + + if(effect->type == AL_EFFECT_REVERB) + { + ALuint size; + ALfloat reverbwait; + + reverbwait = (1.0f-effect->Reverb.Density)*(0.1f-0.075f) + 0.075f; + + size = (ALuint)((ALfloat)Context->Frequency * + (effect->Reverb.ReflectionsDelay + + effect->Reverb.LateReverbDelay + + reverbwait)) + 1; + + ptr = calloc(size, sizeof(ALfloat)); + if(!ptr) + { + alSetError(AL_OUT_OF_MEMORY); + return; + } + ALEffectSlot->ReverbLength = size; + ALEffectSlot->ReverbPos = 0; + ALEffectSlot->ReverbReflectPos = (ALuint)(ALEffectSlot->ReverbLength - + ((ALfloat)Context->Frequency * + effect->Reverb.ReflectionsDelay)) % + ALEffectSlot->ReverbLength; + ALEffectSlot->ReverbLatePos = (ALuint)(ALEffectSlot->ReverbLength - + ((ALfloat)Context->Frequency * + (effect->Reverb.LateReverbDelay + + effect->Reverb.ReflectionsDelay))) % + ALEffectSlot->ReverbLength; + ALEffectSlot->ReverbDecayGain = pow(1.0/32768.0, 1.0/(effect->Reverb.DecayTime/reverbwait)); + } + + memcpy(&ALEffectSlot->effect, effect, sizeof(*effect)); +done: + free(ALEffectSlot->ReverbBuffer); + ALEffectSlot->ReverbBuffer = ptr; +} + + ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) { #ifdef _DEBUG @@ -478,6 +527,8 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) Context->AuxiliaryEffectSlot = Context->AuxiliaryEffectSlot->next; // Release effectslot structure + free(temp->ReverbBuffer); + memset(temp, 0, sizeof(ALeffectslot)); free(temp); } |