static ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect) { ALechoState *state = (ALechoState*)effect; ALuint frequency = Context->Device->Frequency; ALfp lrpan, cw, a, g; state->Tap[0].delay = (ALuint)ALfp2int((ALfpMult(Effect->Echo.Delay, int2ALfp(frequency)) + int2ALfp(1))); state->Tap[1].delay = (ALuint)ALfp2int(ALfpMult(Effect->Echo.LRDelay, int2ALfp(frequency))); state->Tap[1].delay += state->Tap[0].delay; lrpan = (ALfpMult(Effect->Echo.Spread, float2ALfp(0.5f)) + float2ALfp(0.5f)); state->GainL = aluSqrt( lrpan); state->GainR = aluSqrt((int2ALfp(1)-lrpan)); state->FeedGain = Effect->Echo.Feedback; cw = __cos(ALfpDiv(float2ALfp(2.0*M_PI * LOWPASSFREQCUTOFF), int2ALfp(frequency))); g = (int2ALfp(1) - Effect->Echo.Damping); a = int2ALfp(0); if(g < float2ALfp(0.9999f)) { /* 1-epsilon */ // a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g); a = ALfpDiv((int2ALfp(1) - ALfpMult(g,cw) - aluSqrt((ALfpMult(ALfpMult(int2ALfp(2),g),(int2ALfp(1)-cw)) - ALfpMult(ALfpMult(g,g),(int2ALfp(1) - ALfpMult(cw,cw)))))), (int2ALfp(1) - g)); } state->iirFilter.coeff = a; }
static ALvoid ModulatorUpdate(ALeffectState *effect, ALCdevice *Device, const ALeffectslot *Slot) { ALmodulatorState *state = (ALmodulatorState*)effect; ALfloat gain, cw, a = 0.0f; ALuint index; if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) state->Waveform = SINUSOID; else if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) state->Waveform = SAWTOOTH; else if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SQUARE) state->Waveform = SQUARE; state->step = fastf2u(Slot->effect.Modulator.Frequency*WAVEFORM_FRACONE / Device->Frequency); if(state->step == 0) state->step = 1; cw = aluCos(F_PI*2.0f * Slot->effect.Modulator.HighPassCutoff / Device->Frequency); a = (2.0f-cw) - aluSqrt(aluPow(2.0f-cw, 2.0f) - 1.0f); state->iirFilter.coeff = a; gain = aluSqrt(1.0f/Device->NumChan); gain *= Slot->Gain; for(index = 0;index < MAXCHANNELS;index++) state->Gain[index] = 0.0f; for(index = 0;index < Device->NumChan;index++) { enum Channel chan = Device->Speaker2Chan[index]; state->Gain[chan] = gain; } }
static ALvoid EchoUpdate( ALeffectState* effect, ALCcontext* Context, const ALeffect* Effect ) { ALechoState* state = ( ALechoState* )effect; ALuint frequency = Context->Device->Frequency; ALfloat lrpan, cw, a, g; state->Tap[0].delay = ( ALuint )( Effect->Echo.Delay * frequency ) + 1; state->Tap[1].delay = ( ALuint )( Effect->Echo.LRDelay * frequency ); state->Tap[1].delay += state->Tap[0].delay; lrpan = Effect->Echo.Spread * 0.5f + 0.5f; state->GainL = aluSqrt( lrpan ); state->GainR = aluSqrt( 1.0f - lrpan ); state->FeedGain = Effect->Echo.Feedback; cw = cos( 2.0 * M_PI * LOWPASSFREQCUTOFF / frequency ); g = 1.0f - Effect->Echo.Damping; a = 0.0f; if ( g < 0.9999f ) // 1-epsilon { a = ( 1 - g * cw - aluSqrt( 2 * g * ( 1 - cw ) - g * g * ( 1 - cw * cw ) ) ) / ( 1 - g ); } state->iirFilter.coeff = a; }
static ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffectslot *Slot) { ALechoState *state = (ALechoState*)effect; ALCdevice *Device = Context->Device; ALuint frequency = Device->Frequency; ALfloat lrpan, cw, g, gain; ALuint i; state->Tap[0].delay = (ALuint)(Slot->effect.Echo.Delay * frequency) + 1; state->Tap[1].delay = (ALuint)(Slot->effect.Echo.LRDelay * frequency); state->Tap[1].delay += state->Tap[0].delay; lrpan = Slot->effect.Echo.Spread*0.5f + 0.5f; state->GainL = aluSqrt( lrpan); state->GainR = aluSqrt(1.0f-lrpan); state->FeedGain = Slot->effect.Echo.Feedback; cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / frequency); g = 1.0f - Slot->effect.Echo.Damping; state->iirFilter.coeff = lpCoeffCalc(g, cw); gain = Slot->Gain; for(i = 0;i < MAXCHANNELS;i++) state->Gain[i] = 0.0f; for(i = 0;i < Device->NumChan;i++) { enum Channel chan = Device->Speaker2Chan[i]; state->Gain[chan] = gain; } }
static ALboolean EchoDeviceUpdate(ALeffectState *effect, ALCdevice *Device) { ALechoState *state = (ALechoState*)effect; ALuint maxlen, i; // Use the next power of 2 for the buffer length, so the tap offsets can be // wrapped using a mask instead of a modulo maxlen = (ALuint)(AL_ECHO_MAX_DELAY * Device->Frequency) + 1; maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1; maxlen = NextPowerOf2(maxlen); if(maxlen != state->BufferLength) { void *temp; temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat)); if(!temp) return AL_FALSE; state->SampleBuffer = temp; state->BufferLength = maxlen; } for(i = 0;i < state->BufferLength;i++) state->SampleBuffer[i] = 0.0f; state->Scale = aluSqrt(Device->NumChan / 6.0f); state->Scale = __min(state->Scale, 1.0f); return AL_TRUE; }
// This updates the device-dependant reverb state. This is called on // initialization and any time the device parameters (eg. playback frequency, // or format) have been changed. static ALboolean VerbDeviceUpdate( ALeffectState* effect, ALCdevice* Device ) { ALverbState* State = ( ALverbState* )effect; ALuint frequency = Device->Frequency, index; // Allocate the delay lines. if ( !AllocLines( AL_FALSE, frequency, State ) ) { return AL_FALSE; } State->Scale = aluSqrt( Device->NumChan / 8.0f ); // The early reflection and late all-pass filter line lengths are static, // so their offsets only need to be calculated once. for ( index = 0; index < 4; index++ ) { State->Early.Offset[index] = ( ALuint )( EARLY_LINE_LENGTH[index] * frequency ); State->Late.ApOffset[index] = ( ALuint )( ALLPASS_LINE_LENGTH[index] * frequency ); } return AL_TRUE; }
static ALvoid ModulatorUpdate( ALeffectState* effect, ALCcontext* Context, const ALeffect* Effect ) { ALmodulatorState* state = ( ALmodulatorState* )effect; ALfloat cw, a = 0.0f; if ( Effect->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID ) { state->Waveform = SINUSOID; } else if ( Effect->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH ) { state->Waveform = SAWTOOTH; } else if ( Effect->Modulator.Waveform == AL_RING_MODULATOR_SQUARE ) { state->Waveform = SQUARE; } state->step = Effect->Modulator.Frequency * ( 1 << WAVEFORM_FRACBITS ) / Context->Device->Frequency; if ( !state->step ) { state->step = 1; } cw = cos( 2.0 * M_PI * Effect->Modulator.HighPassCutoff / Context->Device->Frequency ); a = ( 2.0f - cw ) - aluSqrt( aluPow( 2.0f - cw, 2.0f ) - 1.0f ); state->iirFilter.coeff = a; }
static ALboolean ModulatorDeviceUpdate( ALeffectState* effect, ALCdevice* Device ) { ALmodulatorState* state = ( ALmodulatorState* )effect; state->Scale = aluSqrt( Device->NumChan / 8.0f ); return AL_TRUE; }
static __inline ALvoid aluNormalize(ALfloat *inVector) { ALfloat length, inverse_length; length = aluSqrt(aluDotproduct(inVector, inVector)); if(length != 0.0f) { inverse_length = 1.0f/length; inVector[0] *= inverse_length; inVector[1] *= inverse_length; inVector[2] *= inverse_length; } }
// Calculate the mixing matrix coefficients given a diffusion factor. static __inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y) { ALfloat n, t; // The matrix is of order 4, so n is sqrt (4 - 1). n = aluSqrt(3.0f); t = diffusion * atan(n); // Calculate the first mixing matrix coefficient. *x = cos(t); // Calculate the second mixing matrix coefficient. *y = sin(t) / n; }
ALfloat lpCoeffCalc(ALfloat g, ALfloat cw) { ALfloat a = 0.0f; /* Be careful with gains < 0.01, as that causes the coefficient * head towards 1, which will flatten the signal */ if(g < 0.9999f) /* 1-epsilon */ { g = maxf(g, 0.01f); a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g); } return a; }
// Calculate an attenuation to be applied to the input of any echo models to // compensate for modal density and decay time. static __inline ALfloat CalcDensityGain(ALfloat a) { /* The energy of a signal can be obtained by finding the area under the * squared signal. This takes the form of Sum(x_n^2), where x is the * amplitude for the sample n. * * Decaying feedback matches exponential decay of the form Sum(a^n), * where a is the attenuation coefficient, and n is the sample. The area * under this decay curve can be calculated as: 1 / (1 - a). * * Modifying the above equation to find the squared area under the curve * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be * calculated by inverting the square root of this approximation, * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). */ return aluSqrt(1.0f - (a * a)); }
// This updates the device-dependant EAX reverb state. This is called on // initialization and any time the device parameters (eg. playback frequency, // format) have been changed. static ALboolean EAXVerbDeviceUpdate( ALeffectState* effect, ALCdevice* Device ) { ALverbState* State = ( ALverbState* )effect; ALuint frequency = Device->Frequency, index; // Allocate the delay lines. if ( !AllocLines( AL_TRUE, frequency, State ) ) { return AL_FALSE; } State->Scale = aluSqrt( Device->NumChan / 8.0f ); // Calculate the modulation filter coefficient. Notice that the exponent // is calculated given the current sample rate. This ensures that the // resulting filter response over time is consistent across all sample // rates. State->Mod.Coeff = aluPow( MODULATION_FILTER_COEFF, MODULATION_FILTER_CONST / frequency ); // The early reflection and late all-pass filter line lengths are static, // so their offsets only need to be calculated once. for ( index = 0; index < 4; index++ ) { State->Early.Offset[index] = ( ALuint )( EARLY_LINE_LENGTH[index] * frequency ); State->Late.ApOffset[index] = ( ALuint )( ALLPASS_LINE_LENGTH[index] * frequency ); } // The echo all-pass filter line length is static, so its offset only // needs to be calculated once. State->Echo.ApOffset = ( ALuint )( ECHO_ALLPASS_LENGTH * frequency ); return AL_TRUE; }
ALvoid aluInitPanning(ALCdevice *Device) { ALfloat SpeakerAngle[MAXCHANNELS]; enum Channel *Speaker2Chan; ALfloat Alpha, Theta; ALint pos; ALuint s; Speaker2Chan = Device->Speaker2Chan; switch(Device->FmtChans) { case DevFmtMono: Device->NumChan = 1; Speaker2Chan[0] = FRONT_CENTER; SpeakerAngle[0] = F_PI/180.0f * 0.0f; break; case DevFmtStereo: Device->NumChan = 2; Speaker2Chan[0] = FRONT_LEFT; Speaker2Chan[1] = FRONT_RIGHT; SpeakerAngle[0] = F_PI/180.0f * -90.0f; SpeakerAngle[1] = F_PI/180.0f * 90.0f; SetSpeakerArrangement("layout_STEREO", SpeakerAngle, Speaker2Chan, Device->NumChan); break; case DevFmtQuad: Device->NumChan = 4; Speaker2Chan[0] = BACK_LEFT; Speaker2Chan[1] = FRONT_LEFT; Speaker2Chan[2] = FRONT_RIGHT; Speaker2Chan[3] = BACK_RIGHT; SpeakerAngle[0] = F_PI/180.0f * -135.0f; SpeakerAngle[1] = F_PI/180.0f * -45.0f; SpeakerAngle[2] = F_PI/180.0f * 45.0f; SpeakerAngle[3] = F_PI/180.0f * 135.0f; SetSpeakerArrangement("layout_QUAD", SpeakerAngle, Speaker2Chan, Device->NumChan); break; case DevFmtX51: Device->NumChan = 5; Speaker2Chan[0] = BACK_LEFT; Speaker2Chan[1] = FRONT_LEFT; Speaker2Chan[2] = FRONT_CENTER; Speaker2Chan[3] = FRONT_RIGHT; Speaker2Chan[4] = BACK_RIGHT; SpeakerAngle[0] = F_PI/180.0f * -110.0f; SpeakerAngle[1] = F_PI/180.0f * -30.0f; SpeakerAngle[2] = F_PI/180.0f * 0.0f; SpeakerAngle[3] = F_PI/180.0f * 30.0f; SpeakerAngle[4] = F_PI/180.0f * 110.0f; SetSpeakerArrangement("layout_51CHN", SpeakerAngle, Speaker2Chan, Device->NumChan); break; case DevFmtX51Side: Device->NumChan = 5; Speaker2Chan[0] = SIDE_LEFT; Speaker2Chan[1] = FRONT_LEFT; Speaker2Chan[2] = FRONT_CENTER; Speaker2Chan[3] = FRONT_RIGHT; Speaker2Chan[4] = SIDE_RIGHT; SpeakerAngle[0] = F_PI/180.0f * -90.0f; SpeakerAngle[1] = F_PI/180.0f * -30.0f; SpeakerAngle[2] = F_PI/180.0f * 0.0f; SpeakerAngle[3] = F_PI/180.0f * 30.0f; SpeakerAngle[4] = F_PI/180.0f * 90.0f; SetSpeakerArrangement("layout_51SIDECHN", SpeakerAngle, Speaker2Chan, Device->NumChan); break; case DevFmtX61: Device->NumChan = 6; Speaker2Chan[0] = SIDE_LEFT; Speaker2Chan[1] = FRONT_LEFT; Speaker2Chan[2] = FRONT_CENTER; Speaker2Chan[3] = FRONT_RIGHT; Speaker2Chan[4] = SIDE_RIGHT; Speaker2Chan[5] = BACK_CENTER; SpeakerAngle[0] = F_PI/180.0f * -90.0f; SpeakerAngle[1] = F_PI/180.0f * -30.0f; SpeakerAngle[2] = F_PI/180.0f * 0.0f; SpeakerAngle[3] = F_PI/180.0f * 30.0f; SpeakerAngle[4] = F_PI/180.0f * 90.0f; SpeakerAngle[5] = F_PI/180.0f * 180.0f; SetSpeakerArrangement("layout_61CHN", SpeakerAngle, Speaker2Chan, Device->NumChan); break; case DevFmtX71: Device->NumChan = 7; Speaker2Chan[0] = BACK_LEFT; Speaker2Chan[1] = SIDE_LEFT; Speaker2Chan[2] = FRONT_LEFT; Speaker2Chan[3] = FRONT_CENTER; Speaker2Chan[4] = FRONT_RIGHT; Speaker2Chan[5] = SIDE_RIGHT; Speaker2Chan[6] = BACK_RIGHT; SpeakerAngle[0] = F_PI/180.0f * -150.0f; SpeakerAngle[1] = F_PI/180.0f * -90.0f; SpeakerAngle[2] = F_PI/180.0f * -30.0f; SpeakerAngle[3] = F_PI/180.0f * 0.0f; SpeakerAngle[4] = F_PI/180.0f * 30.0f; SpeakerAngle[5] = F_PI/180.0f * 90.0f; SpeakerAngle[6] = F_PI/180.0f * 150.0f; SetSpeakerArrangement("layout_71CHN", SpeakerAngle, Speaker2Chan, Device->NumChan); break; } for(pos = 0; pos < LUT_NUM; pos++) { ALfloat *PanningLUT = Device->PanningLUT[pos]; /* clear all values */ for(s = 0; s < MAXCHANNELS; s++) PanningLUT[s] = 0.0f; if(Device->NumChan == 1) { PanningLUT[Speaker2Chan[0]] = 1.0f; continue; } /* source angle */ Theta = aluLUTpos2Angle(pos); /* set panning values */ for(s = 0; s < Device->NumChan - 1; s++) { if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1]) { /* source between speaker s and speaker s+1 */ Alpha = (Theta-SpeakerAngle[s]) / (SpeakerAngle[s+1]-SpeakerAngle[s]); PanningLUT[Speaker2Chan[s]] = aluSqrt(1.0f-Alpha); PanningLUT[Speaker2Chan[s+1]] = aluSqrt( Alpha); break; } } if(s == Device->NumChan - 1) { /* source between last and first speaker */ if(Theta < SpeakerAngle[0]) Theta += F_PI*2.0f; Alpha = (Theta-SpeakerAngle[s]) / (F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[s]); PanningLUT[Speaker2Chan[s]] = aluSqrt(1.0f-Alpha); PanningLUT[Speaker2Chan[0]] = aluSqrt( Alpha); } } }
// Update the early and late 3D panning gains. static ALvoid Update3DPanning( const ALfloat* ReflectionsPan, const ALfloat* LateReverbPan, ALfloat* PanningLUT, ALverbState* State ) { ALfloat length; ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1], ReflectionsPan[2] }; ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1], LateReverbPan[2] }; ALint pos; ALfloat* speakerGain, dirGain, ambientGain; ALuint index; // Calculate the 3D-panning gains for the early reflections and late // reverb. length = earlyPan[0] * earlyPan[0] + earlyPan[1] * earlyPan[1] + earlyPan[2] * earlyPan[2]; if ( length > 1.0f ) { length = 1.0f / aluSqrt( length ); earlyPan[0] *= length; earlyPan[1] *= length; earlyPan[2] *= length; } length = latePan[0] * latePan[0] + latePan[1] * latePan[1] + latePan[2] * latePan[2]; if ( length > 1.0f ) { length = 1.0f / aluSqrt( length ); latePan[0] *= length; latePan[1] *= length; latePan[2] *= length; } /* This code applies directional reverb just like the mixer applies * directional sources. It diffuses the sound toward all speakers as the * magnitude of the panning vector drops, which is only a rough * approximation of the expansion of sound across the speakers from the * panning direction. */ pos = aluCart2LUTpos( earlyPan[2], earlyPan[0] ); speakerGain = &PanningLUT[OUTPUTCHANNELS * pos]; dirGain = aluSqrt( ( earlyPan[0] * earlyPan[0] ) + ( earlyPan[2] * earlyPan[2] ) ); ambientGain = ( 1.0 - dirGain ); for ( index = 0; index < OUTPUTCHANNELS; index++ ) { State->Early.PanGain[index] = dirGain * speakerGain[index] + ambientGain; } pos = aluCart2LUTpos( latePan[2], latePan[0] ); speakerGain = &PanningLUT[OUTPUTCHANNELS * pos]; dirGain = aluSqrt( ( latePan[0] * latePan[0] ) + ( latePan[2] * latePan[2] ) ); ambientGain = ( 1.0 - dirGain ); for ( index = 0; index < OUTPUTCHANNELS; index++ ) { State->Late.PanGain[index] = dirGain * speakerGain[index] + ambientGain; } }
// Update the early and late 3D panning gains. static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALverbState *State) { ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1], ReflectionsPan[2] }; ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1], LateReverbPan[2] }; const ALfloat *speakerGain; ALfloat ambientGain; ALfloat dirGain; ALfloat length; ALuint index; ALint pos; Gain *= ReverbBoost; // Attenuate non-directional reverb according to the number of channels ambientGain = aluSqrt(2.0f/Device->NumChan); // Calculate the 3D-panning gains for the early reflections and late // reverb. length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2]; if(length > 1.0f) { length = 1.0f / aluSqrt(length); earlyPan[0] *= length; earlyPan[1] *= length; earlyPan[2] *= length; } length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2]; if(length > 1.0f) { length = 1.0f / aluSqrt(length); latePan[0] *= length; latePan[1] *= length; latePan[2] *= length; } /* This code applies directional reverb just like the mixer applies * directional sources. It diffuses the sound toward all speakers as the * magnitude of the panning vector drops, which is only a rough * approximation of the expansion of sound across the speakers from the * panning direction. */ pos = aluCart2LUTpos(earlyPan[2], earlyPan[0]); speakerGain = Device->PanningLUT[pos]; dirGain = aluSqrt((earlyPan[0] * earlyPan[0]) + (earlyPan[2] * earlyPan[2])); for(index = 0;index < MAXCHANNELS;index++) State->Early.PanGain[index] = 0.0f; for(index = 0;index < Device->NumChan;index++) { enum Channel chan = Device->Speaker2Chan[index]; State->Early.PanGain[chan] = lerp(ambientGain, speakerGain[chan], dirGain) * Gain; } pos = aluCart2LUTpos(latePan[2], latePan[0]); speakerGain = Device->PanningLUT[pos]; dirGain = aluSqrt((latePan[0] * latePan[0]) + (latePan[2] * latePan[2])); for(index = 0;index < MAXCHANNELS;index++) State->Late.PanGain[index] = 0.0f; for(index = 0;index < Device->NumChan;index++) { enum Channel chan = Device->Speaker2Chan[index]; State->Late.PanGain[chan] = lerp(ambientGain, speakerGain[chan], dirGain) * Gain; } }
// This updates the EAX reverb state. This is called any time the EAX reverb // effect is loaded into a slot. static ALvoid ReverbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffectslot *Slot) { ALverbState *State = (ALverbState*)effect; ALuint frequency = Context->Device->Frequency; ALboolean isEAX = AL_FALSE; ALfloat cw, x, y, hfRatio; if(Slot->effect.type == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) { State->state.Process = EAXVerbProcess; isEAX = AL_TRUE; } else if(Slot->effect.type == AL_EFFECT_REVERB || EmulateEAXReverb) { State->state.Process = VerbProcess; isEAX = AL_FALSE; } // Calculate the master low-pass filter (from the master effect HF gain). cw = CalcI3DL2HFreq(Slot->effect.Params.Reverb.HFReference, frequency); // This is done with 2 chained 1-pole filters, so no need to square g. State->LpFilter.coeff = lpCoeffCalc(Slot->effect.Params.Reverb.GainHF, cw); if(isEAX) { // Update the modulator line. UpdateModulator(Slot->effect.Params.Reverb.ModulationTime, Slot->effect.Params.Reverb.ModulationDepth, frequency, State); } // Update the initial effect delay. UpdateDelayLine(Slot->effect.Params.Reverb.ReflectionsDelay, Slot->effect.Params.Reverb.LateReverbDelay, frequency, State); // Update the early lines. UpdateEarlyLines(Slot->effect.Params.Reverb.Gain, Slot->effect.Params.Reverb.ReflectionsGain, Slot->effect.Params.Reverb.LateReverbDelay, State); // Update the decorrelator. UpdateDecorrelator(Slot->effect.Params.Reverb.Density, frequency, State); // Get the mixing matrix coefficients (x and y). CalcMatrixCoeffs(Slot->effect.Params.Reverb.Diffusion, &x, &y); // Then divide x into y to simplify the matrix calculation. State->Late.MixCoeff = y / x; // If the HF limit parameter is flagged, calculate an appropriate limit // based on the air absorption parameter. hfRatio = Slot->effect.Params.Reverb.DecayHFRatio; if(Slot->effect.Params.Reverb.DecayHFLimit && Slot->effect.Params.Reverb.AirAbsorptionGainHF < 1.0f) hfRatio = CalcLimitedHfRatio(hfRatio, Slot->effect.Params.Reverb.AirAbsorptionGainHF, Slot->effect.Params.Reverb.DecayTime); // Update the late lines. UpdateLateLines(Slot->effect.Params.Reverb.Gain, Slot->effect.Params.Reverb.LateReverbGain, x, Slot->effect.Params.Reverb.Density, Slot->effect.Params.Reverb.DecayTime, Slot->effect.Params.Reverb.Diffusion, hfRatio, cw, frequency, State); if(isEAX) { // Update the echo line. UpdateEchoLine(Slot->effect.Params.Reverb.Gain, Slot->effect.Params.Reverb.LateReverbGain, Slot->effect.Params.Reverb.EchoTime, Slot->effect.Params.Reverb.DecayTime, Slot->effect.Params.Reverb.Diffusion, Slot->effect.Params.Reverb.EchoDepth, hfRatio, cw, frequency, State); // Update early and late 3D panning. Update3DPanning(Context->Device, Slot->effect.Params.Reverb.ReflectionsPan, Slot->effect.Params.Reverb.LateReverbPan, Slot->Gain, State); } else { ALCdevice *Device = Context->Device; ALfloat gain = Slot->Gain; ALuint index; /* Update channel gains */ gain *= aluSqrt(2.0f/Device->NumChan) * ReverbBoost; for(index = 0;index < MAXCHANNELS;index++) State->Gain[index] = 0.0f; for(index = 0;index < Device->NumChan;index++) { enum Channel chan = Device->Speaker2Chan[index]; State->Gain[chan] = gain; } } }
ALvoid aluInitPanning(ALCdevice *Device) { ALfloat SpeakerAngle[MAXCHANNELS]; ALfloat (*Matrix)[MAXCHANNELS]; Channel *Speaker2Chan; ALfloat Alpha, Theta; ALfloat *PanningLUT; ALint pos, offset; ALuint s, s2; for(s = 0;s < MAXCHANNELS;s++) { for(s2 = 0;s2 < MAXCHANNELS;s2++) Device->ChannelMatrix[s][s2] = ((s==s2) ? 1.0f : 0.0f); } Speaker2Chan = Device->Speaker2Chan; Matrix = Device->ChannelMatrix; switch(Device->FmtChans) { case DevFmtMono: Matrix[FRONT_LEFT][FRONT_CENTER] = aluSqrt(0.5); Matrix[FRONT_RIGHT][FRONT_CENTER] = aluSqrt(0.5); Matrix[SIDE_LEFT][FRONT_CENTER] = aluSqrt(0.5); Matrix[SIDE_RIGHT][FRONT_CENTER] = aluSqrt(0.5); Matrix[BACK_LEFT][FRONT_CENTER] = aluSqrt(0.5); Matrix[BACK_RIGHT][FRONT_CENTER] = aluSqrt(0.5); Matrix[BACK_CENTER][FRONT_CENTER] = 1.0f; Device->NumChan = 1; Speaker2Chan[0] = FRONT_CENTER; SpeakerAngle[0] = 0.0f * M_PI/180.0f; break; case DevFmtStereo: Matrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5); Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5); Matrix[SIDE_LEFT][FRONT_LEFT] = 1.0f; Matrix[SIDE_RIGHT][FRONT_RIGHT] = 1.0f; Matrix[BACK_LEFT][FRONT_LEFT] = 1.0f; Matrix[BACK_RIGHT][FRONT_RIGHT] = 1.0f; Matrix[BACK_CENTER][FRONT_LEFT] = aluSqrt(0.5); Matrix[BACK_CENTER][FRONT_RIGHT] = aluSqrt(0.5); Device->NumChan = 2; Speaker2Chan[0] = FRONT_LEFT; Speaker2Chan[1] = FRONT_RIGHT; SpeakerAngle[0] = -90.0f * M_PI/180.0f; SpeakerAngle[1] = 90.0f * M_PI/180.0f; SetSpeakerArrangement("layout_STEREO", SpeakerAngle, Speaker2Chan, Device->NumChan); break; case DevFmtQuad: Matrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5); Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5); Matrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5); Matrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5); Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5); Matrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5); Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5); Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5); Device->NumChan = 4; Speaker2Chan[0] = BACK_LEFT; Speaker2Chan[1] = FRONT_LEFT; Speaker2Chan[2] = FRONT_RIGHT; Speaker2Chan[3] = BACK_RIGHT; SpeakerAngle[0] = -135.0f * M_PI/180.0f; SpeakerAngle[1] = -45.0f * M_PI/180.0f; SpeakerAngle[2] = 45.0f * M_PI/180.0f; SpeakerAngle[3] = 135.0f * M_PI/180.0f; SetSpeakerArrangement("layout_QUAD", SpeakerAngle, Speaker2Chan, Device->NumChan); break; case DevFmtX51: Matrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5); Matrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5); Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5); Matrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5); Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5); Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5); Device->NumChan = 5; Speaker2Chan[0] = BACK_LEFT; Speaker2Chan[1] = FRONT_LEFT; Speaker2Chan[2] = FRONT_CENTER; Speaker2Chan[3] = FRONT_RIGHT; Speaker2Chan[4] = BACK_RIGHT; SpeakerAngle[0] = -110.0f * M_PI/180.0f; SpeakerAngle[1] = -30.0f * M_PI/180.0f; SpeakerAngle[2] = 0.0f * M_PI/180.0f; SpeakerAngle[3] = 30.0f * M_PI/180.0f; SpeakerAngle[4] = 110.0f * M_PI/180.0f; SetSpeakerArrangement("layout_51CHN", SpeakerAngle, Speaker2Chan, Device->NumChan); break; case DevFmtX61: Matrix[BACK_LEFT][BACK_CENTER] = aluSqrt(0.5); Matrix[BACK_LEFT][SIDE_LEFT] = aluSqrt(0.5); Matrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(0.5); Matrix[BACK_RIGHT][SIDE_RIGHT] = aluSqrt(0.5); Device->NumChan = 6; Speaker2Chan[0] = SIDE_LEFT; Speaker2Chan[1] = FRONT_LEFT; Speaker2Chan[2] = FRONT_CENTER; Speaker2Chan[3] = FRONT_RIGHT; Speaker2Chan[4] = SIDE_RIGHT; Speaker2Chan[5] = BACK_CENTER; SpeakerAngle[0] = -90.0f * M_PI/180.0f; SpeakerAngle[1] = -30.0f * M_PI/180.0f; SpeakerAngle[2] = 0.0f * M_PI/180.0f; SpeakerAngle[3] = 30.0f * M_PI/180.0f; SpeakerAngle[4] = 90.0f * M_PI/180.0f; SpeakerAngle[5] = 180.0f * M_PI/180.0f; SetSpeakerArrangement("layout_61CHN", SpeakerAngle, Speaker2Chan, Device->NumChan); break; case DevFmtX71: Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5); Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5); Device->NumChan = 7; Speaker2Chan[0] = BACK_LEFT; Speaker2Chan[1] = SIDE_LEFT; Speaker2Chan[2] = FRONT_LEFT; Speaker2Chan[3] = FRONT_CENTER; Speaker2Chan[4] = FRONT_RIGHT; Speaker2Chan[5] = SIDE_RIGHT; Speaker2Chan[6] = BACK_RIGHT; SpeakerAngle[0] = -150.0f * M_PI/180.0f; SpeakerAngle[1] = -90.0f * M_PI/180.0f; SpeakerAngle[2] = -30.0f * M_PI/180.0f; SpeakerAngle[3] = 0.0f * M_PI/180.0f; SpeakerAngle[4] = 30.0f * M_PI/180.0f; SpeakerAngle[5] = 90.0f * M_PI/180.0f; SpeakerAngle[6] = 150.0f * M_PI/180.0f; SetSpeakerArrangement("layout_71CHN", SpeakerAngle, Speaker2Chan, Device->NumChan); break; } if(GetConfigValueBool(NULL, "scalemix", 0)) { ALfloat maxout = 1.0f; for(s = 0;s < MAXCHANNELS;s++) { ALfloat out = 0.0f; for(s2 = 0;s2 < MAXCHANNELS;s2++) out += Device->ChannelMatrix[s2][s]; maxout = __max(maxout, out); } maxout = 1.0f/maxout; for(s = 0;s < MAXCHANNELS;s++) { for(s2 = 0;s2 < MAXCHANNELS;s2++) Device->ChannelMatrix[s2][s] *= maxout; } } PanningLUT = Device->PanningLUT; for(pos = 0; pos < LUT_NUM; pos++) { /* clear all values */ offset = MAXCHANNELS * pos; for(s = 0; s < MAXCHANNELS; s++) PanningLUT[offset+s] = 0.0f; if(Device->NumChan == 1) { PanningLUT[offset + Speaker2Chan[0]] = 1.0f; continue; } /* source angle */ Theta = aluLUTpos2Angle(pos); /* set panning values */ for(s = 0; s < Device->NumChan - 1; s++) { if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1]) { /* source between speaker s and speaker s+1 */ Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) / (SpeakerAngle[s+1]-SpeakerAngle[s]); PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha); PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha); break; } } if(s == Device->NumChan - 1) { /* source between last and first speaker */ if(Theta < SpeakerAngle[0]) Theta += 2.0f * M_PI; Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) / (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]); PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha); PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha); } } }