static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot) { ALfloat frequency = (ALfloat)Device->Frequency; ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat rate; ALint phase; switch(Slot->EffectProps.Chorus.Waveform) { case AL_CHORUS_WAVEFORM_TRIANGLE: state->waveform = CWF_Triangle; break; case AL_CHORUS_WAVEFORM_SINUSOID: state->waveform = CWF_Sinusoid; break; } state->depth = Slot->EffectProps.Chorus.Depth; state->feedback = Slot->EffectProps.Chorus.Feedback; state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency); /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Slot->Gain, state->Gain[0]); CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Chorus.Phase; rate = Slot->EffectProps.Chorus.Rate; if(!(rate > 0.0f)) { state->lfo_scale = 0.0f; state->lfo_range = 1; state->lfo_disp = 0; } else { /* Calculate LFO coefficient */ state->lfo_range = fastf2u(frequency/rate + 0.5f); switch(state->waveform) { case CWF_Triangle: state->lfo_scale = 4.0f / state->lfo_range; break; case CWF_Sinusoid: state->lfo_scale = F_TAU / state->lfo_range; break; } /* Calculate lfo phase displacement */ state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f)); } }
static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state) { ALfloat lfo_value; lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range)); lfo_value *= state->depth * state->delay; *delay_left = fastf2i(lfo_value) + state->delay; offset += state->lfo_disp; lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range)); lfo_value *= state->depth * state->delay; *delay_right = fastf2i(lfo_value) + state->delay; }
static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state) { ALfloat lfo_value; lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); lfo_value *= state->depth * state->delay; *delay_left = fastf2i(lfo_value) + state->delay; offset += state->lfo_disp; lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); lfo_value *= state->depth * state->delay; *delay_right = fastf2i(lfo_value) + state->delay; }
static inline ALint aluF2I25(ALfloat val) { /* Clamp the value between -1 and +1. This handles that with only a single branch. */ if(fabsf(val) > 1.0f) val = (ALfloat)((0.0f < val) - (val < 0.0f)); /* Convert to a signed integer, between -16777215 and +16777215. */ return fastf2i(val*16777215.0f); }
/* Calculate the azimuth index given the polar azimuth in radians. This will * return an index between 0 and (azcount - 1). Assumes the FPU is in round-to- * zero mode. */ static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu) { ALsizei idx; az = (F_TAU+az) * azcount / F_TAU; idx = fastf2i(az) % azcount; *mu = az - floorf(az); return idx; }
/* Calculate the elevation index given the polar elevation in radians. This * will return an index between 0 and (evcount - 1). Assumes the FPU is in * round-to-zero mode. */ static ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev, ALfloat *mu) { ALsizei idx; ev = (F_PI_2+ev) * (evcount-1) / F_PI; idx = mini(fastf2i(ev), evcount-1); *mu = ev - idx; return idx; }
static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, const ALeffectslot *Slot) { ALfloat frequency = (ALfloat)Device->Frequency; ALfloat rate; ALint phase; state->waveform = Slot->EffectProps.Chorus.Waveform; state->depth = Slot->EffectProps.Chorus.Depth; state->feedback = Slot->EffectProps.Chorus.Feedback; state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency); /* Gains for left and right sides */ ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]); ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Chorus.Phase; rate = Slot->EffectProps.Chorus.Rate; if(!(rate > 0.0f)) { state->lfo_scale = 0.0f; state->lfo_range = 1; state->lfo_disp = 0; } else { /* Calculate LFO coefficient */ state->lfo_range = fastf2u(frequency/rate + 0.5f); switch(state->waveform) { case AL_CHORUS_WAVEFORM_TRIANGLE: state->lfo_scale = 4.0f / state->lfo_range; break; case AL_CHORUS_WAVEFORM_SINUSOID: state->lfo_scale = F_2PI / state->lfo_range; break; } /* Calculate lfo phase displacement */ state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f)); } }
/* Calculates the moving HRIR target coefficients, target delays, and * stepping values for the given polar elevation and azimuth in radians. * Linear interpolation is used to increase the apparent resolution of the * HRIR data set. The coefficients are also normalized and attenuated by the * specified gain. Stepping resolution and count is determined using the * given delta factor between 0.0 and 1.0. */ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep) { ALuint evidx[2], azidx[2]; ALuint lidx[4], ridx[4]; ALfloat mu[3], blend[4]; ALfloat left, right; ALfloat step; ALuint i; // Claculate elevation indices and interpolation factor. CalcEvIndices(Hrtf, elevation, evidx, &mu[2]); // Calculate azimuth indices and interpolation factor for the first // elevation. CalcAzIndices(Hrtf, evidx[0], azimuth, azidx, &mu[0]); // Calculate the first set of linear HRIR indices for left and right // channels. lidx[0] = Hrtf->evOffset[evidx[0]] + azidx[0]; lidx[1] = Hrtf->evOffset[evidx[0]] + azidx[1]; ridx[0] = Hrtf->evOffset[evidx[0]] + ((Hrtf->azCount[evidx[0]]-azidx[0]) % Hrtf->azCount[evidx[0]]); ridx[1] = Hrtf->evOffset[evidx[0]] + ((Hrtf->azCount[evidx[0]]-azidx[1]) % Hrtf->azCount[evidx[0]]); // Calculate azimuth indices and interpolation factor for the second // elevation. CalcAzIndices(Hrtf, evidx[1], azimuth, azidx, &mu[1]); // Calculate the second set of linear HRIR indices for left and right // channels. lidx[2] = Hrtf->evOffset[evidx[1]] + azidx[0]; lidx[3] = Hrtf->evOffset[evidx[1]] + azidx[1]; ridx[2] = Hrtf->evOffset[evidx[1]] + ((Hrtf->azCount[evidx[1]]-azidx[0]) % Hrtf->azCount[evidx[1]]); ridx[3] = Hrtf->evOffset[evidx[1]] + ((Hrtf->azCount[evidx[1]]-azidx[1]) % Hrtf->azCount[evidx[1]]); // Calculate the stepping parameters. delta = maxf(floorf(delta*(Hrtf->sampleRate*0.015f) + 0.5f), 1.0f); step = 1.0f / delta; /* Calculate 4 blending weights for 2D bilinear interpolation. */ blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]); blend[1] = ( mu[0]) * (1.0f-mu[2]); blend[2] = (1.0f-mu[1]) * ( mu[2]); blend[3] = ( mu[1]) * ( mu[2]); /* Calculate the HRIR delays using linear interpolation. Then calculate * the delay stepping values using the target and previous running * delays. */ left = (ALfloat)(delays[0] - (delayStep[0] * counter)); right = (ALfloat)(delays[1] - (delayStep[1] * counter)); delays[0] = fastf2u(Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] + Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3] + 0.5f) << HRTFDELAY_BITS; delays[1] = fastf2u(Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] + Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3] + 0.5f) << HRTFDELAY_BITS; delayStep[0] = fastf2i(step * (delays[0] - left)); delayStep[1] = fastf2i(step * (delays[1] - right)); /* Calculate the sample offsets for the HRIR indices. */ lidx[0] *= Hrtf->irSize; lidx[1] *= Hrtf->irSize; lidx[2] *= Hrtf->irSize; lidx[3] *= Hrtf->irSize; ridx[0] *= Hrtf->irSize; ridx[1] *= Hrtf->irSize; ridx[2] *= Hrtf->irSize; ridx[3] *= Hrtf->irSize; /* Calculate the normalized and attenuated target HRIR coefficients using * linear interpolation when there is enough gain to warrant it. Zero * the target coefficients if gain is too low. Then calculate the * coefficient stepping values using the target and previous running * coefficients. */ if(gain > 0.0001f) { gain *= 1.0f/32767.0f; for(i = 0;i < HRIR_LENGTH;i++) { left = coeffs[i][0] - (coeffStep[i][0] * counter); right = coeffs[i][1] - (coeffStep[i][1] * counter); coeffs[i][0] = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] + Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]) * gain; coeffs[i][1] = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] + Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]) * gain; coeffStep[i][0] = step * (coeffs[i][0] - left); coeffStep[i][1] = step * (coeffs[i][1] - right); } } else { for(i = 0;i < HRIR_LENGTH;i++) { left = coeffs[i][0] - (coeffStep[i][0] * counter); right = coeffs[i][1] - (coeffStep[i][1] * counter); coeffs[i][0] = 0.0f; coeffs[i][1] = 0.0f; coeffStep[i][0] = step * -left; coeffStep[i][1] = step * -right; } } /* The stepping count is the number of samples necessary for the HRIR to * complete its transition. The mixer will only apply stepping for this * many samples. */ return fastf2u(delta); }
ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext) { static const struct ChanMap MonoMap[1] = { { FRONT_CENTER, 0.0f } }; static const struct ChanMap StereoMap[2] = { { FRONT_LEFT, -30.0f }, { FRONT_RIGHT, 30.0f } }; static const struct ChanMap RearMap[2] = { { BACK_LEFT, -150.0f }, { BACK_RIGHT, 150.0f } }; static const struct ChanMap QuadMap[4] = { { FRONT_LEFT, -45.0f }, { FRONT_RIGHT, 45.0f }, { BACK_LEFT, -135.0f }, { BACK_RIGHT, 135.0f } }; static const struct ChanMap X51Map[6] = { { FRONT_LEFT, -30.0f }, { FRONT_RIGHT, 30.0f }, { FRONT_CENTER, 0.0f }, { LFE, 0.0f }, { BACK_LEFT, -110.0f }, { BACK_RIGHT, 110.0f } }; static const struct ChanMap X61Map[7] = { { FRONT_LEFT, -30.0f }, { FRONT_RIGHT, 30.0f }, { FRONT_CENTER, 0.0f }, { LFE, 0.0f }, { BACK_CENTER, 180.0f }, { SIDE_LEFT, -90.0f }, { SIDE_RIGHT, 90.0f } }; static const struct ChanMap X71Map[8] = { { FRONT_LEFT, -30.0f }, { FRONT_RIGHT, 30.0f }, { FRONT_CENTER, 0.0f }, { LFE, 0.0f }, { BACK_LEFT, -110.0f }, { BACK_RIGHT, 110.0f }, { SIDE_LEFT, -90.0f }, { SIDE_RIGHT, 90.0f } }; ALCdevice *Device = ALContext->Device; ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; ALbufferlistitem *BufferListItem; enum DevFmtChannels DevChans; enum FmtChannels Channels; ALfloat (*SrcMatrix)[MAXCHANNELS]; ALfloat DryGain, DryGainHF; ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; ALint NumSends, Frequency; const ALfloat *SpeakerGain; const struct ChanMap *chans = NULL; enum Resampler Resampler; ALint num_channels = 0; ALboolean VirtualChannels; ALfloat Pitch; ALfloat cw; ALuint pos; ALint i, c; /* Get device properties */ DevChans = Device->FmtChans; NumSends = Device->NumAuxSends; Frequency = Device->Frequency; /* Get listener properties */ ListenerGain = ALContext->Listener.Gain; /* Get source properties */ SourceVolume = ALSource->flGain; MinVolume = ALSource->flMinGain; MaxVolume = ALSource->flMaxGain; Pitch = ALSource->flPitch; Resampler = ALSource->Resampler; VirtualChannels = ALSource->VirtualChannels; /* Calculate the stepping value */ Channels = FmtMono; BufferListItem = ALSource->queue; while(BufferListItem != NULL) { ALbuffer *ALBuffer; if((ALBuffer=BufferListItem->buffer) != NULL) { ALsizei maxstep = STACK_DATA_SIZE/sizeof(ALfloat) / ALSource->NumChannels; maxstep -= ResamplerPadding[Resampler] + ResamplerPrePadding[Resampler] + 1; maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS); Pitch = Pitch * ALBuffer->Frequency / Frequency; if(Pitch > (ALfloat)maxstep) ALSource->Params.Step = maxstep<<FRACTIONBITS; else { ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE); if(ALSource->Params.Step == 0) ALSource->Params.Step = 1; } Channels = ALBuffer->FmtChannels; break; } BufferListItem = BufferListItem->next; }
// Calculates the moving HRIR target coefficients, target delays, and // stepping values for the given polar elevation and azimuth in radians. // Linear interpolation is used to increase the apparent resolution of the // HRIR dataset. The coefficients are also normalized and attenuated by the // specified gain. Stepping resolution and count is determined using the // given delta factor between 0.0 and 1.0. ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep) { ALuint evidx[2], azidx[2]; ALuint lidx[4], ridx[4]; ALfloat left, right; ALfloat mu[3]; ALfloat step; ALuint i; // Claculate elevation indices and interpolation factor. CalcEvIndices(elevation, evidx, &mu[2]); // Calculate azimuth indices and interpolation factor for the first // elevation. CalcAzIndices(evidx[0], azimuth, azidx, &mu[0]); // Calculate the first set of linear HRIR indices for left and right // channels. lidx[0] = evOffset[evidx[0]] + azidx[0]; lidx[1] = evOffset[evidx[0]] + azidx[1]; ridx[0] = evOffset[evidx[0]] + ((azCount[evidx[0]]-azidx[0]) % azCount[evidx[0]]); ridx[1] = evOffset[evidx[0]] + ((azCount[evidx[0]]-azidx[1]) % azCount[evidx[0]]); // Calculate azimuth indices and interpolation factor for the second // elevation. CalcAzIndices(evidx[1], azimuth, azidx, &mu[1]); // Calculate the second set of linear HRIR indices for left and right // channels. lidx[2] = evOffset[evidx[1]] + azidx[0]; lidx[3] = evOffset[evidx[1]] + azidx[1]; ridx[2] = evOffset[evidx[1]] + ((azCount[evidx[1]]-azidx[0]) % azCount[evidx[1]]); ridx[3] = evOffset[evidx[1]] + ((azCount[evidx[1]]-azidx[1]) % azCount[evidx[1]]); // Calculate the stepping parameters. delta = maxf(aluFloor(delta*(Hrtf->sampleRate*0.015f) + 0.5f), 1.0f); step = 1.0f / delta; // Calculate the normalized and attenuated target HRIR coefficients using // linear interpolation when there is enough gain to warrant it. Zero // the target coefficients if gain is too low. Then calculate the // coefficient stepping values using the target and previous running // coefficients. if(gain > 0.0001f) { gain *= 1.0f/32767.0f; for(i = 0;i < HRIR_LENGTH;i++) { left = coeffs[i][0] - (coeffStep[i][0] * counter); right = coeffs[i][1] - (coeffStep[i][1] * counter); coeffs[i][0] = lerp(lerp(Hrtf->coeffs[lidx[0]][i], Hrtf->coeffs[lidx[1]][i], mu[0]), lerp(Hrtf->coeffs[lidx[2]][i], Hrtf->coeffs[lidx[3]][i], mu[1]), mu[2]) * gain; coeffs[i][1] = lerp(lerp(Hrtf->coeffs[ridx[0]][i], Hrtf->coeffs[ridx[1]][i], mu[0]), lerp(Hrtf->coeffs[ridx[2]][i], Hrtf->coeffs[ridx[3]][i], mu[1]), mu[2]) * gain; coeffStep[i][0] = step * (coeffs[i][0] - left); coeffStep[i][1] = step * (coeffs[i][1] - right); } } else { for(i = 0;i < HRIR_LENGTH;i++) { left = coeffs[i][0] - (coeffStep[i][0] * counter); right = coeffs[i][1] - (coeffStep[i][1] * counter); coeffs[i][0] = 0.0f; coeffs[i][1] = 0.0f; coeffStep[i][0] = step * -left; coeffStep[i][1] = step * -right; } } // Calculate the HRIR delays using linear interpolation. Then calculate // the delay stepping values using the target and previous running // delays. left = (ALfloat)(delays[0] - (delayStep[0] * counter)); right = (ALfloat)(delays[1] - (delayStep[1] * counter)); delays[0] = fastf2u(lerp(lerp(Hrtf->delays[lidx[0]], Hrtf->delays[lidx[1]], mu[0]), lerp(Hrtf->delays[lidx[2]], Hrtf->delays[lidx[3]], mu[1]), mu[2]) * 65536.0f); delays[1] = fastf2u(lerp(lerp(Hrtf->delays[ridx[0]], Hrtf->delays[ridx[1]], mu[0]), lerp(Hrtf->delays[ridx[2]], Hrtf->delays[ridx[3]], mu[1]), mu[2]) * 65536.0f); delayStep[0] = fastf2i(step * (delays[0] - left)); delayStep[1] = fastf2i(step * (delays[1] - right)); // The stepping count is the number of samples necessary for the HRIR to // complete its transition. The mixer will only apply stepping for this // many samples. return fastf2u(delta); }
ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext) { ALCdevice *Device = ALContext->Device; aluVector Position, Velocity, Direction, SourceToListener; ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist; ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain; ALfloat DopplerFactor, SpeedOfSound; ALfloat AirAbsorptionFactor; ALfloat RoomAirAbsorption[MAX_SENDS]; ALbufferlistitem *BufferListItem; ALfloat Attenuation; ALfloat RoomAttenuation[MAX_SENDS]; ALfloat MetersPerUnit; ALfloat RoomRolloffBase; ALfloat RoomRolloff[MAX_SENDS]; ALfloat DecayDistance[MAX_SENDS]; ALfloat DryGain; ALfloat DryGainHF; ALfloat DryGainLF; ALboolean DryGainHFAuto; ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; ALfloat WetGainLF[MAX_SENDS]; ALboolean WetGainAuto; ALboolean WetGainHFAuto; ALfloat Pitch; ALuint Frequency; ALint NumSends; ALint i, j; DryGainHF = 1.0f; DryGainLF = 1.0f; for(i = 0;i < MAX_SENDS;i++) { WetGainHF[i] = 1.0f; WetGainLF[i] = 1.0f; } /* Get context/device properties */ DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor; SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity; NumSends = Device->NumAuxSends; Frequency = Device->Frequency; /* Get listener properties */ ListenerGain = ALContext->Listener->Gain; MetersPerUnit = ALContext->Listener->MetersPerUnit; /* Get source properties */ SourceVolume = ALSource->Gain; MinVolume = ALSource->MinGain; MaxVolume = ALSource->MaxGain; Pitch = ALSource->Pitch; Position = ALSource->Position; Direction = ALSource->Direction; Velocity = ALSource->Velocity; MinDist = ALSource->RefDistance; MaxDist = ALSource->MaxDistance; Rolloff = ALSource->RollOffFactor; InnerAngle = ALSource->InnerAngle; OuterAngle = ALSource->OuterAngle; AirAbsorptionFactor = ALSource->AirAbsorptionFactor; DryGainHFAuto = ALSource->DryGainHFAuto; WetGainAuto = ALSource->WetGainAuto; WetGainHFAuto = ALSource->WetGainHFAuto; RoomRolloffBase = ALSource->RoomRolloffFactor; voice->Direct.OutBuffer = Device->DryBuffer; voice->Direct.OutChannels = Device->NumChannels; for(i = 0;i < NumSends;i++) { ALeffectslot *Slot = ALSource->Send[i].Slot; if(!Slot && i == 0) Slot = Device->DefaultSlot; if(!Slot || Slot->EffectType == AL_EFFECT_NULL) { Slot = NULL; RoomRolloff[i] = 0.0f; DecayDistance[i] = 0.0f; RoomAirAbsorption[i] = 1.0f; } else if(Slot->AuxSendAuto) { RoomRolloff[i] = RoomRolloffBase; if(IsReverbEffect(Slot->EffectType)) { RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor; DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime * SPEEDOFSOUNDMETRESPERSEC; RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF; } else { DecayDistance[i] = 0.0f; RoomAirAbsorption[i] = 1.0f; } } else { /* If the slot's auxiliary send auto is off, the data sent to the * effect slot is the same as the dry path, sans filter effects */ RoomRolloff[i] = Rolloff; DecayDistance[i] = 0.0f; RoomAirAbsorption[i] = AIRABSORBGAINHF; } if(!Slot || Slot->EffectType == AL_EFFECT_NULL) voice->Send[i].OutBuffer = NULL; else voice->Send[i].OutBuffer = Slot->WetBuffer; } /* Transform source to listener space (convert to head relative) */ if(ALSource->HeadRelative == AL_FALSE) { const aluMatrix *Matrix = &ALContext->Listener->Params.Matrix; /* Transform source vectors */ aluMatrixVector(&Position, Matrix); aluMatrixVector(&Velocity, Matrix); aluMatrixVector(&Direction, Matrix); } else { const aluVector *lvelocity = &ALContext->Listener->Params.Velocity; /* Offset the source velocity to be relative of the listener velocity */ Velocity.v[0] += lvelocity->v[0]; Velocity.v[1] += lvelocity->v[1]; Velocity.v[2] += lvelocity->v[2]; } aluNormalize(Direction.v); SourceToListener.v[0] = -Position.v[0]; SourceToListener.v[1] = -Position.v[1]; SourceToListener.v[2] = -Position.v[2]; SourceToListener.v[3] = 0.0f; Distance = aluNormalize(SourceToListener.v); /* Calculate distance attenuation */ ClampedDist = Distance; Attenuation = 1.0f; for(i = 0;i < NumSends;i++) RoomAttenuation[i] = 1.0f; switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel : ALContext->DistanceModel) { case InverseDistanceClamped: ClampedDist = clampf(ClampedDist, MinDist, MaxDist); if(MaxDist < MinDist) break; /*fall-through*/ case InverseDistance: if(MinDist > 0.0f) { ALfloat dist = lerp(MinDist, ClampedDist, Rolloff); if(dist > 0.0f) Attenuation = MinDist / dist; for(i = 0;i < NumSends;i++) { dist = lerp(MinDist, ClampedDist, RoomRolloff[i]); if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist; } } break; case LinearDistanceClamped: ClampedDist = clampf(ClampedDist, MinDist, MaxDist); if(MaxDist < MinDist) break; /*fall-through*/ case LinearDistance: if(MaxDist != MinDist) { Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist)); Attenuation = maxf(Attenuation, 0.0f); for(i = 0;i < NumSends;i++) { RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist)); RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f); } } break; case ExponentDistanceClamped: ClampedDist = clampf(ClampedDist, MinDist, MaxDist); if(MaxDist < MinDist) break; /*fall-through*/ case ExponentDistance: if(ClampedDist > 0.0f && MinDist > 0.0f) { Attenuation = powf(ClampedDist/MinDist, -Rolloff); for(i = 0;i < NumSends;i++) RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]); } break; case DisableDistance: ClampedDist = MinDist; break; } /* Source Gain + Attenuation */ DryGain = SourceVolume * Attenuation; for(i = 0;i < NumSends;i++) WetGain[i] = SourceVolume * RoomAttenuation[i]; /* Distance-based air absorption */ if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist) { ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit; DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters); for(i = 0;i < NumSends;i++) WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters); } if(WetGainAuto) { ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f; /* Apply a decay-time transformation to the wet path, based on the * attenuation of the dry path. * * Using the apparent distance, based on the distance attenuation, the * initial decay of the reverb effect is calculated and applied to the * wet path. */ for(i = 0;i < NumSends;i++) { if(DecayDistance[i] > 0.0f) WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]); } } /* Calculate directional soundcones */ Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f; if(Angle > InnerAngle && Angle <= OuterAngle) { ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); ConeVolume = lerp(1.0f, ALSource->OuterGain, scale); ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale); } else if(Angle > OuterAngle) { ConeVolume = ALSource->OuterGain; ConeHF = ALSource->OuterGainHF; } else { ConeVolume = 1.0f; ConeHF = 1.0f; } DryGain *= ConeVolume; if(WetGainAuto) { for(i = 0;i < NumSends;i++) WetGain[i] *= ConeVolume; } if(DryGainHFAuto) DryGainHF *= ConeHF; if(WetGainHFAuto) { for(i = 0;i < NumSends;i++) WetGainHF[i] *= ConeHF; } /* Clamp to Min/Max Gain */ DryGain = clampf(DryGain, MinVolume, MaxVolume); for(i = 0;i < NumSends;i++) WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume); /* Apply gain and frequency filters */ DryGain *= ALSource->Direct.Gain * ListenerGain; DryGainHF *= ALSource->Direct.GainHF; DryGainLF *= ALSource->Direct.GainLF; for(i = 0;i < NumSends;i++) { WetGain[i] *= ALSource->Send[i].Gain * ListenerGain; WetGainHF[i] *= ALSource->Send[i].GainHF; WetGainLF[i] *= ALSource->Send[i].GainLF; } /* Calculate velocity-based doppler effect */ if(DopplerFactor > 0.0f) { const aluVector *lvelocity = &ALContext->Listener->Params.Velocity; ALfloat VSS, VLS; if(SpeedOfSound < 1.0f) { DopplerFactor *= 1.0f/SpeedOfSound; SpeedOfSound = 1.0f; } VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor; VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor; Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) / clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f); } BufferListItem = ATOMIC_LOAD(&ALSource->queue); while(BufferListItem != NULL) { ALbuffer *ALBuffer; if((ALBuffer=BufferListItem->buffer) != NULL) { /* Calculate fixed-point stepping value, based on the pitch, buffer * frequency, and output frequency. */ Pitch = Pitch * ALBuffer->Frequency / Frequency; if(Pitch > (ALfloat)MAX_PITCH) voice->Step = MAX_PITCH<<FRACTIONBITS; else { voice->Step = fastf2i(Pitch*FRACTIONONE); if(voice->Step == 0) voice->Step = 1; } break; } BufferListItem = BufferListItem->next; } if(Device->Hrtf_Mode == FullHrtf) { /* Use a binaural HRTF algorithm for stereo headphone playback */ aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }}; ALfloat ev = 0.0f, az = 0.0f; ALfloat radius = ALSource->Radius; ALfloat dirfact = 1.0f; voice->Direct.OutBuffer += voice->Direct.OutChannels; voice->Direct.OutChannels = 2; if(Distance > FLT_EPSILON) { dir.v[0] = -SourceToListener.v[0]; dir.v[1] = -SourceToListener.v[1]; dir.v[2] = -SourceToListener.v[2] * ZScale; /* Calculate elevation and azimuth only when the source is not at * the listener. This prevents +0 and -0 Z from producing * inconsistent panning. Also, clamp Y in case FP precision errors * cause it to land outside of -1..+1. */ ev = asinf(clampf(dir.v[1], -1.0f, 1.0f)); az = atan2f(dir.v[0], -dir.v[2]); } if(radius > 0.0f) { if(radius >= Distance) dirfact *= Distance / radius * 0.5f; else dirfact *= 1.0f - (asinf(radius / Distance) / F_PI); } /* Check to see if the HRIR is already moving. */ if(voice->Direct.Moving) { ALfloat delta; delta = CalcFadeTime(voice->Direct.LastGain, DryGain, &voice->Direct.LastDir, &dir); /* If the delta is large enough, get the moving HRIR target * coefficients, target delays, steppping values, and counter. */ if(delta > 0.000015f) { ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain, delta, voice->Direct.Counter, voice->Direct.Hrtf[0].Params.Coeffs, voice->Direct.Hrtf[0].Params.Delay, voice->Direct.Hrtf[0].Params.CoeffStep, voice->Direct.Hrtf[0].Params.DelayStep ); voice->Direct.Counter = counter; voice->Direct.LastGain = DryGain; voice->Direct.LastDir = dir; } } else { /* Get the initial (static) HRIR coefficients and delays. */ GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain, voice->Direct.Hrtf[0].Params.Coeffs, voice->Direct.Hrtf[0].Params.Delay); voice->Direct.Counter = 0; voice->Direct.Moving = AL_TRUE; voice->Direct.LastGain = DryGain; voice->Direct.LastDir = dir; } voice->IsHrtf = AL_TRUE; } else { MixGains *gains = voice->Direct.Gains[0]; ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; ALfloat radius = ALSource->Radius; ALfloat Target[MAX_OUTPUT_CHANNELS]; /* Get the localized direction, and compute panned gains. */ if(Distance > FLT_EPSILON) { dir[0] = -SourceToListener.v[0]; dir[1] = -SourceToListener.v[1]; dir[2] = -SourceToListener.v[2] * ZScale; } if(radius > 0.0f) { ALfloat dirfact; if(radius >= Distance) dirfact = Distance / radius * 0.5f; else dirfact = 1.0f - (asinf(radius / Distance) / F_PI); dir[0] *= dirfact; dir[1] *= dirfact; dir[2] *= dirfact; } ComputeDirectionalGains(Device, dir, DryGain, Target); for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) gains[j].Target = Target[j]; UpdateDryStepping(&voice->Direct, 1, (voice->Direct.Moving ? 64 : 0)); voice->Direct.Moving = AL_TRUE; voice->IsHrtf = AL_FALSE; } for(i = 0;i < NumSends;i++) { voice->Send[i].Gain.Target = WetGain[i]; UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0)); voice->Send[i].Moving = AL_TRUE; } { ALfloat gainhf = maxf(0.01f, DryGainHF); ALfloat gainlf = maxf(0.01f, DryGainLF); ALfloat hfscale = ALSource->Direct.HFReference / Frequency; ALfloat lfscale = ALSource->Direct.LFReference / Frequency; voice->Direct.Filters[0].ActiveType = AF_None; if(gainhf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass; if(gainlf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass; ALfilterState_setParams( &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf, hfscale, 0.0f ); ALfilterState_setParams( &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf, lfscale, 0.0f ); } for(i = 0;i < NumSends;i++) { ALfloat gainhf = maxf(0.01f, WetGainHF[i]); ALfloat gainlf = maxf(0.01f, WetGainLF[i]); ALfloat hfscale = ALSource->Send[i].HFReference / Frequency; ALfloat lfscale = ALSource->Send[i].LFReference / Frequency; voice->Send[i].Filters[0].ActiveType = AF_None; if(gainhf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass; if(gainlf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass; ALfilterState_setParams( &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf, hfscale, 0.0f ); ALfilterState_setParams( &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf, lfscale, 0.0f ); } }
ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext) { static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } }, StereoMap[2] = { { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) } }, StereoWideMap[2] = { { FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } }, RearMap[2] = { { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) } }, QuadMap[4] = { { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) }, { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) }, { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) } }, X51Map[6] = { { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, { LFE, 0.0f, 0.0f }, { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) }, { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) } }, X61Map[7] = { { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, { LFE, 0.0f, 0.0f }, { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) }, { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } }, X71Map[8] = { { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, { LFE, 0.0f, 0.0f }, { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }, { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) }, { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } }; ALCdevice *Device = ALContext->Device; ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; ALbufferlistitem *BufferListItem; enum FmtChannels Channels; ALfloat DryGain, DryGainHF, DryGainLF; ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; ALfloat WetGainLF[MAX_SENDS]; ALuint NumSends, Frequency; ALboolean Relative; const struct ChanMap *chans = NULL; ALuint num_channels = 0; ALboolean DirectChannels; ALboolean isbformat = AL_FALSE; ALfloat Pitch; ALuint i, j, c; /* Get device properties */ NumSends = Device->NumAuxSends; Frequency = Device->Frequency; /* Get listener properties */ ListenerGain = ALContext->Listener->Gain; /* Get source properties */ SourceVolume = ALSource->Gain; MinVolume = ALSource->MinGain; MaxVolume = ALSource->MaxGain; Pitch = ALSource->Pitch; Relative = ALSource->HeadRelative; DirectChannels = ALSource->DirectChannels; voice->Direct.OutBuffer = Device->DryBuffer; voice->Direct.OutChannels = Device->NumChannels; for(i = 0;i < NumSends;i++) { ALeffectslot *Slot = ALSource->Send[i].Slot; if(!Slot && i == 0) Slot = Device->DefaultSlot; if(!Slot || Slot->EffectType == AL_EFFECT_NULL) voice->Send[i].OutBuffer = NULL; else voice->Send[i].OutBuffer = Slot->WetBuffer; } /* Calculate the stepping value */ Channels = FmtMono; BufferListItem = ATOMIC_LOAD(&ALSource->queue); while(BufferListItem != NULL) { ALbuffer *ALBuffer; if((ALBuffer=BufferListItem->buffer) != NULL) { Pitch = Pitch * ALBuffer->Frequency / Frequency; if(Pitch > (ALfloat)MAX_PITCH) voice->Step = MAX_PITCH<<FRACTIONBITS; else { voice->Step = fastf2i(Pitch*FRACTIONONE); if(voice->Step == 0) voice->Step = 1; } Channels = ALBuffer->FmtChannels; break; } BufferListItem = BufferListItem->next; } /* Calculate gains */ DryGain = clampf(SourceVolume, MinVolume, MaxVolume); DryGain *= ALSource->Direct.Gain * ListenerGain; DryGainHF = ALSource->Direct.GainHF; DryGainLF = ALSource->Direct.GainLF; for(i = 0;i < NumSends;i++) { WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume); WetGain[i] *= ALSource->Send[i].Gain * ListenerGain; WetGainHF[i] = ALSource->Send[i].GainHF; WetGainLF[i] = ALSource->Send[i].GainLF; } switch(Channels) { case FmtMono: chans = MonoMap; num_channels = 1; break; case FmtStereo: /* HACK: Place the stereo channels at +/-90 degrees when using non- * HRTF stereo output. This helps reduce the "monoization" caused * by them panning towards the center. */ if(Device->FmtChans == DevFmtStereo && !Device->Hrtf) chans = StereoWideMap; else chans = StereoMap; num_channels = 2; break; case FmtRear: chans = RearMap; num_channels = 2; break; case FmtQuad: chans = QuadMap; num_channels = 4; break; case FmtX51: chans = X51Map; num_channels = 6; break; case FmtX61: chans = X61Map; num_channels = 7; break; case FmtX71: chans = X71Map; num_channels = 8; break; case FmtBFormat2D: num_channels = 3; isbformat = AL_TRUE; DirectChannels = AL_FALSE; break; case FmtBFormat3D: num_channels = 4; isbformat = AL_TRUE; DirectChannels = AL_FALSE; break; } if(isbformat) { ALfloat N[3], V[3], U[3]; aluMatrix matrix; /* AT then UP */ N[0] = ALSource->Orientation[0][0]; N[1] = ALSource->Orientation[0][1]; N[2] = ALSource->Orientation[0][2]; aluNormalize(N); V[0] = ALSource->Orientation[1][0]; V[1] = ALSource->Orientation[1][1]; V[2] = ALSource->Orientation[1][2]; aluNormalize(V); if(!Relative) { const aluMatrix *lmatrix = &ALContext->Listener->Params.Matrix; aluVector at, up; aluVectorSet(&at, N[0], N[1], N[2], 0.0f); aluVectorSet(&up, V[0], V[1], V[2], 0.0f); aluMatrixVector(&at, lmatrix); aluMatrixVector(&up, lmatrix); N[0] = at.v[0]; N[1] = at.v[1]; N[2] = at.v[2]; V[0] = up.v[0]; V[1] = up.v[1]; V[2] = up.v[2]; } /* Build and normalize right-vector */ aluCrossproduct(N, V, U); aluNormalize(U); aluMatrixSet(&matrix, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -N[2], -N[0], N[1], 0.0f, U[2], U[0], -U[1], 0.0f, -V[2], -V[0], V[1] ); for(c = 0;c < num_channels;c++) { MixGains *gains = voice->Direct.Gains[c]; ALfloat Target[MAX_OUTPUT_CHANNELS]; ComputeBFormatGains(Device, matrix.m[c], DryGain, Target); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) gains[i].Target = Target[i]; } UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); voice->Direct.Moving = AL_TRUE; voice->IsHrtf = AL_FALSE; for(i = 0;i < NumSends;i++) WetGain[i] *= 1.4142f; } else if(DirectChannels != AL_FALSE) { if(Device->Hrtf) { voice->Direct.OutBuffer += voice->Direct.OutChannels; voice->Direct.OutChannels = 2; for(c = 0;c < num_channels;c++) { MixGains *gains = voice->Direct.Gains[c]; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) gains[j].Target = 0.0f; if(chans[c].channel == FrontLeft) gains[0].Target = DryGain; else if(chans[c].channel == FrontRight) gains[1].Target = DryGain; } } else for(c = 0;c < num_channels;c++) { MixGains *gains = voice->Direct.Gains[c]; int idx; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) gains[j].Target = 0.0f; if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1) gains[idx].Target = DryGain; } UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); voice->Direct.Moving = AL_TRUE; voice->IsHrtf = AL_FALSE; } else if(Device->Hrtf_Mode == FullHrtf) { voice->Direct.OutBuffer += voice->Direct.OutChannels; voice->Direct.OutChannels = 2; for(c = 0;c < num_channels;c++) { if(chans[c].channel == LFE) { /* Skip LFE */ voice->Direct.Hrtf[c].Params.Delay[0] = 0; voice->Direct.Hrtf[c].Params.Delay[1] = 0; for(i = 0;i < HRIR_LENGTH;i++) { voice->Direct.Hrtf[c].Params.Coeffs[i][0] = 0.0f; voice->Direct.Hrtf[c].Params.Coeffs[i][1] = 0.0f; } } else { /* Get the static HRIR coefficients and delays for this * channel. */ GetLerpedHrtfCoeffs(Device->Hrtf, chans[c].elevation, chans[c].angle, 1.0f, DryGain, voice->Direct.Hrtf[c].Params.Coeffs, voice->Direct.Hrtf[c].Params.Delay); } } voice->Direct.Counter = 0; voice->Direct.Moving = AL_TRUE; voice->IsHrtf = AL_TRUE; } else { for(c = 0;c < num_channels;c++) { MixGains *gains = voice->Direct.Gains[c]; ALfloat Target[MAX_OUTPUT_CHANNELS]; /* Special-case LFE */ if(chans[c].channel == LFE) { int idx; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) gains[i].Target = 0.0f; if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1) gains[idx].Target = DryGain; continue; } ComputeAngleGains(Device, chans[c].angle, chans[c].elevation, DryGain, Target); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) gains[i].Target = Target[i]; } UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); voice->Direct.Moving = AL_TRUE; voice->IsHrtf = AL_FALSE; } for(i = 0;i < NumSends;i++) { voice->Send[i].Gain.Target = WetGain[i]; UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0)); voice->Send[i].Moving = AL_TRUE; } { ALfloat gainhf = maxf(0.01f, DryGainHF); ALfloat gainlf = maxf(0.01f, DryGainLF); ALfloat hfscale = ALSource->Direct.HFReference / Frequency; ALfloat lfscale = ALSource->Direct.LFReference / Frequency; for(c = 0;c < num_channels;c++) { voice->Direct.Filters[c].ActiveType = AF_None; if(gainhf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass; if(gainlf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass; ALfilterState_setParams( &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf, hfscale, 0.0f ); ALfilterState_setParams( &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf, lfscale, 0.0f ); } } for(i = 0;i < NumSends;i++) { ALfloat gainhf = maxf(0.01f, WetGainHF[i]); ALfloat gainlf = maxf(0.01f, WetGainLF[i]); ALfloat hfscale = ALSource->Send[i].HFReference / Frequency; ALfloat lfscale = ALSource->Send[i].LFReference / Frequency; for(c = 0;c < num_channels;c++) { voice->Send[i].Filters[c].ActiveType = AF_None; if(gainhf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass; if(gainlf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass; ALfilterState_setParams( &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf, hfscale, 0.0f ); ALfilterState_setParams( &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf, lfscale, 0.0f ); } } }