annotate 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
rev   line source
rlm@0 1 /**
rlm@0 2 * Reverb for the OpenAL cross platform audio library
rlm@0 3 * Copyright (C) 2008-2009 by Christopher Fitzgerald.
rlm@0 4 * This library is free software; you can redistribute it and/or
rlm@0 5 * modify it under the terms of the GNU Library General Public
rlm@0 6 * License as published by the Free Software Foundation; either
rlm@0 7 * version 2 of the License, or (at your option) any later version.
rlm@0 8 *
rlm@0 9 * This library is distributed in the hope that it will be useful,
rlm@0 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rlm@0 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
rlm@0 12 * Library General Public License for more details.
rlm@0 13 *
rlm@0 14 * You should have received a copy of the GNU Library General Public
rlm@0 15 * License along with this library; if not, write to the
rlm@0 16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
rlm@0 17 * Boston, MA 02111-1307, USA.
rlm@0 18 * Or go to http://www.gnu.org/copyleft/lgpl.html
rlm@0 19 */
rlm@0 20
rlm@0 21 #include "config.h"
rlm@0 22
rlm@0 23 #include <stdio.h>
rlm@0 24 #include <stdlib.h>
rlm@0 25 #include <math.h>
rlm@0 26
rlm@0 27 #include "AL/al.h"
rlm@0 28 #include "AL/alc.h"
rlm@0 29 #include "alMain.h"
rlm@0 30 #include "alAuxEffectSlot.h"
rlm@0 31 #include "alEffect.h"
rlm@0 32 #include "alError.h"
rlm@0 33 #include "alu.h"
rlm@0 34
rlm@0 35 typedef struct DelayLine
rlm@0 36 {
rlm@0 37 // The delay lines use sample lengths that are powers of 2 to allow the
rlm@0 38 // use of bit-masking instead of a modulus for wrapping.
rlm@0 39 ALuint Mask;
rlm@0 40 ALfloat *Line;
rlm@0 41 } DelayLine;
rlm@0 42
rlm@0 43 typedef struct ALverbState {
rlm@0 44 // Must be first in all effects!
rlm@0 45 ALeffectState state;
rlm@0 46
rlm@0 47 // All delay lines are allocated as a single buffer to reduce memory
rlm@0 48 // fragmentation and management code.
rlm@0 49 ALfloat *SampleBuffer;
rlm@0 50 ALuint TotalSamples;
rlm@0 51 // Master effect low-pass filter (2 chained 1-pole filters).
rlm@0 52 FILTER LpFilter;
rlm@0 53 ALfloat LpHistory[2];
rlm@0 54 struct {
rlm@0 55 // Modulator delay line.
rlm@0 56 DelayLine Delay;
rlm@0 57 // The vibrato time is tracked with an index over a modulus-wrapped
rlm@0 58 // range (in samples).
rlm@0 59 ALuint Index;
rlm@0 60 ALuint Range;
rlm@0 61 // The depth of frequency change (also in samples) and its filter.
rlm@0 62 ALfloat Depth;
rlm@0 63 ALfloat Coeff;
rlm@0 64 ALfloat Filter;
rlm@0 65 } Mod;
rlm@0 66 // Initial effect delay.
rlm@0 67 DelayLine Delay;
rlm@0 68 // The tap points for the initial delay. First tap goes to early
rlm@0 69 // reflections, the last to late reverb.
rlm@0 70 ALuint DelayTap[2];
rlm@0 71 struct {
rlm@0 72 // Output gain for early reflections.
rlm@0 73 ALfloat Gain;
rlm@0 74 // Early reflections are done with 4 delay lines.
rlm@0 75 ALfloat Coeff[4];
rlm@0 76 DelayLine Delay[4];
rlm@0 77 ALuint Offset[4];
rlm@0 78 // The gain for each output channel based on 3D panning (only for the
rlm@0 79 // EAX path).
rlm@0 80 ALfloat PanGain[MAXCHANNELS];
rlm@0 81 } Early;
rlm@0 82 // Decorrelator delay line.
rlm@0 83 DelayLine Decorrelator;
rlm@0 84 // There are actually 4 decorrelator taps, but the first occurs at the
rlm@0 85 // initial sample.
rlm@0 86 ALuint DecoTap[3];
rlm@0 87 struct {
rlm@0 88 // Output gain for late reverb.
rlm@0 89 ALfloat Gain;
rlm@0 90 // Attenuation to compensate for the modal density and decay rate of
rlm@0 91 // the late lines.
rlm@0 92 ALfloat DensityGain;
rlm@0 93 // The feed-back and feed-forward all-pass coefficient.
rlm@0 94 ALfloat ApFeedCoeff;
rlm@0 95 // Mixing matrix coefficient.
rlm@0 96 ALfloat MixCoeff;
rlm@0 97 // Late reverb has 4 parallel all-pass filters.
rlm@0 98 ALfloat ApCoeff[4];
rlm@0 99 DelayLine ApDelay[4];
rlm@0 100 ALuint ApOffset[4];
rlm@0 101 // In addition to 4 cyclical delay lines.
rlm@0 102 ALfloat Coeff[4];
rlm@0 103 DelayLine Delay[4];
rlm@0 104 ALuint Offset[4];
rlm@0 105 // The cyclical delay lines are 1-pole low-pass filtered.
rlm@0 106 ALfloat LpCoeff[4];
rlm@0 107 ALfloat LpSample[4];
rlm@0 108 // The gain for each output channel based on 3D panning (only for the
rlm@0 109 // EAX path).
rlm@0 110 ALfloat PanGain[MAXCHANNELS];
rlm@0 111 } Late;
rlm@0 112 struct {
rlm@0 113 // Attenuation to compensate for the modal density and decay rate of
rlm@0 114 // the echo line.
rlm@0 115 ALfloat DensityGain;
rlm@0 116 // Echo delay and all-pass lines.
rlm@0 117 DelayLine Delay;
rlm@0 118 DelayLine ApDelay;
rlm@0 119 ALfloat Coeff;
rlm@0 120 ALfloat ApFeedCoeff;
rlm@0 121 ALfloat ApCoeff;
rlm@0 122 ALuint Offset;
rlm@0 123 ALuint ApOffset;
rlm@0 124 // The echo line is 1-pole low-pass filtered.
rlm@0 125 ALfloat LpCoeff;
rlm@0 126 ALfloat LpSample;
rlm@0 127 // Echo mixing coefficients.
rlm@0 128 ALfloat MixCoeff[2];
rlm@0 129 } Echo;
rlm@0 130 // The current read offset for all delay lines.
rlm@0 131 ALuint Offset;
rlm@0 132
rlm@0 133 // The gain for each output channel (non-EAX path only; aliased from
rlm@0 134 // Late.PanGain)
rlm@0 135 ALfloat *Gain;
rlm@0 136 } ALverbState;
rlm@0 137
rlm@0 138 /* This is a user config option for modifying the overall output of the reverb
rlm@0 139 * effect.
rlm@0 140 */
rlm@0 141 ALfloat ReverbBoost = 1.0f;
rlm@0 142
rlm@0 143 /* Specifies whether to use a standard reverb effect in place of EAX reverb */
rlm@0 144 ALboolean EmulateEAXReverb = AL_FALSE;
rlm@0 145
rlm@0 146 /* This coefficient is used to define the maximum frequency range controlled
rlm@0 147 * by the modulation depth. The current value of 0.1 will allow it to swing
rlm@0 148 * from 0.9x to 1.1x. This value must be below 1. At 1 it will cause the
rlm@0 149 * sampler to stall on the downswing, and above 1 it will cause it to sample
rlm@0 150 * backwards.
rlm@0 151 */
rlm@0 152 static const ALfloat MODULATION_DEPTH_COEFF = 0.1f;
rlm@0 153
rlm@0 154 /* A filter is used to avoid the terrible distortion caused by changing
rlm@0 155 * modulation time and/or depth. To be consistent across different sample
rlm@0 156 * rates, the coefficient must be raised to a constant divided by the sample
rlm@0 157 * rate: coeff^(constant / rate).
rlm@0 158 */
rlm@0 159 static const ALfloat MODULATION_FILTER_COEFF = 0.048f;
rlm@0 160 static const ALfloat MODULATION_FILTER_CONST = 100000.0f;
rlm@0 161
rlm@0 162 // When diffusion is above 0, an all-pass filter is used to take the edge off
rlm@0 163 // the echo effect. It uses the following line length (in seconds).
rlm@0 164 static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f;
rlm@0 165
rlm@0 166 // Input into the late reverb is decorrelated between four channels. Their
rlm@0 167 // timings are dependent on a fraction and multiplier. See the
rlm@0 168 // UpdateDecorrelator() routine for the calculations involved.
rlm@0 169 static const ALfloat DECO_FRACTION = 0.15f;
rlm@0 170 static const ALfloat DECO_MULTIPLIER = 2.0f;
rlm@0 171
rlm@0 172 // All delay line lengths are specified in seconds.
rlm@0 173
rlm@0 174 // The lengths of the early delay lines.
rlm@0 175 static const ALfloat EARLY_LINE_LENGTH[4] =
rlm@0 176 {
rlm@0 177 0.0015f, 0.0045f, 0.0135f, 0.0405f
rlm@0 178 };
rlm@0 179
rlm@0 180 // The lengths of the late all-pass delay lines.
rlm@0 181 static const ALfloat ALLPASS_LINE_LENGTH[4] =
rlm@0 182 {
rlm@0 183 0.0151f, 0.0167f, 0.0183f, 0.0200f,
rlm@0 184 };
rlm@0 185
rlm@0 186 // The lengths of the late cyclical delay lines.
rlm@0 187 static const ALfloat LATE_LINE_LENGTH[4] =
rlm@0 188 {
rlm@0 189 0.0211f, 0.0311f, 0.0461f, 0.0680f
rlm@0 190 };
rlm@0 191
rlm@0 192 // The late cyclical delay lines have a variable length dependent on the
rlm@0 193 // effect's density parameter (inverted for some reason) and this multiplier.
rlm@0 194 static const ALfloat LATE_LINE_MULTIPLIER = 4.0f;
rlm@0 195
rlm@0 196 // Calculate the length of a delay line and store its mask and offset.
rlm@0 197 static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequency, DelayLine *Delay)
rlm@0 198 {
rlm@0 199 ALuint samples;
rlm@0 200
rlm@0 201 // All line lengths are powers of 2, calculated from their lengths, with
rlm@0 202 // an additional sample in case of rounding errors.
rlm@0 203 samples = NextPowerOf2((ALuint)(length * frequency) + 1);
rlm@0 204 // All lines share a single sample buffer.
rlm@0 205 Delay->Mask = samples - 1;
rlm@0 206 Delay->Line = (ALfloat*)offset;
rlm@0 207 // Return the sample count for accumulation.
rlm@0 208 return samples;
rlm@0 209 }
rlm@0 210
rlm@0 211 // Given the allocated sample buffer, this function updates each delay line
rlm@0 212 // offset.
rlm@0 213 static __inline ALvoid RealizeLineOffset(ALfloat * sampleBuffer, DelayLine *Delay)
rlm@0 214 {
rlm@0 215 Delay->Line = &sampleBuffer[(ALintptrEXT)Delay->Line];
rlm@0 216 }
rlm@0 217
rlm@0 218 /* Calculates the delay line metrics and allocates the shared sample buffer
rlm@0 219 * for all lines given a flag indicating whether or not to allocate the EAX-
rlm@0 220 * related delays (eaxFlag) and the sample rate (frequency). If an
rlm@0 221 * allocation failure occurs, it returns AL_FALSE.
rlm@0 222 */
rlm@0 223 static ALboolean AllocLines(ALboolean eaxFlag, ALuint frequency, ALverbState *State)
rlm@0 224 {
rlm@0 225 ALuint totalSamples, index;
rlm@0 226 ALfloat length;
rlm@0 227 ALfloat *newBuffer = NULL;
rlm@0 228
rlm@0 229 // All delay line lengths are calculated to accomodate the full range of
rlm@0 230 // lengths given their respective paramters.
rlm@0 231 totalSamples = 0;
rlm@0 232 if(eaxFlag)
rlm@0 233 {
rlm@0 234 /* The modulator's line length is calculated from the maximum
rlm@0 235 * modulation time and depth coefficient, and halfed for the low-to-
rlm@0 236 * high frequency swing. An additional sample is added to keep it
rlm@0 237 * stable when there is no modulation.
rlm@0 238 */
rlm@0 239 length = (AL_EAXREVERB_MAX_MODULATION_TIME * MODULATION_DEPTH_COEFF /
rlm@0 240 2.0f) + (1.0f / frequency);
rlm@0 241 totalSamples += CalcLineLength(length, totalSamples, frequency,
rlm@0 242 &State->Mod.Delay);
rlm@0 243 }
rlm@0 244
rlm@0 245 // The initial delay is the sum of the reflections and late reverb
rlm@0 246 // delays.
rlm@0 247 if(eaxFlag)
rlm@0 248 length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
rlm@0 249 AL_EAXREVERB_MAX_LATE_REVERB_DELAY;
rlm@0 250 else
rlm@0 251 length = AL_REVERB_MAX_REFLECTIONS_DELAY +
rlm@0 252 AL_REVERB_MAX_LATE_REVERB_DELAY;
rlm@0 253 totalSamples += CalcLineLength(length, totalSamples, frequency,
rlm@0 254 &State->Delay);
rlm@0 255
rlm@0 256 // The early reflection lines.
rlm@0 257 for(index = 0;index < 4;index++)
rlm@0 258 totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples,
rlm@0 259 frequency, &State->Early.Delay[index]);
rlm@0 260
rlm@0 261 // The decorrelator line is calculated from the lowest reverb density (a
rlm@0 262 // parameter value of 1).
rlm@0 263 length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) *
rlm@0 264 LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER);
rlm@0 265 totalSamples += CalcLineLength(length, totalSamples, frequency,
rlm@0 266 &State->Decorrelator);
rlm@0 267
rlm@0 268 // The late all-pass lines.
rlm@0 269 for(index = 0;index < 4;index++)
rlm@0 270 totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples,
rlm@0 271 frequency, &State->Late.ApDelay[index]);
rlm@0 272
rlm@0 273 // The late delay lines are calculated from the lowest reverb density.
rlm@0 274 for(index = 0;index < 4;index++)
rlm@0 275 {
rlm@0 276 length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER);
rlm@0 277 totalSamples += CalcLineLength(length, totalSamples, frequency,
rlm@0 278 &State->Late.Delay[index]);
rlm@0 279 }
rlm@0 280
rlm@0 281 if(eaxFlag)
rlm@0 282 {
rlm@0 283 // The echo all-pass and delay lines.
rlm@0 284 totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples,
rlm@0 285 frequency, &State->Echo.ApDelay);
rlm@0 286 totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples,
rlm@0 287 frequency, &State->Echo.Delay);
rlm@0 288 }
rlm@0 289
rlm@0 290 if(totalSamples != State->TotalSamples)
rlm@0 291 {
rlm@0 292 newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples);
rlm@0 293 if(newBuffer == NULL)
rlm@0 294 return AL_FALSE;
rlm@0 295 State->SampleBuffer = newBuffer;
rlm@0 296 State->TotalSamples = totalSamples;
rlm@0 297 }
rlm@0 298
rlm@0 299 // Update all delays to reflect the new sample buffer.
rlm@0 300 RealizeLineOffset(State->SampleBuffer, &State->Delay);
rlm@0 301 RealizeLineOffset(State->SampleBuffer, &State->Decorrelator);
rlm@0 302 for(index = 0;index < 4;index++)
rlm@0 303 {
rlm@0 304 RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]);
rlm@0 305 RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]);
rlm@0 306 RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]);
rlm@0 307 }
rlm@0 308 if(eaxFlag)
rlm@0 309 {
rlm@0 310 RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay);
rlm@0 311 RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay);
rlm@0 312 RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay);
rlm@0 313 }
rlm@0 314
rlm@0 315 // Clear the sample buffer.
rlm@0 316 for(index = 0;index < State->TotalSamples;index++)
rlm@0 317 State->SampleBuffer[index] = 0.0f;
rlm@0 318
rlm@0 319 return AL_TRUE;
rlm@0 320 }
rlm@0 321
rlm@0 322 // Calculate a decay coefficient given the length of each cycle and the time
rlm@0 323 // until the decay reaches -60 dB.
rlm@0 324 static __inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime)
rlm@0 325 {
rlm@0 326 return aluPow(0.001f/*-60 dB*/, length/decayTime);
rlm@0 327 }
rlm@0 328
rlm@0 329 // Calculate a decay length from a coefficient and the time until the decay
rlm@0 330 // reaches -60 dB.
rlm@0 331 static __inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime)
rlm@0 332 {
rlm@0 333 return log10(coeff) * decayTime / -3.0f/*log10(0.001)*/;
rlm@0 334 }
rlm@0 335
rlm@0 336 // Calculate the high frequency parameter for the I3DL2 coefficient
rlm@0 337 // calculation.
rlm@0 338 static __inline ALfloat CalcI3DL2HFreq(ALfloat hfRef, ALuint frequency)
rlm@0 339 {
rlm@0 340 return cos(2.0f * M_PI * hfRef / frequency);
rlm@0 341 }
rlm@0 342
rlm@0 343 // Calculate an attenuation to be applied to the input of any echo models to
rlm@0 344 // compensate for modal density and decay time.
rlm@0 345 static __inline ALfloat CalcDensityGain(ALfloat a)
rlm@0 346 {
rlm@0 347 /* The energy of a signal can be obtained by finding the area under the
rlm@0 348 * squared signal. This takes the form of Sum(x_n^2), where x is the
rlm@0 349 * amplitude for the sample n.
rlm@0 350 *
rlm@0 351 * Decaying feedback matches exponential decay of the form Sum(a^n),
rlm@0 352 * where a is the attenuation coefficient, and n is the sample. The area
rlm@0 353 * under this decay curve can be calculated as: 1 / (1 - a).
rlm@0 354 *
rlm@0 355 * Modifying the above equation to find the squared area under the curve
rlm@0 356 * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be
rlm@0 357 * calculated by inverting the square root of this approximation,
rlm@0 358 * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2).
rlm@0 359 */
rlm@0 360 return aluSqrt(1.0f - (a * a));
rlm@0 361 }
rlm@0 362
rlm@0 363 // Calculate the mixing matrix coefficients given a diffusion factor.
rlm@0 364 static __inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y)
rlm@0 365 {
rlm@0 366 ALfloat n, t;
rlm@0 367
rlm@0 368 // The matrix is of order 4, so n is sqrt (4 - 1).
rlm@0 369 n = aluSqrt(3.0f);
rlm@0 370 t = diffusion * atan(n);
rlm@0 371
rlm@0 372 // Calculate the first mixing matrix coefficient.
rlm@0 373 *x = cos(t);
rlm@0 374 // Calculate the second mixing matrix coefficient.
rlm@0 375 *y = sin(t) / n;
rlm@0 376 }
rlm@0 377
rlm@0 378 // Calculate the limited HF ratio for use with the late reverb low-pass
rlm@0 379 // filters.
rlm@0 380 static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime)
rlm@0 381 {
rlm@0 382 ALfloat limitRatio;
rlm@0 383
rlm@0 384 /* Find the attenuation due to air absorption in dB (converting delay
rlm@0 385 * time to meters using the speed of sound). Then reversing the decay
rlm@0 386 * equation, solve for HF ratio. The delay length is cancelled out of
rlm@0 387 * the equation, so it can be calculated once for all lines.
rlm@0 388 */
rlm@0 389 limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) *
rlm@0 390 SPEEDOFSOUNDMETRESPERSEC);
rlm@0 391 /* Using the limit calculated above, apply the upper bound to the HF
rlm@0 392 * ratio. Also need to limit the result to a minimum of 0.1, just like the
rlm@0 393 * HF ratio parameter. */
rlm@0 394 return clampf(limitRatio, 0.1f, hfRatio);
rlm@0 395 }
rlm@0 396
rlm@0 397 // Calculate the coefficient for a HF (and eventually LF) decay damping
rlm@0 398 // filter.
rlm@0 399 static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw)
rlm@0 400 {
rlm@0 401 ALfloat coeff, g;
rlm@0 402
rlm@0 403 // Eventually this should boost the high frequencies when the ratio
rlm@0 404 // exceeds 1.
rlm@0 405 coeff = 0.0f;
rlm@0 406 if (hfRatio < 1.0f)
rlm@0 407 {
rlm@0 408 // Calculate the low-pass coefficient by dividing the HF decay
rlm@0 409 // coefficient by the full decay coefficient.
rlm@0 410 g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff;
rlm@0 411
rlm@0 412 // Damping is done with a 1-pole filter, so g needs to be squared.
rlm@0 413 g *= g;
rlm@0 414 coeff = lpCoeffCalc(g, cw);
rlm@0 415
rlm@0 416 // Very low decay times will produce minimal output, so apply an
rlm@0 417 // upper bound to the coefficient.
rlm@0 418 coeff = minf(coeff, 0.98f);
rlm@0 419 }
rlm@0 420 return coeff;
rlm@0 421 }
rlm@0 422
rlm@0 423 // Update the EAX modulation index, range, and depth. Keep in mind that this
rlm@0 424 // kind of vibrato is additive and not multiplicative as one may expect. The
rlm@0 425 // downswing will sound stronger than the upswing.
rlm@0 426 static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALverbState *State)
rlm@0 427 {
rlm@0 428 ALfloat length;
rlm@0 429
rlm@0 430 /* Modulation is calculated in two parts.
rlm@0 431 *
rlm@0 432 * The modulation time effects the sinus applied to the change in
rlm@0 433 * frequency. An index out of the current time range (both in samples)
rlm@0 434 * is incremented each sample. The range is bound to a reasonable
rlm@0 435 * minimum (1 sample) and when the timing changes, the index is rescaled
rlm@0 436 * to the new range (to keep the sinus consistent).
rlm@0 437 */
rlm@0 438 length = modTime * frequency;
rlm@0 439 if (length >= 1.0f) {
rlm@0 440 State->Mod.Index = (ALuint)(State->Mod.Index * length /
rlm@0 441 State->Mod.Range);
rlm@0 442 State->Mod.Range = (ALuint)length;
rlm@0 443 } else {
rlm@0 444 State->Mod.Index = 0;
rlm@0 445 State->Mod.Range = 1;
rlm@0 446 }
rlm@0 447
rlm@0 448 /* The modulation depth effects the amount of frequency change over the
rlm@0 449 * range of the sinus. It needs to be scaled by the modulation time so
rlm@0 450 * that a given depth produces a consistent change in frequency over all
rlm@0 451 * ranges of time. Since the depth is applied to a sinus value, it needs
rlm@0 452 * to be halfed once for the sinus range and again for the sinus swing
rlm@0 453 * in time (half of it is spent decreasing the frequency, half is spent
rlm@0 454 * increasing it).
rlm@0 455 */
rlm@0 456 State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f /
rlm@0 457 2.0f * frequency;
rlm@0 458 }
rlm@0 459
rlm@0 460 // Update the offsets for the initial effect delay line.
rlm@0 461 static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALverbState *State)
rlm@0 462 {
rlm@0 463 // Calculate the initial delay taps.
rlm@0 464 State->DelayTap[0] = (ALuint)(earlyDelay * frequency);
rlm@0 465 State->DelayTap[1] = (ALuint)((earlyDelay + lateDelay) * frequency);
rlm@0 466 }
rlm@0 467
rlm@0 468 // Update the early reflections gain and line coefficients.
rlm@0 469 static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALverbState *State)
rlm@0 470 {
rlm@0 471 ALuint index;
rlm@0 472
rlm@0 473 // Calculate the early reflections gain (from the master effect gain, and
rlm@0 474 // reflections gain parameters) with a constant attenuation of 0.5.
rlm@0 475 State->Early.Gain = 0.5f * reverbGain * earlyGain;
rlm@0 476
rlm@0 477 // Calculate the gain (coefficient) for each early delay line using the
rlm@0 478 // late delay time. This expands the early reflections to the start of
rlm@0 479 // the late reverb.
rlm@0 480 for(index = 0;index < 4;index++)
rlm@0 481 State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index],
rlm@0 482 lateDelay);
rlm@0 483 }
rlm@0 484
rlm@0 485 // Update the offsets for the decorrelator line.
rlm@0 486 static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState *State)
rlm@0 487 {
rlm@0 488 ALuint index;
rlm@0 489 ALfloat length;
rlm@0 490
rlm@0 491 /* The late reverb inputs are decorrelated to smooth the reverb tail and
rlm@0 492 * reduce harsh echos. The first tap occurs immediately, while the
rlm@0 493 * remaining taps are delayed by multiples of a fraction of the smallest
rlm@0 494 * cyclical delay time.
rlm@0 495 *
rlm@0 496 * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay
rlm@0 497 */
rlm@0 498 for(index = 0;index < 3;index++)
rlm@0 499 {
rlm@0 500 length = (DECO_FRACTION * aluPow(DECO_MULTIPLIER, (ALfloat)index)) *
rlm@0 501 LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER));
rlm@0 502 State->DecoTap[index] = (ALuint)(length * frequency);
rlm@0 503 }
rlm@0 504 }
rlm@0 505
rlm@0 506 // Update the late reverb gains, line lengths, and line coefficients.
rlm@0 507 static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
rlm@0 508 {
rlm@0 509 ALfloat length;
rlm@0 510 ALuint index;
rlm@0 511
rlm@0 512 /* Calculate the late reverb gain (from the master effect gain, and late
rlm@0 513 * reverb gain parameters). Since the output is tapped prior to the
rlm@0 514 * application of the next delay line coefficients, this gain needs to be
rlm@0 515 * attenuated by the 'x' mixing matrix coefficient as well.
rlm@0 516 */
rlm@0 517 State->Late.Gain = reverbGain * lateGain * xMix;
rlm@0 518
rlm@0 519 /* To compensate for changes in modal density and decay time of the late
rlm@0 520 * reverb signal, the input is attenuated based on the maximal energy of
rlm@0 521 * the outgoing signal. This approximation is used to keep the apparent
rlm@0 522 * energy of the signal equal for all ranges of density and decay time.
rlm@0 523 *
rlm@0 524 * The average length of the cyclcical delay lines is used to calculate
rlm@0 525 * the attenuation coefficient.
rlm@0 526 */
rlm@0 527 length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] +
rlm@0 528 LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f;
rlm@0 529 length *= 1.0f + (density * LATE_LINE_MULTIPLIER);
rlm@0 530 State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length,
rlm@0 531 decayTime));
rlm@0 532
rlm@0 533 // Calculate the all-pass feed-back and feed-forward coefficient.
rlm@0 534 State->Late.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);
rlm@0 535
rlm@0 536 for(index = 0;index < 4;index++)
rlm@0 537 {
rlm@0 538 // Calculate the gain (coefficient) for each all-pass line.
rlm@0 539 State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index],
rlm@0 540 decayTime);
rlm@0 541
rlm@0 542 // Calculate the length (in seconds) of each cyclical delay line.
rlm@0 543 length = LATE_LINE_LENGTH[index] * (1.0f + (density *
rlm@0 544 LATE_LINE_MULTIPLIER));
rlm@0 545
rlm@0 546 // Calculate the delay offset for each cyclical delay line.
rlm@0 547 State->Late.Offset[index] = (ALuint)(length * frequency);
rlm@0 548
rlm@0 549 // Calculate the gain (coefficient) for each cyclical line.
rlm@0 550 State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime);
rlm@0 551
rlm@0 552 // Calculate the damping coefficient for each low-pass filter.
rlm@0 553 State->Late.LpCoeff[index] =
rlm@0 554 CalcDampingCoeff(hfRatio, length, decayTime,
rlm@0 555 State->Late.Coeff[index], cw);
rlm@0 556
rlm@0 557 // Attenuate the cyclical line coefficients by the mixing coefficient
rlm@0 558 // (x).
rlm@0 559 State->Late.Coeff[index] *= xMix;
rlm@0 560 }
rlm@0 561 }
rlm@0 562
rlm@0 563 // Update the echo gain, line offset, line coefficients, and mixing
rlm@0 564 // coefficients.
rlm@0 565 static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
rlm@0 566 {
rlm@0 567 // Update the offset and coefficient for the echo delay line.
rlm@0 568 State->Echo.Offset = (ALuint)(echoTime * frequency);
rlm@0 569
rlm@0 570 // Calculate the decay coefficient for the echo line.
rlm@0 571 State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime);
rlm@0 572
rlm@0 573 // Calculate the energy-based attenuation coefficient for the echo delay
rlm@0 574 // line.
rlm@0 575 State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff);
rlm@0 576
rlm@0 577 // Calculate the echo all-pass feed coefficient.
rlm@0 578 State->Echo.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);
rlm@0 579
rlm@0 580 // Calculate the echo all-pass attenuation coefficient.
rlm@0 581 State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime);
rlm@0 582
rlm@0 583 // Calculate the damping coefficient for each low-pass filter.
rlm@0 584 State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime,
rlm@0 585 State->Echo.Coeff, cw);
rlm@0 586
rlm@0 587 /* Calculate the echo mixing coefficients. The first is applied to the
rlm@0 588 * echo itself. The second is used to attenuate the late reverb when
rlm@0 589 * echo depth is high and diffusion is low, so the echo is slightly
rlm@0 590 * stronger than the decorrelated echos in the reverb tail.
rlm@0 591 */
rlm@0 592 State->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth;
rlm@0 593 State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion));
rlm@0 594 }
rlm@0 595
rlm@0 596 // Update the early and late 3D panning gains.
rlm@0 597 static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALverbState *State)
rlm@0 598 {
rlm@0 599 ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1],
rlm@0 600 ReflectionsPan[2] };
rlm@0 601 ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1],
rlm@0 602 LateReverbPan[2] };
rlm@0 603 const ALfloat *speakerGain;
rlm@0 604 ALfloat ambientGain;
rlm@0 605 ALfloat dirGain;
rlm@0 606 ALfloat length;
rlm@0 607 ALuint index;
rlm@0 608 ALint pos;
rlm@0 609
rlm@0 610 Gain *= ReverbBoost;
rlm@0 611
rlm@0 612 // Attenuate non-directional reverb according to the number of channels
rlm@0 613 ambientGain = aluSqrt(2.0f/Device->NumChan);
rlm@0 614
rlm@0 615 // Calculate the 3D-panning gains for the early reflections and late
rlm@0 616 // reverb.
rlm@0 617 length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2];
rlm@0 618 if(length > 1.0f)
rlm@0 619 {
rlm@0 620 length = 1.0f / aluSqrt(length);
rlm@0 621 earlyPan[0] *= length;
rlm@0 622 earlyPan[1] *= length;
rlm@0 623 earlyPan[2] *= length;
rlm@0 624 }
rlm@0 625 length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2];
rlm@0 626 if(length > 1.0f)
rlm@0 627 {
rlm@0 628 length = 1.0f / aluSqrt(length);
rlm@0 629 latePan[0] *= length;
rlm@0 630 latePan[1] *= length;
rlm@0 631 latePan[2] *= length;
rlm@0 632 }
rlm@0 633
rlm@0 634 /* This code applies directional reverb just like the mixer applies
rlm@0 635 * directional sources. It diffuses the sound toward all speakers as the
rlm@0 636 * magnitude of the panning vector drops, which is only a rough
rlm@0 637 * approximation of the expansion of sound across the speakers from the
rlm@0 638 * panning direction.
rlm@0 639 */
rlm@0 640 pos = aluCart2LUTpos(earlyPan[2], earlyPan[0]);
rlm@0 641 speakerGain = Device->PanningLUT[pos];
rlm@0 642 dirGain = aluSqrt((earlyPan[0] * earlyPan[0]) + (earlyPan[2] * earlyPan[2]));
rlm@0 643
rlm@0 644 for(index = 0;index < MAXCHANNELS;index++)
rlm@0 645 State->Early.PanGain[index] = 0.0f;
rlm@0 646 for(index = 0;index < Device->NumChan;index++)
rlm@0 647 {
rlm@0 648 enum Channel chan = Device->Speaker2Chan[index];
rlm@0 649 State->Early.PanGain[chan] = lerp(ambientGain, speakerGain[chan], dirGain) * Gain;
rlm@0 650 }
rlm@0 651
rlm@0 652
rlm@0 653 pos = aluCart2LUTpos(latePan[2], latePan[0]);
rlm@0 654 speakerGain = Device->PanningLUT[pos];
rlm@0 655 dirGain = aluSqrt((latePan[0] * latePan[0]) + (latePan[2] * latePan[2]));
rlm@0 656
rlm@0 657 for(index = 0;index < MAXCHANNELS;index++)
rlm@0 658 State->Late.PanGain[index] = 0.0f;
rlm@0 659 for(index = 0;index < Device->NumChan;index++)
rlm@0 660 {
rlm@0 661 enum Channel chan = Device->Speaker2Chan[index];
rlm@0 662 State->Late.PanGain[chan] = lerp(ambientGain, speakerGain[chan], dirGain) * Gain;
rlm@0 663 }
rlm@0 664 }
rlm@0 665
rlm@0 666 // Basic delay line input/output routines.
rlm@0 667 static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
rlm@0 668 {
rlm@0 669 return Delay->Line[offset&Delay->Mask];
rlm@0 670 }
rlm@0 671
rlm@0 672 static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
rlm@0 673 {
rlm@0 674 Delay->Line[offset&Delay->Mask] = in;
rlm@0 675 }
rlm@0 676
rlm@0 677 // Attenuated delay line output routine.
rlm@0 678 static __inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff)
rlm@0 679 {
rlm@0 680 return coeff * Delay->Line[offset&Delay->Mask];
rlm@0 681 }
rlm@0 682
rlm@0 683 // Basic attenuated all-pass input/output routine.
rlm@0 684 static __inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
rlm@0 685 {
rlm@0 686 ALfloat out, feed;
rlm@0 687
rlm@0 688 out = DelayLineOut(Delay, outOffset);
rlm@0 689 feed = feedCoeff * in;
rlm@0 690 DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in);
rlm@0 691
rlm@0 692 // The time-based attenuation is only applied to the delay output to
rlm@0 693 // keep it from affecting the feed-back path (which is already controlled
rlm@0 694 // by the all-pass feed coefficient).
rlm@0 695 return (coeff * out) - feed;
rlm@0 696 }
rlm@0 697
rlm@0 698 // Given an input sample, this function produces modulation for the late
rlm@0 699 // reverb.
rlm@0 700 static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in)
rlm@0 701 {
rlm@0 702 ALfloat sinus, frac;
rlm@0 703 ALuint offset;
rlm@0 704 ALfloat out0, out1;
rlm@0 705
rlm@0 706 // Calculate the sinus rythm (dependent on modulation time and the
rlm@0 707 // sampling rate). The center of the sinus is moved to reduce the delay
rlm@0 708 // of the effect when the time or depth are low.
rlm@0 709 sinus = 1.0f - cos(2.0f * M_PI * State->Mod.Index / State->Mod.Range);
rlm@0 710
rlm@0 711 // The depth determines the range over which to read the input samples
rlm@0 712 // from, so it must be filtered to reduce the distortion caused by even
rlm@0 713 // small parameter changes.
rlm@0 714 State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth,
rlm@0 715 State->Mod.Coeff);
rlm@0 716
rlm@0 717 // Calculate the read offset and fraction between it and the next sample.
rlm@0 718 frac = (1.0f + (State->Mod.Filter * sinus));
rlm@0 719 offset = (ALuint)frac;
rlm@0 720 frac -= offset;
rlm@0 721
rlm@0 722 // Get the two samples crossed by the offset, and feed the delay line
rlm@0 723 // with the next input sample.
rlm@0 724 out0 = DelayLineOut(&State->Mod.Delay, State->Offset - offset);
rlm@0 725 out1 = DelayLineOut(&State->Mod.Delay, State->Offset - offset - 1);
rlm@0 726 DelayLineIn(&State->Mod.Delay, State->Offset, in);
rlm@0 727
rlm@0 728 // Step the modulation index forward, keeping it bound to its range.
rlm@0 729 State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range;
rlm@0 730
rlm@0 731 // The output is obtained by linearly interpolating the two samples that
rlm@0 732 // were acquired above.
rlm@0 733 return lerp(out0, out1, frac);
rlm@0 734 }
rlm@0 735
rlm@0 736 // Delay line output routine for early reflections.
rlm@0 737 static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
rlm@0 738 {
rlm@0 739 return AttenuatedDelayLineOut(&State->Early.Delay[index],
rlm@0 740 State->Offset - State->Early.Offset[index],
rlm@0 741 State->Early.Coeff[index]);
rlm@0 742 }
rlm@0 743
rlm@0 744 // Given an input sample, this function produces four-channel output for the
rlm@0 745 // early reflections.
rlm@0 746 static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *out)
rlm@0 747 {
rlm@0 748 ALfloat d[4], v, f[4];
rlm@0 749
rlm@0 750 // Obtain the decayed results of each early delay line.
rlm@0 751 d[0] = EarlyDelayLineOut(State, 0);
rlm@0 752 d[1] = EarlyDelayLineOut(State, 1);
rlm@0 753 d[2] = EarlyDelayLineOut(State, 2);
rlm@0 754 d[3] = EarlyDelayLineOut(State, 3);
rlm@0 755
rlm@0 756 /* The following uses a lossless scattering junction from waveguide
rlm@0 757 * theory. It actually amounts to a householder mixing matrix, which
rlm@0 758 * will produce a maximally diffuse response, and means this can probably
rlm@0 759 * be considered a simple feed-back delay network (FDN).
rlm@0 760 * N
rlm@0 761 * ---
rlm@0 762 * \
rlm@0 763 * v = 2/N / d_i
rlm@0 764 * ---
rlm@0 765 * i=1
rlm@0 766 */
rlm@0 767 v = (d[0] + d[1] + d[2] + d[3]) * 0.5f;
rlm@0 768 // The junction is loaded with the input here.
rlm@0 769 v += in;
rlm@0 770
rlm@0 771 // Calculate the feed values for the delay lines.
rlm@0 772 f[0] = v - d[0];
rlm@0 773 f[1] = v - d[1];
rlm@0 774 f[2] = v - d[2];
rlm@0 775 f[3] = v - d[3];
rlm@0 776
rlm@0 777 // Re-feed the delay lines.
rlm@0 778 DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]);
rlm@0 779 DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]);
rlm@0 780 DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]);
rlm@0 781 DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]);
rlm@0 782
rlm@0 783 // Output the results of the junction for all four channels.
rlm@0 784 out[0] = State->Early.Gain * f[0];
rlm@0 785 out[1] = State->Early.Gain * f[1];
rlm@0 786 out[2] = State->Early.Gain * f[2];
rlm@0 787 out[3] = State->Early.Gain * f[3];
rlm@0 788 }
rlm@0 789
rlm@0 790 // All-pass input/output routine for late reverb.
rlm@0 791 static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALfloat in)
rlm@0 792 {
rlm@0 793 return AllpassInOut(&State->Late.ApDelay[index],
rlm@0 794 State->Offset - State->Late.ApOffset[index],
rlm@0 795 State->Offset, in, State->Late.ApFeedCoeff,
rlm@0 796 State->Late.ApCoeff[index]);
rlm@0 797 }
rlm@0 798
rlm@0 799 // Delay line output routine for late reverb.
rlm@0 800 static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
rlm@0 801 {
rlm@0 802 return AttenuatedDelayLineOut(&State->Late.Delay[index],
rlm@0 803 State->Offset - State->Late.Offset[index],
rlm@0 804 State->Late.Coeff[index]);
rlm@0 805 }
rlm@0 806
rlm@0 807 // Low-pass filter input/output routine for late reverb.
rlm@0 808 static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in)
rlm@0 809 {
rlm@0 810 in = lerp(in, State->Late.LpSample[index], State->Late.LpCoeff[index]);
rlm@0 811 State->Late.LpSample[index] = in;
rlm@0 812 return in;
rlm@0 813 }
rlm@0 814
rlm@0 815 // Given four decorrelated input samples, this function produces four-channel
rlm@0 816 // output for the late reverb.
rlm@0 817 static __inline ALvoid LateReverb(ALverbState *State, ALfloat *in, ALfloat *out)
rlm@0 818 {
rlm@0 819 ALfloat d[4], f[4];
rlm@0 820
rlm@0 821 // Obtain the decayed results of the cyclical delay lines, and add the
rlm@0 822 // corresponding input channels. Then pass the results through the
rlm@0 823 // low-pass filters.
rlm@0 824
rlm@0 825 // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and back
rlm@0 826 // to 0.
rlm@0 827 d[0] = LateLowPassInOut(State, 2, in[2] + LateDelayLineOut(State, 2));
rlm@0 828 d[1] = LateLowPassInOut(State, 0, in[0] + LateDelayLineOut(State, 0));
rlm@0 829 d[2] = LateLowPassInOut(State, 3, in[3] + LateDelayLineOut(State, 3));
rlm@0 830 d[3] = LateLowPassInOut(State, 1, in[1] + LateDelayLineOut(State, 1));
rlm@0 831
rlm@0 832 // To help increase diffusion, run each line through an all-pass filter.
rlm@0 833 // When there is no diffusion, the shortest all-pass filter will feed the
rlm@0 834 // shortest delay line.
rlm@0 835 d[0] = LateAllPassInOut(State, 0, d[0]);
rlm@0 836 d[1] = LateAllPassInOut(State, 1, d[1]);
rlm@0 837 d[2] = LateAllPassInOut(State, 2, d[2]);
rlm@0 838 d[3] = LateAllPassInOut(State, 3, d[3]);
rlm@0 839
rlm@0 840 /* Late reverb is done with a modified feed-back delay network (FDN)
rlm@0 841 * topology. Four input lines are each fed through their own all-pass
rlm@0 842 * filter and then into the mixing matrix. The four outputs of the
rlm@0 843 * mixing matrix are then cycled back to the inputs. Each output feeds
rlm@0 844 * a different input to form a circlular feed cycle.
rlm@0 845 *
rlm@0 846 * The mixing matrix used is a 4D skew-symmetric rotation matrix derived
rlm@0 847 * using a single unitary rotational parameter:
rlm@0 848 *
rlm@0 849 * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
rlm@0 850 * [ -a, d, c, -b ]
rlm@0 851 * [ -b, -c, d, a ]
rlm@0 852 * [ -c, b, -a, d ]
rlm@0 853 *
rlm@0 854 * The rotation is constructed from the effect's diffusion parameter,
rlm@0 855 * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
rlm@0 856 * with differing signs, and d is the coefficient x. The matrix is thus:
rlm@0 857 *
rlm@0 858 * [ x, y, -y, y ] n = sqrt(matrix_order - 1)
rlm@0 859 * [ -y, x, y, y ] t = diffusion_parameter * atan(n)
rlm@0 860 * [ y, -y, x, y ] x = cos(t)
rlm@0 861 * [ -y, -y, -y, x ] y = sin(t) / n
rlm@0 862 *
rlm@0 863 * To reduce the number of multiplies, the x coefficient is applied with
rlm@0 864 * the cyclical delay line coefficients. Thus only the y coefficient is
rlm@0 865 * applied when mixing, and is modified to be: y / x.
rlm@0 866 */
rlm@0 867 f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3]));
rlm@0 868 f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3]));
rlm@0 869 f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3]));
rlm@0 870 f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] ));
rlm@0 871
rlm@0 872 // Output the results of the matrix for all four channels, attenuated by
rlm@0 873 // the late reverb gain (which is attenuated by the 'x' mix coefficient).
rlm@0 874 out[0] = State->Late.Gain * f[0];
rlm@0 875 out[1] = State->Late.Gain * f[1];
rlm@0 876 out[2] = State->Late.Gain * f[2];
rlm@0 877 out[3] = State->Late.Gain * f[3];
rlm@0 878
rlm@0 879 // Re-feed the cyclical delay lines.
rlm@0 880 DelayLineIn(&State->Late.Delay[0], State->Offset, f[0]);
rlm@0 881 DelayLineIn(&State->Late.Delay[1], State->Offset, f[1]);
rlm@0 882 DelayLineIn(&State->Late.Delay[2], State->Offset, f[2]);
rlm@0 883 DelayLineIn(&State->Late.Delay[3], State->Offset, f[3]);
rlm@0 884 }
rlm@0 885
rlm@0 886 // Given an input sample, this function mixes echo into the four-channel late
rlm@0 887 // reverb.
rlm@0 888 static __inline ALvoid EAXEcho(ALverbState *State, ALfloat in, ALfloat *late)
rlm@0 889 {
rlm@0 890 ALfloat out, feed;
rlm@0 891
rlm@0 892 // Get the latest attenuated echo sample for output.
rlm@0 893 feed = AttenuatedDelayLineOut(&State->Echo.Delay,
rlm@0 894 State->Offset - State->Echo.Offset,
rlm@0 895 State->Echo.Coeff);
rlm@0 896
rlm@0 897 // Mix the output into the late reverb channels.
rlm@0 898 out = State->Echo.MixCoeff[0] * feed;
rlm@0 899 late[0] = (State->Echo.MixCoeff[1] * late[0]) + out;
rlm@0 900 late[1] = (State->Echo.MixCoeff[1] * late[1]) + out;
rlm@0 901 late[2] = (State->Echo.MixCoeff[1] * late[2]) + out;
rlm@0 902 late[3] = (State->Echo.MixCoeff[1] * late[3]) + out;
rlm@0 903
rlm@0 904 // Mix the energy-attenuated input with the output and pass it through
rlm@0 905 // the echo low-pass filter.
rlm@0 906 feed += State->Echo.DensityGain * in;
rlm@0 907 feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff);
rlm@0 908 State->Echo.LpSample = feed;
rlm@0 909
rlm@0 910 // Then the echo all-pass filter.
rlm@0 911 feed = AllpassInOut(&State->Echo.ApDelay,
rlm@0 912 State->Offset - State->Echo.ApOffset,
rlm@0 913 State->Offset, feed, State->Echo.ApFeedCoeff,
rlm@0 914 State->Echo.ApCoeff);
rlm@0 915
rlm@0 916 // Feed the delay with the mixed and filtered sample.
rlm@0 917 DelayLineIn(&State->Echo.Delay, State->Offset, feed);
rlm@0 918 }
rlm@0 919
rlm@0 920 // Perform the non-EAX reverb pass on a given input sample, resulting in
rlm@0 921 // four-channel output.
rlm@0 922 static __inline ALvoid VerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
rlm@0 923 {
rlm@0 924 ALfloat feed, taps[4];
rlm@0 925
rlm@0 926 // Low-pass filter the incoming sample.
rlm@0 927 in = lpFilter2P(&State->LpFilter, 0, in);
rlm@0 928
rlm@0 929 // Feed the initial delay line.
rlm@0 930 DelayLineIn(&State->Delay, State->Offset, in);
rlm@0 931
rlm@0 932 // Calculate the early reflection from the first delay tap.
rlm@0 933 in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
rlm@0 934 EarlyReflection(State, in, early);
rlm@0 935
rlm@0 936 // Feed the decorrelator from the energy-attenuated output of the second
rlm@0 937 // delay tap.
rlm@0 938 in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
rlm@0 939 feed = in * State->Late.DensityGain;
rlm@0 940 DelayLineIn(&State->Decorrelator, State->Offset, feed);
rlm@0 941
rlm@0 942 // Calculate the late reverb from the decorrelator taps.
rlm@0 943 taps[0] = feed;
rlm@0 944 taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
rlm@0 945 taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
rlm@0 946 taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
rlm@0 947 LateReverb(State, taps, late);
rlm@0 948
rlm@0 949 // Step all delays forward one sample.
rlm@0 950 State->Offset++;
rlm@0 951 }
rlm@0 952
rlm@0 953 // Perform the EAX reverb pass on a given input sample, resulting in four-
rlm@0 954 // channel output.
rlm@0 955 static __inline ALvoid EAXVerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
rlm@0 956 {
rlm@0 957 ALfloat feed, taps[4];
rlm@0 958
rlm@0 959 // Low-pass filter the incoming sample.
rlm@0 960 in = lpFilter2P(&State->LpFilter, 0, in);
rlm@0 961
rlm@0 962 // Perform any modulation on the input.
rlm@0 963 in = EAXModulation(State, in);
rlm@0 964
rlm@0 965 // Feed the initial delay line.
rlm@0 966 DelayLineIn(&State->Delay, State->Offset, in);
rlm@0 967
rlm@0 968 // Calculate the early reflection from the first delay tap.
rlm@0 969 in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
rlm@0 970 EarlyReflection(State, in, early);
rlm@0 971
rlm@0 972 // Feed the decorrelator from the energy-attenuated output of the second
rlm@0 973 // delay tap.
rlm@0 974 in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
rlm@0 975 feed = in * State->Late.DensityGain;
rlm@0 976 DelayLineIn(&State->Decorrelator, State->Offset, feed);
rlm@0 977
rlm@0 978 // Calculate the late reverb from the decorrelator taps.
rlm@0 979 taps[0] = feed;
rlm@0 980 taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
rlm@0 981 taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
rlm@0 982 taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
rlm@0 983 LateReverb(State, taps, late);
rlm@0 984
rlm@0 985 // Calculate and mix in any echo.
rlm@0 986 EAXEcho(State, in, late);
rlm@0 987
rlm@0 988 // Step all delays forward one sample.
rlm@0 989 State->Offset++;
rlm@0 990 }
rlm@0 991
rlm@0 992 // This destroys the reverb state. It should be called only when the effect
rlm@0 993 // slot has a different (or no) effect loaded over the reverb effect.
rlm@0 994 static ALvoid VerbDestroy(ALeffectState *effect)
rlm@0 995 {
rlm@0 996 ALverbState *State = (ALverbState*)effect;
rlm@0 997 if(State)
rlm@0 998 {
rlm@0 999 free(State->SampleBuffer);
rlm@0 1000 State->SampleBuffer = NULL;
rlm@0 1001 free(State);
rlm@0 1002 }
rlm@0 1003 }
rlm@0 1004
rlm@0 1005 // This updates the device-dependant reverb state. This is called on
rlm@0 1006 // initialization and any time the device parameters (eg. playback frequency,
rlm@0 1007 // or format) have been changed.
rlm@0 1008 static ALboolean VerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
rlm@0 1009 {
rlm@0 1010 ALverbState *State = (ALverbState*)effect;
rlm@0 1011 ALuint frequency = Device->Frequency;
rlm@0 1012 ALuint index;
rlm@0 1013
rlm@0 1014 // Allocate the delay lines.
rlm@0 1015 if(!AllocLines(AL_FALSE, frequency, State))
rlm@0 1016 return AL_FALSE;
rlm@0 1017
rlm@0 1018 // The early reflection and late all-pass filter line lengths are static,
rlm@0 1019 // so their offsets only need to be calculated once.
rlm@0 1020 for(index = 0;index < 4;index++)
rlm@0 1021 {
rlm@0 1022 State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
rlm@0 1023 frequency);
rlm@0 1024 State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
rlm@0 1025 frequency);
rlm@0 1026 }
rlm@0 1027
rlm@0 1028 return AL_TRUE;
rlm@0 1029 }
rlm@0 1030
rlm@0 1031 // This updates the device-dependant EAX reverb state. This is called on
rlm@0 1032 // initialization and any time the device parameters (eg. playback frequency,
rlm@0 1033 // format) have been changed.
rlm@0 1034 static ALboolean EAXVerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
rlm@0 1035 {
rlm@0 1036 ALverbState *State = (ALverbState*)effect;
rlm@0 1037 ALuint frequency = Device->Frequency, index;
rlm@0 1038
rlm@0 1039 // Allocate the delay lines.
rlm@0 1040 if(!AllocLines(AL_TRUE, frequency, State))
rlm@0 1041 return AL_FALSE;
rlm@0 1042
rlm@0 1043 // Calculate the modulation filter coefficient. Notice that the exponent
rlm@0 1044 // is calculated given the current sample rate. This ensures that the
rlm@0 1045 // resulting filter response over time is consistent across all sample
rlm@0 1046 // rates.
rlm@0 1047 State->Mod.Coeff = aluPow(MODULATION_FILTER_COEFF,
rlm@0 1048 MODULATION_FILTER_CONST / frequency);
rlm@0 1049
rlm@0 1050 // The early reflection and late all-pass filter line lengths are static,
rlm@0 1051 // so their offsets only need to be calculated once.
rlm@0 1052 for(index = 0;index < 4;index++)
rlm@0 1053 {
rlm@0 1054 State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
rlm@0 1055 frequency);
rlm@0 1056 State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
rlm@0 1057 frequency);
rlm@0 1058 }
rlm@0 1059
rlm@0 1060 // The echo all-pass filter line length is static, so its offset only
rlm@0 1061 // needs to be calculated once.
rlm@0 1062 State->Echo.ApOffset = (ALuint)(ECHO_ALLPASS_LENGTH * frequency);
rlm@0 1063
rlm@0 1064 return AL_TRUE;
rlm@0 1065 }
rlm@0 1066
rlm@0 1067 // This updates the reverb state. This is called any time the reverb effect
rlm@0 1068 // is loaded into a slot.
rlm@0 1069 static ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffectslot *Slot)
rlm@0 1070 {
rlm@0 1071 ALverbState *State = (ALverbState*)effect;
rlm@0 1072 ALCdevice *Device = Context->Device;
rlm@0 1073 ALuint frequency = Device->Frequency;
rlm@0 1074 ALfloat cw, x, y, hfRatio, gain;
rlm@0 1075 ALuint index;
rlm@0 1076
rlm@0 1077 // Calculate the master low-pass filter (from the master effect HF gain).
rlm@0 1078 cw = CalcI3DL2HFreq(Slot->effect.Params.Reverb.HFReference, frequency);
rlm@0 1079 // This is done with 2 chained 1-pole filters, so no need to square g.
rlm@0 1080 State->LpFilter.coeff = lpCoeffCalc(Slot->effect.Params.Reverb.GainHF, cw);
rlm@0 1081
rlm@0 1082 // Update the initial effect delay.
rlm@0 1083 UpdateDelayLine(Slot->effect.Params.Reverb.ReflectionsDelay,
rlm@0 1084 Slot->effect.Params.Reverb.LateReverbDelay,
rlm@0 1085 frequency, State);
rlm@0 1086
rlm@0 1087 // Update the early lines.
rlm@0 1088 UpdateEarlyLines(Slot->effect.Params.Reverb.Gain,
rlm@0 1089 Slot->effect.Params.Reverb.ReflectionsGain,
rlm@0 1090 Slot->effect.Params.Reverb.LateReverbDelay, State);
rlm@0 1091
rlm@0 1092 // Update the decorrelator.
rlm@0 1093 UpdateDecorrelator(Slot->effect.Params.Reverb.Density, frequency, State);
rlm@0 1094
rlm@0 1095 // Get the mixing matrix coefficients (x and y).
rlm@0 1096 CalcMatrixCoeffs(Slot->effect.Params.Reverb.Diffusion, &x, &y);
rlm@0 1097 // Then divide x into y to simplify the matrix calculation.
rlm@0 1098 State->Late.MixCoeff = y / x;
rlm@0 1099
rlm@0 1100 // If the HF limit parameter is flagged, calculate an appropriate limit
rlm@0 1101 // based on the air absorption parameter.
rlm@0 1102 hfRatio = Slot->effect.Params.Reverb.DecayHFRatio;
rlm@0 1103 if(Slot->effect.Params.Reverb.DecayHFLimit &&
rlm@0 1104 Slot->effect.Params.Reverb.AirAbsorptionGainHF < 1.0f)
rlm@0 1105 hfRatio = CalcLimitedHfRatio(hfRatio,
rlm@0 1106 Slot->effect.Params.Reverb.AirAbsorptionGainHF,
rlm@0 1107 Slot->effect.Params.Reverb.DecayTime);
rlm@0 1108
rlm@0 1109 // Update the late lines.
rlm@0 1110 UpdateLateLines(Slot->effect.Params.Reverb.Gain, Slot->effect.Params.Reverb.LateReverbGain,
rlm@0 1111 x, Slot->effect.Params.Reverb.Density, Slot->effect.Params.Reverb.DecayTime,
rlm@0 1112 Slot->effect.Params.Reverb.Diffusion, hfRatio, cw, frequency, State);
rlm@0 1113
rlm@0 1114 // Update channel gains
rlm@0 1115 gain = Slot->Gain;
rlm@0 1116 gain *= aluSqrt(2.0f/Device->NumChan);
rlm@0 1117 gain *= ReverbBoost;
rlm@0 1118 for(index = 0;index < MAXCHANNELS;index++)
rlm@0 1119 State->Gain[index] = 0.0f;
rlm@0 1120 for(index = 0;index < Device->NumChan;index++)
rlm@0 1121 {
rlm@0 1122 enum Channel chan = Device->Speaker2Chan[index];
rlm@0 1123 State->Gain[chan] = gain;
rlm@0 1124 }
rlm@0 1125 }
rlm@0 1126
rlm@0 1127 // This updates the EAX reverb state. This is called any time the EAX reverb
rlm@0 1128 // effect is loaded into a slot.
rlm@0 1129 static ALvoid EAXVerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffectslot *Slot)
rlm@0 1130 {
rlm@0 1131 ALverbState *State = (ALverbState*)effect;
rlm@0 1132 ALuint frequency = Context->Device->Frequency;
rlm@0 1133 ALfloat cw, x, y, hfRatio;
rlm@0 1134
rlm@0 1135 // Calculate the master low-pass filter (from the master effect HF gain).
rlm@0 1136 cw = CalcI3DL2HFreq(Slot->effect.Params.Reverb.HFReference, frequency);
rlm@0 1137 // This is done with 2 chained 1-pole filters, so no need to square g.
rlm@0 1138 State->LpFilter.coeff = lpCoeffCalc(Slot->effect.Params.Reverb.GainHF, cw);
rlm@0 1139
rlm@0 1140 // Update the modulator line.
rlm@0 1141 UpdateModulator(Slot->effect.Params.Reverb.ModulationTime,
rlm@0 1142 Slot->effect.Params.Reverb.ModulationDepth,
rlm@0 1143 frequency, State);
rlm@0 1144
rlm@0 1145 // Update the initial effect delay.
rlm@0 1146 UpdateDelayLine(Slot->effect.Params.Reverb.ReflectionsDelay,
rlm@0 1147 Slot->effect.Params.Reverb.LateReverbDelay,
rlm@0 1148 frequency, State);
rlm@0 1149
rlm@0 1150 // Update the early lines.
rlm@0 1151 UpdateEarlyLines(Slot->effect.Params.Reverb.Gain,
rlm@0 1152 Slot->effect.Params.Reverb.ReflectionsGain,
rlm@0 1153 Slot->effect.Params.Reverb.LateReverbDelay, State);
rlm@0 1154
rlm@0 1155 // Update the decorrelator.
rlm@0 1156 UpdateDecorrelator(Slot->effect.Params.Reverb.Density, frequency, State);
rlm@0 1157
rlm@0 1158 // Get the mixing matrix coefficients (x and y).
rlm@0 1159 CalcMatrixCoeffs(Slot->effect.Params.Reverb.Diffusion, &x, &y);
rlm@0 1160 // Then divide x into y to simplify the matrix calculation.
rlm@0 1161 State->Late.MixCoeff = y / x;
rlm@0 1162
rlm@0 1163 // If the HF limit parameter is flagged, calculate an appropriate limit
rlm@0 1164 // based on the air absorption parameter.
rlm@0 1165 hfRatio = Slot->effect.Params.Reverb.DecayHFRatio;
rlm@0 1166 if(Slot->effect.Params.Reverb.DecayHFLimit &&
rlm@0 1167 Slot->effect.Params.Reverb.AirAbsorptionGainHF < 1.0f)
rlm@0 1168 hfRatio = CalcLimitedHfRatio(hfRatio,
rlm@0 1169 Slot->effect.Params.Reverb.AirAbsorptionGainHF,
rlm@0 1170 Slot->effect.Params.Reverb.DecayTime);
rlm@0 1171
rlm@0 1172 // Update the late lines.
rlm@0 1173 UpdateLateLines(Slot->effect.Params.Reverb.Gain, Slot->effect.Params.Reverb.LateReverbGain,
rlm@0 1174 x, Slot->effect.Params.Reverb.Density, Slot->effect.Params.Reverb.DecayTime,
rlm@0 1175 Slot->effect.Params.Reverb.Diffusion, hfRatio, cw, frequency, State);
rlm@0 1176
rlm@0 1177 // Update the echo line.
rlm@0 1178 UpdateEchoLine(Slot->effect.Params.Reverb.Gain, Slot->effect.Params.Reverb.LateReverbGain,
rlm@0 1179 Slot->effect.Params.Reverb.EchoTime, Slot->effect.Params.Reverb.DecayTime,
rlm@0 1180 Slot->effect.Params.Reverb.Diffusion, Slot->effect.Params.Reverb.EchoDepth,
rlm@0 1181 hfRatio, cw, frequency, State);
rlm@0 1182
rlm@0 1183 // Update early and late 3D panning.
rlm@0 1184 Update3DPanning(Context->Device, Slot->effect.Params.Reverb.ReflectionsPan,
rlm@0 1185 Slot->effect.Params.Reverb.LateReverbPan, Slot->Gain, State);
rlm@0 1186 }
rlm@0 1187
rlm@0 1188 // This processes the reverb state, given the input samples and an output
rlm@0 1189 // buffer.
rlm@0 1190 static ALvoid VerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
rlm@0 1191 {
rlm@0 1192 ALverbState *State = (ALverbState*)effect;
rlm@0 1193 ALuint index;
rlm@0 1194 ALfloat early[4], late[4], out[4];
rlm@0 1195 const ALfloat *panGain = State->Gain;
rlm@0 1196 (void)Slot;
rlm@0 1197
rlm@0 1198 for(index = 0;index < SamplesToDo;index++)
rlm@0 1199 {
rlm@0 1200 // Process reverb for this sample.
rlm@0 1201 VerbPass(State, SamplesIn[index], early, late);
rlm@0 1202
rlm@0 1203 // Mix early reflections and late reverb.
rlm@0 1204 out[0] = (early[0] + late[0]);
rlm@0 1205 out[1] = (early[1] + late[1]);
rlm@0 1206 out[2] = (early[2] + late[2]);
rlm@0 1207 out[3] = (early[3] + late[3]);
rlm@0 1208
rlm@0 1209 // Output the results.
rlm@0 1210 SamplesOut[index][FRONT_LEFT] += panGain[FRONT_LEFT] * out[0];
rlm@0 1211 SamplesOut[index][FRONT_RIGHT] += panGain[FRONT_RIGHT] * out[1];
rlm@0 1212 SamplesOut[index][FRONT_CENTER] += panGain[FRONT_CENTER] * out[3];
rlm@0 1213 SamplesOut[index][SIDE_LEFT] += panGain[SIDE_LEFT] * out[0];
rlm@0 1214 SamplesOut[index][SIDE_RIGHT] += panGain[SIDE_RIGHT] * out[1];
rlm@0 1215 SamplesOut[index][BACK_LEFT] += panGain[BACK_LEFT] * out[0];
rlm@0 1216 SamplesOut[index][BACK_RIGHT] += panGain[BACK_RIGHT] * out[1];
rlm@0 1217 SamplesOut[index][BACK_CENTER] += panGain[BACK_CENTER] * out[2];
rlm@0 1218 }
rlm@0 1219 }
rlm@0 1220
rlm@0 1221 // This processes the EAX reverb state, given the input samples and an output
rlm@0 1222 // buffer.
rlm@0 1223 static ALvoid EAXVerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
rlm@0 1224 {
rlm@0 1225 ALverbState *State = (ALverbState*)effect;
rlm@0 1226 ALuint index;
rlm@0 1227 ALfloat early[4], late[4];
rlm@0 1228 (void)Slot;
rlm@0 1229
rlm@0 1230 for(index = 0;index < SamplesToDo;index++)
rlm@0 1231 {
rlm@0 1232 // Process reverb for this sample.
rlm@0 1233 EAXVerbPass(State, SamplesIn[index], early, late);
rlm@0 1234
rlm@0 1235 // Unfortunately, while the number and configuration of gains for
rlm@0 1236 // panning adjust according to MAXCHANNELS, the output from the
rlm@0 1237 // reverb engine is not so scalable.
rlm@0 1238 SamplesOut[index][FRONT_LEFT] +=
rlm@0 1239 (State->Early.PanGain[FRONT_LEFT]*early[0] +
rlm@0 1240 State->Late.PanGain[FRONT_LEFT]*late[0]);
rlm@0 1241 SamplesOut[index][FRONT_RIGHT] +=
rlm@0 1242 (State->Early.PanGain[FRONT_RIGHT]*early[1] +
rlm@0 1243 State->Late.PanGain[FRONT_RIGHT]*late[1]);
rlm@0 1244 SamplesOut[index][FRONT_CENTER] +=
rlm@0 1245 (State->Early.PanGain[FRONT_CENTER]*early[3] +
rlm@0 1246 State->Late.PanGain[FRONT_CENTER]*late[3]);
rlm@0 1247 SamplesOut[index][SIDE_LEFT] +=
rlm@0 1248 (State->Early.PanGain[SIDE_LEFT]*early[0] +
rlm@0 1249 State->Late.PanGain[SIDE_LEFT]*late[0]);
rlm@0 1250 SamplesOut[index][SIDE_RIGHT] +=
rlm@0 1251 (State->Early.PanGain[SIDE_RIGHT]*early[1] +
rlm@0 1252 State->Late.PanGain[SIDE_RIGHT]*late[1]);
rlm@0 1253 SamplesOut[index][BACK_LEFT] +=
rlm@0 1254 (State->Early.PanGain[BACK_LEFT]*early[0] +
rlm@0 1255 State->Late.PanGain[BACK_LEFT]*late[0]);
rlm@0 1256 SamplesOut[index][BACK_RIGHT] +=
rlm@0 1257 (State->Early.PanGain[BACK_RIGHT]*early[1] +
rlm@0 1258 State->Late.PanGain[BACK_RIGHT]*late[1]);
rlm@0 1259 SamplesOut[index][BACK_CENTER] +=
rlm@0 1260 (State->Early.PanGain[BACK_CENTER]*early[2] +
rlm@0 1261 State->Late.PanGain[BACK_CENTER]*late[2]);
rlm@0 1262 }
rlm@0 1263 }
rlm@0 1264
rlm@0 1265 // This creates the reverb state. It should be called only when the reverb
rlm@0 1266 // effect is loaded into a slot that doesn't already have a reverb effect.
rlm@0 1267 ALeffectState *VerbCreate(void)
rlm@0 1268 {
rlm@0 1269 ALverbState *State = NULL;
rlm@0 1270 ALuint index;
rlm@0 1271
rlm@0 1272 State = malloc(sizeof(ALverbState));
rlm@0 1273 if(!State)
rlm@0 1274 return NULL;
rlm@0 1275
rlm@0 1276 State->state.Destroy = VerbDestroy;
rlm@0 1277 State->state.DeviceUpdate = VerbDeviceUpdate;
rlm@0 1278 State->state.Update = VerbUpdate;
rlm@0 1279 State->state.Process = VerbProcess;
rlm@0 1280
rlm@0 1281 State->TotalSamples = 0;
rlm@0 1282 State->SampleBuffer = NULL;
rlm@0 1283
rlm@0 1284 State->LpFilter.coeff = 0.0f;
rlm@0 1285 State->LpFilter.history[0] = 0.0f;
rlm@0 1286 State->LpFilter.history[1] = 0.0f;
rlm@0 1287
rlm@0 1288 State->Mod.Delay.Mask = 0;
rlm@0 1289 State->Mod.Delay.Line = NULL;
rlm@0 1290 State->Mod.Index = 0;
rlm@0 1291 State->Mod.Range = 1;
rlm@0 1292 State->Mod.Depth = 0.0f;
rlm@0 1293 State->Mod.Coeff = 0.0f;
rlm@0 1294 State->Mod.Filter = 0.0f;
rlm@0 1295
rlm@0 1296 State->Delay.Mask = 0;
rlm@0 1297 State->Delay.Line = NULL;
rlm@0 1298 State->DelayTap[0] = 0;
rlm@0 1299 State->DelayTap[1] = 0;
rlm@0 1300
rlm@0 1301 State->Early.Gain = 0.0f;
rlm@0 1302 for(index = 0;index < 4;index++)
rlm@0 1303 {
rlm@0 1304 State->Early.Coeff[index] = 0.0f;
rlm@0 1305 State->Early.Delay[index].Mask = 0;
rlm@0 1306 State->Early.Delay[index].Line = NULL;
rlm@0 1307 State->Early.Offset[index] = 0;
rlm@0 1308 }
rlm@0 1309
rlm@0 1310 State->Decorrelator.Mask = 0;
rlm@0 1311 State->Decorrelator.Line = NULL;
rlm@0 1312 State->DecoTap[0] = 0;
rlm@0 1313 State->DecoTap[1] = 0;
rlm@0 1314 State->DecoTap[2] = 0;
rlm@0 1315
rlm@0 1316 State->Late.Gain = 0.0f;
rlm@0 1317 State->Late.DensityGain = 0.0f;
rlm@0 1318 State->Late.ApFeedCoeff = 0.0f;
rlm@0 1319 State->Late.MixCoeff = 0.0f;
rlm@0 1320 for(index = 0;index < 4;index++)
rlm@0 1321 {
rlm@0 1322 State->Late.ApCoeff[index] = 0.0f;
rlm@0 1323 State->Late.ApDelay[index].Mask = 0;
rlm@0 1324 State->Late.ApDelay[index].Line = NULL;
rlm@0 1325 State->Late.ApOffset[index] = 0;
rlm@0 1326
rlm@0 1327 State->Late.Coeff[index] = 0.0f;
rlm@0 1328 State->Late.Delay[index].Mask = 0;
rlm@0 1329 State->Late.Delay[index].Line = NULL;
rlm@0 1330 State->Late.Offset[index] = 0;
rlm@0 1331
rlm@0 1332 State->Late.LpCoeff[index] = 0.0f;
rlm@0 1333 State->Late.LpSample[index] = 0.0f;
rlm@0 1334 }
rlm@0 1335
rlm@0 1336 for(index = 0;index < MAXCHANNELS;index++)
rlm@0 1337 {
rlm@0 1338 State->Early.PanGain[index] = 0.0f;
rlm@0 1339 State->Late.PanGain[index] = 0.0f;
rlm@0 1340 }
rlm@0 1341
rlm@0 1342 State->Echo.DensityGain = 0.0f;
rlm@0 1343 State->Echo.Delay.Mask = 0;
rlm@0 1344 State->Echo.Delay.Line = NULL;
rlm@0 1345 State->Echo.ApDelay.Mask = 0;
rlm@0 1346 State->Echo.ApDelay.Line = NULL;
rlm@0 1347 State->Echo.Coeff = 0.0f;
rlm@0 1348 State->Echo.ApFeedCoeff = 0.0f;
rlm@0 1349 State->Echo.ApCoeff = 0.0f;
rlm@0 1350 State->Echo.Offset = 0;
rlm@0 1351 State->Echo.ApOffset = 0;
rlm@0 1352 State->Echo.LpCoeff = 0.0f;
rlm@0 1353 State->Echo.LpSample = 0.0f;
rlm@0 1354 State->Echo.MixCoeff[0] = 0.0f;
rlm@0 1355 State->Echo.MixCoeff[1] = 0.0f;
rlm@0 1356
rlm@0 1357 State->Offset = 0;
rlm@0 1358
rlm@0 1359 State->Gain = State->Late.PanGain;
rlm@0 1360
rlm@0 1361 return &State->state;
rlm@0 1362 }
rlm@0 1363
rlm@0 1364 ALeffectState *EAXVerbCreate(void)
rlm@0 1365 {
rlm@0 1366 ALeffectState *State = VerbCreate();
rlm@0 1367 if(State && EmulateEAXReverb == AL_FALSE)
rlm@0 1368 {
rlm@0 1369 State->DeviceUpdate = EAXVerbDeviceUpdate;
rlm@0 1370 State->Update = EAXVerbUpdate;
rlm@0 1371 State->Process = EAXVerbProcess;
rlm@0 1372 }
rlm@0 1373 return State;
rlm@0 1374 }