diff Alc/alcReverb.c @ 0:f9476ff7637e

initial forking of open-al to create multiple listeners
author Robert McIntyre <rlm@mit.edu>
date Tue, 25 Oct 2011 13:02:31 -0700
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Alc/alcReverb.c	Tue Oct 25 13:02:31 2011 -0700
     1.3 @@ -0,0 +1,1374 @@
     1.4 +/**
     1.5 + * Reverb for the OpenAL cross platform audio library
     1.6 + * Copyright (C) 2008-2009 by Christopher Fitzgerald.
     1.7 + * This library is free software; you can redistribute it and/or
     1.8 + *  modify it under the terms of the GNU Library General Public
     1.9 + *  License as published by the Free Software Foundation; either
    1.10 + *  version 2 of the License, or (at your option) any later version.
    1.11 + *
    1.12 + * This library is distributed in the hope that it will be useful,
    1.13 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.15 + *  Library General Public License for more details.
    1.16 + *
    1.17 + * You should have received a copy of the GNU Library General Public
    1.18 + *  License along with this library; if not, write to the
    1.19 + *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1.20 + *  Boston, MA  02111-1307, USA.
    1.21 + * Or go to http://www.gnu.org/copyleft/lgpl.html
    1.22 + */
    1.23 +
    1.24 +#include "config.h"
    1.25 +
    1.26 +#include <stdio.h>
    1.27 +#include <stdlib.h>
    1.28 +#include <math.h>
    1.29 +
    1.30 +#include "AL/al.h"
    1.31 +#include "AL/alc.h"
    1.32 +#include "alMain.h"
    1.33 +#include "alAuxEffectSlot.h"
    1.34 +#include "alEffect.h"
    1.35 +#include "alError.h"
    1.36 +#include "alu.h"
    1.37 +
    1.38 +typedef struct DelayLine
    1.39 +{
    1.40 +    // The delay lines use sample lengths that are powers of 2 to allow the
    1.41 +    // use of bit-masking instead of a modulus for wrapping.
    1.42 +    ALuint   Mask;
    1.43 +    ALfloat *Line;
    1.44 +} DelayLine;
    1.45 +
    1.46 +typedef struct ALverbState {
    1.47 +    // Must be first in all effects!
    1.48 +    ALeffectState state;
    1.49 +
    1.50 +    // All delay lines are allocated as a single buffer to reduce memory
    1.51 +    // fragmentation and management code.
    1.52 +    ALfloat  *SampleBuffer;
    1.53 +    ALuint    TotalSamples;
    1.54 +    // Master effect low-pass filter (2 chained 1-pole filters).
    1.55 +    FILTER    LpFilter;
    1.56 +    ALfloat   LpHistory[2];
    1.57 +    struct {
    1.58 +        // Modulator delay line.
    1.59 +        DelayLine Delay;
    1.60 +        // The vibrato time is tracked with an index over a modulus-wrapped
    1.61 +        // range (in samples).
    1.62 +        ALuint    Index;
    1.63 +        ALuint    Range;
    1.64 +        // The depth of frequency change (also in samples) and its filter.
    1.65 +        ALfloat   Depth;
    1.66 +        ALfloat   Coeff;
    1.67 +        ALfloat   Filter;
    1.68 +    } Mod;
    1.69 +    // Initial effect delay.
    1.70 +    DelayLine Delay;
    1.71 +    // The tap points for the initial delay.  First tap goes to early
    1.72 +    // reflections, the last to late reverb.
    1.73 +    ALuint    DelayTap[2];
    1.74 +    struct {
    1.75 +        // Output gain for early reflections.
    1.76 +        ALfloat   Gain;
    1.77 +        // Early reflections are done with 4 delay lines.
    1.78 +        ALfloat   Coeff[4];
    1.79 +        DelayLine Delay[4];
    1.80 +        ALuint    Offset[4];
    1.81 +        // The gain for each output channel based on 3D panning (only for the
    1.82 +        // EAX path).
    1.83 +        ALfloat   PanGain[MAXCHANNELS];
    1.84 +    } Early;
    1.85 +    // Decorrelator delay line.
    1.86 +    DelayLine Decorrelator;
    1.87 +    // There are actually 4 decorrelator taps, but the first occurs at the
    1.88 +    // initial sample.
    1.89 +    ALuint    DecoTap[3];
    1.90 +    struct {
    1.91 +        // Output gain for late reverb.
    1.92 +        ALfloat   Gain;
    1.93 +        // Attenuation to compensate for the modal density and decay rate of
    1.94 +        // the late lines.
    1.95 +        ALfloat   DensityGain;
    1.96 +        // The feed-back and feed-forward all-pass coefficient.
    1.97 +        ALfloat   ApFeedCoeff;
    1.98 +        // Mixing matrix coefficient.
    1.99 +        ALfloat   MixCoeff;
   1.100 +        // Late reverb has 4 parallel all-pass filters.
   1.101 +        ALfloat   ApCoeff[4];
   1.102 +        DelayLine ApDelay[4];
   1.103 +        ALuint    ApOffset[4];
   1.104 +        // In addition to 4 cyclical delay lines.
   1.105 +        ALfloat   Coeff[4];
   1.106 +        DelayLine Delay[4];
   1.107 +        ALuint    Offset[4];
   1.108 +        // The cyclical delay lines are 1-pole low-pass filtered.
   1.109 +        ALfloat   LpCoeff[4];
   1.110 +        ALfloat   LpSample[4];
   1.111 +        // The gain for each output channel based on 3D panning (only for the
   1.112 +        // EAX path).
   1.113 +        ALfloat   PanGain[MAXCHANNELS];
   1.114 +    } Late;
   1.115 +    struct {
   1.116 +        // Attenuation to compensate for the modal density and decay rate of
   1.117 +        // the echo line.
   1.118 +        ALfloat   DensityGain;
   1.119 +        // Echo delay and all-pass lines.
   1.120 +        DelayLine Delay;
   1.121 +        DelayLine ApDelay;
   1.122 +        ALfloat   Coeff;
   1.123 +        ALfloat   ApFeedCoeff;
   1.124 +        ALfloat   ApCoeff;
   1.125 +        ALuint    Offset;
   1.126 +        ALuint    ApOffset;
   1.127 +        // The echo line is 1-pole low-pass filtered.
   1.128 +        ALfloat   LpCoeff;
   1.129 +        ALfloat   LpSample;
   1.130 +        // Echo mixing coefficients.
   1.131 +        ALfloat   MixCoeff[2];
   1.132 +    } Echo;
   1.133 +    // The current read offset for all delay lines.
   1.134 +    ALuint Offset;
   1.135 +
   1.136 +    // The gain for each output channel (non-EAX path only; aliased from
   1.137 +    // Late.PanGain)
   1.138 +    ALfloat *Gain;
   1.139 +} ALverbState;
   1.140 +
   1.141 +/* This is a user config option for modifying the overall output of the reverb
   1.142 + * effect.
   1.143 + */
   1.144 +ALfloat ReverbBoost = 1.0f;
   1.145 +
   1.146 +/* Specifies whether to use a standard reverb effect in place of EAX reverb */
   1.147 +ALboolean EmulateEAXReverb = AL_FALSE;
   1.148 +
   1.149 +/* This coefficient is used to define the maximum frequency range controlled
   1.150 + * by the modulation depth.  The current value of 0.1 will allow it to swing
   1.151 + * from 0.9x to 1.1x.  This value must be below 1.  At 1 it will cause the
   1.152 + * sampler to stall on the downswing, and above 1 it will cause it to sample
   1.153 + * backwards.
   1.154 + */
   1.155 +static const ALfloat MODULATION_DEPTH_COEFF = 0.1f;
   1.156 +
   1.157 +/* A filter is used to avoid the terrible distortion caused by changing
   1.158 + * modulation time and/or depth.  To be consistent across different sample
   1.159 + * rates, the coefficient must be raised to a constant divided by the sample
   1.160 + * rate:  coeff^(constant / rate).
   1.161 + */
   1.162 +static const ALfloat MODULATION_FILTER_COEFF = 0.048f;
   1.163 +static const ALfloat MODULATION_FILTER_CONST = 100000.0f;
   1.164 +
   1.165 +// When diffusion is above 0, an all-pass filter is used to take the edge off
   1.166 +// the echo effect.  It uses the following line length (in seconds).
   1.167 +static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f;
   1.168 +
   1.169 +// Input into the late reverb is decorrelated between four channels.  Their
   1.170 +// timings are dependent on a fraction and multiplier.  See the
   1.171 +// UpdateDecorrelator() routine for the calculations involved.
   1.172 +static const ALfloat DECO_FRACTION = 0.15f;
   1.173 +static const ALfloat DECO_MULTIPLIER = 2.0f;
   1.174 +
   1.175 +// All delay line lengths are specified in seconds.
   1.176 +
   1.177 +// The lengths of the early delay lines.
   1.178 +static const ALfloat EARLY_LINE_LENGTH[4] =
   1.179 +{
   1.180 +    0.0015f, 0.0045f, 0.0135f, 0.0405f
   1.181 +};
   1.182 +
   1.183 +// The lengths of the late all-pass delay lines.
   1.184 +static const ALfloat ALLPASS_LINE_LENGTH[4] =
   1.185 +{
   1.186 +    0.0151f, 0.0167f, 0.0183f, 0.0200f,
   1.187 +};
   1.188 +
   1.189 +// The lengths of the late cyclical delay lines.
   1.190 +static const ALfloat LATE_LINE_LENGTH[4] =
   1.191 +{
   1.192 +    0.0211f, 0.0311f, 0.0461f, 0.0680f
   1.193 +};
   1.194 +
   1.195 +// The late cyclical delay lines have a variable length dependent on the
   1.196 +// effect's density parameter (inverted for some reason) and this multiplier.
   1.197 +static const ALfloat LATE_LINE_MULTIPLIER = 4.0f;
   1.198 +
   1.199 +// Calculate the length of a delay line and store its mask and offset.
   1.200 +static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequency, DelayLine *Delay)
   1.201 +{
   1.202 +    ALuint samples;
   1.203 +
   1.204 +    // All line lengths are powers of 2, calculated from their lengths, with
   1.205 +    // an additional sample in case of rounding errors.
   1.206 +    samples = NextPowerOf2((ALuint)(length * frequency) + 1);
   1.207 +    // All lines share a single sample buffer.
   1.208 +    Delay->Mask = samples - 1;
   1.209 +    Delay->Line = (ALfloat*)offset;
   1.210 +    // Return the sample count for accumulation.
   1.211 +    return samples;
   1.212 +}
   1.213 +
   1.214 +// Given the allocated sample buffer, this function updates each delay line
   1.215 +// offset.
   1.216 +static __inline ALvoid RealizeLineOffset(ALfloat * sampleBuffer, DelayLine *Delay)
   1.217 +{
   1.218 +    Delay->Line = &sampleBuffer[(ALintptrEXT)Delay->Line];
   1.219 +}
   1.220 +
   1.221 +/* Calculates the delay line metrics and allocates the shared sample buffer
   1.222 + * for all lines given a flag indicating whether or not to allocate the EAX-
   1.223 + * related delays (eaxFlag) and the sample rate (frequency).  If an
   1.224 + * allocation failure occurs, it returns AL_FALSE.
   1.225 + */
   1.226 +static ALboolean AllocLines(ALboolean eaxFlag, ALuint frequency, ALverbState *State)
   1.227 +{
   1.228 +    ALuint totalSamples, index;
   1.229 +    ALfloat length;
   1.230 +    ALfloat *newBuffer = NULL;
   1.231 +
   1.232 +    // All delay line lengths are calculated to accomodate the full range of
   1.233 +    // lengths given their respective paramters.
   1.234 +    totalSamples = 0;
   1.235 +    if(eaxFlag)
   1.236 +    {
   1.237 +        /* The modulator's line length is calculated from the maximum
   1.238 +         * modulation time and depth coefficient, and halfed for the low-to-
   1.239 +         * high frequency swing.  An additional sample is added to keep it
   1.240 +         * stable when there is no modulation.
   1.241 +         */
   1.242 +        length = (AL_EAXREVERB_MAX_MODULATION_TIME * MODULATION_DEPTH_COEFF /
   1.243 +                  2.0f) + (1.0f / frequency);
   1.244 +        totalSamples += CalcLineLength(length, totalSamples, frequency,
   1.245 +                                       &State->Mod.Delay);
   1.246 +    }
   1.247 +
   1.248 +    // The initial delay is the sum of the reflections and late reverb
   1.249 +    // delays.
   1.250 +    if(eaxFlag)
   1.251 +        length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
   1.252 +                 AL_EAXREVERB_MAX_LATE_REVERB_DELAY;
   1.253 +    else
   1.254 +        length = AL_REVERB_MAX_REFLECTIONS_DELAY +
   1.255 +                 AL_REVERB_MAX_LATE_REVERB_DELAY;
   1.256 +    totalSamples += CalcLineLength(length, totalSamples, frequency,
   1.257 +                                   &State->Delay);
   1.258 +
   1.259 +    // The early reflection lines.
   1.260 +    for(index = 0;index < 4;index++)
   1.261 +        totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples,
   1.262 +                                       frequency, &State->Early.Delay[index]);
   1.263 +
   1.264 +    // The decorrelator line is calculated from the lowest reverb density (a
   1.265 +    // parameter value of 1).
   1.266 +    length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) *
   1.267 +             LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER);
   1.268 +    totalSamples += CalcLineLength(length, totalSamples, frequency,
   1.269 +                                   &State->Decorrelator);
   1.270 +
   1.271 +    // The late all-pass lines.
   1.272 +    for(index = 0;index < 4;index++)
   1.273 +        totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples,
   1.274 +                                       frequency, &State->Late.ApDelay[index]);
   1.275 +
   1.276 +    // The late delay lines are calculated from the lowest reverb density.
   1.277 +    for(index = 0;index < 4;index++)
   1.278 +    {
   1.279 +        length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER);
   1.280 +        totalSamples += CalcLineLength(length, totalSamples, frequency,
   1.281 +                                       &State->Late.Delay[index]);
   1.282 +    }
   1.283 +
   1.284 +    if(eaxFlag)
   1.285 +    {
   1.286 +        // The echo all-pass and delay lines.
   1.287 +        totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples,
   1.288 +                                       frequency, &State->Echo.ApDelay);
   1.289 +        totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples,
   1.290 +                                       frequency, &State->Echo.Delay);
   1.291 +    }
   1.292 +
   1.293 +    if(totalSamples != State->TotalSamples)
   1.294 +    {
   1.295 +        newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples);
   1.296 +        if(newBuffer == NULL)
   1.297 +            return AL_FALSE;
   1.298 +        State->SampleBuffer = newBuffer;
   1.299 +        State->TotalSamples = totalSamples;
   1.300 +    }
   1.301 +
   1.302 +    // Update all delays to reflect the new sample buffer.
   1.303 +    RealizeLineOffset(State->SampleBuffer, &State->Delay);
   1.304 +    RealizeLineOffset(State->SampleBuffer, &State->Decorrelator);
   1.305 +    for(index = 0;index < 4;index++)
   1.306 +    {
   1.307 +        RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]);
   1.308 +        RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]);
   1.309 +        RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]);
   1.310 +    }
   1.311 +    if(eaxFlag)
   1.312 +    {
   1.313 +        RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay);
   1.314 +        RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay);
   1.315 +        RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay);
   1.316 +    }
   1.317 +
   1.318 +    // Clear the sample buffer.
   1.319 +    for(index = 0;index < State->TotalSamples;index++)
   1.320 +        State->SampleBuffer[index] = 0.0f;
   1.321 +
   1.322 +    return AL_TRUE;
   1.323 +}
   1.324 +
   1.325 +// Calculate a decay coefficient given the length of each cycle and the time
   1.326 +// until the decay reaches -60 dB.
   1.327 +static __inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime)
   1.328 +{
   1.329 +    return aluPow(0.001f/*-60 dB*/, length/decayTime);
   1.330 +}
   1.331 +
   1.332 +// Calculate a decay length from a coefficient and the time until the decay
   1.333 +// reaches -60 dB.
   1.334 +static __inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime)
   1.335 +{
   1.336 +    return log10(coeff) * decayTime / -3.0f/*log10(0.001)*/;
   1.337 +}
   1.338 +
   1.339 +// Calculate the high frequency parameter for the I3DL2 coefficient
   1.340 +// calculation.
   1.341 +static __inline ALfloat CalcI3DL2HFreq(ALfloat hfRef, ALuint frequency)
   1.342 +{
   1.343 +    return cos(2.0f * M_PI * hfRef / frequency);
   1.344 +}
   1.345 +
   1.346 +// Calculate an attenuation to be applied to the input of any echo models to
   1.347 +// compensate for modal density and decay time.
   1.348 +static __inline ALfloat CalcDensityGain(ALfloat a)
   1.349 +{
   1.350 +    /* The energy of a signal can be obtained by finding the area under the
   1.351 +     * squared signal.  This takes the form of Sum(x_n^2), where x is the
   1.352 +     * amplitude for the sample n.
   1.353 +     *
   1.354 +     * Decaying feedback matches exponential decay of the form Sum(a^n),
   1.355 +     * where a is the attenuation coefficient, and n is the sample.  The area
   1.356 +     * under this decay curve can be calculated as:  1 / (1 - a).
   1.357 +     *
   1.358 +     * Modifying the above equation to find the squared area under the curve
   1.359 +     * (for energy) yields:  1 / (1 - a^2).  Input attenuation can then be
   1.360 +     * calculated by inverting the square root of this approximation,
   1.361 +     * yielding:  1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2).
   1.362 +     */
   1.363 +    return aluSqrt(1.0f - (a * a));
   1.364 +}
   1.365 +
   1.366 +// Calculate the mixing matrix coefficients given a diffusion factor.
   1.367 +static __inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y)
   1.368 +{
   1.369 +    ALfloat n, t;
   1.370 +
   1.371 +    // The matrix is of order 4, so n is sqrt (4 - 1).
   1.372 +    n = aluSqrt(3.0f);
   1.373 +    t = diffusion * atan(n);
   1.374 +
   1.375 +    // Calculate the first mixing matrix coefficient.
   1.376 +    *x = cos(t);
   1.377 +    // Calculate the second mixing matrix coefficient.
   1.378 +    *y = sin(t) / n;
   1.379 +}
   1.380 +
   1.381 +// Calculate the limited HF ratio for use with the late reverb low-pass
   1.382 +// filters.
   1.383 +static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime)
   1.384 +{
   1.385 +    ALfloat limitRatio;
   1.386 +
   1.387 +    /* Find the attenuation due to air absorption in dB (converting delay
   1.388 +     * time to meters using the speed of sound).  Then reversing the decay
   1.389 +     * equation, solve for HF ratio.  The delay length is cancelled out of
   1.390 +     * the equation, so it can be calculated once for all lines.
   1.391 +     */
   1.392 +    limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) *
   1.393 +                         SPEEDOFSOUNDMETRESPERSEC);
   1.394 +    /* Using the limit calculated above, apply the upper bound to the HF
   1.395 +     * ratio. Also need to limit the result to a minimum of 0.1, just like the
   1.396 +     * HF ratio parameter. */
   1.397 +    return clampf(limitRatio, 0.1f, hfRatio);
   1.398 +}
   1.399 +
   1.400 +// Calculate the coefficient for a HF (and eventually LF) decay damping
   1.401 +// filter.
   1.402 +static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw)
   1.403 +{
   1.404 +    ALfloat coeff, g;
   1.405 +
   1.406 +    // Eventually this should boost the high frequencies when the ratio
   1.407 +    // exceeds 1.
   1.408 +    coeff = 0.0f;
   1.409 +    if (hfRatio < 1.0f)
   1.410 +    {
   1.411 +        // Calculate the low-pass coefficient by dividing the HF decay
   1.412 +        // coefficient by the full decay coefficient.
   1.413 +        g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff;
   1.414 +
   1.415 +        // Damping is done with a 1-pole filter, so g needs to be squared.
   1.416 +        g *= g;
   1.417 +        coeff = lpCoeffCalc(g, cw);
   1.418 +
   1.419 +        // Very low decay times will produce minimal output, so apply an
   1.420 +        // upper bound to the coefficient.
   1.421 +        coeff = minf(coeff, 0.98f);
   1.422 +    }
   1.423 +    return coeff;
   1.424 +}
   1.425 +
   1.426 +// Update the EAX modulation index, range, and depth.  Keep in mind that this
   1.427 +// kind of vibrato is additive and not multiplicative as one may expect.  The
   1.428 +// downswing will sound stronger than the upswing.
   1.429 +static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALverbState *State)
   1.430 +{
   1.431 +    ALfloat length;
   1.432 +
   1.433 +    /* Modulation is calculated in two parts.
   1.434 +     *
   1.435 +     * The modulation time effects the sinus applied to the change in
   1.436 +     * frequency.  An index out of the current time range (both in samples)
   1.437 +     * is incremented each sample.  The range is bound to a reasonable
   1.438 +     * minimum (1 sample) and when the timing changes, the index is rescaled
   1.439 +     * to the new range (to keep the sinus consistent).
   1.440 +     */
   1.441 +    length = modTime * frequency;
   1.442 +    if (length >= 1.0f) {
   1.443 +       State->Mod.Index = (ALuint)(State->Mod.Index * length /
   1.444 +                                   State->Mod.Range);
   1.445 +       State->Mod.Range = (ALuint)length;
   1.446 +    } else {
   1.447 +       State->Mod.Index = 0;
   1.448 +       State->Mod.Range = 1;
   1.449 +    }
   1.450 +
   1.451 +    /* The modulation depth effects the amount of frequency change over the
   1.452 +     * range of the sinus.  It needs to be scaled by the modulation time so
   1.453 +     * that a given depth produces a consistent change in frequency over all
   1.454 +     * ranges of time.  Since the depth is applied to a sinus value, it needs
   1.455 +     * to be halfed once for the sinus range and again for the sinus swing
   1.456 +     * in time (half of it is spent decreasing the frequency, half is spent
   1.457 +     * increasing it).
   1.458 +     */
   1.459 +    State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f /
   1.460 +                       2.0f * frequency;
   1.461 +}
   1.462 +
   1.463 +// Update the offsets for the initial effect delay line.
   1.464 +static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALverbState *State)
   1.465 +{
   1.466 +    // Calculate the initial delay taps.
   1.467 +    State->DelayTap[0] = (ALuint)(earlyDelay * frequency);
   1.468 +    State->DelayTap[1] = (ALuint)((earlyDelay + lateDelay) * frequency);
   1.469 +}
   1.470 +
   1.471 +// Update the early reflections gain and line coefficients.
   1.472 +static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALverbState *State)
   1.473 +{
   1.474 +    ALuint index;
   1.475 +
   1.476 +    // Calculate the early reflections gain (from the master effect gain, and
   1.477 +    // reflections gain parameters) with a constant attenuation of 0.5.
   1.478 +    State->Early.Gain = 0.5f * reverbGain * earlyGain;
   1.479 +
   1.480 +    // Calculate the gain (coefficient) for each early delay line using the
   1.481 +    // late delay time.  This expands the early reflections to the start of
   1.482 +    // the late reverb.
   1.483 +    for(index = 0;index < 4;index++)
   1.484 +        State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index],
   1.485 +                                                   lateDelay);
   1.486 +}
   1.487 +
   1.488 +// Update the offsets for the decorrelator line.
   1.489 +static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState *State)
   1.490 +{
   1.491 +    ALuint index;
   1.492 +    ALfloat length;
   1.493 +
   1.494 +    /* The late reverb inputs are decorrelated to smooth the reverb tail and
   1.495 +     * reduce harsh echos.  The first tap occurs immediately, while the
   1.496 +     * remaining taps are delayed by multiples of a fraction of the smallest
   1.497 +     * cyclical delay time.
   1.498 +     *
   1.499 +     * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay
   1.500 +     */
   1.501 +    for(index = 0;index < 3;index++)
   1.502 +    {
   1.503 +        length = (DECO_FRACTION * aluPow(DECO_MULTIPLIER, (ALfloat)index)) *
   1.504 +                 LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER));
   1.505 +        State->DecoTap[index] = (ALuint)(length * frequency);
   1.506 +    }
   1.507 +}
   1.508 +
   1.509 +// Update the late reverb gains, line lengths, and line coefficients.
   1.510 +static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
   1.511 +{
   1.512 +    ALfloat length;
   1.513 +    ALuint index;
   1.514 +
   1.515 +    /* Calculate the late reverb gain (from the master effect gain, and late
   1.516 +     * reverb gain parameters).  Since the output is tapped prior to the
   1.517 +     * application of the next delay line coefficients, this gain needs to be
   1.518 +     * attenuated by the 'x' mixing matrix coefficient as well.
   1.519 +     */
   1.520 +    State->Late.Gain = reverbGain * lateGain * xMix;
   1.521 +
   1.522 +    /* To compensate for changes in modal density and decay time of the late
   1.523 +     * reverb signal, the input is attenuated based on the maximal energy of
   1.524 +     * the outgoing signal.  This approximation is used to keep the apparent
   1.525 +     * energy of the signal equal for all ranges of density and decay time.
   1.526 +     *
   1.527 +     * The average length of the cyclcical delay lines is used to calculate
   1.528 +     * the attenuation coefficient.
   1.529 +     */
   1.530 +    length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] +
   1.531 +              LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f;
   1.532 +    length *= 1.0f + (density * LATE_LINE_MULTIPLIER);
   1.533 +    State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length,
   1.534 +                                                             decayTime));
   1.535 +
   1.536 +    // Calculate the all-pass feed-back and feed-forward coefficient.
   1.537 +    State->Late.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);
   1.538 +
   1.539 +    for(index = 0;index < 4;index++)
   1.540 +    {
   1.541 +        // Calculate the gain (coefficient) for each all-pass line.
   1.542 +        State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index],
   1.543 +                                                    decayTime);
   1.544 +
   1.545 +        // Calculate the length (in seconds) of each cyclical delay line.
   1.546 +        length = LATE_LINE_LENGTH[index] * (1.0f + (density *
   1.547 +                                                    LATE_LINE_MULTIPLIER));
   1.548 +
   1.549 +        // Calculate the delay offset for each cyclical delay line.
   1.550 +        State->Late.Offset[index] = (ALuint)(length * frequency);
   1.551 +
   1.552 +        // Calculate the gain (coefficient) for each cyclical line.
   1.553 +        State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime);
   1.554 +
   1.555 +        // Calculate the damping coefficient for each low-pass filter.
   1.556 +        State->Late.LpCoeff[index] =
   1.557 +            CalcDampingCoeff(hfRatio, length, decayTime,
   1.558 +                             State->Late.Coeff[index], cw);
   1.559 +
   1.560 +        // Attenuate the cyclical line coefficients by the mixing coefficient
   1.561 +        // (x).
   1.562 +        State->Late.Coeff[index] *= xMix;
   1.563 +    }
   1.564 +}
   1.565 +
   1.566 +// Update the echo gain, line offset, line coefficients, and mixing
   1.567 +// coefficients.
   1.568 +static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
   1.569 +{
   1.570 +    // Update the offset and coefficient for the echo delay line.
   1.571 +    State->Echo.Offset = (ALuint)(echoTime * frequency);
   1.572 +
   1.573 +    // Calculate the decay coefficient for the echo line.
   1.574 +    State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime);
   1.575 +
   1.576 +    // Calculate the energy-based attenuation coefficient for the echo delay
   1.577 +    // line.
   1.578 +    State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff);
   1.579 +
   1.580 +    // Calculate the echo all-pass feed coefficient.
   1.581 +    State->Echo.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);
   1.582 +
   1.583 +    // Calculate the echo all-pass attenuation coefficient.
   1.584 +    State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime);
   1.585 +
   1.586 +    // Calculate the damping coefficient for each low-pass filter.
   1.587 +    State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime,
   1.588 +                                           State->Echo.Coeff, cw);
   1.589 +
   1.590 +    /* Calculate the echo mixing coefficients.  The first is applied to the
   1.591 +     * echo itself.  The second is used to attenuate the late reverb when
   1.592 +     * echo depth is high and diffusion is low, so the echo is slightly
   1.593 +     * stronger than the decorrelated echos in the reverb tail.
   1.594 +     */
   1.595 +    State->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth;
   1.596 +    State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion));
   1.597 +}
   1.598 +
   1.599 +// Update the early and late 3D panning gains.
   1.600 +static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALverbState *State)
   1.601 +{
   1.602 +    ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1],
   1.603 +                            ReflectionsPan[2] };
   1.604 +    ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1],
   1.605 +                           LateReverbPan[2] };
   1.606 +    const ALfloat *speakerGain;
   1.607 +    ALfloat ambientGain;
   1.608 +    ALfloat dirGain;
   1.609 +    ALfloat length;
   1.610 +    ALuint index;
   1.611 +    ALint pos;
   1.612 +
   1.613 +    Gain *= ReverbBoost;
   1.614 +
   1.615 +    // Attenuate non-directional reverb according to the number of channels
   1.616 +    ambientGain = aluSqrt(2.0f/Device->NumChan);
   1.617 +
   1.618 +    // Calculate the 3D-panning gains for the early reflections and late
   1.619 +    // reverb.
   1.620 +    length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2];
   1.621 +    if(length > 1.0f)
   1.622 +    {
   1.623 +        length = 1.0f / aluSqrt(length);
   1.624 +        earlyPan[0] *= length;
   1.625 +        earlyPan[1] *= length;
   1.626 +        earlyPan[2] *= length;
   1.627 +    }
   1.628 +    length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2];
   1.629 +    if(length > 1.0f)
   1.630 +    {
   1.631 +        length = 1.0f / aluSqrt(length);
   1.632 +        latePan[0] *= length;
   1.633 +        latePan[1] *= length;
   1.634 +        latePan[2] *= length;
   1.635 +    }
   1.636 +
   1.637 +    /* This code applies directional reverb just like the mixer applies
   1.638 +     * directional sources.  It diffuses the sound toward all speakers as the
   1.639 +     * magnitude of the panning vector drops, which is only a rough
   1.640 +     * approximation of the expansion of sound across the speakers from the
   1.641 +     * panning direction.
   1.642 +     */
   1.643 +    pos = aluCart2LUTpos(earlyPan[2], earlyPan[0]);
   1.644 +    speakerGain = Device->PanningLUT[pos];
   1.645 +    dirGain = aluSqrt((earlyPan[0] * earlyPan[0]) + (earlyPan[2] * earlyPan[2]));
   1.646 +
   1.647 +    for(index = 0;index < MAXCHANNELS;index++)
   1.648 +        State->Early.PanGain[index] = 0.0f;
   1.649 +    for(index = 0;index < Device->NumChan;index++)
   1.650 +    {
   1.651 +        enum Channel chan = Device->Speaker2Chan[index];
   1.652 +        State->Early.PanGain[chan] = lerp(ambientGain, speakerGain[chan], dirGain) * Gain;
   1.653 +    }
   1.654 +
   1.655 +
   1.656 +    pos = aluCart2LUTpos(latePan[2], latePan[0]);
   1.657 +    speakerGain = Device->PanningLUT[pos];
   1.658 +    dirGain = aluSqrt((latePan[0] * latePan[0]) + (latePan[2] * latePan[2]));
   1.659 +
   1.660 +    for(index = 0;index < MAXCHANNELS;index++)
   1.661 +         State->Late.PanGain[index] = 0.0f;
   1.662 +    for(index = 0;index < Device->NumChan;index++)
   1.663 +    {
   1.664 +        enum Channel chan = Device->Speaker2Chan[index];
   1.665 +        State->Late.PanGain[chan] = lerp(ambientGain, speakerGain[chan], dirGain) * Gain;
   1.666 +    }
   1.667 +}
   1.668 +
   1.669 +// Basic delay line input/output routines.
   1.670 +static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
   1.671 +{
   1.672 +    return Delay->Line[offset&Delay->Mask];
   1.673 +}
   1.674 +
   1.675 +static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
   1.676 +{
   1.677 +    Delay->Line[offset&Delay->Mask] = in;
   1.678 +}
   1.679 +
   1.680 +// Attenuated delay line output routine.
   1.681 +static __inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff)
   1.682 +{
   1.683 +    return coeff * Delay->Line[offset&Delay->Mask];
   1.684 +}
   1.685 +
   1.686 +// Basic attenuated all-pass input/output routine.
   1.687 +static __inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
   1.688 +{
   1.689 +    ALfloat out, feed;
   1.690 +
   1.691 +    out = DelayLineOut(Delay, outOffset);
   1.692 +    feed = feedCoeff * in;
   1.693 +    DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in);
   1.694 +
   1.695 +    // The time-based attenuation is only applied to the delay output to
   1.696 +    // keep it from affecting the feed-back path (which is already controlled
   1.697 +    // by the all-pass feed coefficient).
   1.698 +    return (coeff * out) - feed;
   1.699 +}
   1.700 +
   1.701 +// Given an input sample, this function produces modulation for the late
   1.702 +// reverb.
   1.703 +static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in)
   1.704 +{
   1.705 +    ALfloat sinus, frac;
   1.706 +    ALuint offset;
   1.707 +    ALfloat out0, out1;
   1.708 +
   1.709 +    // Calculate the sinus rythm (dependent on modulation time and the
   1.710 +    // sampling rate).  The center of the sinus is moved to reduce the delay
   1.711 +    // of the effect when the time or depth are low.
   1.712 +    sinus = 1.0f - cos(2.0f * M_PI * State->Mod.Index / State->Mod.Range);
   1.713 +
   1.714 +    // The depth determines the range over which to read the input samples
   1.715 +    // from, so it must be filtered to reduce the distortion caused by even
   1.716 +    // small parameter changes.
   1.717 +    State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth,
   1.718 +                             State->Mod.Coeff);
   1.719 +
   1.720 +    // Calculate the read offset and fraction between it and the next sample.
   1.721 +    frac   = (1.0f + (State->Mod.Filter * sinus));
   1.722 +    offset = (ALuint)frac;
   1.723 +    frac  -= offset;
   1.724 +
   1.725 +    // Get the two samples crossed by the offset, and feed the delay line
   1.726 +    // with the next input sample.
   1.727 +    out0 = DelayLineOut(&State->Mod.Delay, State->Offset - offset);
   1.728 +    out1 = DelayLineOut(&State->Mod.Delay, State->Offset - offset - 1);
   1.729 +    DelayLineIn(&State->Mod.Delay, State->Offset, in);
   1.730 +
   1.731 +    // Step the modulation index forward, keeping it bound to its range.
   1.732 +    State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range;
   1.733 +
   1.734 +    // The output is obtained by linearly interpolating the two samples that
   1.735 +    // were acquired above.
   1.736 +    return lerp(out0, out1, frac);
   1.737 +}
   1.738 +
   1.739 +// Delay line output routine for early reflections.
   1.740 +static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
   1.741 +{
   1.742 +    return AttenuatedDelayLineOut(&State->Early.Delay[index],
   1.743 +                                  State->Offset - State->Early.Offset[index],
   1.744 +                                  State->Early.Coeff[index]);
   1.745 +}
   1.746 +
   1.747 +// Given an input sample, this function produces four-channel output for the
   1.748 +// early reflections.
   1.749 +static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *out)
   1.750 +{
   1.751 +    ALfloat d[4], v, f[4];
   1.752 +
   1.753 +    // Obtain the decayed results of each early delay line.
   1.754 +    d[0] = EarlyDelayLineOut(State, 0);
   1.755 +    d[1] = EarlyDelayLineOut(State, 1);
   1.756 +    d[2] = EarlyDelayLineOut(State, 2);
   1.757 +    d[3] = EarlyDelayLineOut(State, 3);
   1.758 +
   1.759 +    /* The following uses a lossless scattering junction from waveguide
   1.760 +     * theory.  It actually amounts to a householder mixing matrix, which
   1.761 +     * will produce a maximally diffuse response, and means this can probably
   1.762 +     * be considered a simple feed-back delay network (FDN).
   1.763 +     *          N
   1.764 +     *         ---
   1.765 +     *         \
   1.766 +     * v = 2/N /   d_i
   1.767 +     *         ---
   1.768 +     *         i=1
   1.769 +     */
   1.770 +    v = (d[0] + d[1] + d[2] + d[3]) * 0.5f;
   1.771 +    // The junction is loaded with the input here.
   1.772 +    v += in;
   1.773 +
   1.774 +    // Calculate the feed values for the delay lines.
   1.775 +    f[0] = v - d[0];
   1.776 +    f[1] = v - d[1];
   1.777 +    f[2] = v - d[2];
   1.778 +    f[3] = v - d[3];
   1.779 +
   1.780 +    // Re-feed the delay lines.
   1.781 +    DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]);
   1.782 +    DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]);
   1.783 +    DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]);
   1.784 +    DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]);
   1.785 +
   1.786 +    // Output the results of the junction for all four channels.
   1.787 +    out[0] = State->Early.Gain * f[0];
   1.788 +    out[1] = State->Early.Gain * f[1];
   1.789 +    out[2] = State->Early.Gain * f[2];
   1.790 +    out[3] = State->Early.Gain * f[3];
   1.791 +}
   1.792 +
   1.793 +// All-pass input/output routine for late reverb.
   1.794 +static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALfloat in)
   1.795 +{
   1.796 +    return AllpassInOut(&State->Late.ApDelay[index],
   1.797 +                        State->Offset - State->Late.ApOffset[index],
   1.798 +                        State->Offset, in, State->Late.ApFeedCoeff,
   1.799 +                        State->Late.ApCoeff[index]);
   1.800 +}
   1.801 +
   1.802 +// Delay line output routine for late reverb.
   1.803 +static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
   1.804 +{
   1.805 +    return AttenuatedDelayLineOut(&State->Late.Delay[index],
   1.806 +                                  State->Offset - State->Late.Offset[index],
   1.807 +                                  State->Late.Coeff[index]);
   1.808 +}
   1.809 +
   1.810 +// Low-pass filter input/output routine for late reverb.
   1.811 +static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in)
   1.812 +{
   1.813 +    in = lerp(in, State->Late.LpSample[index], State->Late.LpCoeff[index]);
   1.814 +    State->Late.LpSample[index] = in;
   1.815 +    return in;
   1.816 +}
   1.817 +
   1.818 +// Given four decorrelated input samples, this function produces four-channel
   1.819 +// output for the late reverb.
   1.820 +static __inline ALvoid LateReverb(ALverbState *State, ALfloat *in, ALfloat *out)
   1.821 +{
   1.822 +    ALfloat d[4], f[4];
   1.823 +
   1.824 +    // Obtain the decayed results of the cyclical delay lines, and add the
   1.825 +    // corresponding input channels.  Then pass the results through the
   1.826 +    // low-pass filters.
   1.827 +
   1.828 +    // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and back
   1.829 +    // to 0.
   1.830 +    d[0] = LateLowPassInOut(State, 2, in[2] + LateDelayLineOut(State, 2));
   1.831 +    d[1] = LateLowPassInOut(State, 0, in[0] + LateDelayLineOut(State, 0));
   1.832 +    d[2] = LateLowPassInOut(State, 3, in[3] + LateDelayLineOut(State, 3));
   1.833 +    d[3] = LateLowPassInOut(State, 1, in[1] + LateDelayLineOut(State, 1));
   1.834 +
   1.835 +    // To help increase diffusion, run each line through an all-pass filter.
   1.836 +    // When there is no diffusion, the shortest all-pass filter will feed the
   1.837 +    // shortest delay line.
   1.838 +    d[0] = LateAllPassInOut(State, 0, d[0]);
   1.839 +    d[1] = LateAllPassInOut(State, 1, d[1]);
   1.840 +    d[2] = LateAllPassInOut(State, 2, d[2]);
   1.841 +    d[3] = LateAllPassInOut(State, 3, d[3]);
   1.842 +
   1.843 +    /* Late reverb is done with a modified feed-back delay network (FDN)
   1.844 +     * topology.  Four input lines are each fed through their own all-pass
   1.845 +     * filter and then into the mixing matrix.  The four outputs of the
   1.846 +     * mixing matrix are then cycled back to the inputs.  Each output feeds
   1.847 +     * a different input to form a circlular feed cycle.
   1.848 +     *
   1.849 +     * The mixing matrix used is a 4D skew-symmetric rotation matrix derived
   1.850 +     * using a single unitary rotational parameter:
   1.851 +     *
   1.852 +     *  [  d,  a,  b,  c ]          1 = a^2 + b^2 + c^2 + d^2
   1.853 +     *  [ -a,  d,  c, -b ]
   1.854 +     *  [ -b, -c,  d,  a ]
   1.855 +     *  [ -c,  b, -a,  d ]
   1.856 +     *
   1.857 +     * The rotation is constructed from the effect's diffusion parameter,
   1.858 +     * yielding:  1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
   1.859 +     * with differing signs, and d is the coefficient x.  The matrix is thus:
   1.860 +     *
   1.861 +     *  [  x,  y, -y,  y ]          n = sqrt(matrix_order - 1)
   1.862 +     *  [ -y,  x,  y,  y ]          t = diffusion_parameter * atan(n)
   1.863 +     *  [  y, -y,  x,  y ]          x = cos(t)
   1.864 +     *  [ -y, -y, -y,  x ]          y = sin(t) / n
   1.865 +     *
   1.866 +     * To reduce the number of multiplies, the x coefficient is applied with
   1.867 +     * the cyclical delay line coefficients.  Thus only the y coefficient is
   1.868 +     * applied when mixing, and is modified to be:  y / x.
   1.869 +     */
   1.870 +    f[0] = d[0] + (State->Late.MixCoeff * (         d[1] + -d[2] + d[3]));
   1.871 +    f[1] = d[1] + (State->Late.MixCoeff * (-d[0]         +  d[2] + d[3]));
   1.872 +    f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1]         + d[3]));
   1.873 +    f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2]       ));
   1.874 +
   1.875 +    // Output the results of the matrix for all four channels, attenuated by
   1.876 +    // the late reverb gain (which is attenuated by the 'x' mix coefficient).
   1.877 +    out[0] = State->Late.Gain * f[0];
   1.878 +    out[1] = State->Late.Gain * f[1];
   1.879 +    out[2] = State->Late.Gain * f[2];
   1.880 +    out[3] = State->Late.Gain * f[3];
   1.881 +
   1.882 +    // Re-feed the cyclical delay lines.
   1.883 +    DelayLineIn(&State->Late.Delay[0], State->Offset, f[0]);
   1.884 +    DelayLineIn(&State->Late.Delay[1], State->Offset, f[1]);
   1.885 +    DelayLineIn(&State->Late.Delay[2], State->Offset, f[2]);
   1.886 +    DelayLineIn(&State->Late.Delay[3], State->Offset, f[3]);
   1.887 +}
   1.888 +
   1.889 +// Given an input sample, this function mixes echo into the four-channel late
   1.890 +// reverb.
   1.891 +static __inline ALvoid EAXEcho(ALverbState *State, ALfloat in, ALfloat *late)
   1.892 +{
   1.893 +    ALfloat out, feed;
   1.894 +
   1.895 +    // Get the latest attenuated echo sample for output.
   1.896 +    feed = AttenuatedDelayLineOut(&State->Echo.Delay,
   1.897 +                                  State->Offset - State->Echo.Offset,
   1.898 +                                  State->Echo.Coeff);
   1.899 +
   1.900 +    // Mix the output into the late reverb channels.
   1.901 +    out = State->Echo.MixCoeff[0] * feed;
   1.902 +    late[0] = (State->Echo.MixCoeff[1] * late[0]) + out;
   1.903 +    late[1] = (State->Echo.MixCoeff[1] * late[1]) + out;
   1.904 +    late[2] = (State->Echo.MixCoeff[1] * late[2]) + out;
   1.905 +    late[3] = (State->Echo.MixCoeff[1] * late[3]) + out;
   1.906 +
   1.907 +    // Mix the energy-attenuated input with the output and pass it through
   1.908 +    // the echo low-pass filter.
   1.909 +    feed += State->Echo.DensityGain * in;
   1.910 +    feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff);
   1.911 +    State->Echo.LpSample = feed;
   1.912 +
   1.913 +    // Then the echo all-pass filter.
   1.914 +    feed = AllpassInOut(&State->Echo.ApDelay,
   1.915 +                        State->Offset - State->Echo.ApOffset,
   1.916 +                        State->Offset, feed, State->Echo.ApFeedCoeff,
   1.917 +                        State->Echo.ApCoeff);
   1.918 +
   1.919 +    // Feed the delay with the mixed and filtered sample.
   1.920 +    DelayLineIn(&State->Echo.Delay, State->Offset, feed);
   1.921 +}
   1.922 +
   1.923 +// Perform the non-EAX reverb pass on a given input sample, resulting in
   1.924 +// four-channel output.
   1.925 +static __inline ALvoid VerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
   1.926 +{
   1.927 +    ALfloat feed, taps[4];
   1.928 +
   1.929 +    // Low-pass filter the incoming sample.
   1.930 +    in = lpFilter2P(&State->LpFilter, 0, in);
   1.931 +
   1.932 +    // Feed the initial delay line.
   1.933 +    DelayLineIn(&State->Delay, State->Offset, in);
   1.934 +
   1.935 +    // Calculate the early reflection from the first delay tap.
   1.936 +    in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
   1.937 +    EarlyReflection(State, in, early);
   1.938 +
   1.939 +    // Feed the decorrelator from the energy-attenuated output of the second
   1.940 +    // delay tap.
   1.941 +    in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
   1.942 +    feed = in * State->Late.DensityGain;
   1.943 +    DelayLineIn(&State->Decorrelator, State->Offset, feed);
   1.944 +
   1.945 +    // Calculate the late reverb from the decorrelator taps.
   1.946 +    taps[0] = feed;
   1.947 +    taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
   1.948 +    taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
   1.949 +    taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
   1.950 +    LateReverb(State, taps, late);
   1.951 +
   1.952 +    // Step all delays forward one sample.
   1.953 +    State->Offset++;
   1.954 +}
   1.955 +
   1.956 +// Perform the EAX reverb pass on a given input sample, resulting in four-
   1.957 +// channel output.
   1.958 +static __inline ALvoid EAXVerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
   1.959 +{
   1.960 +    ALfloat feed, taps[4];
   1.961 +
   1.962 +    // Low-pass filter the incoming sample.
   1.963 +    in = lpFilter2P(&State->LpFilter, 0, in);
   1.964 +
   1.965 +    // Perform any modulation on the input.
   1.966 +    in = EAXModulation(State, in);
   1.967 +
   1.968 +    // Feed the initial delay line.
   1.969 +    DelayLineIn(&State->Delay, State->Offset, in);
   1.970 +
   1.971 +    // Calculate the early reflection from the first delay tap.
   1.972 +    in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
   1.973 +    EarlyReflection(State, in, early);
   1.974 +
   1.975 +    // Feed the decorrelator from the energy-attenuated output of the second
   1.976 +    // delay tap.
   1.977 +    in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
   1.978 +    feed = in * State->Late.DensityGain;
   1.979 +    DelayLineIn(&State->Decorrelator, State->Offset, feed);
   1.980 +
   1.981 +    // Calculate the late reverb from the decorrelator taps.
   1.982 +    taps[0] = feed;
   1.983 +    taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
   1.984 +    taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
   1.985 +    taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
   1.986 +    LateReverb(State, taps, late);
   1.987 +
   1.988 +    // Calculate and mix in any echo.
   1.989 +    EAXEcho(State, in, late);
   1.990 +
   1.991 +    // Step all delays forward one sample.
   1.992 +    State->Offset++;
   1.993 +}
   1.994 +
   1.995 +// This destroys the reverb state.  It should be called only when the effect
   1.996 +// slot has a different (or no) effect loaded over the reverb effect.
   1.997 +static ALvoid VerbDestroy(ALeffectState *effect)
   1.998 +{
   1.999 +    ALverbState *State = (ALverbState*)effect;
  1.1000 +    if(State)
  1.1001 +    {
  1.1002 +        free(State->SampleBuffer);
  1.1003 +        State->SampleBuffer = NULL;
  1.1004 +        free(State);
  1.1005 +    }
  1.1006 +}
  1.1007 +
  1.1008 +// This updates the device-dependant reverb state.  This is called on
  1.1009 +// initialization and any time the device parameters (eg. playback frequency,
  1.1010 +// or format) have been changed.
  1.1011 +static ALboolean VerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
  1.1012 +{
  1.1013 +    ALverbState *State = (ALverbState*)effect;
  1.1014 +    ALuint frequency = Device->Frequency;
  1.1015 +    ALuint index;
  1.1016 +
  1.1017 +    // Allocate the delay lines.
  1.1018 +    if(!AllocLines(AL_FALSE, frequency, State))
  1.1019 +        return AL_FALSE;
  1.1020 +
  1.1021 +    // The early reflection and late all-pass filter line lengths are static,
  1.1022 +    // so their offsets only need to be calculated once.
  1.1023 +    for(index = 0;index < 4;index++)
  1.1024 +    {
  1.1025 +        State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
  1.1026 +                                              frequency);
  1.1027 +        State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
  1.1028 +                                               frequency);
  1.1029 +    }
  1.1030 +
  1.1031 +    return AL_TRUE;
  1.1032 +}
  1.1033 +
  1.1034 +// This updates the device-dependant EAX reverb state.  This is called on
  1.1035 +// initialization and any time the device parameters (eg. playback frequency,
  1.1036 +// format) have been changed.
  1.1037 +static ALboolean EAXVerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
  1.1038 +{
  1.1039 +    ALverbState *State = (ALverbState*)effect;
  1.1040 +    ALuint frequency = Device->Frequency, index;
  1.1041 +
  1.1042 +    // Allocate the delay lines.
  1.1043 +    if(!AllocLines(AL_TRUE, frequency, State))
  1.1044 +        return AL_FALSE;
  1.1045 +
  1.1046 +    // Calculate the modulation filter coefficient.  Notice that the exponent
  1.1047 +    // is calculated given the current sample rate.  This ensures that the
  1.1048 +    // resulting filter response over time is consistent across all sample
  1.1049 +    // rates.
  1.1050 +    State->Mod.Coeff = aluPow(MODULATION_FILTER_COEFF,
  1.1051 +                              MODULATION_FILTER_CONST / frequency);
  1.1052 +
  1.1053 +    // The early reflection and late all-pass filter line lengths are static,
  1.1054 +    // so their offsets only need to be calculated once.
  1.1055 +    for(index = 0;index < 4;index++)
  1.1056 +    {
  1.1057 +        State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
  1.1058 +                                              frequency);
  1.1059 +        State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
  1.1060 +                                               frequency);
  1.1061 +    }
  1.1062 +
  1.1063 +    // The echo all-pass filter line length is static, so its offset only
  1.1064 +    // needs to be calculated once.
  1.1065 +    State->Echo.ApOffset = (ALuint)(ECHO_ALLPASS_LENGTH * frequency);
  1.1066 +
  1.1067 +    return AL_TRUE;
  1.1068 +}
  1.1069 +
  1.1070 +// This updates the reverb state.  This is called any time the reverb effect
  1.1071 +// is loaded into a slot.
  1.1072 +static ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffectslot *Slot)
  1.1073 +{
  1.1074 +    ALverbState *State = (ALverbState*)effect;
  1.1075 +    ALCdevice *Device = Context->Device;
  1.1076 +    ALuint frequency = Device->Frequency;
  1.1077 +    ALfloat cw, x, y, hfRatio, gain;
  1.1078 +    ALuint index;
  1.1079 +
  1.1080 +    // Calculate the master low-pass filter (from the master effect HF gain).
  1.1081 +    cw = CalcI3DL2HFreq(Slot->effect.Params.Reverb.HFReference, frequency);
  1.1082 +    // This is done with 2 chained 1-pole filters, so no need to square g.
  1.1083 +    State->LpFilter.coeff = lpCoeffCalc(Slot->effect.Params.Reverb.GainHF, cw);
  1.1084 +
  1.1085 +    // Update the initial effect delay.
  1.1086 +    UpdateDelayLine(Slot->effect.Params.Reverb.ReflectionsDelay,
  1.1087 +                    Slot->effect.Params.Reverb.LateReverbDelay,
  1.1088 +                    frequency, State);
  1.1089 +
  1.1090 +    // Update the early lines.
  1.1091 +    UpdateEarlyLines(Slot->effect.Params.Reverb.Gain,
  1.1092 +                     Slot->effect.Params.Reverb.ReflectionsGain,
  1.1093 +                     Slot->effect.Params.Reverb.LateReverbDelay, State);
  1.1094 +
  1.1095 +    // Update the decorrelator.
  1.1096 +    UpdateDecorrelator(Slot->effect.Params.Reverb.Density, frequency, State);
  1.1097 +
  1.1098 +    // Get the mixing matrix coefficients (x and y).
  1.1099 +    CalcMatrixCoeffs(Slot->effect.Params.Reverb.Diffusion, &x, &y);
  1.1100 +    // Then divide x into y to simplify the matrix calculation.
  1.1101 +    State->Late.MixCoeff = y / x;
  1.1102 +
  1.1103 +    // If the HF limit parameter is flagged, calculate an appropriate limit
  1.1104 +    // based on the air absorption parameter.
  1.1105 +    hfRatio = Slot->effect.Params.Reverb.DecayHFRatio;
  1.1106 +    if(Slot->effect.Params.Reverb.DecayHFLimit &&
  1.1107 +       Slot->effect.Params.Reverb.AirAbsorptionGainHF < 1.0f)
  1.1108 +        hfRatio = CalcLimitedHfRatio(hfRatio,
  1.1109 +                                     Slot->effect.Params.Reverb.AirAbsorptionGainHF,
  1.1110 +                                     Slot->effect.Params.Reverb.DecayTime);
  1.1111 +
  1.1112 +    // Update the late lines.
  1.1113 +    UpdateLateLines(Slot->effect.Params.Reverb.Gain, Slot->effect.Params.Reverb.LateReverbGain,
  1.1114 +                    x, Slot->effect.Params.Reverb.Density, Slot->effect.Params.Reverb.DecayTime,
  1.1115 +                    Slot->effect.Params.Reverb.Diffusion, hfRatio, cw, frequency, State);
  1.1116 +
  1.1117 +    // Update channel gains
  1.1118 +    gain = Slot->Gain;
  1.1119 +    gain *= aluSqrt(2.0f/Device->NumChan);
  1.1120 +    gain *= ReverbBoost;
  1.1121 +    for(index = 0;index < MAXCHANNELS;index++)
  1.1122 +         State->Gain[index] = 0.0f;
  1.1123 +    for(index = 0;index < Device->NumChan;index++)
  1.1124 +    {
  1.1125 +        enum Channel chan = Device->Speaker2Chan[index];
  1.1126 +        State->Gain[chan] = gain;
  1.1127 +    }
  1.1128 +}
  1.1129 +
  1.1130 +// This updates the EAX reverb state.  This is called any time the EAX reverb
  1.1131 +// effect is loaded into a slot.
  1.1132 +static ALvoid EAXVerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffectslot *Slot)
  1.1133 +{
  1.1134 +    ALverbState *State = (ALverbState*)effect;
  1.1135 +    ALuint frequency = Context->Device->Frequency;
  1.1136 +    ALfloat cw, x, y, hfRatio;
  1.1137 +
  1.1138 +    // Calculate the master low-pass filter (from the master effect HF gain).
  1.1139 +    cw = CalcI3DL2HFreq(Slot->effect.Params.Reverb.HFReference, frequency);
  1.1140 +    // This is done with 2 chained 1-pole filters, so no need to square g.
  1.1141 +    State->LpFilter.coeff = lpCoeffCalc(Slot->effect.Params.Reverb.GainHF, cw);
  1.1142 +
  1.1143 +    // Update the modulator line.
  1.1144 +    UpdateModulator(Slot->effect.Params.Reverb.ModulationTime,
  1.1145 +                    Slot->effect.Params.Reverb.ModulationDepth,
  1.1146 +                    frequency, State);
  1.1147 +
  1.1148 +    // Update the initial effect delay.
  1.1149 +    UpdateDelayLine(Slot->effect.Params.Reverb.ReflectionsDelay,
  1.1150 +                    Slot->effect.Params.Reverb.LateReverbDelay,
  1.1151 +                    frequency, State);
  1.1152 +
  1.1153 +    // Update the early lines.
  1.1154 +    UpdateEarlyLines(Slot->effect.Params.Reverb.Gain,
  1.1155 +                     Slot->effect.Params.Reverb.ReflectionsGain,
  1.1156 +                     Slot->effect.Params.Reverb.LateReverbDelay, State);
  1.1157 +
  1.1158 +    // Update the decorrelator.
  1.1159 +    UpdateDecorrelator(Slot->effect.Params.Reverb.Density, frequency, State);
  1.1160 +
  1.1161 +    // Get the mixing matrix coefficients (x and y).
  1.1162 +    CalcMatrixCoeffs(Slot->effect.Params.Reverb.Diffusion, &x, &y);
  1.1163 +    // Then divide x into y to simplify the matrix calculation.
  1.1164 +    State->Late.MixCoeff = y / x;
  1.1165 +
  1.1166 +    // If the HF limit parameter is flagged, calculate an appropriate limit
  1.1167 +    // based on the air absorption parameter.
  1.1168 +    hfRatio = Slot->effect.Params.Reverb.DecayHFRatio;
  1.1169 +    if(Slot->effect.Params.Reverb.DecayHFLimit &&
  1.1170 +       Slot->effect.Params.Reverb.AirAbsorptionGainHF < 1.0f)
  1.1171 +        hfRatio = CalcLimitedHfRatio(hfRatio,
  1.1172 +                                     Slot->effect.Params.Reverb.AirAbsorptionGainHF,
  1.1173 +                                     Slot->effect.Params.Reverb.DecayTime);
  1.1174 +
  1.1175 +    // Update the late lines.
  1.1176 +    UpdateLateLines(Slot->effect.Params.Reverb.Gain, Slot->effect.Params.Reverb.LateReverbGain,
  1.1177 +                    x, Slot->effect.Params.Reverb.Density, Slot->effect.Params.Reverb.DecayTime,
  1.1178 +                    Slot->effect.Params.Reverb.Diffusion, hfRatio, cw, frequency, State);
  1.1179 +
  1.1180 +    // Update the echo line.
  1.1181 +    UpdateEchoLine(Slot->effect.Params.Reverb.Gain, Slot->effect.Params.Reverb.LateReverbGain,
  1.1182 +                   Slot->effect.Params.Reverb.EchoTime, Slot->effect.Params.Reverb.DecayTime,
  1.1183 +                   Slot->effect.Params.Reverb.Diffusion, Slot->effect.Params.Reverb.EchoDepth,
  1.1184 +                   hfRatio, cw, frequency, State);
  1.1185 +
  1.1186 +    // Update early and late 3D panning.
  1.1187 +    Update3DPanning(Context->Device, Slot->effect.Params.Reverb.ReflectionsPan,
  1.1188 +                    Slot->effect.Params.Reverb.LateReverbPan, Slot->Gain, State);
  1.1189 +}
  1.1190 +
  1.1191 +// This processes the reverb state, given the input samples and an output
  1.1192 +// buffer.
  1.1193 +static ALvoid VerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
  1.1194 +{
  1.1195 +    ALverbState *State = (ALverbState*)effect;
  1.1196 +    ALuint index;
  1.1197 +    ALfloat early[4], late[4], out[4];
  1.1198 +    const ALfloat *panGain = State->Gain;
  1.1199 +    (void)Slot;
  1.1200 +
  1.1201 +    for(index = 0;index < SamplesToDo;index++)
  1.1202 +    {
  1.1203 +        // Process reverb for this sample.
  1.1204 +        VerbPass(State, SamplesIn[index], early, late);
  1.1205 +
  1.1206 +        // Mix early reflections and late reverb.
  1.1207 +        out[0] = (early[0] + late[0]);
  1.1208 +        out[1] = (early[1] + late[1]);
  1.1209 +        out[2] = (early[2] + late[2]);
  1.1210 +        out[3] = (early[3] + late[3]);
  1.1211 +
  1.1212 +        // Output the results.
  1.1213 +        SamplesOut[index][FRONT_LEFT]   += panGain[FRONT_LEFT]   * out[0];
  1.1214 +        SamplesOut[index][FRONT_RIGHT]  += panGain[FRONT_RIGHT]  * out[1];
  1.1215 +        SamplesOut[index][FRONT_CENTER] += panGain[FRONT_CENTER] * out[3];
  1.1216 +        SamplesOut[index][SIDE_LEFT]    += panGain[SIDE_LEFT]    * out[0];
  1.1217 +        SamplesOut[index][SIDE_RIGHT]   += panGain[SIDE_RIGHT]   * out[1];
  1.1218 +        SamplesOut[index][BACK_LEFT]    += panGain[BACK_LEFT]    * out[0];
  1.1219 +        SamplesOut[index][BACK_RIGHT]   += panGain[BACK_RIGHT]   * out[1];
  1.1220 +        SamplesOut[index][BACK_CENTER]  += panGain[BACK_CENTER]  * out[2];
  1.1221 +    }
  1.1222 +}
  1.1223 +
  1.1224 +// This processes the EAX reverb state, given the input samples and an output
  1.1225 +// buffer.
  1.1226 +static ALvoid EAXVerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
  1.1227 +{
  1.1228 +    ALverbState *State = (ALverbState*)effect;
  1.1229 +    ALuint index;
  1.1230 +    ALfloat early[4], late[4];
  1.1231 +    (void)Slot;
  1.1232 +
  1.1233 +    for(index = 0;index < SamplesToDo;index++)
  1.1234 +    {
  1.1235 +        // Process reverb for this sample.
  1.1236 +        EAXVerbPass(State, SamplesIn[index], early, late);
  1.1237 +
  1.1238 +        // Unfortunately, while the number and configuration of gains for
  1.1239 +        // panning adjust according to MAXCHANNELS, the output from the
  1.1240 +        // reverb engine is not so scalable.
  1.1241 +        SamplesOut[index][FRONT_LEFT] +=
  1.1242 +           (State->Early.PanGain[FRONT_LEFT]*early[0] +
  1.1243 +            State->Late.PanGain[FRONT_LEFT]*late[0]);
  1.1244 +        SamplesOut[index][FRONT_RIGHT] +=
  1.1245 +           (State->Early.PanGain[FRONT_RIGHT]*early[1] +
  1.1246 +            State->Late.PanGain[FRONT_RIGHT]*late[1]);
  1.1247 +        SamplesOut[index][FRONT_CENTER] +=
  1.1248 +           (State->Early.PanGain[FRONT_CENTER]*early[3] +
  1.1249 +            State->Late.PanGain[FRONT_CENTER]*late[3]);
  1.1250 +        SamplesOut[index][SIDE_LEFT] +=
  1.1251 +           (State->Early.PanGain[SIDE_LEFT]*early[0] +
  1.1252 +            State->Late.PanGain[SIDE_LEFT]*late[0]);
  1.1253 +        SamplesOut[index][SIDE_RIGHT] +=
  1.1254 +           (State->Early.PanGain[SIDE_RIGHT]*early[1] +
  1.1255 +            State->Late.PanGain[SIDE_RIGHT]*late[1]);
  1.1256 +        SamplesOut[index][BACK_LEFT] +=
  1.1257 +           (State->Early.PanGain[BACK_LEFT]*early[0] +
  1.1258 +            State->Late.PanGain[BACK_LEFT]*late[0]);
  1.1259 +        SamplesOut[index][BACK_RIGHT] +=
  1.1260 +           (State->Early.PanGain[BACK_RIGHT]*early[1] +
  1.1261 +            State->Late.PanGain[BACK_RIGHT]*late[1]);
  1.1262 +        SamplesOut[index][BACK_CENTER] +=
  1.1263 +           (State->Early.PanGain[BACK_CENTER]*early[2] +
  1.1264 +            State->Late.PanGain[BACK_CENTER]*late[2]);
  1.1265 +    }
  1.1266 +}
  1.1267 +
  1.1268 +// This creates the reverb state.  It should be called only when the reverb
  1.1269 +// effect is loaded into a slot that doesn't already have a reverb effect.
  1.1270 +ALeffectState *VerbCreate(void)
  1.1271 +{
  1.1272 +    ALverbState *State = NULL;
  1.1273 +    ALuint index;
  1.1274 +
  1.1275 +    State = malloc(sizeof(ALverbState));
  1.1276 +    if(!State)
  1.1277 +        return NULL;
  1.1278 +
  1.1279 +    State->state.Destroy = VerbDestroy;
  1.1280 +    State->state.DeviceUpdate = VerbDeviceUpdate;
  1.1281 +    State->state.Update = VerbUpdate;
  1.1282 +    State->state.Process = VerbProcess;
  1.1283 +
  1.1284 +    State->TotalSamples = 0;
  1.1285 +    State->SampleBuffer = NULL;
  1.1286 +
  1.1287 +    State->LpFilter.coeff = 0.0f;
  1.1288 +    State->LpFilter.history[0] = 0.0f;
  1.1289 +    State->LpFilter.history[1] = 0.0f;
  1.1290 +
  1.1291 +    State->Mod.Delay.Mask = 0;
  1.1292 +    State->Mod.Delay.Line = NULL;
  1.1293 +    State->Mod.Index = 0;
  1.1294 +    State->Mod.Range = 1;
  1.1295 +    State->Mod.Depth = 0.0f;
  1.1296 +    State->Mod.Coeff = 0.0f;
  1.1297 +    State->Mod.Filter = 0.0f;
  1.1298 +
  1.1299 +    State->Delay.Mask = 0;
  1.1300 +    State->Delay.Line = NULL;
  1.1301 +    State->DelayTap[0] = 0;
  1.1302 +    State->DelayTap[1] = 0;
  1.1303 +
  1.1304 +    State->Early.Gain = 0.0f;
  1.1305 +    for(index = 0;index < 4;index++)
  1.1306 +    {
  1.1307 +        State->Early.Coeff[index] = 0.0f;
  1.1308 +        State->Early.Delay[index].Mask = 0;
  1.1309 +        State->Early.Delay[index].Line = NULL;
  1.1310 +        State->Early.Offset[index] = 0;
  1.1311 +    }
  1.1312 +
  1.1313 +    State->Decorrelator.Mask = 0;
  1.1314 +    State->Decorrelator.Line = NULL;
  1.1315 +    State->DecoTap[0] = 0;
  1.1316 +    State->DecoTap[1] = 0;
  1.1317 +    State->DecoTap[2] = 0;
  1.1318 +
  1.1319 +    State->Late.Gain = 0.0f;
  1.1320 +    State->Late.DensityGain = 0.0f;
  1.1321 +    State->Late.ApFeedCoeff = 0.0f;
  1.1322 +    State->Late.MixCoeff = 0.0f;
  1.1323 +    for(index = 0;index < 4;index++)
  1.1324 +    {
  1.1325 +        State->Late.ApCoeff[index] = 0.0f;
  1.1326 +        State->Late.ApDelay[index].Mask = 0;
  1.1327 +        State->Late.ApDelay[index].Line = NULL;
  1.1328 +        State->Late.ApOffset[index] = 0;
  1.1329 +
  1.1330 +        State->Late.Coeff[index] = 0.0f;
  1.1331 +        State->Late.Delay[index].Mask = 0;
  1.1332 +        State->Late.Delay[index].Line = NULL;
  1.1333 +        State->Late.Offset[index] = 0;
  1.1334 +
  1.1335 +        State->Late.LpCoeff[index] = 0.0f;
  1.1336 +        State->Late.LpSample[index] = 0.0f;
  1.1337 +    }
  1.1338 +
  1.1339 +    for(index = 0;index < MAXCHANNELS;index++)
  1.1340 +    {
  1.1341 +        State->Early.PanGain[index] = 0.0f;
  1.1342 +        State->Late.PanGain[index] = 0.0f;
  1.1343 +    }
  1.1344 +
  1.1345 +    State->Echo.DensityGain = 0.0f;
  1.1346 +    State->Echo.Delay.Mask = 0;
  1.1347 +    State->Echo.Delay.Line = NULL;
  1.1348 +    State->Echo.ApDelay.Mask = 0;
  1.1349 +    State->Echo.ApDelay.Line = NULL;
  1.1350 +    State->Echo.Coeff = 0.0f;
  1.1351 +    State->Echo.ApFeedCoeff = 0.0f;
  1.1352 +    State->Echo.ApCoeff = 0.0f;
  1.1353 +    State->Echo.Offset = 0;
  1.1354 +    State->Echo.ApOffset = 0;
  1.1355 +    State->Echo.LpCoeff = 0.0f;
  1.1356 +    State->Echo.LpSample = 0.0f;
  1.1357 +    State->Echo.MixCoeff[0] = 0.0f;
  1.1358 +    State->Echo.MixCoeff[1] = 0.0f;
  1.1359 +
  1.1360 +    State->Offset = 0;
  1.1361 +
  1.1362 +    State->Gain = State->Late.PanGain;
  1.1363 +
  1.1364 +    return &State->state;
  1.1365 +}
  1.1366 +
  1.1367 +ALeffectState *EAXVerbCreate(void)
  1.1368 +{
  1.1369 +    ALeffectState *State = VerbCreate();
  1.1370 +    if(State && EmulateEAXReverb == AL_FALSE)
  1.1371 +    {
  1.1372 +        State->DeviceUpdate = EAXVerbDeviceUpdate;
  1.1373 +        State->Update = EAXVerbUpdate;
  1.1374 +        State->Process = EAXVerbProcess;
  1.1375 +    }
  1.1376 +    return State;
  1.1377 +}