Update ChangeLog
[openal-soft.git] / Alc / effects / reverb.c
blob867abbcc0191e88987b152dd5ac1b246af198317
1 /**
2 * Ambisonic reverb engine for the OpenAL cross platform audio library
3 * Copyright (C) 2008-2017 by Chris Robinson and Christopher Fitzgerald.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <math.h>
27 #include "alMain.h"
28 #include "alu.h"
29 #include "alAuxEffectSlot.h"
30 #include "alEffect.h"
31 #include "alFilter.h"
32 #include "alError.h"
33 #include "mixer_defs.h"
35 /* This is the maximum number of samples processed for each inner loop
36 * iteration. */
37 #define MAX_UPDATE_SAMPLES 256
39 /* The number of samples used for cross-faded delay lines. This can be used
40 * to balance the compensation for abrupt line changes and attenuation due to
41 * minimally lengthed recursive lines. Try to keep this below the device
42 * update size.
44 #define FADE_SAMPLES 128
46 #ifdef __GNUC__
47 #define UNEXPECTED(x) __builtin_expect((bool)(x), 0)
48 #else
49 #define UNEXPECTED(x) (x)
50 #endif
52 static MixerFunc MixSamples = Mix_C;
53 static RowMixerFunc MixRowSamples = MixRow_C;
55 static alonce_flag mixfunc_inited = AL_ONCE_FLAG_INIT;
56 static void init_mixfunc(void)
58 MixSamples = SelectMixer();
59 MixRowSamples = SelectRowMixer();
62 typedef struct DelayLineI {
63 /* The delay lines use interleaved samples, with the lengths being powers
64 * of 2 to allow the use of bit-masking instead of a modulus for wrapping.
66 ALsizei Mask;
67 ALfloat (*Line)[4];
68 } DelayLineI;
70 typedef struct VecAllpass {
71 DelayLineI Delay;
72 ALsizei Offset[4][2];
73 } VecAllpass;
75 typedef struct ALreverbState {
76 DERIVE_FROM_TYPE(ALeffectState);
78 ALboolean IsEax;
80 /* All delay lines are allocated as a single buffer to reduce memory
81 * fragmentation and management code.
83 ALfloat *SampleBuffer;
84 ALuint TotalSamples;
86 /* Master effect filters */
87 struct {
88 ALfilterState Lp;
89 ALfilterState Hp; /* EAX only */
90 } Filter[4];
92 /* Core delay line (early reflections and late reverb tap from this). */
93 DelayLineI Delay;
95 /* Tap points for early reflection delay. */
96 ALsizei EarlyDelayTap[4][2];
97 ALfloat EarlyDelayCoeff[4];
99 /* Tap points for late reverb feed and delay. */
100 ALsizei LateFeedTap;
101 ALsizei LateDelayTap[4][2];
103 /* The feed-back and feed-forward all-pass coefficient. */
104 ALfloat ApFeedCoeff;
106 /* Coefficients for the all-pass and line scattering matrices. */
107 ALfloat MixX;
108 ALfloat MixY;
110 struct {
111 /* A Gerzon vector all-pass filter is used to simulate initial
112 * diffusion. The spread from this filter also helps smooth out the
113 * reverb tail.
115 VecAllpass VecAp;
117 /* An echo line is used to complete the second half of the early
118 * reflections.
120 DelayLineI Delay;
121 ALsizei Offset[4][2];
122 ALfloat Coeff[4];
124 /* The gain for each output channel based on 3D panning. */
125 ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS];
126 ALfloat PanGain[4][MAX_OUTPUT_CHANNELS];
127 } Early;
129 struct {
130 /* The vibrato time is tracked with an index over a modulus-wrapped
131 * range (in samples).
133 ALuint Index;
134 ALuint Range;
136 /* The depth of frequency change (also in samples) and its filter. */
137 ALfloat Depth;
138 ALfloat Coeff;
139 ALfloat Filter;
140 } Mod; /* EAX only */
142 struct {
143 /* Attenuation to compensate for the modal density and decay rate of
144 * the late lines.
146 ALfloat DensityGain;
148 /* A recursive delay line is used fill in the reverb tail. */
149 DelayLineI Delay;
150 ALsizei Offset[4][2];
152 /* T60 decay filters are used to simulate absorption. */
153 struct {
154 ALfloat LFCoeffs[3];
155 ALfloat HFCoeffs[3];
156 ALfloat MidCoeff;
157 /* The LF and HF filters keep a state of the last input and last
158 * output sample.
160 ALfloat States[2][2];
161 } Filters[4];
163 /* A Gerzon vector all-pass filter is used to simulate diffusion. */
164 VecAllpass VecAp;
166 /* The gain for each output channel based on 3D panning. */
167 ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS];
168 ALfloat PanGain[4][MAX_OUTPUT_CHANNELS];
169 } Late;
171 /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */
172 ALsizei FadeCount;
174 /* The current write offset for all delay lines. */
175 ALsizei Offset;
177 /* Temporary storage used when processing. */
178 alignas(16) ALfloat AFormatSamples[4][MAX_UPDATE_SAMPLES];
179 alignas(16) ALfloat ReverbSamples[4][MAX_UPDATE_SAMPLES];
180 alignas(16) ALfloat EarlySamples[4][MAX_UPDATE_SAMPLES];
181 } ALreverbState;
183 static ALvoid ALreverbState_Destruct(ALreverbState *State);
184 static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device);
185 static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
186 static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
187 DECLARE_DEFAULT_ALLOCATORS(ALreverbState)
189 DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState);
191 static void ALreverbState_Construct(ALreverbState *state)
193 ALsizei i, j;
195 ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
196 SET_VTABLE2(ALreverbState, ALeffectState, state);
198 state->IsEax = AL_FALSE;
200 state->TotalSamples = 0;
201 state->SampleBuffer = NULL;
203 for(i = 0;i < 4;i++)
205 ALfilterState_clear(&state->Filter[i].Lp);
206 ALfilterState_clear(&state->Filter[i].Hp);
209 state->Delay.Mask = 0;
210 state->Delay.Line = NULL;
212 for(i = 0;i < 4;i++)
214 state->EarlyDelayTap[i][0] = 0;
215 state->EarlyDelayTap[i][1] = 0;
216 state->EarlyDelayCoeff[i] = 0.0f;
219 state->LateFeedTap = 0;
221 for(i = 0;i < 4;i++)
223 state->LateDelayTap[i][0] = 0;
224 state->LateDelayTap[i][1] = 0;
227 state->ApFeedCoeff = 0.0f;
228 state->MixX = 0.0f;
229 state->MixY = 0.0f;
231 state->Early.VecAp.Delay.Mask = 0;
232 state->Early.VecAp.Delay.Line = NULL;
233 state->Early.Delay.Mask = 0;
234 state->Early.Delay.Line = NULL;
235 for(i = 0;i < 4;i++)
237 state->Early.VecAp.Offset[i][0] = 0;
238 state->Early.VecAp.Offset[i][1] = 0;
239 state->Early.Offset[i][0] = 0;
240 state->Early.Offset[i][1] = 0;
241 state->Early.Coeff[i] = 0.0f;
244 state->Mod.Index = 0;
245 state->Mod.Range = 1;
246 state->Mod.Depth = 0.0f;
247 state->Mod.Coeff = 0.0f;
248 state->Mod.Filter = 0.0f;
250 state->Late.DensityGain = 0.0f;
252 state->Late.Delay.Mask = 0;
253 state->Late.Delay.Line = NULL;
254 state->Late.VecAp.Delay.Mask = 0;
255 state->Late.VecAp.Delay.Line = NULL;
256 for(i = 0;i < 4;i++)
258 state->Late.Offset[i][0] = 0;
259 state->Late.Offset[i][1] = 0;
261 state->Late.VecAp.Offset[i][0] = 0;
262 state->Late.VecAp.Offset[i][1] = 0;
264 for(j = 0;j < 3;j++)
266 state->Late.Filters[i].LFCoeffs[j] = 0.0f;
267 state->Late.Filters[i].HFCoeffs[j] = 0.0f;
269 state->Late.Filters[i].MidCoeff = 0.0f;
271 state->Late.Filters[i].States[0][0] = 0.0f;
272 state->Late.Filters[i].States[0][1] = 0.0f;
273 state->Late.Filters[i].States[1][0] = 0.0f;
274 state->Late.Filters[i].States[1][1] = 0.0f;
277 for(i = 0;i < 4;i++)
279 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
281 state->Early.CurrentGain[i][j] = 0.0f;
282 state->Early.PanGain[i][j] = 0.0f;
283 state->Late.CurrentGain[i][j] = 0.0f;
284 state->Late.PanGain[i][j] = 0.0f;
288 state->FadeCount = 0;
289 state->Offset = 0;
292 static ALvoid ALreverbState_Destruct(ALreverbState *State)
294 al_free(State->SampleBuffer);
295 State->SampleBuffer = NULL;
297 ALeffectState_Destruct(STATIC_CAST(ALeffectState,State));
300 /* The B-Format to A-Format conversion matrix. The arrangement of rows is
301 * deliberately chosen to align the resulting lines to their spatial opposites
302 * (0:above front left <-> 3:above back right, 1:below front right <-> 2:below
303 * back left). It's not quite opposite, since the A-Format results in a
304 * tetrahedron, but it's close enough. Should the model be extended to 8-lines
305 * in the future, true opposites can be used.
307 static const aluMatrixf B2A = {{
308 { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f },
309 { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f },
310 { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f },
311 { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f }
314 /* Converts A-Format to B-Format. */
315 static const aluMatrixf A2B = {{
316 { 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f },
317 { 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f },
318 { 0.866025403785f, -0.866025403785f, -0.866025403785f, 0.866025403785f },
319 { 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f }
322 static const ALfloat FadeStep = 1.0f / FADE_SAMPLES;
324 /* This is a user config option for modifying the overall output of the reverb
325 * effect.
327 ALfloat ReverbBoost = 1.0f;
329 /* Specifies whether to use a standard reverb effect in place of EAX reverb (no
330 * high-pass, modulation, or echo).
332 ALboolean EmulateEAXReverb = AL_FALSE;
334 /* The all-pass and delay lines have a variable length dependent on the
335 * effect's density parameter. The resulting density multiplier is:
337 * multiplier = 1 + (density * LINE_MULTIPLIER)
339 * Thus the line multiplier below will result in a maximum density multiplier
340 * of 10.
342 static const ALfloat LINE_MULTIPLIER = 9.0f;
344 /* All delay line lengths are specified in seconds.
346 * To approximate early reflections, we break them up into primary (those
347 * arriving from the same direction as the source) and secondary (those
348 * arriving from the opposite direction).
350 * The early taps decorrelate the 4-channel signal to approximate an average
351 * room response for the primary reflections after the initial early delay.
353 * Given an average room dimension (d_a) and the speed of sound (c) we can
354 * calculate the average reflection delay (r_a) regardless of listener and
355 * source positions as:
357 * r_a = d_a / c
358 * c = 343.3
360 * This can extended to finding the average difference (r_d) between the
361 * maximum (r_1) and minimum (r_0) reflection delays:
363 * r_0 = 2 / 3 r_a
364 * = r_a - r_d / 2
365 * = r_d
366 * r_1 = 4 / 3 r_a
367 * = r_a + r_d / 2
368 * = 2 r_d
369 * r_d = 2 / 3 r_a
370 * = r_1 - r_0
372 * As can be determined by integrating the 1D model with a source (s) and
373 * listener (l) positioned across the dimension of length (d_a):
375 * r_d = int_(l=0)^d_a (int_(s=0)^d_a |2 d_a - 2 (l + s)| ds) dl / c
377 * The initial taps (T_(i=0)^N) are then specified by taking a power series
378 * that ranges between r_0 and half of r_1 less r_0:
380 * R_i = 2^(i / (2 N - 1)) r_d
381 * = r_0 + (2^(i / (2 N - 1)) - 1) r_d
382 * = r_0 + T_i
383 * T_i = R_i - r_0
384 * = (2^(i / (2 N - 1)) - 1) r_d
386 * Assuming an average of 5m (up to 50m with the density multiplier), we get
387 * the following taps:
389 static const ALfloat EARLY_TAP_LENGTHS[4] =
391 0.000000e+0f, 1.010676e-3f, 2.126553e-3f, 3.358580e-3f
394 /* The early all-pass filter lengths are based on the early tap lengths:
396 * A_i = R_i / a
398 * Where a is the approximate maximum all-pass cycle limit (20).
400 static const ALfloat EARLY_ALLPASS_LENGTHS[4] =
402 4.854840e-4f, 5.360178e-4f, 5.918117e-4f, 6.534130e-4f
405 /* The early delay lines are used to transform the primary reflections into
406 * the secondary reflections. The A-format is arranged in such a way that
407 * the channels/lines are spatially opposite:
409 * C_i is opposite C_(N-i-1)
411 * The delays of the two opposing reflections (R_i and O_i) from a source
412 * anywhere along a particular dimension always sum to twice its full delay:
414 * 2 r_a = R_i + O_i
416 * With that in mind we can determine the delay between the two reflections
417 * and thus specify our early line lengths (L_(i=0)^N) using:
419 * O_i = 2 r_a - R_(N-i-1)
420 * L_i = O_i - R_(N-i-1)
421 * = 2 (r_a - R_(N-i-1))
422 * = 2 (r_a - T_(N-i-1) - r_0)
423 * = 2 r_a (1 - (2 / 3) 2^((N - i - 1) / (2 N - 1)))
425 * Using an average dimension of 5m, we get:
427 static const ALfloat EARLY_LINE_LENGTHS[4] =
429 2.992520e-3f, 5.456575e-3f, 7.688329e-3f, 9.709681e-3f
432 /* The late all-pass filter lengths are based on the late line lengths:
434 * A_i = (5 / 3) L_i / r_1
436 static const ALfloat LATE_ALLPASS_LENGTHS[4] =
438 8.091400e-4f, 1.019453e-3f, 1.407968e-3f, 1.618280e-3f
441 /* The late lines are used to approximate the decaying cycle of recursive
442 * late reflections.
444 * Splitting the lines in half, we start with the shortest reflection paths
445 * (L_(i=0)^(N/2)):
447 * L_i = 2^(i / (N - 1)) r_d
449 * Then for the opposite (longest) reflection paths (L_(i=N/2)^N):
451 * L_i = 2 r_a - L_(i-N/2)
452 * = 2 r_a - 2^((i - N / 2) / (N - 1)) r_d
454 * For our 5m average room, we get:
456 static const ALfloat LATE_LINE_LENGTHS[4] =
458 9.709681e-3f, 1.223343e-2f, 1.689561e-2f, 1.941936e-2f
461 /* This coefficient is used to define the sinus depth according to the
462 * modulation depth property. This value must be below half the shortest late
463 * line length (0.0097/2 = ~0.0048), otherwise with certain parameters (high
464 * mod time, low density) the downswing can sample before the input.
466 static const ALfloat MODULATION_DEPTH_COEFF = 1.0f / 4096.0f;
468 /* A filter is used to avoid the terrible distortion caused by changing
469 * modulation time and/or depth. To be consistent across different sample
470 * rates, the coefficient must be raised to a constant divided by the sample
471 * rate: coeff^(constant / rate).
473 static const ALfloat MODULATION_FILTER_COEFF = 0.048f;
474 static const ALfloat MODULATION_FILTER_CONST = 100000.0f;
477 /* Prior to VS2013, MSVC lacks the round() family of functions. */
478 #if defined(_MSC_VER) && _MSC_VER < 1800
479 static inline long lroundf(float val)
481 if(val < 0.0)
482 return fastf2i(ceilf(val-0.5f));
483 return fastf2i(floorf(val+0.5f));
485 #endif
488 /**************************************
489 * Device Update *
490 **************************************/
492 /* Given the allocated sample buffer, this function updates each delay line
493 * offset.
495 static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay)
497 union {
498 ALfloat *f;
499 ALfloat (*f4)[4];
500 } u;
501 u.f = &sampleBuffer[(ptrdiff_t)Delay->Line * 4];
502 Delay->Line = u.f4;
505 /* Calculate the length of a delay line and store its mask and offset. */
506 static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALuint frequency,
507 const ALuint extra, DelayLineI *Delay)
509 ALuint samples;
511 /* All line lengths are powers of 2, calculated from their lengths in
512 * seconds, rounded up.
514 samples = fastf2i(ceilf(length*frequency));
515 samples = NextPowerOf2(samples + extra);
517 /* All lines share a single sample buffer. */
518 Delay->Mask = samples - 1;
519 Delay->Line = (ALfloat(*)[4])offset;
521 /* Return the sample count for accumulation. */
522 return samples;
525 /* Calculates the delay line metrics and allocates the shared sample buffer
526 * for all lines given the sample rate (frequency). If an allocation failure
527 * occurs, it returns AL_FALSE.
529 static ALboolean AllocLines(const ALuint frequency, ALreverbState *State)
531 ALuint totalSamples, i;
532 ALfloat multiplier, length;
534 /* All delay line lengths are calculated to accomodate the full range of
535 * lengths given their respective paramters.
537 totalSamples = 0;
539 /* Multiplier for the maximum density value, i.e. density=1, which is
540 * actually the least density...
542 multiplier = 1.0f + LINE_MULTIPLIER;
544 /* The main delay length includes the maximum early reflection delay, the
545 * largest early tap width, the maximum late reverb delay, and the
546 * largest late tap width. Finally, it must also be extended by the
547 * update size (MAX_UPDATE_SAMPLES) for block processing.
549 length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
550 EARLY_TAP_LENGTHS[3]*multiplier +
551 AL_EAXREVERB_MAX_LATE_REVERB_DELAY +
552 (LATE_LINE_LENGTHS[3] - LATE_LINE_LENGTHS[0])*0.25f*multiplier;
553 totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES,
554 &State->Delay);
556 /* The early vector all-pass line. */
557 length = EARLY_ALLPASS_LENGTHS[3] * multiplier;
558 totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
559 &State->Early.VecAp.Delay);
561 /* The early reflection line. */
562 length = EARLY_LINE_LENGTHS[3] * multiplier;
563 totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
564 &State->Early.Delay);
566 /* The late vector all-pass line. */
567 length = LATE_ALLPASS_LENGTHS[3] * multiplier;
568 totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
569 &State->Late.VecAp.Delay);
571 /* The late delay lines are calculated from the larger of the maximum
572 * density line length or the maximum echo time, and includes the maximum
573 * modulation-related delay. The modulator's delay is calculated from the
574 * maximum modulation time and depth coefficient, and halved for the low-
575 * to-high frequency swing.
577 length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[3]*multiplier) +
578 AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f;
579 totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
580 &State->Late.Delay);
582 if(totalSamples != State->TotalSamples)
584 ALfloat *newBuffer;
586 TRACE("New reverb buffer length: %ux4 samples\n", totalSamples);
587 newBuffer = al_calloc(16, sizeof(ALfloat[4]) * totalSamples);
588 if(!newBuffer) return AL_FALSE;
590 al_free(State->SampleBuffer);
591 State->SampleBuffer = newBuffer;
592 State->TotalSamples = totalSamples;
595 /* Update all delays to reflect the new sample buffer. */
596 RealizeLineOffset(State->SampleBuffer, &State->Delay);
597 RealizeLineOffset(State->SampleBuffer, &State->Early.VecAp.Delay);
598 RealizeLineOffset(State->SampleBuffer, &State->Early.Delay);
599 RealizeLineOffset(State->SampleBuffer, &State->Late.VecAp.Delay);
600 RealizeLineOffset(State->SampleBuffer, &State->Late.Delay);
602 /* Clear the sample buffer. */
603 for(i = 0;i < State->TotalSamples;i++)
604 State->SampleBuffer[i] = 0.0f;
606 return AL_TRUE;
609 static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device)
611 ALuint frequency = Device->Frequency, i;
612 ALfloat multiplier;
614 /* Allocate the delay lines. */
615 if(!AllocLines(frequency, State))
616 return AL_FALSE;
618 /* Calculate the modulation filter coefficient. Notice that the exponent
619 * is calculated given the current sample rate. This ensures that the
620 * resulting filter response over time is consistent across all sample
621 * rates.
623 State->Mod.Coeff = powf(MODULATION_FILTER_COEFF,
624 MODULATION_FILTER_CONST / frequency);
626 multiplier = 1.0f + LINE_MULTIPLIER;
628 /* The late feed taps are set a fixed position past the latest delay tap. */
629 for(i = 0;i < 4;i++)
630 State->LateFeedTap = fastf2i((AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
631 EARLY_TAP_LENGTHS[3]*multiplier) *
632 frequency);
634 return AL_TRUE;
637 /**************************************
638 * Effect Update *
639 **************************************/
641 /* Calculate a decay coefficient given the length of each cycle and the time
642 * until the decay reaches -60 dB.
644 static inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTime)
646 return powf(REVERB_DECAY_GAIN, length/decayTime);
649 /* Calculate a decay length from a coefficient and the time until the decay
650 * reaches -60 dB.
652 static inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime)
654 return log10f(coeff) * decayTime / log10f(REVERB_DECAY_GAIN);
657 /* Calculate an attenuation to be applied to the input of any echo models to
658 * compensate for modal density and decay time.
660 static inline ALfloat CalcDensityGain(const ALfloat a)
662 /* The energy of a signal can be obtained by finding the area under the
663 * squared signal. This takes the form of Sum(x_n^2), where x is the
664 * amplitude for the sample n.
666 * Decaying feedback matches exponential decay of the form Sum(a^n),
667 * where a is the attenuation coefficient, and n is the sample. The area
668 * under this decay curve can be calculated as: 1 / (1 - a).
670 * Modifying the above equation to find the area under the squared curve
671 * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be
672 * calculated by inverting the square root of this approximation,
673 * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2).
675 return sqrtf(1.0f - a*a);
678 /* Calculate the scattering matrix coefficients given a diffusion factor. */
679 static inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y)
681 ALfloat n, t;
683 /* The matrix is of order 4, so n is sqrt(4 - 1). */
684 n = sqrtf(3.0f);
685 t = diffusion * atanf(n);
687 /* Calculate the first mixing matrix coefficient. */
688 *x = cosf(t);
689 /* Calculate the second mixing matrix coefficient. */
690 *y = sinf(t) / n;
693 /* Calculate the limited HF ratio for use with the late reverb low-pass
694 * filters.
696 static ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF,
697 const ALfloat decayTime)
699 ALfloat limitRatio;
701 /* Find the attenuation due to air absorption in dB (converting delay
702 * time to meters using the speed of sound). Then reversing the decay
703 * equation, solve for HF ratio. The delay length is cancelled out of
704 * the equation, so it can be calculated once for all lines.
706 limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) *
707 SPEEDOFSOUNDMETRESPERSEC);
708 /* Using the limit calculated above, apply the upper bound to the HF
709 * ratio. Also need to limit the result to a minimum of 0.1, just like
710 * the HF ratio parameter.
712 return clampf(limitRatio, 0.1f, hfRatio);
715 /* Calculates the first-order high-pass coefficients following the I3DL2
716 * reference model. This is the transfer function:
718 * 1 - z^-1
719 * H(z) = p ------------
720 * 1 - p z^-1
722 * And this is the I3DL2 coefficient calculation given gain (g) and reference
723 * angular frequency (w):
726 * p = ------------------------------------------------------
727 * g cos(w) + sqrt((cos(w) - 1) (g^2 cos(w) + g^2 - 2))
729 * The coefficient is applied to the partial differential filter equation as:
731 * c_0 = p
732 * c_1 = -p
733 * c_2 = p
734 * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1)
737 static inline void CalcHighpassCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3])
739 ALfloat g, g2, cw, p;
741 if(gain >= 1.0f)
743 coeffs[0] = 1.0f;
744 coeffs[1] = 0.0f;
745 coeffs[2] = 0.0f;
747 return;
750 g = maxf(0.001f, gain);
751 g2 = g * g;
752 cw = cosf(w);
753 p = g / (g*cw + sqrtf((cw - 1.0f) * (g2*cw + g2 - 2.0f)));
755 coeffs[0] = p;
756 coeffs[1] = -p;
757 coeffs[2] = p;
760 /* Calculates the first-order low-pass coefficients following the I3DL2
761 * reference model. This is the transfer function:
763 * (1 - a) z^0
764 * H(z) = ----------------
765 * 1 z^0 - a z^-1
767 * And this is the I3DL2 coefficient calculation given gain (g) and reference
768 * angular frequency (w):
770 * 1 - g^2 cos(w) - sqrt(2 g^2 (1 - cos(w)) - g^4 (1 - cos(w)^2))
771 * a = ----------------------------------------------------------------
772 * 1 - g^2
774 * The coefficient is applied to the partial differential filter equation as:
776 * c_0 = 1 - a
777 * c_1 = 0
778 * c_2 = a
779 * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1)
782 static inline void CalcLowpassCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3])
784 ALfloat g, g2, cw, a;
786 if(gain >= 1.0f)
788 coeffs[0] = 1.0f;
789 coeffs[1] = 0.0f;
790 coeffs[2] = 0.0f;
792 return;
795 /* Be careful with gains < 0.001, as that causes the coefficient
796 * to head towards 1, which will flatten the signal. */
797 g = maxf(0.001f, gain);
798 g2 = g * g;
799 cw = cosf(w);
800 a = (1.0f - g2*cw - sqrtf((2.0f*g2*(1.0f - cw)) - g2*g2*(1.0f - cw*cw))) /
801 (1.0f - g2);
803 coeffs[0] = 1.0f - a;
804 coeffs[1] = 0.0f;
805 coeffs[2] = a;
808 /* Calculates the first-order low-shelf coefficients. The shelf filters are
809 * used in place of low/high-pass filters to preserve the mid-band. This is
810 * the transfer function:
812 * a_0 + a_1 z^-1
813 * H(z) = ----------------
814 * 1 + b_1 z^-1
816 * And these are the coefficient calculations given cut gain (g) and a center
817 * angular frequency (w):
819 * sin(0.5 (pi - w) - 0.25 pi)
820 * p = -----------------------------
821 * sin(0.5 (pi - w) + 0.25 pi)
823 * g + 1 g + 1
824 * a = ------- + sqrt((-------)^2 - 1)
825 * g - 1 g - 1
827 * 1 + g + (1 - g) a
828 * b_0 = -------------------
831 * 1 - g + (1 + g) a
832 * b_1 = -------------------
835 * The coefficients are applied to the partial differential filter equation
836 * as:
838 * b_0 + p b_1
839 * c_0 = -------------
840 * 1 + p a
842 * -(b_1 + p b_0)
843 * c_1 = ----------------
844 * 1 + p a
846 * p + a
847 * c_2 = ---------
848 * 1 + p a
850 * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1)
853 static inline void CalcLowShelfCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3])
855 ALfloat g, rw, p, n;
856 ALfloat alpha, beta0, beta1;
858 if(gain >= 1.0f)
860 coeffs[0] = 1.0f;
861 coeffs[1] = 0.0f;
862 coeffs[2] = 0.0f;
864 return;
867 g = maxf(0.001f, gain);
868 rw = F_PI - w;
869 p = sinf(0.5f*rw - 0.25f*F_PI) / sinf(0.5f*rw + 0.25f*F_PI);
870 n = (g + 1.0f) / (g - 1.0f);
871 alpha = n + sqrtf(n*n - 1.0f);
872 beta0 = (1.0f + g + (1.0f - g)*alpha) / 2.0f;
873 beta1 = (1.0f - g + (1.0f + g)*alpha) / 2.0f;
875 coeffs[0] = (beta0 + p*beta1) / (1.0f + p*alpha);
876 coeffs[1] = -(beta1 + p*beta0) / (1.0f + p*alpha);
877 coeffs[2] = (p + alpha) / (1.0f + p*alpha);
880 /* Calculates the first-order high-shelf coefficients. The shelf filters are
881 * used in place of low/high-pass filters to preserve the mid-band. This is
882 * the transfer function:
884 * a_0 + a_1 z^-1
885 * H(z) = ----------------
886 * 1 + b_1 z^-1
888 * And these are the coefficient calculations given cut gain (g) and a center
889 * angular frequency (w):
891 * sin(0.5 w - 0.25 pi)
892 * p = ----------------------
893 * sin(0.5 w + 0.25 pi)
895 * g + 1 g + 1
896 * a = ------- + sqrt((-------)^2 - 1)
897 * g - 1 g - 1
899 * 1 + g + (1 - g) a
900 * b_0 = -------------------
903 * 1 - g + (1 + g) a
904 * b_1 = -------------------
907 * The coefficients are applied to the partial differential filter equation
908 * as:
910 * b_0 + p b_1
911 * c_0 = -------------
912 * 1 + p a
914 * b_1 + p b_0
915 * c_1 = -------------
916 * 1 + p a
918 * -(p + a)
919 * c_2 = ----------
920 * 1 + p a
922 * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1)
925 static inline void CalcHighShelfCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3])
927 ALfloat g, p, n;
928 ALfloat alpha, beta0, beta1;
930 if(gain >= 1.0f)
932 coeffs[0] = 1.0f;
933 coeffs[1] = 0.0f;
934 coeffs[2] = 0.0f;
936 return;
939 g = maxf(0.001f, gain);
940 p = sinf(0.5f*w - 0.25f*F_PI) / sinf(0.5f*w + 0.25f*F_PI);
941 n = (g + 1.0f) / (g - 1.0f);
942 alpha = n + sqrtf(n*n - 1.0f);
943 beta0 = (1.0f + g + (1.0f - g)*alpha) / 2.0f;
944 beta1 = (1.0f - g + (1.0f + g)*alpha) / 2.0f;
946 coeffs[0] = (beta0 + p*beta1) / (1.0f + p*alpha);
947 coeffs[1] = (beta1 + p*beta0) / (1.0f + p*alpha);
948 coeffs[2] = -(p + alpha) / (1.0f + p*alpha);
951 /* Calculates the 3-band T60 damping coefficients for a particular delay line
952 * of specified length using a combination of two low/high-pass/shelf or
953 * pass-through filter sections (producing 3 coefficients each) and a general
954 * gain (7th coefficient) given decay times for each band split at two (LF/
955 * HF) reference frequencies (w).
957 static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime,
958 const ALfloat mfDecayTime, const ALfloat hfDecayTime,
959 const ALfloat lfW, const ALfloat hfW, ALfloat lfcoeffs[3],
960 ALfloat hfcoeffs[3], ALfloat *midcoeff)
962 ALfloat lfGain = CalcDecayCoeff(length, lfDecayTime);
963 ALfloat mfGain = CalcDecayCoeff(length, mfDecayTime);
964 ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime);
966 if(lfGain < mfGain)
968 if(mfGain < hfGain)
970 CalcLowShelfCoeffs(mfGain / hfGain, hfW, lfcoeffs);
971 CalcHighpassCoeffs(lfGain / mfGain, lfW, hfcoeffs);
972 *midcoeff = hfGain;
974 else if(mfGain > hfGain)
976 CalcHighpassCoeffs(lfGain / mfGain, lfW, lfcoeffs);
977 CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs);
978 *midcoeff = mfGain;
980 else
982 lfcoeffs[0] = 1.0f;
983 lfcoeffs[1] = 0.0f;
984 lfcoeffs[2] = 0.0f;
985 CalcHighpassCoeffs(lfGain / mfGain, lfW, hfcoeffs);
986 *midcoeff = mfGain;
989 else if(lfGain > mfGain)
991 if(mfGain < hfGain)
993 ALfloat hg = mfGain / lfGain;
994 ALfloat lg = mfGain / hfGain;
996 CalcHighShelfCoeffs(hg, lfW, lfcoeffs);
997 CalcLowShelfCoeffs(lg, hfW, hfcoeffs);
998 *midcoeff = maxf(lfGain, hfGain) / maxf(hg, lg);
1000 else if(mfGain > hfGain)
1002 CalcHighShelfCoeffs(mfGain / lfGain, lfW, lfcoeffs);
1003 CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs);
1004 *midcoeff = lfGain;
1006 else
1008 lfcoeffs[0] = 1.0f;
1009 lfcoeffs[1] = 0.0f;
1010 lfcoeffs[2] = 0.0f;
1011 CalcHighShelfCoeffs(mfGain / lfGain, lfW, hfcoeffs);
1012 *midcoeff = lfGain;
1015 else
1017 lfcoeffs[0] = 1.0f;
1018 lfcoeffs[1] = 0.0f;
1019 lfcoeffs[2] = 0.0f;
1021 if(mfGain < hfGain)
1023 CalcLowShelfCoeffs(mfGain / hfGain, hfW, hfcoeffs);
1024 *midcoeff = hfGain;
1026 else if(mfGain > hfGain)
1028 CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs);
1029 *midcoeff = mfGain;
1031 else
1033 hfcoeffs[3] = 1.0f;
1034 hfcoeffs[4] = 0.0f;
1035 hfcoeffs[5] = 0.0f;
1036 *midcoeff = mfGain;
1041 /* Update the EAX modulation index, range, and depth. Keep in mind that this
1042 * kind of vibrato is additive and not multiplicative as one may expect. The
1043 * downswing will sound stronger than the upswing.
1045 static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth,
1046 const ALuint frequency, ALreverbState *State)
1048 ALuint range;
1050 /* Modulation is calculated in two parts.
1052 * The modulation time effects the speed of the sinus. An index out of the
1053 * current range (both in samples) is incremented each sample, so a longer
1054 * time implies a larger range. The range is bound to a reasonable minimum
1055 * (1 sample) and when the timing changes, the index is rescaled to the new
1056 * range to keep the sinus consistent.
1058 range = maxi(fastf2i(modTime*frequency), 1);
1059 State->Mod.Index = (ALuint)(State->Mod.Index * (ALuint64)range /
1060 State->Mod.Range);
1061 State->Mod.Range = range;
1063 /* The modulation depth effects the scale of the sinus, which changes how
1064 * much extra delay is added to the delay line. This delay changing over
1065 * time changes the pitch, creating the modulation effect. The scale needs
1066 * to be multiplied by the modulation time so that a given depth produces a
1067 * consistent shift in frequency over all ranges of time. Since the depth
1068 * is applied to a sinus value, it needs to be halved for the sinus swing
1069 * in time (half of it is spent decreasing the frequency, half is spent
1070 * increasing it).
1072 State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f *
1073 frequency;
1076 /* Update the offsets for the main effect delay line. */
1077 static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, const ALfloat decayTime, const ALuint frequency, ALreverbState *State)
1079 ALfloat multiplier, length;
1080 ALuint i;
1082 multiplier = 1.0f + density*LINE_MULTIPLIER;
1084 /* Early reflection taps are decorrelated by means of an average room
1085 * reflection approximation described above the definition of the taps.
1086 * This approximation is linear and so the above density multiplier can
1087 * be applied to adjust the width of the taps. A single-band decay
1088 * coefficient is applied to simulate initial attenuation and absorption.
1090 * Late reverb taps are based on the late line lengths to allow a zero-
1091 * delay path and offsets that would continue the propagation naturally
1092 * into the late lines.
1094 for(i = 0;i < 4;i++)
1096 length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier;
1097 State->EarlyDelayTap[i][1] = fastf2i(length * frequency);
1099 length = EARLY_TAP_LENGTHS[i]*multiplier;
1100 State->EarlyDelayCoeff[i] = CalcDecayCoeff(length, decayTime);
1102 length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS[0])*0.25f*multiplier;
1103 State->LateDelayTap[i][1] = State->LateFeedTap + fastf2i(length * frequency);
1107 /* Update the early reflection line lengths and gain coefficients. */
1108 static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, const ALuint frequency, ALreverbState *State)
1110 ALfloat multiplier, length;
1111 ALsizei i;
1113 multiplier = 1.0f + density*LINE_MULTIPLIER;
1115 for(i = 0;i < 4;i++)
1117 /* Calculate the length (in seconds) of each all-pass line. */
1118 length = EARLY_ALLPASS_LENGTHS[i] * multiplier;
1120 /* Calculate the delay offset for each all-pass line. */
1121 State->Early.VecAp.Offset[i][1] = fastf2i(length * frequency);
1123 /* Calculate the length (in seconds) of each delay line. */
1124 length = EARLY_LINE_LENGTHS[i] * multiplier;
1126 /* Calculate the delay offset for each delay line. */
1127 State->Early.Offset[i][1] = fastf2i(length * frequency);
1129 /* Calculate the gain (coefficient) for each line. */
1130 State->Early.Coeff[i] = CalcDecayCoeff(length, decayTime);
1134 /* Update the late reverb line lengths and T60 coefficients. */
1135 static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lfW, const ALfloat hfW, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, ALreverbState *State)
1137 ALfloat multiplier, length, bandWeights[3];
1138 ALsizei i;
1140 /* To compensate for changes in modal density and decay time of the late
1141 * reverb signal, the input is attenuated based on the maximal energy of
1142 * the outgoing signal. This approximation is used to keep the apparent
1143 * energy of the signal equal for all ranges of density and decay time.
1145 * The average length of the delay lines is used to calculate the
1146 * attenuation coefficient.
1148 multiplier = 1.0f + density*LINE_MULTIPLIER;
1149 length = (LATE_LINE_LENGTHS[0] + LATE_LINE_LENGTHS[1] +
1150 LATE_LINE_LENGTHS[2] + LATE_LINE_LENGTHS[3]) / 4.0f * multiplier;
1151 /* Include the echo transformation (see below). */
1152 length = lerp(length, echoTime, echoDepth);
1153 length += (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] +
1154 LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f * multiplier;
1155 /* The density gain calculation uses an average decay time weighted by
1156 * approximate bandwidth. This attempts to compensate for losses of
1157 * energy that reduce decay time due to scattering into highly attenuated
1158 * bands.
1160 bandWeights[0] = lfW;
1161 bandWeights[1] = hfW - lfW;
1162 bandWeights[2] = F_TAU - hfW;
1163 State->Late.DensityGain = CalcDensityGain(
1164 CalcDecayCoeff(length, (bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime +
1165 bandWeights[2]*hfDecayTime) / F_TAU)
1168 for(i = 0;i < 4;i++)
1170 /* Calculate the length (in seconds) of each all-pass line. */
1171 length = LATE_ALLPASS_LENGTHS[i] * multiplier;
1173 /* Calculate the delay offset for each all-pass line. */
1174 State->Late.VecAp.Offset[i][1] = fastf2i(length * frequency);
1176 /* Calculate the length (in seconds) of each delay line. This also
1177 * applies the echo transformation. As the EAX echo depth approaches
1178 * 1, the line lengths approach a length equal to the echoTime. This
1179 * helps to produce distinct echoes along the tail.
1181 length = lerp(LATE_LINE_LENGTHS[i] * multiplier, echoTime, echoDepth);
1183 /* Calculate the delay offset for each delay line. */
1184 State->Late.Offset[i][1] = fastf2i(length * frequency);
1186 /* Approximate the absorption that the vector all-pass would exhibit
1187 * given the current diffusion so we don't have to process a full T60
1188 * filter for each of its four lines.
1190 length += lerp(LATE_ALLPASS_LENGTHS[i],
1191 (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] +
1192 LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f,
1193 diffusion) * multiplier;
1195 /* Calculate the T60 damping coefficients for each line. */
1196 CalcT60DampingCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime,
1197 lfW, hfW, State->Late.Filters[i].LFCoeffs,
1198 State->Late.Filters[i].HFCoeffs,
1199 &State->Late.Filters[i].MidCoeff);
1203 /* Creates a transform matrix given a reverb vector. This works by creating a
1204 * Z-focus transform, then a rotate transform around X, then Y, to place the
1205 * focal point in the direction of the vector, using the vector length as a
1206 * focus strength.
1208 * This isn't technically correct since the vector is supposed to define the
1209 * aperture and not rotate the perceived soundfield, but in practice it's
1210 * probably good enough.
1212 static aluMatrixf GetTransformFromVector(const ALfloat *vec)
1214 aluMatrixf zfocus, xrot, yrot;
1215 aluMatrixf tmp1, tmp2;
1216 ALfloat length;
1217 ALfloat sa, a;
1219 length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
1221 /* Define a Z-focus (X in Ambisonics) transform, given the panning vector
1222 * length.
1224 sa = sinf(minf(length, 1.0f) * (F_PI/4.0f));
1225 aluMatrixfSet(&zfocus,
1226 1.0f/(1.0f+sa), 0.0f, 0.0f, (sa/(1.0f+sa))/1.732050808f,
1227 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, 0.0f,
1228 0.0f, 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f,
1229 (sa/(1.0f+sa))*1.732050808f, 0.0f, 0.0f, 1.0f/(1.0f+sa)
1232 /* Define rotation around X (Y in Ambisonics) */
1233 a = atan2f(vec[1], sqrtf(vec[0]*vec[0] + vec[2]*vec[2]));
1234 aluMatrixfSet(&xrot,
1235 1.0f, 0.0f, 0.0f, 0.0f,
1236 0.0f, 1.0f, 0.0f, 0.0f,
1237 0.0f, 0.0f, cosf(a), sinf(a),
1238 0.0f, 0.0f, -sinf(a), cosf(a)
1241 /* Define rotation around Y (Z in Ambisonics). NOTE: EFX's reverb vectors
1242 * use a right-handled coordinate system, compared to the rest of OpenAL
1243 * which uses left-handed. This is fixed by negating Z, however it would
1244 * need to also be negated to get a proper Ambisonics angle, thus
1245 * cancelling it out.
1247 a = atan2f(-vec[0], vec[2]);
1248 aluMatrixfSet(&yrot,
1249 1.0f, 0.0f, 0.0f, 0.0f,
1250 0.0f, cosf(a), 0.0f, sinf(a),
1251 0.0f, 0.0f, 1.0f, 0.0f,
1252 0.0f, -sinf(a), 0.0f, cosf(a)
1255 #define MATRIX_MULT(_res, _m1, _m2) do { \
1256 int row, col; \
1257 for(col = 0;col < 4;col++) \
1259 for(row = 0;row < 4;row++) \
1260 _res.m[row][col] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \
1261 _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \
1263 } while(0)
1264 /* Define a matrix that first focuses on Z, then rotates around X then Y to
1265 * focus the output in the direction of the vector.
1267 MATRIX_MULT(tmp1, xrot, zfocus);
1268 MATRIX_MULT(tmp2, yrot, tmp1);
1269 #undef MATRIX_MULT
1271 return tmp2;
1274 /* Update the early and late 3D panning gains. */
1275 static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat gain, const ALfloat earlyGain, const ALfloat lateGain, ALreverbState *State)
1277 aluMatrixf transform, rot;
1278 ALsizei i;
1280 STATIC_CAST(ALeffectState,State)->OutBuffer = Device->FOAOut.Buffer;
1281 STATIC_CAST(ALeffectState,State)->OutChannels = Device->FOAOut.NumChannels;
1283 /* Note: _res is transposed. */
1284 #define MATRIX_MULT(_res, _m1, _m2) do { \
1285 int row, col; \
1286 for(col = 0;col < 4;col++) \
1288 for(row = 0;row < 4;row++) \
1289 _res.m[col][row] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \
1290 _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \
1292 } while(0)
1293 /* Create a matrix that first converts A-Format to B-Format, then rotates
1294 * the B-Format soundfield according to the panning vector.
1296 rot = GetTransformFromVector(ReflectionsPan);
1297 MATRIX_MULT(transform, rot, A2B);
1298 memset(&State->Early.PanGain, 0, sizeof(State->Early.PanGain));
1299 for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
1300 ComputeFirstOrderGains(Device->FOAOut, transform.m[i], gain*earlyGain, State->Early.PanGain[i]);
1302 rot = GetTransformFromVector(LateReverbPan);
1303 MATRIX_MULT(transform, rot, A2B);
1304 memset(&State->Late.PanGain, 0, sizeof(State->Late.PanGain));
1305 for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
1306 ComputeFirstOrderGains(Device->FOAOut, transform.m[i], gain*lateGain, State->Late.PanGain[i]);
1307 #undef MATRIX_MULT
1310 static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
1312 ALuint frequency = Device->Frequency;
1313 ALfloat lfScale, hfScale, hfRatio;
1314 ALfloat lfDecayTime, hfDecayTime;
1315 ALfloat gain, gainlf, gainhf;
1316 ALsizei i;
1318 if(Slot->Params.EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb)
1319 State->IsEax = AL_TRUE;
1320 else if(Slot->Params.EffectType == AL_EFFECT_REVERB || EmulateEAXReverb)
1321 State->IsEax = AL_FALSE;
1323 /* Calculate the master filters */
1324 hfScale = props->Reverb.HFReference / frequency;
1325 /* Restrict the filter gains from going below -60dB to keep the filter from
1326 * killing most of the signal.
1328 gainhf = maxf(props->Reverb.GainHF, 0.001f);
1329 ALfilterState_setParams(&State->Filter[0].Lp, ALfilterType_HighShelf,
1330 gainhf, hfScale, calc_rcpQ_from_slope(gainhf, 1.0f));
1331 lfScale = props->Reverb.LFReference / frequency;
1332 gainlf = maxf(props->Reverb.GainLF, 0.001f);
1333 ALfilterState_setParams(&State->Filter[0].Hp, ALfilterType_LowShelf,
1334 gainlf, lfScale, calc_rcpQ_from_slope(gainlf, 1.0f));
1335 for(i = 1;i < 4;i++)
1337 ALfilterState_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp);
1338 ALfilterState_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp);
1341 /* Update the main effect delay and associated taps. */
1342 UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay,
1343 props->Reverb.Density, props->Reverb.DecayTime, frequency,
1344 State);
1346 /* Calculate the all-pass feed-back/forward coefficient. */
1347 State->ApFeedCoeff = sqrtf(0.5f) * powf(props->Reverb.Diffusion, 2.0f);
1349 /* Update the early lines. */
1350 UpdateEarlyLines(props->Reverb.Density, props->Reverb.DecayTime,
1351 frequency, State);
1353 /* Get the mixing matrix coefficients. */
1354 CalcMatrixCoeffs(props->Reverb.Diffusion, &State->MixX, &State->MixY);
1356 /* If the HF limit parameter is flagged, calculate an appropriate limit
1357 * based on the air absorption parameter.
1359 hfRatio = props->Reverb.DecayHFRatio;
1360 if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f)
1361 hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF,
1362 props->Reverb.DecayTime);
1364 /* Calculate the LF/HF decay times. */
1365 lfDecayTime = clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio,
1366 AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME);
1367 hfDecayTime = clampf(props->Reverb.DecayTime * hfRatio,
1368 AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME);
1370 /* Update the modulator line. */
1371 UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth,
1372 frequency, State);
1374 /* Update the late lines. */
1375 UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion,
1376 lfDecayTime, props->Reverb.DecayTime, hfDecayTime,
1377 F_TAU * lfScale, F_TAU * hfScale,
1378 props->Reverb.EchoTime, props->Reverb.EchoDepth,
1379 frequency, State);
1381 /* Update early and late 3D panning. */
1382 gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost;
1383 Update3DPanning(Device, props->Reverb.ReflectionsPan,
1384 props->Reverb.LateReverbPan, gain,
1385 props->Reverb.ReflectionsGain,
1386 props->Reverb.LateReverbGain, State);
1388 /* Determine if delay-line cross-fading is required. */
1389 for(i = 0;i < 4;i++)
1391 if((State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0]) ||
1392 (State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0]) ||
1393 (State->Early.Offset[i][1] != State->Early.Offset[i][0]) ||
1394 (State->LateDelayTap[i][1] != State->LateDelayTap[i][0]) ||
1395 (State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0]) ||
1396 (State->Late.Offset[i][1] != State->Late.Offset[i][0]))
1398 State->FadeCount = 0;
1399 break;
1405 /**************************************
1406 * Effect Processing *
1407 **************************************/
1409 /* Basic delay line input/output routines. */
1410 static inline ALfloat DelayLineOut(const DelayLineI *Delay, const ALsizei offset, const ALsizei c)
1412 return Delay->Line[offset&Delay->Mask][c];
1415 /* Cross-faded delay line output routine. Instead of interpolating the
1416 * offsets, this interpolates (cross-fades) the outputs at each offset.
1418 static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei off0,
1419 const ALsizei off1, const ALsizei c, const ALfloat mu)
1421 return lerp(Delay->Line[off0&Delay->Mask][c], Delay->Line[off1&Delay->Mask][c], mu);
1423 #define DELAY_OUT_Faded(d, o0, o1, c, mu) FadedDelayLineOut(d, o0, o1, c, mu)
1424 #define DELAY_OUT_Unfaded(d, o0, o1, c, mu) DelayLineOut(d, o0, c)
1426 static inline ALvoid DelayLineIn(DelayLineI *Delay, const ALsizei offset, const ALsizei c, const ALfloat in)
1428 Delay->Line[offset&Delay->Mask][c] = in;
1431 static inline ALvoid DelayLineIn4(DelayLineI *Delay, ALsizei offset, const ALfloat in[4])
1433 ALsizei i;
1434 offset &= Delay->Mask;
1435 for(i = 0;i < 4;i++)
1436 Delay->Line[offset][i] = in[i];
1439 static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const ALfloat in[4])
1441 ALsizei i;
1442 offset &= Delay->Mask;
1443 for(i = 0;i < 4;i++)
1444 Delay->Line[offset][i] = in[3-i];
1447 static void CalcModulationDelays(ALreverbState *State, ALint *restrict delays, const ALsizei todo)
1449 ALfloat sinus, range;
1450 ALsizei index, i;
1452 index = State->Mod.Index;
1453 range = State->Mod.Filter;
1454 for(i = 0;i < todo;i++)
1456 /* Calculate the sinus rhythm (dependent on modulation time and the
1457 * sampling rate).
1459 sinus = sinf(F_TAU * index / State->Mod.Range);
1461 /* Step the modulation index forward, keeping it bound to its range. */
1462 index = (index+1) % State->Mod.Range;
1464 /* The depth determines the range over which to read the input samples
1465 * from, so it must be filtered to reduce the distortion caused by even
1466 * small parameter changes.
1468 range = lerp(range, State->Mod.Depth, State->Mod.Coeff);
1470 /* Calculate the read offset. */
1471 delays[i] = lroundf(range*sinus);
1473 State->Mod.Index = index;
1474 State->Mod.Filter = range;
1477 /* Applies a scattering matrix to the 4-line (vector) input. This is used
1478 * for both the below vector all-pass model and to perform modal feed-back
1479 * delay network (FDN) mixing.
1481 * The matrix is derived from a skew-symmetric matrix to form a 4D rotation
1482 * matrix with a single unitary rotational parameter:
1484 * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
1485 * [ -a, d, c, -b ]
1486 * [ -b, -c, d, a ]
1487 * [ -c, b, -a, d ]
1489 * The rotation is constructed from the effect's diffusion parameter,
1490 * yielding:
1492 * 1 = x^2 + 3 y^2
1494 * Where a, b, and c are the coefficient y with differing signs, and d is the
1495 * coefficient x. The final matrix is thus:
1497 * [ x, y, -y, y ] n = sqrt(matrix_order - 1)
1498 * [ -y, x, y, y ] t = diffusion_parameter * atan(n)
1499 * [ y, -y, x, y ] x = cos(t)
1500 * [ -y, -y, -y, x ] y = sin(t) / n
1502 * Any square orthogonal matrix with an order that is a power of two will
1503 * work (where ^T is transpose, ^-1 is inverse):
1505 * M^T = M^-1
1507 * Using that knowledge, finding an appropriate matrix can be accomplished
1508 * naively by searching all combinations of:
1510 * M = D + S - S^T
1512 * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y)
1513 * whose combination of signs are being iterated.
1515 static inline void VectorPartialScatter(ALfloat *restrict vec, const ALfloat xCoeff, const ALfloat yCoeff)
1517 const ALfloat f[4] = { vec[0], vec[1], vec[2], vec[3] };
1519 vec[0] = xCoeff*f[0] + yCoeff*( f[1] + -f[2] + f[3]);
1520 vec[1] = xCoeff*f[1] + yCoeff*(-f[0] + f[2] + f[3]);
1521 vec[2] = xCoeff*f[2] + yCoeff*( f[0] + -f[1] + f[3]);
1522 vec[3] = xCoeff*f[3] + yCoeff*(-f[0] + -f[1] + -f[2] );
1525 /* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass
1526 * filter to the 4-line input.
1528 * It works by vectorizing a regular all-pass filter and replacing the delay
1529 * element with a scattering matrix (like the one above) and a diagonal
1530 * matrix of delay elements.
1532 * Two static specializations are used for transitional (cross-faded) delay
1533 * line processing and non-transitional processing.
1535 #define DECL_TEMPLATE(T) \
1536 static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \
1537 const ALfloat feedCoeff, const ALfloat xCoeff, \
1538 const ALfloat yCoeff, const ALfloat mu, \
1539 VecAllpass *Vap) \
1541 ALfloat input; \
1542 ALfloat f[4]; \
1543 ALsizei i; \
1545 (void)mu; /* Ignore for Unfaded. */ \
1547 for(i = 0;i < 4;i++) \
1549 input = vec[i]; \
1550 vec[i] = DELAY_OUT_##T(&Vap->Delay, offset-Vap->Offset[i][0], \
1551 offset-Vap->Offset[i][1], i, mu) - \
1552 feedCoeff*input; \
1553 f[i] = input + feedCoeff*vec[i]; \
1556 VectorPartialScatter(f, xCoeff, yCoeff); \
1558 DelayLineIn4(&Vap->Delay, offset, f); \
1560 DECL_TEMPLATE(Unfaded)
1561 DECL_TEMPLATE(Faded)
1562 #undef DECL_TEMPLATE
1564 /* A helper to reverse vector components. */
1565 static inline void VectorReverse(ALfloat vec[4])
1567 const ALfloat f[4] = { vec[0], vec[1], vec[2], vec[3] };
1569 vec[0] = f[3];
1570 vec[1] = f[2];
1571 vec[2] = f[1];
1572 vec[3] = f[0];
1575 /* This generates early reflections.
1577 * This is done by obtaining the primary reflections (those arriving from the
1578 * same direction as the source) from the main delay line. These are
1579 * attenuated and all-pass filtered (based on the diffusion parameter).
1581 * The early lines are then fed in reverse (according to the approximately
1582 * opposite spatial location of the A-Format lines) to create the secondary
1583 * reflections (those arriving from the opposite direction as the source).
1585 * The early response is then completed by combining the primary reflections
1586 * with the delayed and attenuated output from the early lines.
1588 * Finally, the early response is reversed, scattered (based on diffusion),
1589 * and fed into the late reverb section of the main delay line.
1591 * Two static specializations are used for transitional (cross-faded) delay
1592 * line processing and non-transitional processing.
1594 #define DECL_TEMPLATE(T) \
1595 static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \
1596 ALfloat fade, \
1597 ALfloat (*restrict out)[MAX_UPDATE_SAMPLES])\
1599 ALsizei offset = State->Offset; \
1600 const ALfloat apFeedCoeff = State->ApFeedCoeff; \
1601 const ALfloat mixX = State->MixX; \
1602 const ALfloat mixY = State->MixY; \
1603 ALfloat f[4]; \
1604 ALsizei i, j; \
1606 for(i = 0;i < todo;i++) \
1608 for(j = 0;j < 4;j++) \
1609 f[j] = DELAY_OUT_##T(&State->Delay, \
1610 offset-State->EarlyDelayTap[j][0], \
1611 offset-State->EarlyDelayTap[j][1], j, fade \
1612 ) * State->EarlyDelayCoeff[j]; \
1614 VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \
1615 &State->Early.VecAp); \
1617 DelayLineIn4Rev(&State->Early.Delay, offset, f); \
1619 for(j = 0;j < 4;j++) \
1620 f[j] += DELAY_OUT_##T(&State->Early.Delay, \
1621 offset-State->Early.Offset[j][0], \
1622 offset-State->Early.Offset[j][1], j, fade \
1623 ) * State->Early.Coeff[j]; \
1625 for(j = 0;j < 4;j++) \
1626 out[j][i] = f[j]; \
1628 VectorReverse(f); \
1630 VectorPartialScatter(f, mixX, mixY); \
1632 DelayLineIn4(&State->Delay, offset-State->LateFeedTap, f); \
1634 offset++; \
1635 fade += FadeStep; \
1638 DECL_TEMPLATE(Unfaded)
1639 DECL_TEMPLATE(Faded)
1640 #undef DECL_TEMPLATE
1642 /* Applies a first order filter section. */
1643 static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat coeffs[3], ALfloat state[2])
1645 ALfloat out = coeffs[0]*in + coeffs[1]*state[0] + coeffs[2]*state[1];
1647 state[0] = in;
1648 state[1] = out;
1650 return out;
1653 /* Applies the two T60 damping filter sections. */
1654 static inline ALfloat LateT60Filter(const ALsizei index, const ALfloat in, ALreverbState *State)
1656 ALfloat out = FirstOrderFilter(in, State->Late.Filters[index].LFCoeffs,
1657 State->Late.Filters[index].States[0]);
1659 return State->Late.Filters[index].MidCoeff *
1660 FirstOrderFilter(out, State->Late.Filters[index].HFCoeffs,
1661 State->Late.Filters[index].States[1]);
1664 /* This generates the reverb tail using a modified feed-back delay network
1665 * (FDN).
1667 * Results from the early reflections are attenuated by the density gain and
1668 * mixed with the output from the late delay lines.
1670 * The late response is then completed by T60 and all-pass filtering the mix.
1672 * Finally, the lines are reversed (so they feed their opposite directions)
1673 * and scattered with the FDN matrix before re-feeding the delay lines.
1675 * Two static specializations are used for transitional (cross-faded) delay
1676 * line processing and non-transitional processing.
1678 #define DECL_TEMPLATE(T) \
1679 static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \
1680 ALfloat fade, \
1681 ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) \
1683 const ALfloat apFeedCoeff = State->ApFeedCoeff; \
1684 const ALfloat mixX = State->MixX; \
1685 const ALfloat mixY = State->MixY; \
1686 ALint moddelay[MAX_UPDATE_SAMPLES]; \
1687 ALsizei delay; \
1688 ALsizei offset; \
1689 ALsizei i, j; \
1690 ALfloat f[4]; \
1692 CalcModulationDelays(State, moddelay, todo); \
1694 offset = State->Offset; \
1695 for(i = 0;i < todo;i++) \
1697 for(j = 0;j < 4;j++) \
1698 f[j] = DELAY_OUT_##T(&State->Delay, \
1699 offset-State->LateDelayTap[j][0], \
1700 offset-State->LateDelayTap[j][1], j, fade \
1701 ) * State->Late.DensityGain; \
1703 delay = offset - moddelay[i]; \
1704 for(j = 0;j < 4;j++) \
1705 f[j] += DELAY_OUT_##T(&State->Late.Delay, \
1706 delay-State->Late.Offset[j][0], \
1707 delay-State->Late.Offset[j][1], j, fade \
1708 ); \
1710 for(j = 0;j < 4;j++) \
1711 f[j] = LateT60Filter(j, f[j], State); \
1713 VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \
1714 &State->Late.VecAp); \
1716 for(j = 0;j < 4;j++) \
1717 out[j][i] = f[j]; \
1719 VectorReverse(f); \
1721 VectorPartialScatter(f, mixX, mixY); \
1723 DelayLineIn4(&State->Late.Delay, offset, f); \
1725 offset++; \
1726 fade += FadeStep; \
1729 DECL_TEMPLATE(Unfaded)
1730 DECL_TEMPLATE(Faded)
1731 #undef DECL_TEMPLATE
1733 typedef ALfloat (*ProcMethodType)(ALreverbState *State, const ALsizei todo, ALfloat fade,
1734 const ALfloat (*restrict input)[MAX_UPDATE_SAMPLES],
1735 ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]);
1737 /* Perform the non-EAX reverb pass on a given input sample, resulting in
1738 * four-channel output.
1740 static ALfloat VerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade,
1741 const ALfloat (*restrict input)[MAX_UPDATE_SAMPLES],
1742 ALfloat (*restrict early)[MAX_UPDATE_SAMPLES],
1743 ALfloat (*restrict late)[MAX_UPDATE_SAMPLES])
1745 ALsizei i, c;
1747 for(c = 0;c < 4;c++)
1749 /* Low-pass filter the incoming samples (use the early buffer as temp
1750 * storage).
1752 ALfilterState_process(&State->Filter[c].Lp, &early[0][0], input[c], todo);
1754 /* Feed the initial delay line. */
1755 for(i = 0;i < todo;i++)
1756 DelayLineIn(&State->Delay, State->Offset+i, c, early[0][i]);
1759 if(fade < 1.0f)
1761 /* Generate early reflections. */
1762 EarlyReflection_Faded(State, todo, fade, early);
1764 /* Generate late reverb. */
1765 LateReverb_Faded(State, todo, fade, late);
1766 fade = minf(1.0f, fade + todo*FadeStep);
1768 else
1770 /* Generate early reflections. */
1771 EarlyReflection_Unfaded(State, todo, fade, early);
1773 /* Generate late reverb. */
1774 LateReverb_Unfaded(State, todo, fade, late);
1777 /* Step all delays forward one sample. */
1778 State->Offset += todo;
1780 return fade;
1783 /* Perform the EAX reverb pass on a given input sample, resulting in four-
1784 * channel output.
1786 static ALfloat EAXVerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade,
1787 const ALfloat (*restrict input)[MAX_UPDATE_SAMPLES],
1788 ALfloat (*restrict early)[MAX_UPDATE_SAMPLES],
1789 ALfloat (*restrict late)[MAX_UPDATE_SAMPLES])
1791 ALsizei i, c;
1793 for(c = 0;c < 4;c++)
1795 /* Band-pass the incoming samples. Use the early output lines for temp
1796 * storage.
1798 ALfilterState_process(&State->Filter[c].Lp, early[0], input[c], todo);
1799 ALfilterState_process(&State->Filter[c].Hp, early[1], early[0], todo);
1801 /* Feed the initial delay line. */
1802 for(i = 0;i < todo;i++)
1803 DelayLineIn(&State->Delay, State->Offset+i, c, early[1][i]);
1806 if(fade < 1.0f)
1808 /* Generate early reflections. */
1809 EarlyReflection_Faded(State, todo, fade, early);
1811 /* Generate late reverb. */
1812 LateReverb_Faded(State, todo, fade, late);
1813 fade = minf(1.0f, fade + todo*FadeStep);
1815 else
1817 /* Generate early reflections. */
1818 EarlyReflection_Unfaded(State, todo, fade, early);
1820 /* Generate late reverb. */
1821 LateReverb_Unfaded(State, todo, fade, late);
1824 /* Step all delays forward. */
1825 State->Offset += todo;
1827 return fade;
1830 static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
1832 ProcMethodType ReverbProc = State->IsEax ? EAXVerbPass : VerbPass;
1833 ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples;
1834 ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples;
1835 ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples;
1836 ALsizei fadeCount = State->FadeCount;
1837 ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES;
1838 ALsizei base, c;
1840 /* Process reverb for these samples. */
1841 for(base = 0;base < SamplesToDo;)
1843 ALsizei todo = mini(SamplesToDo-base, MAX_UPDATE_SAMPLES);
1844 /* If cross-fading, don't do more samples than there are to fade. */
1845 if(FADE_SAMPLES-fadeCount > 0)
1846 todo = mini(todo, FADE_SAMPLES-fadeCount);
1848 /* Convert B-Format to A-Format for processing. */
1849 memset(afmt, 0, sizeof(*afmt)*4);
1850 for(c = 0;c < 4;c++)
1851 MixRowSamples(afmt[c], B2A.m[c],
1852 SamplesIn, MAX_EFFECT_CHANNELS, base, todo
1855 /* Process the samples for reverb. */
1856 fade = ReverbProc(State, todo, fade, afmt, early, late);
1857 if(UNEXPECTED(fadeCount < FADE_SAMPLES) && (fadeCount += todo) >= FADE_SAMPLES)
1859 /* Update the cross-fading delay line taps. */
1860 fadeCount = FADE_SAMPLES;
1861 fade = 1.0f;
1862 for(c = 0;c < 4;c++)
1864 State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1];
1865 State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1];
1866 State->Early.Offset[c][0] = State->Early.Offset[c][1];
1867 State->LateDelayTap[c][0] = State->LateDelayTap[c][1];
1868 State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1];
1869 State->Late.Offset[c][0] = State->Late.Offset[c][1];
1873 /* Mix the A-Format results to output, implicitly converting back to
1874 * B-Format.
1876 for(c = 0;c < 4;c++)
1877 MixSamples(early[c], NumChannels, SamplesOut,
1878 State->Early.CurrentGain[c], State->Early.PanGain[c],
1879 SamplesToDo-base, base, todo
1881 for(c = 0;c < 4;c++)
1882 MixSamples(late[c], NumChannels, SamplesOut,
1883 State->Late.CurrentGain[c], State->Late.PanGain[c],
1884 SamplesToDo-base, base, todo
1887 base += todo;
1889 State->FadeCount = fadeCount;
1893 typedef struct ALreverbStateFactory {
1894 DERIVE_FROM_TYPE(ALeffectStateFactory);
1895 } ALreverbStateFactory;
1897 static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(factory))
1899 ALreverbState *state;
1901 alcall_once(&mixfunc_inited, init_mixfunc);
1903 NEW_OBJ0(state, ALreverbState)();
1904 if(!state) return NULL;
1906 return STATIC_CAST(ALeffectState, state);
1909 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALreverbStateFactory);
1911 ALeffectStateFactory *ALreverbStateFactory_getFactory(void)
1913 static ALreverbStateFactory ReverbFactory = { { GET_VTABLE2(ALreverbStateFactory, ALeffectStateFactory) } };
1915 return STATIC_CAST(ALeffectStateFactory, &ReverbFactory);
1919 void ALeaxreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
1921 ALeffectProps *props = &effect->Props;
1922 switch(param)
1924 case AL_EAXREVERB_DECAY_HFLIMIT:
1925 if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT))
1926 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1927 props->Reverb.DecayHFLimit = val;
1928 break;
1930 default:
1931 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
1934 void ALeaxreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
1936 ALeaxreverb_setParami(effect, context, param, vals[0]);
1938 void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
1940 ALeffectProps *props = &effect->Props;
1941 switch(param)
1943 case AL_EAXREVERB_DENSITY:
1944 if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY))
1945 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1946 props->Reverb.Density = val;
1947 break;
1949 case AL_EAXREVERB_DIFFUSION:
1950 if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION))
1951 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1952 props->Reverb.Diffusion = val;
1953 break;
1955 case AL_EAXREVERB_GAIN:
1956 if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN))
1957 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1958 props->Reverb.Gain = val;
1959 break;
1961 case AL_EAXREVERB_GAINHF:
1962 if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF))
1963 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1964 props->Reverb.GainHF = val;
1965 break;
1967 case AL_EAXREVERB_GAINLF:
1968 if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF))
1969 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1970 props->Reverb.GainLF = val;
1971 break;
1973 case AL_EAXREVERB_DECAY_TIME:
1974 if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME))
1975 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1976 props->Reverb.DecayTime = val;
1977 break;
1979 case AL_EAXREVERB_DECAY_HFRATIO:
1980 if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO))
1981 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1982 props->Reverb.DecayHFRatio = val;
1983 break;
1985 case AL_EAXREVERB_DECAY_LFRATIO:
1986 if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO))
1987 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1988 props->Reverb.DecayLFRatio = val;
1989 break;
1991 case AL_EAXREVERB_REFLECTIONS_GAIN:
1992 if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN))
1993 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1994 props->Reverb.ReflectionsGain = val;
1995 break;
1997 case AL_EAXREVERB_REFLECTIONS_DELAY:
1998 if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY))
1999 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2000 props->Reverb.ReflectionsDelay = val;
2001 break;
2003 case AL_EAXREVERB_LATE_REVERB_GAIN:
2004 if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN))
2005 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2006 props->Reverb.LateReverbGain = val;
2007 break;
2009 case AL_EAXREVERB_LATE_REVERB_DELAY:
2010 if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY))
2011 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2012 props->Reverb.LateReverbDelay = val;
2013 break;
2015 case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
2016 if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF))
2017 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2018 props->Reverb.AirAbsorptionGainHF = val;
2019 break;
2021 case AL_EAXREVERB_ECHO_TIME:
2022 if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME))
2023 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2024 props->Reverb.EchoTime = val;
2025 break;
2027 case AL_EAXREVERB_ECHO_DEPTH:
2028 if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH))
2029 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2030 props->Reverb.EchoDepth = val;
2031 break;
2033 case AL_EAXREVERB_MODULATION_TIME:
2034 if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME))
2035 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2036 props->Reverb.ModulationTime = val;
2037 break;
2039 case AL_EAXREVERB_MODULATION_DEPTH:
2040 if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH))
2041 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2042 props->Reverb.ModulationDepth = val;
2043 break;
2045 case AL_EAXREVERB_HFREFERENCE:
2046 if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE))
2047 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2048 props->Reverb.HFReference = val;
2049 break;
2051 case AL_EAXREVERB_LFREFERENCE:
2052 if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE))
2053 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2054 props->Reverb.LFReference = val;
2055 break;
2057 case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
2058 if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR))
2059 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2060 props->Reverb.RoomRolloffFactor = val;
2061 break;
2063 default:
2064 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2067 void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
2069 ALeffectProps *props = &effect->Props;
2070 switch(param)
2072 case AL_EAXREVERB_REFLECTIONS_PAN:
2073 if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])))
2074 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2075 props->Reverb.ReflectionsPan[0] = vals[0];
2076 props->Reverb.ReflectionsPan[1] = vals[1];
2077 props->Reverb.ReflectionsPan[2] = vals[2];
2078 break;
2079 case AL_EAXREVERB_LATE_REVERB_PAN:
2080 if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])))
2081 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2082 props->Reverb.LateReverbPan[0] = vals[0];
2083 props->Reverb.LateReverbPan[1] = vals[1];
2084 props->Reverb.LateReverbPan[2] = vals[2];
2085 break;
2087 default:
2088 ALeaxreverb_setParamf(effect, context, param, vals[0]);
2089 break;
2093 void ALeaxreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
2095 const ALeffectProps *props = &effect->Props;
2096 switch(param)
2098 case AL_EAXREVERB_DECAY_HFLIMIT:
2099 *val = props->Reverb.DecayHFLimit;
2100 break;
2102 default:
2103 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2106 void ALeaxreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
2108 ALeaxreverb_getParami(effect, context, param, vals);
2110 void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
2112 const ALeffectProps *props = &effect->Props;
2113 switch(param)
2115 case AL_EAXREVERB_DENSITY:
2116 *val = props->Reverb.Density;
2117 break;
2119 case AL_EAXREVERB_DIFFUSION:
2120 *val = props->Reverb.Diffusion;
2121 break;
2123 case AL_EAXREVERB_GAIN:
2124 *val = props->Reverb.Gain;
2125 break;
2127 case AL_EAXREVERB_GAINHF:
2128 *val = props->Reverb.GainHF;
2129 break;
2131 case AL_EAXREVERB_GAINLF:
2132 *val = props->Reverb.GainLF;
2133 break;
2135 case AL_EAXREVERB_DECAY_TIME:
2136 *val = props->Reverb.DecayTime;
2137 break;
2139 case AL_EAXREVERB_DECAY_HFRATIO:
2140 *val = props->Reverb.DecayHFRatio;
2141 break;
2143 case AL_EAXREVERB_DECAY_LFRATIO:
2144 *val = props->Reverb.DecayLFRatio;
2145 break;
2147 case AL_EAXREVERB_REFLECTIONS_GAIN:
2148 *val = props->Reverb.ReflectionsGain;
2149 break;
2151 case AL_EAXREVERB_REFLECTIONS_DELAY:
2152 *val = props->Reverb.ReflectionsDelay;
2153 break;
2155 case AL_EAXREVERB_LATE_REVERB_GAIN:
2156 *val = props->Reverb.LateReverbGain;
2157 break;
2159 case AL_EAXREVERB_LATE_REVERB_DELAY:
2160 *val = props->Reverb.LateReverbDelay;
2161 break;
2163 case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
2164 *val = props->Reverb.AirAbsorptionGainHF;
2165 break;
2167 case AL_EAXREVERB_ECHO_TIME:
2168 *val = props->Reverb.EchoTime;
2169 break;
2171 case AL_EAXREVERB_ECHO_DEPTH:
2172 *val = props->Reverb.EchoDepth;
2173 break;
2175 case AL_EAXREVERB_MODULATION_TIME:
2176 *val = props->Reverb.ModulationTime;
2177 break;
2179 case AL_EAXREVERB_MODULATION_DEPTH:
2180 *val = props->Reverb.ModulationDepth;
2181 break;
2183 case AL_EAXREVERB_HFREFERENCE:
2184 *val = props->Reverb.HFReference;
2185 break;
2187 case AL_EAXREVERB_LFREFERENCE:
2188 *val = props->Reverb.LFReference;
2189 break;
2191 case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
2192 *val = props->Reverb.RoomRolloffFactor;
2193 break;
2195 default:
2196 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2199 void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
2201 const ALeffectProps *props = &effect->Props;
2202 switch(param)
2204 case AL_EAXREVERB_REFLECTIONS_PAN:
2205 vals[0] = props->Reverb.ReflectionsPan[0];
2206 vals[1] = props->Reverb.ReflectionsPan[1];
2207 vals[2] = props->Reverb.ReflectionsPan[2];
2208 break;
2209 case AL_EAXREVERB_LATE_REVERB_PAN:
2210 vals[0] = props->Reverb.LateReverbPan[0];
2211 vals[1] = props->Reverb.LateReverbPan[1];
2212 vals[2] = props->Reverb.LateReverbPan[2];
2213 break;
2215 default:
2216 ALeaxreverb_getParamf(effect, context, param, vals);
2217 break;
2221 DEFINE_ALEFFECT_VTABLE(ALeaxreverb);
2223 void ALreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
2225 ALeffectProps *props = &effect->Props;
2226 switch(param)
2228 case AL_REVERB_DECAY_HFLIMIT:
2229 if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT))
2230 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2231 props->Reverb.DecayHFLimit = val;
2232 break;
2234 default:
2235 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2238 void ALreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
2240 ALreverb_setParami(effect, context, param, vals[0]);
2242 void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
2244 ALeffectProps *props = &effect->Props;
2245 switch(param)
2247 case AL_REVERB_DENSITY:
2248 if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY))
2249 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2250 props->Reverb.Density = val;
2251 break;
2253 case AL_REVERB_DIFFUSION:
2254 if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION))
2255 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2256 props->Reverb.Diffusion = val;
2257 break;
2259 case AL_REVERB_GAIN:
2260 if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN))
2261 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2262 props->Reverb.Gain = val;
2263 break;
2265 case AL_REVERB_GAINHF:
2266 if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF))
2267 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2268 props->Reverb.GainHF = val;
2269 break;
2271 case AL_REVERB_DECAY_TIME:
2272 if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME))
2273 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2274 props->Reverb.DecayTime = val;
2275 break;
2277 case AL_REVERB_DECAY_HFRATIO:
2278 if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO))
2279 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2280 props->Reverb.DecayHFRatio = val;
2281 break;
2283 case AL_REVERB_REFLECTIONS_GAIN:
2284 if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN))
2285 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2286 props->Reverb.ReflectionsGain = val;
2287 break;
2289 case AL_REVERB_REFLECTIONS_DELAY:
2290 if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY))
2291 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2292 props->Reverb.ReflectionsDelay = val;
2293 break;
2295 case AL_REVERB_LATE_REVERB_GAIN:
2296 if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN))
2297 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2298 props->Reverb.LateReverbGain = val;
2299 break;
2301 case AL_REVERB_LATE_REVERB_DELAY:
2302 if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY))
2303 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2304 props->Reverb.LateReverbDelay = val;
2305 break;
2307 case AL_REVERB_AIR_ABSORPTION_GAINHF:
2308 if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF))
2309 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2310 props->Reverb.AirAbsorptionGainHF = val;
2311 break;
2313 case AL_REVERB_ROOM_ROLLOFF_FACTOR:
2314 if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR))
2315 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2316 props->Reverb.RoomRolloffFactor = val;
2317 break;
2319 default:
2320 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2323 void ALreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
2325 ALreverb_setParamf(effect, context, param, vals[0]);
2328 void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
2330 const ALeffectProps *props = &effect->Props;
2331 switch(param)
2333 case AL_REVERB_DECAY_HFLIMIT:
2334 *val = props->Reverb.DecayHFLimit;
2335 break;
2337 default:
2338 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2341 void ALreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
2343 ALreverb_getParami(effect, context, param, vals);
2345 void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
2347 const ALeffectProps *props = &effect->Props;
2348 switch(param)
2350 case AL_REVERB_DENSITY:
2351 *val = props->Reverb.Density;
2352 break;
2354 case AL_REVERB_DIFFUSION:
2355 *val = props->Reverb.Diffusion;
2356 break;
2358 case AL_REVERB_GAIN:
2359 *val = props->Reverb.Gain;
2360 break;
2362 case AL_REVERB_GAINHF:
2363 *val = props->Reverb.GainHF;
2364 break;
2366 case AL_REVERB_DECAY_TIME:
2367 *val = props->Reverb.DecayTime;
2368 break;
2370 case AL_REVERB_DECAY_HFRATIO:
2371 *val = props->Reverb.DecayHFRatio;
2372 break;
2374 case AL_REVERB_REFLECTIONS_GAIN:
2375 *val = props->Reverb.ReflectionsGain;
2376 break;
2378 case AL_REVERB_REFLECTIONS_DELAY:
2379 *val = props->Reverb.ReflectionsDelay;
2380 break;
2382 case AL_REVERB_LATE_REVERB_GAIN:
2383 *val = props->Reverb.LateReverbGain;
2384 break;
2386 case AL_REVERB_LATE_REVERB_DELAY:
2387 *val = props->Reverb.LateReverbDelay;
2388 break;
2390 case AL_REVERB_AIR_ABSORPTION_GAINHF:
2391 *val = props->Reverb.AirAbsorptionGainHF;
2392 break;
2394 case AL_REVERB_ROOM_ROLLOFF_FACTOR:
2395 *val = props->Reverb.RoomRolloffFactor;
2396 break;
2398 default:
2399 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2402 void ALreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
2404 ALreverb_getParamf(effect, context, param, vals);
2407 DEFINE_ALEFFECT_VTABLE(ALreverb);