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;
}
// Update the echo gain, line offset, line coefficients, and mixing
// coefficients.
static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
{
    // Update the offset and coefficient for the echo delay line.
    State->Echo.Offset = (ALuint)(echoTime * frequency);

    // Calculate the decay coefficient for the echo line.
    State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime);

    // Calculate the energy-based attenuation coefficient for the echo delay
    // line.
    State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff);

    // Calculate the echo all-pass feed coefficient.
    State->Echo.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);

    // Calculate the echo all-pass attenuation coefficient.
    State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime);

    // Calculate the damping coefficient for each low-pass filter.
    State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime,
                                           State->Echo.Coeff, cw);

    /* Calculate the echo mixing coefficients.  The first is applied to the
     * echo itself.  The second is used to attenuate the late reverb when
     * echo depth is high and diffusion is low, so the echo is slightly
     * stronger than the decorrelated echos in the reverb tail.
     */
    State->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth;
    State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion));
}
Exemple #3
0
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;
    }
}
// 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 ReverbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
{
    ALverbState *State = (ALverbState*)effect;
    ALuint frequency = Device->Frequency, index;

    // Allocate the delay lines.
    if(!AllocLines(frequency, State))
        return AL_FALSE;

    // 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;
}
// Update the late reverb gains, line lengths, and line coefficients.
static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
{
    ALfloat length;
    ALuint 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 * aluPow(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] = (ALuint)(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;
    }
}
// Update the offsets for the decorrelator line.
static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState *State)
{
    ALuint index;
    ALfloat 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 * aluPow(DECO_MULTIPLIER, (ALfloat)index)) *
                 LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER));
        State->DecoTap[index] = (ALuint)(length * frequency);
    }
}
// Calculate a decay coefficient given the length of each cycle and the time
// until the decay reaches -60 dB.
static __inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime)
{
    return aluPow(0.001f/*-60 dB*/, length/decayTime);
}
// Calculate a decay coefficient given the length of each cycle and the time
// until the decay reaches -60 dB.
static __inline ALfloat CalcDecayCoeff( ALfloat length, ALfloat decayTime )
{
	return aluPow( 10.0f, length / decayTime * -60.0f / 20.0f );
}