diff options
Diffstat (limited to 'Alc')
-rw-r--r-- | Alc/ALc.c | 46 | ||||
-rw-r--r-- | Alc/ALu.c | 131 |
2 files changed, 157 insertions, 20 deletions
@@ -27,6 +27,7 @@ #include <stdio.h> #include <memory.h> #include "alMain.h" +#include "alSource.h" #include "AL/al.h" #include "AL/alc.h" @@ -63,6 +64,9 @@ struct { /////////////////////////////////////////////////////// +#define ALC_EFX_MAJOR_VERSION 0x20001 +#define ALC_EFX_MINOR_VERSION 0x20002 +#define ALC_MAX_AUXILIARY_SENDS 0x20003 /////////////////////////////////////////////////////// // STRING and EXTENSIONS @@ -83,6 +87,7 @@ static ALCextension alcExtensions[] = { { "ALC_ENUMERATE_ALL_EXT", (ALvoid *) NULL }, { "ALC_ENUMERATION_EXT", (ALvoid *) NULL }, { "ALC_EXT_CAPTURE", (ALvoid *) NULL }, + { "ALC_EXT_EFX", (ALvoid *) NULL }, { NULL, (ALvoid *) NULL } }; @@ -132,9 +137,14 @@ static ALenums enumeration[]={ { (ALchar *)"ALC_MONO_SOURCES", ALC_MONO_SOURCES }, { (ALchar *)"ALC_STEREO_SOURCES", ALC_STEREO_SOURCES }, { (ALchar *)"ALC_CAPTURE_DEVICE_SPECIFIER", ALC_CAPTURE_DEVICE_SPECIFIER }, - { (ALchar *)"ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER }, + { (ALchar *)"ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER}, { (ALchar *)"ALC_CAPTURE_SAMPLES", ALC_CAPTURE_SAMPLES }, + // EFX Properties + { (ALchar *)"ALC_EFX_MAJOR_VERSION", ALC_EFX_MAJOR_VERSION }, + { (ALchar *)"ALC_EFX_MINOR_VERSION", ALC_EFX_MINOR_VERSION }, + { (ALchar *)"ALC_MAX_AUXILIARY_SENDS", ALC_MAX_AUXILIARY_SENDS }, + // ALC Error Message { (ALchar *)"ALC_NO_ERROR", ALC_NO_ERROR }, { (ALchar *)"ALC_INVALID_DEVICE", ALC_INVALID_DEVICE }, @@ -162,10 +172,13 @@ static ALCchar *alcDefaultAllDeviceSpecifier = alcAllDeviceList; static ALCchar *alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList; -static ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE"; +static ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE ALC_EXT_EFX"; static ALCint alcMajorVersion = 1; static ALCint alcMinorVersion = 1; +static ALCint alcEFXMajorVersion = 1; +static ALCint alcEFXMinorVersion = 0; + /////////////////////////////////////////////////////// @@ -328,6 +341,7 @@ static ALvoid InitContext(ALCcontext *pContext) { //Initialise listener pContext->Listener.Gain = 1.0f; + pContext->Listener.MetersPerUnit = 1.0f; pContext->Listener.Position[0] = 0.0f; pContext->Listener.Position[1] = 0.0f; pContext->Listener.Position[2] = 0.0f; @@ -665,13 +679,34 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize *data = alcMinorVersion; break; + case ALC_EFX_MAJOR_VERSION: + if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = alcEFXMajorVersion; + break; + + case ALC_EFX_MINOR_VERSION: + if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = alcEFXMinorVersion; + break; + + case ALC_MAX_AUXILIARY_SENDS: + if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = MAX_SENDS; + break; + case ALC_ATTRIBUTES_SIZE: if(!device) SetALCError(ALC_INVALID_DEVICE); else if(!size) SetALCError(ALC_INVALID_VALUE); else - *data = 11; + *data = 12; break; case ALC_ALL_ATTRIBUTES: @@ -693,13 +728,16 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize data[i++] = ALC_FALSE; SuspendContext(NULL); - if(device->Context && size >= 11) + if(device->Context && size >= 12) { data[i++] = ALC_MONO_SOURCES; data[i++] = device->Context->lNumMonoSources; data[i++] = ALC_STEREO_SOURCES; data[i++] = device->Context->lNumStereoSources; + + data[i++] = ALC_MAX_AUXILIARY_SENDS; + data[i++] = MAX_SENDS; } ProcessContext(NULL); @@ -150,15 +150,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; @@ -167,6 +192,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; @@ -176,6 +206,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)); @@ -196,10 +227,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) @@ -216,6 +245,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: @@ -229,6 +259,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; @@ -241,7 +273,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: @@ -252,17 +287,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); @@ -277,9 +319,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; @@ -319,7 +378,34 @@ 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 pannings into channel volumes + WetMix *= ALSource->Send[0].Slot.Gain; + + //8. Convert normalized position into pannings, then into channel volumes aluNormalize(Position); switch(OutputFormat) { @@ -373,6 +459,9 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, wetsend[3] = SourceVolume * 0.0f * ListenerGain; pitch[0] = Pitch; + + *drygainhf = DryGainHF; + *wetgainhf = WetGainHF; } } @@ -382,6 +471,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 }; ALfloat WetSend[OUTPUTCHANNELS] = { 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; @@ -441,7 +532,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; @@ -504,17 +596,24 @@ 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][0] += value*DrySend[0]; DryBuffer[j][1] += value*DrySend[1]; DryBuffer[j][2] += value*DrySend[2]; DryBuffer[j][3] += value*DrySend[3]; - //Room path final mix buffer and panning - WetBuffer[j][0] += value*WetSend[0]; - WetBuffer[j][1] += value*WetSend[1]; - WetBuffer[j][2] += value*WetSend[2]; - WetBuffer[j][3] += value*WetSend[3]; + + if(ALSource->Send[0].Slot.effectslot) + { + //Room path final mix buffer and panning + value = aluComputeWetSample(ALSource, WetGainHF, sample); + WetBuffer[j][0] += value*WetSend[0]; + WetBuffer[j][1] += value*WetSend[1]; + WetBuffer[j][2] += value*WetSend[2]; + WetBuffer[j][3] += value*WetSend[3]; + } } else { |