static ALvoid EchoUpdate(ALeffectState *effect, ALCdevice *Device, const ALeffectslot *Slot) { ALechoState *state = (ALechoState*)effect; ALuint frequency = Device->Frequency; ALfloat lrpan, cw, g, gain; ALfloat dirGain; ALuint i; state->Tap[0].delay = fastf2u(Slot->effect.Echo.Delay * frequency) + 1; state->Tap[1].delay = fastf2u(Slot->effect.Echo.LRDelay * frequency); state->Tap[1].delay += state->Tap[0].delay; lrpan = Slot->effect.Echo.Spread; state->FeedGain = Slot->effect.Echo.Feedback; cw = aluCos(F_PI*2.0f * LOWPASSFREQREF / 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[0][i] = 0.0f; state->Gain[1][i] = 0.0f; } dirGain = aluFabs(lrpan); /* First tap panning */ ComputeAngleGains(Device, aluAtan2(-lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[0]); /* Second tap panning */ ComputeAngleGains(Device, aluAtan2(+lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[1]); }
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 = fastf2u(AL_ECHO_MAX_DELAY * Device->Frequency) + 1; maxlen += fastf2u(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; return AL_TRUE; }
/* Calculate the azimuth indices given the polar azimuth in radians. This * will return two indices between 0 and (Hrtf->azCount[ei] - 1) and an * interpolation factor between 0.0 and 1.0. */ static void CalcAzIndices(const struct Hrtf *Hrtf, ALuint evidx, ALfloat az, ALuint *azidx, ALfloat *azmu) { az = (F_PI*2.0f + az) * Hrtf->azCount[evidx] / (F_PI*2.0f); azidx[0] = fastf2u(az) % Hrtf->azCount[evidx]; azidx[1] = (azidx[0] + 1) % Hrtf->azCount[evidx]; *azmu = az - floorf(az); }
// Calculate the azimuth indices given the polar azimuth in radians. This // will return two indices between 0 and (azCount [ei] - 1) and an // interpolation factor between 0.0 and 1.0. static void CalcAzIndices(ALuint evidx, ALfloat az, ALuint *azidx, ALfloat *azmu) { az = (F_PI*2.0f + az) * azCount[evidx] / (F_PI*2.0f); azidx[0] = fastf2u(az) % azCount[evidx]; azidx[1] = (azidx[0] + 1) % azCount[evidx]; *azmu = az - aluFloor(az); }
static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device, const ALeffectslot *Slot) { ALfloat cw, a; if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) state->Waveform = SINUSOID; else if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) state->Waveform = SAWTOOTH; else if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE) state->Waveform = SQUARE; state->step = fastf2u(Slot->EffectProps.Modulator.Frequency*WAVEFORM_FRACONE / Device->Frequency); if(state->step == 0) state->step = 1; /* Custom filter coeffs, which match the old version instead of a low-shelf. */ cw = cosf(F_TAU * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency); a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); state->Filter.b[0] = a; state->Filter.b[1] = -a; state->Filter.b[2] = 0.0f; state->Filter.a[0] = 1.0f; state->Filter.a[1] = -a; state->Filter.a[2] = 0.0f; ComputeAmbientGains(Device, Slot->Gain, state->Gain); }
// Calculate the elevation indices given the polar elevation in radians. // This will return two indices between 0 and (ELEV_COUNT-1) and an // interpolation factor between 0.0 and 1.0. static void CalcEvIndices(ALfloat ev, ALuint *evidx, ALfloat *evmu) { ev = (F_PI_2 + ev) * (ELEV_COUNT-1) / F_PI; evidx[0] = fastf2u(ev); evidx[1] = minu(evidx[0] + 1, ELEV_COUNT-1); *evmu = ev - evidx[0]; }
static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device) { ALuint maxlen; ALuint it; maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 3.0f * Device->Frequency) + 1; maxlen = NextPowerOf2(maxlen); if(maxlen != state->BufferLength) { void *temp; temp = realloc(state->SampleBuffer[0], maxlen * sizeof(ALfloat) * 2); if(!temp) return AL_FALSE; state->SampleBuffer[0] = temp; state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen; state->BufferLength = maxlen; } for(it = 0;it < state->BufferLength;it++) { state->SampleBuffer[0][it] = 0.0f; state->SampleBuffer[1][it] = 0.0f; } return AL_TRUE; }
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 = cosf(F_PI*2.0f * Slot->effect.Modulator.HighPassCutoff / Device->Frequency); a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); state->iirFilter.coeff = a; gain = sqrtf(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; } }
// Given an input sample, this function produces modulation for the late // reverb. static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in) { ALfloat sinus, frac; ALuint offset; ALfloat out0, out1; // Calculate the sinus rythm (dependent on modulation time and the // sampling rate). The center of the sinus is moved to reduce the delay // of the effect when the time or depth are low. sinus = 1.0f - cosf(F_PI*2.0f * State->Mod.Index / State->Mod.Range); // The depth determines the range over which to read the input samples // from, so it must be filtered to reduce the distortion caused by even // small parameter changes. State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth, State->Mod.Coeff); // Calculate the read offset and fraction between it and the next sample. frac = (1.0f + (State->Mod.Filter * sinus)); offset = fastf2u(frac); frac -= offset; // Get the two samples crossed by the offset, and feed the delay line // with the next input sample. out0 = DelayLineOut(&State->Mod.Delay, State->Offset - offset); out1 = DelayLineOut(&State->Mod.Delay, State->Offset - offset - 1); DelayLineIn(&State->Mod.Delay, State->Offset, in); // Step the modulation index forward, keeping it bound to its range. State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range; // The output is obtained by linearly interpolating the two samples that // were acquired above. return lerp(out0, out1, frac); }
/* Calculate the elevation indices given the polar elevation in radians. * This will return two indices between 0 and (Hrtf->evCount - 1) and an * interpolation factor between 0.0 and 1.0. */ static void CalcEvIndices(const struct Hrtf *Hrtf, ALfloat ev, ALuint *evidx, ALfloat *evmu) { ev = (F_PI_2 + ev) * (Hrtf->evCount-1) / F_PI; evidx[0] = fastf2u(ev); evidx[1] = minu(evidx[0] + 1, Hrtf->evCount-1); *evmu = ev - evidx[0]; }
static void UpdateLateLines(float reverbGain, float lateGain, float xMix, float density, float decayTime, float diffusion, float hfRatio, float cw, unsigned int frequency, eax_buffer_info *State) { float length; unsigned int index; /* Calculate the late reverb gain (from the master effect gain, and late * reverb gain parameters). Since the output is tapped prior to the * application of the next delay line coefficients, this gain needs to be * attenuated by the 'x' mixing matrix coefficient as well. */ State->Late.Gain = reverbGain * lateGain * xMix; /* To compensate for changes in modal density and decay time of the late * reverb signal, the input is attenuated based on the maximal energy of * the outgoing signal. This approximation is used to keep the apparent * energy of the signal equal for all ranges of density and decay time. * * The average length of the cyclcical delay lines is used to calculate * the attenuation coefficient. */ length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] + LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f; length *= 1.0f + (density * LATE_LINE_MULTIPLIER); State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length, decayTime)); /* Calculate the all-pass feed-back and feed-forward coefficient. */ State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); for(index = 0; index < 4; index++) { /* Calculate the gain (coefficient) for each all-pass line. */ State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index], decayTime); /* Calculate the length (in seconds) of each cyclical delay line. */ length = LATE_LINE_LENGTH[index] * (1.0f + (density * LATE_LINE_MULTIPLIER)); /* Calculate the delay offset for each cyclical delay line. */ State->Late.Offset[index] = fastf2u(length * frequency); /* Calculate the gain (coefficient) for each cyclical line. */ State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime); /* Calculate the damping coefficient for each low-pass filter. */ State->Late.LpCoeff[index] = CalcDampingCoeff(hfRatio, length, decayTime, State->Late.Coeff[index], cw); /* Attenuate the cyclical line coefficients by the mixing coefficient * (x). */ State->Late.Coeff[index] *= xMix; } }
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 ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) { aluMatrixf matrix; ALfloat cw, a; ALuint i; if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) state->Process = ModulateSin; else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) state->Process = ModulateSaw; else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ state->Process = ModulateSquare; state->step = fastf2u(props->Modulator.Frequency*WAVEFORM_FRACONE / Device->Frequency); if(state->step == 0) state->step = 1; /* Custom filter coeffs, which match the old version instead of a low-shelf. */ cw = cosf(F_TAU * props->Modulator.HighPassCutoff / Device->Frequency); a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) { state->Filter[i].a1 = -a; state->Filter[i].a2 = 0.0f; state->Filter[i].b1 = -a; state->Filter[i].b2 = 0.0f; state->Filter[i].input_gain = a; state->Filter[i].process = ALfilterState_processC; } aluMatrixfSet(&matrix, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = Device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputeFirstOrderGains(Device->FOAOut, matrix.m[i], Slot->Params.Gain, state->Gain[i]); }
static void UpdateDecorrelator(float density, unsigned int frequency, eax_buffer_info *State) { unsigned int index; float length; /* The late reverb inputs are decorrelated to smooth the reverb tail and * reduce harsh echos. The first tap occurs immediately, while the * remaining taps are delayed by multiples of a fraction of the smallest * cyclical delay time. * * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay */ for (index = 0; index < 3; index++) { length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (float)index)) * LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); State->DecoTap[index] = fastf2u(length * frequency); } }
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 static HRIR coefficients and delays 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. void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays) { ALuint evidx[2], azidx[2]; ALfloat mu[3]; ALuint lidx[4], ridx[4]; 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 normalized and attenuated HRIR coefficients using linear // interpolation when there is enough gain to warrant it. Zero the // coefficients if gain is too low. if(gain > 0.0001f) { gain *= 1.0f/32767.0f; for(i = 0;i < HRIR_LENGTH;i++) { 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; } } else { for(i = 0;i < HRIR_LENGTH;i++) { coeffs[i][0] = 0.0f; coeffs[i][1] = 0.0f; } } // Calculate the HRIR delays using linear interpolation. 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); }
/* 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); }
/* Calculates static HRIR coefficients and delays 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. */ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays) { ALuint evidx[2], azidx[2]; ALuint lidx[4], ridx[4]; ALfloat mu[3], blend[4]; 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 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. */ 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; /* 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 HRIR coefficients using linear * interpolation when there is enough gain to warrant it. Zero the * coefficients if gain is too low. */ if(gain > 0.0001f) { gain *= 1.0f/32767.0f; for(i = 0;i < Hrtf->irSize;i++) { 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; } } else { for(i = 0;i < Hrtf->irSize;i++) { coeffs[i][0] = 0.0f; coeffs[i][1] = 0.0f; } } }
static void UpdateDelayLine(float earlyDelay, float lateDelay, unsigned int frequency, eax_buffer_info *State) { State->DelayTap[0] = fastf2u(earlyDelay * frequency); State->DelayTap[1] = fastf2u((earlyDelay + lateDelay) * frequency); }
// 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); }