diff options
Diffstat (limited to 'Alc/ALu.c')
-rw-r--r-- | Alc/ALu.c | 196 |
1 files changed, 161 insertions, 35 deletions
@@ -206,15 +206,40 @@ static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat matrix[3][3]) memcpy(vector, result, sizeof(result)); } +static __inline ALfloat aluComputeDrySample(ALsource *source, ALfloat DryGainHF, ALfloat sample) +{ + if(DryGainHF < 1.0f) + { + sample *= DryGainHF; + sample += source->LastDrySample * (1.0f - DryGainHF); + } + + source->LastDrySample = sample; + return sample; +} + +static __inline ALfloat aluComputeWetSample(ALsource *source, ALfloat WetGainHF, ALfloat sample) +{ + if(WetGainHF < 1.0f) + { + sample *= WetGainHF; + sample += source->LastWetSample * (1.0f - WetGainHF); + } + + source->LastWetSample = sample; + return sample; +} + static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, ALenum isMono, ALenum OutputFormat, ALfloat *drysend, ALfloat *wetsend, - ALfloat *pitch) + ALfloat *pitch, ALfloat *drygainhf, + ALfloat *wetgainhf) { ALfloat ListenerOrientation[6],ListenerPosition[3],ListenerVelocity[3]; ALfloat InnerAngle,OuterAngle,OuterGain,Angle,Distance,DryMix,WetMix; ALfloat Direction[3],Position[3],Velocity[3],SourceToListener[3]; - ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; + ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF; ALfloat Pitch,ConeVolume,SourceVolume,PanningFB,PanningLR,ListenerGain; ALfloat U[3],V[3],N[3]; ALfloat DopplerFactor, DopplerVelocity, flSpeedOfSound, flMaxVelocity; @@ -223,6 +248,11 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, ALfloat Matrix[3][3]; ALint HeadRelative; ALfloat flAttenuation; + ALfloat RoomAttenuation; + ALfloat MetersPerUnit; + ALfloat RoomRolloff; + ALfloat DryGainHF = 1.0f; + ALfloat WetGainHF = 1.0f; //Get context properties DopplerFactor = ALContext->DopplerFactor; @@ -232,6 +262,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, //Get listener properties ListenerGain = ALContext->Listener.Gain; + MetersPerUnit = ALContext->Listener.MetersPerUnit; memcpy(ListenerPosition, ALContext->Listener.Position, sizeof(ALContext->Listener.Position)); memcpy(ListenerVelocity, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity)); memcpy(&ListenerOrientation[0], ALContext->Listener.Forward, sizeof(ALContext->Listener.Forward)); @@ -252,10 +283,8 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, InnerAngle = ALSource->flInnerAngle; OuterAngle = ALSource->flOuterAngle; HeadRelative = ALSource->bHeadRelative; - - //Set working variables - DryMix = (ALfloat)(1.0f); - WetMix = (ALfloat)(0.0f); + OuterGainHF = ALSource->OuterGainHF; + RoomRolloff = ALSource->RoomRolloffFactor; //Only apply 3D calculations for mono buffers if(isMono != AL_FALSE) @@ -272,6 +301,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, Distance = aluSqrt(aluDotproduct(Position, Position)); flAttenuation = 1.0f; + RoomAttenuation = 1.0f; switch (DistanceModel) { case AL_INVERSE_DISTANCE_CLAMPED: @@ -285,6 +315,8 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, { if ((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f) flAttenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist))); + if ((MinDist + (RoomRolloff * (Distance - MinDist))) > 0.0f) + RoomAttenuation = MinDist / (MinDist + (RoomRolloff * (Distance - MinDist))); } break; @@ -297,7 +329,10 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, case AL_LINEAR_DISTANCE: Distance=__min(Distance,MaxDist); if (MaxDist != MinDist) + { flAttenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist)); + RoomAttenuation = 1.0f - (RoomRolloff*(Distance-MinDist)/(MaxDist - MinDist)); + } break; case AL_EXPONENT_DISTANCE_CLAMPED: @@ -308,17 +343,24 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, //fall-through case AL_EXPONENT_DISTANCE: if ((Distance > 0.0f) && (MinDist > 0.0f)) + { flAttenuation = (ALfloat)pow(Distance/MinDist, -Rolloff); + RoomAttenuation = (ALfloat)pow(Distance/MinDist, -RoomRolloff); + } break; case AL_NONE: default: flAttenuation = 1.0f; + RoomAttenuation = 1.0f; break; } // Source Gain + Attenuation DryMix = SourceVolume * flAttenuation; + WetMix = SourceVolume * ((ALSource->WetGainAuto && + ALSource->Send[0].Slot.AuxSendAuto) ? + RoomAttenuation : 1.0f); // Clamp to Min/Max Gain DryMix = __min(DryMix,MaxVolume); @@ -333,9 +375,26 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, aluNormalize(SourceToListener); Angle = (ALfloat)(180.0*acos(aluDotproduct(Direction,SourceToListener))/3.141592654f); if(Angle >= InnerAngle && Angle <= OuterAngle) - ConeVolume = (1.0f+(OuterGain-1.0f)*(Angle-InnerAngle)/(OuterAngle-InnerAngle)); + { + ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); + ConeVolume = (1.0f+(OuterGain-1.0f)*scale); + if(ALSource->WetGainAuto) + WetMix *= ConeVolume; + if(ALSource->DryGainHFAuto) + DryGainHF *= (1.0f+(OuterGainHF-1.0f)*scale); + if(ALSource->WetGainHFAuto) + WetGainHF *= (1.0f+(OuterGainHF-1.0f)*scale); + } else if(Angle > OuterAngle) - ConeVolume = (1.0f+(OuterGain-1.0f) ); + { + ConeVolume = (1.0f+(OuterGain-1.0f)); + if(ALSource->WetGainAuto) + WetMix *= ConeVolume; + if(ALSource->DryGainHFAuto) + DryGainHF *= (1.0f+(OuterGainHF-1.0f)); + if(ALSource->WetGainHFAuto) + WetGainHF *= (1.0f+(OuterGainHF-1.0f)); + } else ConeVolume = 1.0f; @@ -375,22 +434,65 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; aluMatrixVector(Position, Matrix); - //6. Convert normalized position into pannings, then into channel volumes + //6. Apply filter gains and filters + switch(ALSource->DirectFilter.filter) + { + case AL_FILTER_LOWPASS: + DryMix *= ALSource->DirectFilter.Gain; + DryGainHF *= ALSource->DirectFilter.GainHF; + break; + } + + switch(ALSource->Send[0].WetFilter.filter) + { + case AL_FILTER_LOWPASS: + WetMix *= ALSource->Send[0].WetFilter.Gain; + WetGainHF *= ALSource->Send[0].WetFilter.GainHF; + break; + } + + if(ALSource->AirAbsorptionFactor > 0.0f) + DryGainHF *= pow(ALSource->AirAbsorptionFactor * AIRABSORBGAINHF, + Distance * MetersPerUnit); + + *drygainhf = DryGainHF; + *wetgainhf = WetGainHF; + + //7. Convert normalized position into pannings, then into channel volumes aluNormalize(Position); + WetMix *= ALSource->Send[0].Slot.Gain; switch(aluChannelsFromFormat(OutputFormat)) { case 1: drysend[FRONT_LEFT] = ConeVolume * ListenerGain * DryMix * aluSqrt(1.0f); //Direct drysend[FRONT_RIGHT] = ConeVolume * ListenerGain * DryMix * aluSqrt(1.0f); //Direct - wetsend[FRONT_LEFT] = ListenerGain * WetMix * aluSqrt(1.0f); //Room - wetsend[FRONT_RIGHT] = ListenerGain * WetMix * aluSqrt(1.0f); //Room + if(ALSource->Send[0].Slot.effectslot) + { + wetsend[FRONT_LEFT] = ListenerGain * WetMix * aluSqrt(1.0f); //Room + wetsend[FRONT_RIGHT] = ListenerGain * WetMix * aluSqrt(1.0f); //Room + } + else + { + wetsend[FRONT_LEFT] = 0.0f; + wetsend[FRONT_RIGHT] = 0.0f; + *wetgainhf = 1.0f; + } break; case 2: PanningLR = 0.5f + 0.5f*Position[0]; - drysend[FRONT_LEFT] = ConeVolume * ListenerGain * DryMix * aluSqrt(1.0f-PanningLR); - drysend[FRONT_RIGHT] = ConeVolume * ListenerGain * DryMix * aluSqrt( PanningLR); - wetsend[FRONT_LEFT] = ListenerGain * WetMix * aluSqrt(1.0f-PanningLR); - wetsend[FRONT_RIGHT] = ListenerGain * WetMix * aluSqrt( PanningLR); + drysend[FRONT_LEFT] = ConeVolume * ListenerGain * DryMix * aluSqrt(1.0f-PanningLR); //L Direct + drysend[FRONT_RIGHT] = ConeVolume * ListenerGain * DryMix * aluSqrt( PanningLR); //R Direct + if(ALSource->Send[0].Slot.effectslot) + { + wetsend[FRONT_LEFT] = ListenerGain * WetMix * aluSqrt(1.0f-PanningLR); //L Room + wetsend[FRONT_RIGHT] = ListenerGain * WetMix * aluSqrt( PanningLR); //R Room + } + else + { + wetsend[FRONT_LEFT] = 0.0f; + wetsend[FRONT_RIGHT] = 0.0f; + *wetgainhf = 1.0f; + } break; case 4: /* TODO: Add center/lfe channel in spatial calculations? */ @@ -405,18 +507,29 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, PanningFB = 0.5f + (0.5f*Position[2]*1.41421356f); PanningFB = __min(1.0f, PanningFB); PanningFB = __max(0.0f, PanningFB); - drysend[FRONT_LEFT] = ConeVolume * ListenerGain * DryMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB)); - drysend[FRONT_RIGHT] = ConeVolume * ListenerGain * DryMix * aluSqrt(( PanningLR)*(1.0f-PanningFB)); - drysend[BACK_LEFT] = ConeVolume * ListenerGain * DryMix * aluSqrt((1.0f-PanningLR)*( PanningFB)); - drysend[BACK_RIGHT] = ConeVolume * ListenerGain * DryMix * aluSqrt(( PanningLR)*( PanningFB)); + drysend[FRONT_LEFT] = ConeVolume * ListenerGain * DryMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB)); //FL Direct + drysend[FRONT_RIGHT] = ConeVolume * ListenerGain * DryMix * aluSqrt(( PanningLR)*(1.0f-PanningFB)); //FR Direct + drysend[BACK_LEFT] = ConeVolume * ListenerGain * DryMix * aluSqrt((1.0f-PanningLR)*( PanningFB)); //BL Direct + drysend[BACK_RIGHT] = ConeVolume * ListenerGain * DryMix * aluSqrt(( PanningLR)*( PanningFB)); //BR Direct drysend[SIDE_LEFT] = 0.0f; drysend[SIDE_RIGHT] = 0.0f; - 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)); - wetsend[BACK_RIGHT] = ListenerGain * WetMix * aluSqrt(( PanningLR)*( PanningFB)); - wetsend[SIDE_LEFT] = 0.0f; - wetsend[SIDE_RIGHT] = 0.0f; + if(ALSource->Send[0].Slot.effectslot) + { + wetsend[FRONT_LEFT] = ListenerGain * WetMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB)); //FL Room + wetsend[FRONT_RIGHT] = ListenerGain * WetMix * aluSqrt(( PanningLR)*(1.0f-PanningFB)); //FR Room + wetsend[BACK_LEFT] = ListenerGain * WetMix * aluSqrt((1.0f-PanningLR)*( PanningFB)); //BL Room + wetsend[BACK_RIGHT] = ListenerGain * WetMix * aluSqrt(( PanningLR)*( PanningFB)); //BR Room + } + else + { + wetsend[FRONT_LEFT] = 0.0f; + wetsend[FRONT_RIGHT] = 0.0f; + wetsend[BACK_LEFT] = 0.0f; + wetsend[BACK_RIGHT] = 0.0f; + *wetgainhf = 1.0f; + } + wetsend[SIDE_LEFT] = 0.0f; + wetsend[SIDE_RIGHT] = 0.0f; break; default: break; @@ -424,6 +537,9 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, } else { + *drygainhf = DryGainHF; + *wetgainhf = WetGainHF; + //1. Multi-channel buffers always play "normal" drysend[FRONT_LEFT] = SourceVolume * 1.0f * ListenerGain; drysend[FRONT_RIGHT] = SourceVolume * 1.0f * ListenerGain; @@ -433,14 +549,18 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, drysend[BACK_RIGHT] = SourceVolume * 1.0f * ListenerGain; drysend[CENTER] = SourceVolume * 1.0f * ListenerGain; drysend[LFE] = SourceVolume * 1.0f * ListenerGain; - wetsend[FRONT_LEFT] = SourceVolume * 0.0f * ListenerGain; - wetsend[FRONT_RIGHT] = SourceVolume * 0.0f * ListenerGain; - wetsend[SIDE_LEFT] = SourceVolume * 0.0f * ListenerGain; - wetsend[SIDE_RIGHT] = SourceVolume * 0.0f * ListenerGain; - wetsend[BACK_LEFT] = SourceVolume * 0.0f * ListenerGain; - wetsend[BACK_RIGHT] = SourceVolume * 0.0f * ListenerGain; - wetsend[CENTER] = SourceVolume * 0.0f * ListenerGain; - wetsend[LFE] = SourceVolume * 0.0f * ListenerGain; + if(ALSource->Send[0].Slot.effectslot) + { + wetsend[FRONT_LEFT] = SourceVolume * 0.0f * ListenerGain; + wetsend[FRONT_RIGHT] = SourceVolume * 0.0f * ListenerGain; + wetsend[SIDE_LEFT] = SourceVolume * 0.0f * ListenerGain; + wetsend[SIDE_RIGHT] = SourceVolume * 0.0f * ListenerGain; + wetsend[BACK_LEFT] = SourceVolume * 0.0f * ListenerGain; + wetsend[BACK_RIGHT] = SourceVolume * 0.0f * ListenerGain; + wetsend[CENTER] = SourceVolume * 0.0f * ListenerGain; + wetsend[LFE] = SourceVolume * 0.0f * ListenerGain; + *wetgainhf = 1.0f; + } pitch[0] = Pitch; } @@ -452,6 +572,8 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma static float WetBuffer[BUFFERSIZE][OUTPUTCHANNELS]; 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; + ALfloat WetGainHF = 0.0f; ALuint BlockAlign,BufferSize; ALuint DataSize=0,DataPosInt=0,DataPosFrac=0; ALuint Channels,Bits,Frequency,ulExtraSamples; @@ -511,7 +633,8 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma CalcSourceParams(ALContext, ALSource, (Channels==1) ? AL_TRUE : AL_FALSE, - format, DrySend, WetSend, &Pitch); + format, DrySend, WetSend, &Pitch, + &DryGainHF, &WetGainHF); Pitch = (Pitch*Frequency) / ALContext->Frequency; @@ -574,8 +697,10 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma if(Channels==1) { //First order interpolator - value = (ALfloat)((ALshort)(((Data[k]*((1L<<FRACTIONBITS)-fraction))+(Data[k+1]*(fraction)))>>FRACTIONBITS)); + ALfloat sample = (ALfloat)((ALshort)(((Data[k]*((1L<<FRACTIONBITS)-fraction))+(Data[k+1]*(fraction)))>>FRACTIONBITS)); + //Direct path final mix buffer and panning + value = aluComputeDrySample(ALSource, DryGainHF, sample); DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; #if 0 /* FIXME: Re-enable when proper 6-channel spatialization is used */ @@ -585,6 +710,7 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; 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]; #if 0 /* FIXME: Re-enable when proper 6-channel spatialization is used */ |