Add an option to ignore the app's speed of sound for reverb decay
[openal-soft.git] / Alc / effects / reverb.c
blobee7954c42619a5b6fa6b8c15a8d241939294b7ca
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 "alListener.h"
33 #include "alError.h"
34 #include "mixer_defs.h"
36 /* This is the maximum number of samples processed for each inner loop
37 * iteration. */
38 #define MAX_UPDATE_SAMPLES 256
40 /* The number of samples used for cross-faded delay lines. This can be used
41 * to balance the compensation for abrupt line changes and attenuation due to
42 * minimally lengthed recursive lines. Try to keep this below the device
43 * update size.
45 #define FADE_SAMPLES 128
47 #ifdef __GNUC__
48 #define UNEXPECTED(x) __builtin_expect((bool)(x), 0)
49 #else
50 #define UNEXPECTED(x) (x)
51 #endif
53 static MixerFunc MixSamples = Mix_C;
54 static RowMixerFunc MixRowSamples = MixRow_C;
56 static alonce_flag mixfunc_inited = AL_ONCE_FLAG_INIT;
57 static void init_mixfunc(void)
59 MixSamples = SelectMixer();
60 MixRowSamples = SelectRowMixer();
63 typedef struct DelayLineI {
64 /* The delay lines use interleaved samples, with the lengths being powers
65 * of 2 to allow the use of bit-masking instead of a modulus for wrapping.
67 ALsizei Mask;
68 ALfloat (*Line)[4];
69 } DelayLineI;
71 typedef struct VecAllpass {
72 DelayLineI Delay;
73 ALsizei Offset[4][2];
74 } VecAllpass;
76 typedef struct ALreverbState {
77 DERIVE_FROM_TYPE(ALeffectState);
79 ALboolean IsEax;
81 /* All delay lines are allocated as a single buffer to reduce memory
82 * fragmentation and management code.
84 ALfloat *SampleBuffer;
85 ALuint TotalSamples;
87 /* Master effect filters */
88 struct {
89 ALfilterState Lp;
90 ALfilterState Hp; /* EAX only */
91 } Filter[4];
93 /* Core delay line (early reflections and late reverb tap from this). */
94 DelayLineI Delay;
96 /* Tap points for early reflection delay. */
97 ALsizei EarlyDelayTap[4][2];
98 ALfloat EarlyDelayCoeff[4];
100 /* Tap points for late reverb feed and delay. */
101 ALsizei LateFeedTap;
102 ALsizei LateDelayTap[4][2];
104 /* The feed-back and feed-forward all-pass coefficient. */
105 ALfloat ApFeedCoeff;
107 /* Coefficients for the all-pass and line scattering matrices. */
108 ALfloat MixX;
109 ALfloat MixY;
111 struct {
112 /* A Gerzon vector all-pass filter is used to simulate initial
113 * diffusion. The spread from this filter also helps smooth out the
114 * reverb tail.
116 VecAllpass VecAp;
118 /* An echo line is used to complete the second half of the early
119 * reflections.
121 DelayLineI Delay;
122 ALsizei Offset[4][2];
123 ALfloat Coeff[4];
125 /* The gain for each output channel based on 3D panning. */
126 ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS];
127 ALfloat PanGain[4][MAX_OUTPUT_CHANNELS];
128 } Early;
130 struct {
131 /* The vibrato time is tracked with an index over a modulus-wrapped
132 * range (in samples).
134 ALuint Index;
135 ALuint Range;
137 /* The depth of frequency change (also in samples) and its filter. */
138 ALfloat Depth;
139 ALfloat Coeff;
140 ALfloat Filter;
141 } Mod; /* EAX only */
143 struct {
144 /* Attenuation to compensate for the modal density and decay rate of
145 * the late lines.
147 ALfloat DensityGain;
149 /* A recursive delay line is used fill in the reverb tail. */
150 DelayLineI Delay;
151 ALsizei Offset[4][2];
153 /* T60 decay filters are used to simulate absorption. */
154 struct {
155 ALfloat LFCoeffs[3];
156 ALfloat HFCoeffs[3];
157 ALfloat MidCoeff;
158 /* The LF and HF filters keep a state of the last input and last
159 * output sample.
161 ALfloat States[2][2];
162 } Filters[4];
164 /* A Gerzon vector all-pass filter is used to simulate diffusion. */
165 VecAllpass VecAp;
167 /* The gain for each output channel based on 3D panning. */
168 ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS];
169 ALfloat PanGain[4][MAX_OUTPUT_CHANNELS];
170 } Late;
172 /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */
173 ALsizei FadeCount;
175 /* The current write offset for all delay lines. */
176 ALsizei Offset;
178 /* Temporary storage used when processing. */
179 alignas(16) ALfloat AFormatSamples[4][MAX_UPDATE_SAMPLES];
180 alignas(16) ALfloat ReverbSamples[4][MAX_UPDATE_SAMPLES];
181 alignas(16) ALfloat EarlySamples[4][MAX_UPDATE_SAMPLES];
182 } ALreverbState;
184 static ALvoid ALreverbState_Destruct(ALreverbState *State);
185 static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device);
186 static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props);
187 static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
188 DECLARE_DEFAULT_ALLOCATORS(ALreverbState)
190 DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState);
192 static void ALreverbState_Construct(ALreverbState *state)
194 ALsizei i, j;
196 ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
197 SET_VTABLE2(ALreverbState, ALeffectState, state);
199 state->IsEax = AL_FALSE;
201 state->TotalSamples = 0;
202 state->SampleBuffer = NULL;
204 for(i = 0;i < 4;i++)
206 ALfilterState_clear(&state->Filter[i].Lp);
207 ALfilterState_clear(&state->Filter[i].Hp);
210 state->Delay.Mask = 0;
211 state->Delay.Line = NULL;
213 for(i = 0;i < 4;i++)
215 state->EarlyDelayTap[i][0] = 0;
216 state->EarlyDelayTap[i][1] = 0;
217 state->EarlyDelayCoeff[i] = 0.0f;
220 state->LateFeedTap = 0;
222 for(i = 0;i < 4;i++)
224 state->LateDelayTap[i][0] = 0;
225 state->LateDelayTap[i][1] = 0;
228 state->ApFeedCoeff = 0.0f;
229 state->MixX = 0.0f;
230 state->MixY = 0.0f;
232 state->Early.VecAp.Delay.Mask = 0;
233 state->Early.VecAp.Delay.Line = NULL;
234 state->Early.Delay.Mask = 0;
235 state->Early.Delay.Line = NULL;
236 for(i = 0;i < 4;i++)
238 state->Early.VecAp.Offset[i][0] = 0;
239 state->Early.VecAp.Offset[i][1] = 0;
240 state->Early.Offset[i][0] = 0;
241 state->Early.Offset[i][1] = 0;
242 state->Early.Coeff[i] = 0.0f;
245 state->Mod.Index = 0;
246 state->Mod.Range = 1;
247 state->Mod.Depth = 0.0f;
248 state->Mod.Coeff = 0.0f;
249 state->Mod.Filter = 0.0f;
251 state->Late.DensityGain = 0.0f;
253 state->Late.Delay.Mask = 0;
254 state->Late.Delay.Line = NULL;
255 state->Late.VecAp.Delay.Mask = 0;
256 state->Late.VecAp.Delay.Line = NULL;
257 for(i = 0;i < 4;i++)
259 state->Late.Offset[i][0] = 0;
260 state->Late.Offset[i][1] = 0;
262 state->Late.VecAp.Offset[i][0] = 0;
263 state->Late.VecAp.Offset[i][1] = 0;
265 for(j = 0;j < 3;j++)
267 state->Late.Filters[i].LFCoeffs[j] = 0.0f;
268 state->Late.Filters[i].HFCoeffs[j] = 0.0f;
270 state->Late.Filters[i].MidCoeff = 0.0f;
272 state->Late.Filters[i].States[0][0] = 0.0f;
273 state->Late.Filters[i].States[0][1] = 0.0f;
274 state->Late.Filters[i].States[1][0] = 0.0f;
275 state->Late.Filters[i].States[1][1] = 0.0f;
278 for(i = 0;i < 4;i++)
280 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
282 state->Early.CurrentGain[i][j] = 0.0f;
283 state->Early.PanGain[i][j] = 0.0f;
284 state->Late.CurrentGain[i][j] = 0.0f;
285 state->Late.PanGain[i][j] = 0.0f;
289 state->FadeCount = 0;
290 state->Offset = 0;
293 static ALvoid ALreverbState_Destruct(ALreverbState *State)
295 al_free(State->SampleBuffer);
296 State->SampleBuffer = NULL;
298 ALeffectState_Destruct(STATIC_CAST(ALeffectState,State));
301 /* The B-Format to A-Format conversion matrix. The arrangement of rows is
302 * deliberately chosen to align the resulting lines to their spatial opposites
303 * (0:above front left <-> 3:above back right, 1:below front right <-> 2:below
304 * back left). It's not quite opposite, since the A-Format results in a
305 * tetrahedron, but it's close enough. Should the model be extended to 8-lines
306 * in the future, true opposites can be used.
308 static const aluMatrixf B2A = {{
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 },
312 { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f }
315 /* Converts A-Format to B-Format. */
316 static const aluMatrixf A2B = {{
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 },
320 { 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f }
323 static const ALfloat FadeStep = 1.0f / FADE_SAMPLES;
325 /* This is a user config option for modifying the overall output of the reverb
326 * effect.
328 ALfloat ReverbBoost = 1.0f;
330 /* Specifies whether to use a standard reverb effect in place of EAX reverb (no
331 * high-pass, modulation, or echo).
333 ALboolean EmulateEAXReverb = AL_FALSE;
335 /* The all-pass and delay lines have a variable length dependent on the
336 * effect's density parameter. The resulting density multiplier is:
338 * multiplier = 1 + (density * LINE_MULTIPLIER)
340 * Thus the line multiplier below will result in a maximum density multiplier
341 * of 10.
343 static const ALfloat LINE_MULTIPLIER = 9.0f;
345 /* All delay line lengths are specified in seconds.
347 * To approximate early reflections, we break them up into primary (those
348 * arriving from the same direction as the source) and secondary (those
349 * arriving from the opposite direction).
351 * The early taps decorrelate the 4-channel signal to approximate an average
352 * room response for the primary reflections after the initial early delay.
354 * Given an average room dimension (d_a) and the speed of sound (c) we can
355 * calculate the average reflection delay (r_a) regardless of listener and
356 * source positions as:
358 * r_a = d_a / c
359 * c = 343.3
361 * This can extended to finding the average difference (r_d) between the
362 * maximum (r_1) and minimum (r_0) reflection delays:
364 * r_0 = 2 / 3 r_a
365 * = r_a - r_d / 2
366 * = r_d
367 * r_1 = 4 / 3 r_a
368 * = r_a + r_d / 2
369 * = 2 r_d
370 * r_d = 2 / 3 r_a
371 * = r_1 - r_0
373 * As can be determined by integrating the 1D model with a source (s) and
374 * listener (l) positioned across the dimension of length (d_a):
376 * r_d = int_(l=0)^d_a (int_(s=0)^d_a |2 d_a - 2 (l + s)| ds) dl / c
378 * The initial taps (T_(i=0)^N) are then specified by taking a power series
379 * that ranges between r_0 and half of r_1 less r_0:
381 * R_i = 2^(i / (2 N - 1)) r_d
382 * = r_0 + (2^(i / (2 N - 1)) - 1) r_d
383 * = r_0 + T_i
384 * T_i = R_i - r_0
385 * = (2^(i / (2 N - 1)) - 1) r_d
387 * Assuming an average of 5m (up to 50m with the density multiplier), we get
388 * the following taps:
390 static const ALfloat EARLY_TAP_LENGTHS[4] =
392 0.000000e+0f, 1.010676e-3f, 2.126553e-3f, 3.358580e-3f
395 /* The early all-pass filter lengths are based on the early tap lengths:
397 * A_i = R_i / a
399 * Where a is the approximate maximum all-pass cycle limit (20).
401 static const ALfloat EARLY_ALLPASS_LENGTHS[4] =
403 4.854840e-4f, 5.360178e-4f, 5.918117e-4f, 6.534130e-4f
406 /* The early delay lines are used to transform the primary reflections into
407 * the secondary reflections. The A-format is arranged in such a way that
408 * the channels/lines are spatially opposite:
410 * C_i is opposite C_(N-i-1)
412 * The delays of the two opposing reflections (R_i and O_i) from a source
413 * anywhere along a particular dimension always sum to twice its full delay:
415 * 2 r_a = R_i + O_i
417 * With that in mind we can determine the delay between the two reflections
418 * and thus specify our early line lengths (L_(i=0)^N) using:
420 * O_i = 2 r_a - R_(N-i-1)
421 * L_i = O_i - R_(N-i-1)
422 * = 2 (r_a - R_(N-i-1))
423 * = 2 (r_a - T_(N-i-1) - r_0)
424 * = 2 r_a (1 - (2 / 3) 2^((N - i - 1) / (2 N - 1)))
426 * Using an average dimension of 5m, we get:
428 static const ALfloat EARLY_LINE_LENGTHS[4] =
430 2.992520e-3f, 5.456575e-3f, 7.688329e-3f, 9.709681e-3f
433 /* The late all-pass filter lengths are based on the late line lengths:
435 * A_i = (5 / 3) L_i / r_1
437 static const ALfloat LATE_ALLPASS_LENGTHS[4] =
439 8.091400e-4f, 1.019453e-3f, 1.407968e-3f, 1.618280e-3f
442 /* The late lines are used to approximate the decaying cycle of recursive
443 * late reflections.
445 * Splitting the lines in half, we start with the shortest reflection paths
446 * (L_(i=0)^(N/2)):
448 * L_i = 2^(i / (N - 1)) r_d
450 * Then for the opposite (longest) reflection paths (L_(i=N/2)^N):
452 * L_i = 2 r_a - L_(i-N/2)
453 * = 2 r_a - 2^((i - N / 2) / (N - 1)) r_d
455 * For our 5m average room, we get:
457 static const ALfloat LATE_LINE_LENGTHS[4] =
459 9.709681e-3f, 1.223343e-2f, 1.689561e-2f, 1.941936e-2f
462 /* This coefficient is used to define the sinus depth according to the
463 * modulation depth property. This value must be below half the shortest late
464 * line length (0.0097/2 = ~0.0048), otherwise with certain parameters (high
465 * mod time, low density) the downswing can sample before the input.
467 static const ALfloat MODULATION_DEPTH_COEFF = 1.0f / 4096.0f;
469 /* A filter is used to avoid the terrible distortion caused by changing
470 * modulation time and/or depth. To be consistent across different sample
471 * rates, the coefficient must be raised to a constant divided by the sample
472 * rate: coeff^(constant / rate).
474 static const ALfloat MODULATION_FILTER_COEFF = 0.048f;
475 static const ALfloat MODULATION_FILTER_CONST = 100000.0f;
478 /* Prior to VS2013, MSVC lacks the round() family of functions. */
479 #if defined(_MSC_VER) && _MSC_VER < 1800
480 static inline long lroundf(float val)
482 if(val < 0.0)
483 return fastf2i(ceilf(val-0.5f));
484 return fastf2i(floorf(val+0.5f));
486 #endif
489 /**************************************
490 * Device Update *
491 **************************************/
493 /* Given the allocated sample buffer, this function updates each delay line
494 * offset.
496 static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay)
498 union {
499 ALfloat *f;
500 ALfloat (*f4)[4];
501 } u;
502 u.f = &sampleBuffer[(ptrdiff_t)Delay->Line * 4];
503 Delay->Line = u.f4;
506 /* Calculate the length of a delay line and store its mask and offset. */
507 static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALuint frequency,
508 const ALuint extra, DelayLineI *Delay)
510 ALuint samples;
512 /* All line lengths are powers of 2, calculated from their lengths in
513 * seconds, rounded up.
515 samples = fastf2i(ceilf(length*frequency));
516 samples = NextPowerOf2(samples + extra);
518 /* All lines share a single sample buffer. */
519 Delay->Mask = samples - 1;
520 Delay->Line = (ALfloat(*)[4])offset;
522 /* Return the sample count for accumulation. */
523 return samples;
526 /* Calculates the delay line metrics and allocates the shared sample buffer
527 * for all lines given the sample rate (frequency). If an allocation failure
528 * occurs, it returns AL_FALSE.
530 static ALboolean AllocLines(const ALuint frequency, ALreverbState *State)
532 ALuint totalSamples, i;
533 ALfloat multiplier, length;
535 /* All delay line lengths are calculated to accomodate the full range of
536 * lengths given their respective paramters.
538 totalSamples = 0;
540 /* Multiplier for the maximum density value, i.e. density=1, which is
541 * actually the least density...
543 multiplier = 1.0f + LINE_MULTIPLIER;
545 /* The main delay length includes the maximum early reflection delay, the
546 * largest early tap width, the maximum late reverb delay, and the
547 * largest late tap width. Finally, it must also be extended by the
548 * update size (MAX_UPDATE_SAMPLES) for block processing.
550 length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
551 EARLY_TAP_LENGTHS[3]*multiplier +
552 AL_EAXREVERB_MAX_LATE_REVERB_DELAY +
553 (LATE_LINE_LENGTHS[3] - LATE_LINE_LENGTHS[0])*0.25f*multiplier;
554 totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES,
555 &State->Delay);
557 /* The early vector all-pass line. */
558 length = EARLY_ALLPASS_LENGTHS[3] * multiplier;
559 totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
560 &State->Early.VecAp.Delay);
562 /* The early reflection line. */
563 length = EARLY_LINE_LENGTHS[3] * multiplier;
564 totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
565 &State->Early.Delay);
567 /* The late vector all-pass line. */
568 length = LATE_ALLPASS_LENGTHS[3] * multiplier;
569 totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
570 &State->Late.VecAp.Delay);
572 /* The late delay lines are calculated from the larger of the maximum
573 * density line length or the maximum echo time, and includes the maximum
574 * modulation-related delay. The modulator's delay is calculated from the
575 * maximum modulation time and depth coefficient, and halved for the low-
576 * to-high frequency swing.
578 length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[3]*multiplier) +
579 AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f;
580 totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
581 &State->Late.Delay);
583 if(totalSamples != State->TotalSamples)
585 ALfloat *newBuffer;
587 TRACE("New reverb buffer length: %ux4 samples\n", totalSamples);
588 newBuffer = al_calloc(16, sizeof(ALfloat[4]) * totalSamples);
589 if(!newBuffer) return AL_FALSE;
591 al_free(State->SampleBuffer);
592 State->SampleBuffer = newBuffer;
593 State->TotalSamples = totalSamples;
596 /* Update all delays to reflect the new sample buffer. */
597 RealizeLineOffset(State->SampleBuffer, &State->Delay);
598 RealizeLineOffset(State->SampleBuffer, &State->Early.VecAp.Delay);
599 RealizeLineOffset(State->SampleBuffer, &State->Early.Delay);
600 RealizeLineOffset(State->SampleBuffer, &State->Late.VecAp.Delay);
601 RealizeLineOffset(State->SampleBuffer, &State->Late.Delay);
603 /* Clear the sample buffer. */
604 for(i = 0;i < State->TotalSamples;i++)
605 State->SampleBuffer[i] = 0.0f;
607 return AL_TRUE;
610 static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device)
612 ALuint frequency = Device->Frequency, i;
613 ALfloat multiplier;
615 /* Allocate the delay lines. */
616 if(!AllocLines(frequency, State))
617 return AL_FALSE;
619 /* Calculate the modulation filter coefficient. Notice that the exponent
620 * is calculated given the current sample rate. This ensures that the
621 * resulting filter response over time is consistent across all sample
622 * rates.
624 State->Mod.Coeff = powf(MODULATION_FILTER_COEFF,
625 MODULATION_FILTER_CONST / frequency);
627 multiplier = 1.0f + LINE_MULTIPLIER;
629 /* The late feed taps are set a fixed position past the latest delay tap. */
630 for(i = 0;i < 4;i++)
631 State->LateFeedTap = fastf2i((AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
632 EARLY_TAP_LENGTHS[3]*multiplier) *
633 frequency);
635 return AL_TRUE;
638 /**************************************
639 * Effect Update *
640 **************************************/
642 /* Calculate a decay coefficient given the length of each cycle and the time
643 * until the decay reaches -60 dB.
645 static inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTime)
647 return powf(REVERB_DECAY_GAIN, length/decayTime);
650 /* Calculate a decay length from a coefficient and the time until the decay
651 * reaches -60 dB.
653 static inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime)
655 return log10f(coeff) * decayTime / log10f(REVERB_DECAY_GAIN);
658 /* Calculate an attenuation to be applied to the input of any echo models to
659 * compensate for modal density and decay time.
661 static inline ALfloat CalcDensityGain(const ALfloat a)
663 /* The energy of a signal can be obtained by finding the area under the
664 * squared signal. This takes the form of Sum(x_n^2), where x is the
665 * amplitude for the sample n.
667 * Decaying feedback matches exponential decay of the form Sum(a^n),
668 * where a is the attenuation coefficient, and n is the sample. The area
669 * under this decay curve can be calculated as: 1 / (1 - a).
671 * Modifying the above equation to find the area under the squared curve
672 * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be
673 * calculated by inverting the square root of this approximation,
674 * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2).
676 return sqrtf(1.0f - a*a);
679 /* Calculate the scattering matrix coefficients given a diffusion factor. */
680 static inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y)
682 ALfloat n, t;
684 /* The matrix is of order 4, so n is sqrt(4 - 1). */
685 n = sqrtf(3.0f);
686 t = diffusion * atanf(n);
688 /* Calculate the first mixing matrix coefficient. */
689 *x = cosf(t);
690 /* Calculate the second mixing matrix coefficient. */
691 *y = sinf(t) / n;
694 /* Calculate the limited HF ratio for use with the late reverb low-pass
695 * filters.
697 static ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF,
698 const ALfloat decayTime, const ALfloat SpeedOfSound)
700 ALfloat limitRatio;
702 /* Find the attenuation due to air absorption in dB (converting delay
703 * time to meters using the speed of sound). Then reversing the decay
704 * equation, solve for HF ratio. The delay length is cancelled out of
705 * the equation, so it can be calculated once for all lines.
707 limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SpeedOfSound);
709 /* Using the limit calculated above, apply the upper bound to the HF
710 * ratio. Also need to limit the result to a minimum of 0.1, just like
711 * the HF ratio parameter.
713 return clampf(limitRatio, 0.1f, hfRatio);
716 /* Calculates the first-order high-pass coefficients following the I3DL2
717 * reference model. This is the transfer function:
719 * 1 - z^-1
720 * H(z) = p ------------
721 * 1 - p z^-1
723 * And this is the I3DL2 coefficient calculation given gain (g) and reference
724 * angular frequency (w):
727 * p = ------------------------------------------------------
728 * g cos(w) + sqrt((cos(w) - 1) (g^2 cos(w) + g^2 - 2))
730 * The coefficient is applied to the partial differential filter equation as:
732 * c_0 = p
733 * c_1 = -p
734 * c_2 = p
735 * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1)
738 static inline void CalcHighpassCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3])
740 ALfloat g, g2, cw, p;
742 if(gain >= 1.0f)
744 coeffs[0] = 1.0f;
745 coeffs[1] = 0.0f;
746 coeffs[2] = 0.0f;
748 return;
751 g = maxf(0.001f, gain);
752 g2 = g * g;
753 cw = cosf(w);
754 p = g / (g*cw + sqrtf((cw - 1.0f) * (g2*cw + g2 - 2.0f)));
756 coeffs[0] = p;
757 coeffs[1] = -p;
758 coeffs[2] = p;
761 /* Calculates the first-order low-pass coefficients following the I3DL2
762 * reference model. This is the transfer function:
764 * (1 - a) z^0
765 * H(z) = ----------------
766 * 1 z^0 - a z^-1
768 * And this is the I3DL2 coefficient calculation given gain (g) and reference
769 * angular frequency (w):
771 * 1 - g^2 cos(w) - sqrt(2 g^2 (1 - cos(w)) - g^4 (1 - cos(w)^2))
772 * a = ----------------------------------------------------------------
773 * 1 - g^2
775 * The coefficient is applied to the partial differential filter equation as:
777 * c_0 = 1 - a
778 * c_1 = 0
779 * c_2 = a
780 * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1)
783 static inline void CalcLowpassCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3])
785 ALfloat g, g2, cw, a;
787 if(gain >= 1.0f)
789 coeffs[0] = 1.0f;
790 coeffs[1] = 0.0f;
791 coeffs[2] = 0.0f;
793 return;
796 /* Be careful with gains < 0.001, as that causes the coefficient
797 * to head towards 1, which will flatten the signal. */
798 g = maxf(0.001f, gain);
799 g2 = g * g;
800 cw = cosf(w);
801 a = (1.0f - g2*cw - sqrtf((2.0f*g2*(1.0f - cw)) - g2*g2*(1.0f - cw*cw))) /
802 (1.0f - g2);
804 coeffs[0] = 1.0f - a;
805 coeffs[1] = 0.0f;
806 coeffs[2] = a;
809 /* Calculates the first-order low-shelf coefficients. The shelf filters are
810 * used in place of low/high-pass filters to preserve the mid-band. This is
811 * the transfer function:
813 * a_0 + a_1 z^-1
814 * H(z) = ----------------
815 * 1 + b_1 z^-1
817 * And these are the coefficient calculations given cut gain (g) and a center
818 * angular frequency (w):
820 * sin(0.5 (pi - w) - 0.25 pi)
821 * p = -----------------------------
822 * sin(0.5 (pi - w) + 0.25 pi)
824 * g + 1 g + 1
825 * a = ------- + sqrt((-------)^2 - 1)
826 * g - 1 g - 1
828 * 1 + g + (1 - g) a
829 * b_0 = -------------------
832 * 1 - g + (1 + g) a
833 * b_1 = -------------------
836 * The coefficients are applied to the partial differential filter equation
837 * as:
839 * b_0 + p b_1
840 * c_0 = -------------
841 * 1 + p a
843 * -(b_1 + p b_0)
844 * c_1 = ----------------
845 * 1 + p a
847 * p + a
848 * c_2 = ---------
849 * 1 + p a
851 * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1)
854 static inline void CalcLowShelfCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3])
856 ALfloat g, rw, p, n;
857 ALfloat alpha, beta0, beta1;
859 if(gain >= 1.0f)
861 coeffs[0] = 1.0f;
862 coeffs[1] = 0.0f;
863 coeffs[2] = 0.0f;
865 return;
868 g = maxf(0.001f, gain);
869 rw = F_PI - w;
870 p = sinf(0.5f*rw - 0.25f*F_PI) / sinf(0.5f*rw + 0.25f*F_PI);
871 n = (g + 1.0f) / (g - 1.0f);
872 alpha = n + sqrtf(n*n - 1.0f);
873 beta0 = (1.0f + g + (1.0f - g)*alpha) / 2.0f;
874 beta1 = (1.0f - g + (1.0f + g)*alpha) / 2.0f;
876 coeffs[0] = (beta0 + p*beta1) / (1.0f + p*alpha);
877 coeffs[1] = -(beta1 + p*beta0) / (1.0f + p*alpha);
878 coeffs[2] = (p + alpha) / (1.0f + p*alpha);
881 /* Calculates the first-order high-shelf coefficients. The shelf filters are
882 * used in place of low/high-pass filters to preserve the mid-band. This is
883 * the transfer function:
885 * a_0 + a_1 z^-1
886 * H(z) = ----------------
887 * 1 + b_1 z^-1
889 * And these are the coefficient calculations given cut gain (g) and a center
890 * angular frequency (w):
892 * sin(0.5 w - 0.25 pi)
893 * p = ----------------------
894 * sin(0.5 w + 0.25 pi)
896 * g + 1 g + 1
897 * a = ------- + sqrt((-------)^2 - 1)
898 * g - 1 g - 1
900 * 1 + g + (1 - g) a
901 * b_0 = -------------------
904 * 1 - g + (1 + g) a
905 * b_1 = -------------------
908 * The coefficients are applied to the partial differential filter equation
909 * as:
911 * b_0 + p b_1
912 * c_0 = -------------
913 * 1 + p a
915 * b_1 + p b_0
916 * c_1 = -------------
917 * 1 + p a
919 * -(p + a)
920 * c_2 = ----------
921 * 1 + p a
923 * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1)
926 static inline void CalcHighShelfCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3])
928 ALfloat g, p, n;
929 ALfloat alpha, beta0, beta1;
931 if(gain >= 1.0f)
933 coeffs[0] = 1.0f;
934 coeffs[1] = 0.0f;
935 coeffs[2] = 0.0f;
937 return;
940 g = maxf(0.001f, gain);
941 p = sinf(0.5f*w - 0.25f*F_PI) / sinf(0.5f*w + 0.25f*F_PI);
942 n = (g + 1.0f) / (g - 1.0f);
943 alpha = n + sqrtf(n*n - 1.0f);
944 beta0 = (1.0f + g + (1.0f - g)*alpha) / 2.0f;
945 beta1 = (1.0f - g + (1.0f + g)*alpha) / 2.0f;
947 coeffs[0] = (beta0 + p*beta1) / (1.0f + p*alpha);
948 coeffs[1] = (beta1 + p*beta0) / (1.0f + p*alpha);
949 coeffs[2] = -(p + alpha) / (1.0f + p*alpha);
952 /* Calculates the 3-band T60 damping coefficients for a particular delay line
953 * of specified length using a combination of two low/high-pass/shelf or
954 * pass-through filter sections (producing 3 coefficients each) and a general
955 * gain (7th coefficient) given decay times for each band split at two (LF/
956 * HF) reference frequencies (w).
958 static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime,
959 const ALfloat mfDecayTime, const ALfloat hfDecayTime,
960 const ALfloat lfW, const ALfloat hfW, ALfloat lfcoeffs[3],
961 ALfloat hfcoeffs[3], ALfloat *midcoeff)
963 ALfloat lfGain = CalcDecayCoeff(length, lfDecayTime);
964 ALfloat mfGain = CalcDecayCoeff(length, mfDecayTime);
965 ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime);
967 if(lfGain < mfGain)
969 if(mfGain < hfGain)
971 CalcLowShelfCoeffs(mfGain / hfGain, hfW, lfcoeffs);
972 CalcHighpassCoeffs(lfGain / mfGain, lfW, hfcoeffs);
973 *midcoeff = hfGain;
975 else if(mfGain > hfGain)
977 CalcHighpassCoeffs(lfGain / mfGain, lfW, lfcoeffs);
978 CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs);
979 *midcoeff = mfGain;
981 else
983 lfcoeffs[0] = 1.0f;
984 lfcoeffs[1] = 0.0f;
985 lfcoeffs[2] = 0.0f;
986 CalcHighpassCoeffs(lfGain / mfGain, lfW, hfcoeffs);
987 *midcoeff = mfGain;
990 else if(lfGain > mfGain)
992 if(mfGain < hfGain)
994 ALfloat hg = mfGain / lfGain;
995 ALfloat lg = mfGain / hfGain;
997 CalcHighShelfCoeffs(hg, lfW, lfcoeffs);
998 CalcLowShelfCoeffs(lg, hfW, hfcoeffs);
999 *midcoeff = maxf(lfGain, hfGain) / maxf(hg, lg);
1001 else if(mfGain > hfGain)
1003 CalcHighShelfCoeffs(mfGain / lfGain, lfW, lfcoeffs);
1004 CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs);
1005 *midcoeff = lfGain;
1007 else
1009 lfcoeffs[0] = 1.0f;
1010 lfcoeffs[1] = 0.0f;
1011 lfcoeffs[2] = 0.0f;
1012 CalcHighShelfCoeffs(mfGain / lfGain, lfW, hfcoeffs);
1013 *midcoeff = lfGain;
1016 else
1018 lfcoeffs[0] = 1.0f;
1019 lfcoeffs[1] = 0.0f;
1020 lfcoeffs[2] = 0.0f;
1022 if(mfGain < hfGain)
1024 CalcLowShelfCoeffs(mfGain / hfGain, hfW, hfcoeffs);
1025 *midcoeff = hfGain;
1027 else if(mfGain > hfGain)
1029 CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs);
1030 *midcoeff = mfGain;
1032 else
1034 hfcoeffs[3] = 1.0f;
1035 hfcoeffs[4] = 0.0f;
1036 hfcoeffs[5] = 0.0f;
1037 *midcoeff = mfGain;
1042 /* Update the EAX modulation index, range, and depth. Keep in mind that this
1043 * kind of vibrato is additive and not multiplicative as one may expect. The
1044 * downswing will sound stronger than the upswing.
1046 static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth,
1047 const ALuint frequency, ALreverbState *State)
1049 ALuint range;
1051 /* Modulation is calculated in two parts.
1053 * The modulation time effects the speed of the sinus. An index out of the
1054 * current range (both in samples) is incremented each sample, so a longer
1055 * time implies a larger range. The range is bound to a reasonable minimum
1056 * (1 sample) and when the timing changes, the index is rescaled to the new
1057 * range to keep the sinus consistent.
1059 range = maxi(fastf2i(modTime*frequency), 1);
1060 State->Mod.Index = (ALuint)(State->Mod.Index * (ALuint64)range /
1061 State->Mod.Range);
1062 State->Mod.Range = range;
1064 /* The modulation depth effects the scale of the sinus, which changes how
1065 * much extra delay is added to the delay line. This delay changing over
1066 * time changes the pitch, creating the modulation effect. The scale needs
1067 * to be multiplied by the modulation time so that a given depth produces a
1068 * consistent shift in frequency over all ranges of time. Since the depth
1069 * is applied to a sinus value, it needs to be halved for the sinus swing
1070 * in time (half of it is spent decreasing the frequency, half is spent
1071 * increasing it).
1073 State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f *
1074 frequency;
1077 /* Update the offsets for the main effect delay line. */
1078 static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, const ALfloat decayTime, const ALuint frequency, ALreverbState *State)
1080 ALfloat multiplier, length;
1081 ALuint i;
1083 multiplier = 1.0f + density*LINE_MULTIPLIER;
1085 /* Early reflection taps are decorrelated by means of an average room
1086 * reflection approximation described above the definition of the taps.
1087 * This approximation is linear and so the above density multiplier can
1088 * be applied to adjust the width of the taps. A single-band decay
1089 * coefficient is applied to simulate initial attenuation and absorption.
1091 * Late reverb taps are based on the late line lengths to allow a zero-
1092 * delay path and offsets that would continue the propagation naturally
1093 * into the late lines.
1095 for(i = 0;i < 4;i++)
1097 length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier;
1098 State->EarlyDelayTap[i][1] = fastf2i(length * frequency);
1100 length = EARLY_TAP_LENGTHS[i]*multiplier;
1101 State->EarlyDelayCoeff[i] = CalcDecayCoeff(length, decayTime);
1103 length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS[0])*0.25f*multiplier;
1104 State->LateDelayTap[i][1] = State->LateFeedTap + fastf2i(length * frequency);
1108 /* Update the early reflection line lengths and gain coefficients. */
1109 static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, const ALuint frequency, ALreverbState *State)
1111 ALfloat multiplier, length;
1112 ALsizei i;
1114 multiplier = 1.0f + density*LINE_MULTIPLIER;
1116 for(i = 0;i < 4;i++)
1118 /* Calculate the length (in seconds) of each all-pass line. */
1119 length = EARLY_ALLPASS_LENGTHS[i] * multiplier;
1121 /* Calculate the delay offset for each all-pass line. */
1122 State->Early.VecAp.Offset[i][1] = fastf2i(length * frequency);
1124 /* Calculate the length (in seconds) of each delay line. */
1125 length = EARLY_LINE_LENGTHS[i] * multiplier;
1127 /* Calculate the delay offset for each delay line. */
1128 State->Early.Offset[i][1] = fastf2i(length * frequency);
1130 /* Calculate the gain (coefficient) for each line. */
1131 State->Early.Coeff[i] = CalcDecayCoeff(length, decayTime);
1135 /* Update the late reverb line lengths and T60 coefficients. */
1136 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)
1138 ALfloat multiplier, length, bandWeights[3];
1139 ALsizei i;
1141 /* To compensate for changes in modal density and decay time of the late
1142 * reverb signal, the input is attenuated based on the maximal energy of
1143 * the outgoing signal. This approximation is used to keep the apparent
1144 * energy of the signal equal for all ranges of density and decay time.
1146 * The average length of the delay lines is used to calculate the
1147 * attenuation coefficient.
1149 multiplier = 1.0f + density*LINE_MULTIPLIER;
1150 length = (LATE_LINE_LENGTHS[0] + LATE_LINE_LENGTHS[1] +
1151 LATE_LINE_LENGTHS[2] + LATE_LINE_LENGTHS[3]) / 4.0f * multiplier;
1152 /* Include the echo transformation (see below). */
1153 length = lerp(length, echoTime, echoDepth);
1154 length += (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] +
1155 LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f * multiplier;
1156 /* The density gain calculation uses an average decay time weighted by
1157 * approximate bandwidth. This attempts to compensate for losses of
1158 * energy that reduce decay time due to scattering into highly attenuated
1159 * bands.
1161 bandWeights[0] = lfW;
1162 bandWeights[1] = hfW - lfW;
1163 bandWeights[2] = F_TAU - hfW;
1164 State->Late.DensityGain = CalcDensityGain(
1165 CalcDecayCoeff(length, (bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime +
1166 bandWeights[2]*hfDecayTime) / F_TAU)
1169 for(i = 0;i < 4;i++)
1171 /* Calculate the length (in seconds) of each all-pass line. */
1172 length = LATE_ALLPASS_LENGTHS[i] * multiplier;
1174 /* Calculate the delay offset for each all-pass line. */
1175 State->Late.VecAp.Offset[i][1] = fastf2i(length * frequency);
1177 /* Calculate the length (in seconds) of each delay line. This also
1178 * applies the echo transformation. As the EAX echo depth approaches
1179 * 1, the line lengths approach a length equal to the echoTime. This
1180 * helps to produce distinct echoes along the tail.
1182 length = lerp(LATE_LINE_LENGTHS[i] * multiplier, echoTime, echoDepth);
1184 /* Calculate the delay offset for each delay line. */
1185 State->Late.Offset[i][1] = fastf2i(length * frequency);
1187 /* Approximate the absorption that the vector all-pass would exhibit
1188 * given the current diffusion so we don't have to process a full T60
1189 * filter for each of its four lines.
1191 length += lerp(LATE_ALLPASS_LENGTHS[i],
1192 (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] +
1193 LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f,
1194 diffusion) * multiplier;
1196 /* Calculate the T60 damping coefficients for each line. */
1197 CalcT60DampingCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime,
1198 lfW, hfW, State->Late.Filters[i].LFCoeffs,
1199 State->Late.Filters[i].HFCoeffs,
1200 &State->Late.Filters[i].MidCoeff);
1204 /* Creates a transform matrix given a reverb vector. This works by creating a
1205 * Z-focus transform, then a rotate transform around X, then Y, to place the
1206 * focal point in the direction of the vector, using the vector length as a
1207 * focus strength.
1209 * This isn't technically correct since the vector is supposed to define the
1210 * aperture and not rotate the perceived soundfield, but in practice it's
1211 * probably good enough.
1213 static aluMatrixf GetTransformFromVector(const ALfloat *vec)
1215 aluMatrixf zfocus, xrot, yrot;
1216 aluMatrixf tmp1, tmp2;
1217 ALfloat length;
1218 ALfloat sa, a;
1220 length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
1222 /* Define a Z-focus (X in Ambisonics) transform, given the panning vector
1223 * length.
1225 sa = sinf(minf(length, 1.0f) * (F_PI/4.0f));
1226 aluMatrixfSet(&zfocus,
1227 1.0f/(1.0f+sa), 0.0f, 0.0f, (sa/(1.0f+sa))/1.732050808f,
1228 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, 0.0f,
1229 0.0f, 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f,
1230 (sa/(1.0f+sa))*1.732050808f, 0.0f, 0.0f, 1.0f/(1.0f+sa)
1233 /* Define rotation around X (Y in Ambisonics) */
1234 a = atan2f(vec[1], sqrtf(vec[0]*vec[0] + vec[2]*vec[2]));
1235 aluMatrixfSet(&xrot,
1236 1.0f, 0.0f, 0.0f, 0.0f,
1237 0.0f, 1.0f, 0.0f, 0.0f,
1238 0.0f, 0.0f, cosf(a), sinf(a),
1239 0.0f, 0.0f, -sinf(a), cosf(a)
1242 /* Define rotation around Y (Z in Ambisonics). NOTE: EFX's reverb vectors
1243 * use a right-handled coordinate system, compared to the rest of OpenAL
1244 * which uses left-handed. This is fixed by negating Z, however it would
1245 * need to also be negated to get a proper Ambisonics angle, thus
1246 * cancelling it out.
1248 a = atan2f(-vec[0], vec[2]);
1249 aluMatrixfSet(&yrot,
1250 1.0f, 0.0f, 0.0f, 0.0f,
1251 0.0f, cosf(a), 0.0f, sinf(a),
1252 0.0f, 0.0f, 1.0f, 0.0f,
1253 0.0f, -sinf(a), 0.0f, cosf(a)
1256 #define MATRIX_MULT(_res, _m1, _m2) do { \
1257 int row, col; \
1258 for(col = 0;col < 4;col++) \
1260 for(row = 0;row < 4;row++) \
1261 _res.m[row][col] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \
1262 _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \
1264 } while(0)
1265 /* Define a matrix that first focuses on Z, then rotates around X then Y to
1266 * focus the output in the direction of the vector.
1268 MATRIX_MULT(tmp1, xrot, zfocus);
1269 MATRIX_MULT(tmp2, yrot, tmp1);
1270 #undef MATRIX_MULT
1272 return tmp2;
1275 /* Update the early and late 3D panning gains. */
1276 static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat gain, const ALfloat earlyGain, const ALfloat lateGain, ALreverbState *State)
1278 aluMatrixf transform, rot;
1279 ALsizei i;
1281 STATIC_CAST(ALeffectState,State)->OutBuffer = Device->FOAOut.Buffer;
1282 STATIC_CAST(ALeffectState,State)->OutChannels = Device->FOAOut.NumChannels;
1284 /* Note: _res is transposed. */
1285 #define MATRIX_MULT(_res, _m1, _m2) do { \
1286 int row, col; \
1287 for(col = 0;col < 4;col++) \
1289 for(row = 0;row < 4;row++) \
1290 _res.m[col][row] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \
1291 _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \
1293 } while(0)
1294 /* Create a matrix that first converts A-Format to B-Format, then rotates
1295 * the B-Format soundfield according to the panning vector.
1297 rot = GetTransformFromVector(ReflectionsPan);
1298 MATRIX_MULT(transform, rot, A2B);
1299 memset(&State->Early.PanGain, 0, sizeof(State->Early.PanGain));
1300 for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
1301 ComputeFirstOrderGains(Device->FOAOut, transform.m[i], gain*earlyGain, State->Early.PanGain[i]);
1303 rot = GetTransformFromVector(LateReverbPan);
1304 MATRIX_MULT(transform, rot, A2B);
1305 memset(&State->Late.PanGain, 0, sizeof(State->Late.PanGain));
1306 for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
1307 ComputeFirstOrderGains(Device->FOAOut, transform.m[i], gain*lateGain, State->Late.PanGain[i]);
1308 #undef MATRIX_MULT
1311 static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props)
1313 const ALCdevice *Device = Context->Device;
1314 const ALlistener *Listener = Context->Listener;
1315 ALuint frequency = Device->Frequency;
1316 ALfloat lfScale, hfScale, hfRatio;
1317 ALfloat lfDecayTime, hfDecayTime;
1318 ALfloat gain, gainlf, gainhf;
1319 ALsizei i;
1321 if(Slot->Params.EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb)
1322 State->IsEax = AL_TRUE;
1323 else if(Slot->Params.EffectType == AL_EFFECT_REVERB || EmulateEAXReverb)
1324 State->IsEax = AL_FALSE;
1326 /* Calculate the master filters */
1327 hfScale = props->Reverb.HFReference / frequency;
1328 /* Restrict the filter gains from going below -60dB to keep the filter from
1329 * killing most of the signal.
1331 gainhf = maxf(props->Reverb.GainHF, 0.001f);
1332 ALfilterState_setParams(&State->Filter[0].Lp, ALfilterType_HighShelf,
1333 gainhf, hfScale, calc_rcpQ_from_slope(gainhf, 1.0f));
1334 lfScale = props->Reverb.LFReference / frequency;
1335 gainlf = maxf(props->Reverb.GainLF, 0.001f);
1336 ALfilterState_setParams(&State->Filter[0].Hp, ALfilterType_LowShelf,
1337 gainlf, lfScale, calc_rcpQ_from_slope(gainlf, 1.0f));
1338 for(i = 1;i < 4;i++)
1340 ALfilterState_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp);
1341 ALfilterState_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp);
1344 /* Update the main effect delay and associated taps. */
1345 UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay,
1346 props->Reverb.Density, props->Reverb.DecayTime, frequency,
1347 State);
1349 /* Calculate the all-pass feed-back/forward coefficient. */
1350 State->ApFeedCoeff = sqrtf(0.5f) * powf(props->Reverb.Diffusion, 2.0f);
1352 /* Update the early lines. */
1353 UpdateEarlyLines(props->Reverb.Density, props->Reverb.DecayTime,
1354 frequency, State);
1356 /* Get the mixing matrix coefficients. */
1357 CalcMatrixCoeffs(props->Reverb.Diffusion, &State->MixX, &State->MixY);
1359 /* If the HF limit parameter is flagged, calculate an appropriate limit
1360 * based on the air absorption parameter.
1362 hfRatio = props->Reverb.DecayHFRatio;
1363 if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f)
1364 hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF,
1365 props->Reverb.DecayTime, Listener->Params.ReverbSpeedOfSound
1368 /* Calculate the LF/HF decay times. */
1369 lfDecayTime = clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio,
1370 AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME);
1371 hfDecayTime = clampf(props->Reverb.DecayTime * hfRatio,
1372 AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME);
1374 /* Update the modulator line. */
1375 UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth,
1376 frequency, State);
1378 /* Update the late lines. */
1379 UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion,
1380 lfDecayTime, props->Reverb.DecayTime, hfDecayTime,
1381 F_TAU * lfScale, F_TAU * hfScale,
1382 props->Reverb.EchoTime, props->Reverb.EchoDepth,
1383 frequency, State);
1385 /* Update early and late 3D panning. */
1386 gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost;
1387 Update3DPanning(Device, props->Reverb.ReflectionsPan,
1388 props->Reverb.LateReverbPan, gain,
1389 props->Reverb.ReflectionsGain,
1390 props->Reverb.LateReverbGain, State);
1392 /* Determine if delay-line cross-fading is required. */
1393 for(i = 0;i < 4;i++)
1395 if((State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0]) ||
1396 (State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0]) ||
1397 (State->Early.Offset[i][1] != State->Early.Offset[i][0]) ||
1398 (State->LateDelayTap[i][1] != State->LateDelayTap[i][0]) ||
1399 (State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0]) ||
1400 (State->Late.Offset[i][1] != State->Late.Offset[i][0]))
1402 State->FadeCount = 0;
1403 break;
1409 /**************************************
1410 * Effect Processing *
1411 **************************************/
1413 /* Basic delay line input/output routines. */
1414 static inline ALfloat DelayLineOut(const DelayLineI *Delay, const ALsizei offset, const ALsizei c)
1416 return Delay->Line[offset&Delay->Mask][c];
1419 /* Cross-faded delay line output routine. Instead of interpolating the
1420 * offsets, this interpolates (cross-fades) the outputs at each offset.
1422 static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei off0,
1423 const ALsizei off1, const ALsizei c, const ALfloat mu)
1425 return lerp(Delay->Line[off0&Delay->Mask][c], Delay->Line[off1&Delay->Mask][c], mu);
1427 #define DELAY_OUT_Faded(d, o0, o1, c, mu) FadedDelayLineOut(d, o0, o1, c, mu)
1428 #define DELAY_OUT_Unfaded(d, o0, o1, c, mu) DelayLineOut(d, o0, c)
1430 static inline ALvoid DelayLineIn(DelayLineI *Delay, const ALsizei offset, const ALsizei c, const ALfloat in)
1432 Delay->Line[offset&Delay->Mask][c] = in;
1435 static inline ALvoid DelayLineIn4(DelayLineI *Delay, ALsizei offset, const ALfloat in[4])
1437 ALsizei i;
1438 offset &= Delay->Mask;
1439 for(i = 0;i < 4;i++)
1440 Delay->Line[offset][i] = in[i];
1443 static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const ALfloat in[4])
1445 ALsizei i;
1446 offset &= Delay->Mask;
1447 for(i = 0;i < 4;i++)
1448 Delay->Line[offset][i] = in[3-i];
1451 static void CalcModulationDelays(ALreverbState *State, ALint *restrict delays, const ALsizei todo)
1453 ALfloat sinus, range;
1454 ALsizei index, i;
1456 index = State->Mod.Index;
1457 range = State->Mod.Filter;
1458 for(i = 0;i < todo;i++)
1460 /* Calculate the sinus rhythm (dependent on modulation time and the
1461 * sampling rate).
1463 sinus = sinf(F_TAU * index / State->Mod.Range);
1465 /* Step the modulation index forward, keeping it bound to its range. */
1466 index = (index+1) % State->Mod.Range;
1468 /* The depth determines the range over which to read the input samples
1469 * from, so it must be filtered to reduce the distortion caused by even
1470 * small parameter changes.
1472 range = lerp(range, State->Mod.Depth, State->Mod.Coeff);
1474 /* Calculate the read offset. */
1475 delays[i] = lroundf(range*sinus);
1477 State->Mod.Index = index;
1478 State->Mod.Filter = range;
1481 /* Applies a scattering matrix to the 4-line (vector) input. This is used
1482 * for both the below vector all-pass model and to perform modal feed-back
1483 * delay network (FDN) mixing.
1485 * The matrix is derived from a skew-symmetric matrix to form a 4D rotation
1486 * matrix with a single unitary rotational parameter:
1488 * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
1489 * [ -a, d, c, -b ]
1490 * [ -b, -c, d, a ]
1491 * [ -c, b, -a, d ]
1493 * The rotation is constructed from the effect's diffusion parameter,
1494 * yielding:
1496 * 1 = x^2 + 3 y^2
1498 * Where a, b, and c are the coefficient y with differing signs, and d is the
1499 * coefficient x. The final matrix is thus:
1501 * [ x, y, -y, y ] n = sqrt(matrix_order - 1)
1502 * [ -y, x, y, y ] t = diffusion_parameter * atan(n)
1503 * [ y, -y, x, y ] x = cos(t)
1504 * [ -y, -y, -y, x ] y = sin(t) / n
1506 * Any square orthogonal matrix with an order that is a power of two will
1507 * work (where ^T is transpose, ^-1 is inverse):
1509 * M^T = M^-1
1511 * Using that knowledge, finding an appropriate matrix can be accomplished
1512 * naively by searching all combinations of:
1514 * M = D + S - S^T
1516 * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y)
1517 * whose combination of signs are being iterated.
1519 static inline void VectorPartialScatter(ALfloat *restrict vec, const ALfloat xCoeff, const ALfloat yCoeff)
1521 const ALfloat f[4] = { vec[0], vec[1], vec[2], vec[3] };
1523 vec[0] = xCoeff*f[0] + yCoeff*( f[1] + -f[2] + f[3]);
1524 vec[1] = xCoeff*f[1] + yCoeff*(-f[0] + f[2] + f[3]);
1525 vec[2] = xCoeff*f[2] + yCoeff*( f[0] + -f[1] + f[3]);
1526 vec[3] = xCoeff*f[3] + yCoeff*(-f[0] + -f[1] + -f[2] );
1529 /* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass
1530 * filter to the 4-line input.
1532 * It works by vectorizing a regular all-pass filter and replacing the delay
1533 * element with a scattering matrix (like the one above) and a diagonal
1534 * matrix of delay elements.
1536 * Two static specializations are used for transitional (cross-faded) delay
1537 * line processing and non-transitional processing.
1539 #define DECL_TEMPLATE(T) \
1540 static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \
1541 const ALfloat feedCoeff, const ALfloat xCoeff, \
1542 const ALfloat yCoeff, const ALfloat mu, \
1543 VecAllpass *Vap) \
1545 ALfloat input; \
1546 ALfloat f[4]; \
1547 ALsizei i; \
1549 (void)mu; /* Ignore for Unfaded. */ \
1551 for(i = 0;i < 4;i++) \
1553 input = vec[i]; \
1554 vec[i] = DELAY_OUT_##T(&Vap->Delay, offset-Vap->Offset[i][0], \
1555 offset-Vap->Offset[i][1], i, mu) - \
1556 feedCoeff*input; \
1557 f[i] = input + feedCoeff*vec[i]; \
1560 VectorPartialScatter(f, xCoeff, yCoeff); \
1562 DelayLineIn4(&Vap->Delay, offset, f); \
1564 DECL_TEMPLATE(Unfaded)
1565 DECL_TEMPLATE(Faded)
1566 #undef DECL_TEMPLATE
1568 /* A helper to reverse vector components. */
1569 static inline void VectorReverse(ALfloat vec[4])
1571 const ALfloat f[4] = { vec[0], vec[1], vec[2], vec[3] };
1573 vec[0] = f[3];
1574 vec[1] = f[2];
1575 vec[2] = f[1];
1576 vec[3] = f[0];
1579 /* This generates early reflections.
1581 * This is done by obtaining the primary reflections (those arriving from the
1582 * same direction as the source) from the main delay line. These are
1583 * attenuated and all-pass filtered (based on the diffusion parameter).
1585 * The early lines are then fed in reverse (according to the approximately
1586 * opposite spatial location of the A-Format lines) to create the secondary
1587 * reflections (those arriving from the opposite direction as the source).
1589 * The early response is then completed by combining the primary reflections
1590 * with the delayed and attenuated output from the early lines.
1592 * Finally, the early response is reversed, scattered (based on diffusion),
1593 * and fed into the late reverb section of the main delay line.
1595 * Two static specializations are used for transitional (cross-faded) delay
1596 * line processing and non-transitional processing.
1598 #define DECL_TEMPLATE(T) \
1599 static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \
1600 ALfloat fade, \
1601 ALfloat (*restrict out)[MAX_UPDATE_SAMPLES])\
1603 ALsizei offset = State->Offset; \
1604 const ALfloat apFeedCoeff = State->ApFeedCoeff; \
1605 const ALfloat mixX = State->MixX; \
1606 const ALfloat mixY = State->MixY; \
1607 ALfloat f[4]; \
1608 ALsizei i, j; \
1610 for(i = 0;i < todo;i++) \
1612 for(j = 0;j < 4;j++) \
1613 f[j] = DELAY_OUT_##T(&State->Delay, \
1614 offset-State->EarlyDelayTap[j][0], \
1615 offset-State->EarlyDelayTap[j][1], j, fade \
1616 ) * State->EarlyDelayCoeff[j]; \
1618 VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \
1619 &State->Early.VecAp); \
1621 DelayLineIn4Rev(&State->Early.Delay, offset, f); \
1623 for(j = 0;j < 4;j++) \
1624 f[j] += DELAY_OUT_##T(&State->Early.Delay, \
1625 offset-State->Early.Offset[j][0], \
1626 offset-State->Early.Offset[j][1], j, fade \
1627 ) * State->Early.Coeff[j]; \
1629 for(j = 0;j < 4;j++) \
1630 out[j][i] = f[j]; \
1632 VectorReverse(f); \
1634 VectorPartialScatter(f, mixX, mixY); \
1636 DelayLineIn4(&State->Delay, offset-State->LateFeedTap, f); \
1638 offset++; \
1639 fade += FadeStep; \
1642 DECL_TEMPLATE(Unfaded)
1643 DECL_TEMPLATE(Faded)
1644 #undef DECL_TEMPLATE
1646 /* Applies a first order filter section. */
1647 static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat coeffs[3], ALfloat state[2])
1649 ALfloat out = coeffs[0]*in + coeffs[1]*state[0] + coeffs[2]*state[1];
1651 state[0] = in;
1652 state[1] = out;
1654 return out;
1657 /* Applies the two T60 damping filter sections. */
1658 static inline ALfloat LateT60Filter(const ALsizei index, const ALfloat in, ALreverbState *State)
1660 ALfloat out = FirstOrderFilter(in, State->Late.Filters[index].LFCoeffs,
1661 State->Late.Filters[index].States[0]);
1663 return State->Late.Filters[index].MidCoeff *
1664 FirstOrderFilter(out, State->Late.Filters[index].HFCoeffs,
1665 State->Late.Filters[index].States[1]);
1668 /* This generates the reverb tail using a modified feed-back delay network
1669 * (FDN).
1671 * Results from the early reflections are attenuated by the density gain and
1672 * mixed with the output from the late delay lines.
1674 * The late response is then completed by T60 and all-pass filtering the mix.
1676 * Finally, the lines are reversed (so they feed their opposite directions)
1677 * and scattered with the FDN matrix before re-feeding the delay lines.
1679 * Two static specializations are used for transitional (cross-faded) delay
1680 * line processing and non-transitional processing.
1682 #define DECL_TEMPLATE(T) \
1683 static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \
1684 ALfloat fade, \
1685 ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) \
1687 const ALfloat apFeedCoeff = State->ApFeedCoeff; \
1688 const ALfloat mixX = State->MixX; \
1689 const ALfloat mixY = State->MixY; \
1690 ALint moddelay[MAX_UPDATE_SAMPLES]; \
1691 ALsizei delay; \
1692 ALsizei offset; \
1693 ALsizei i, j; \
1694 ALfloat f[4]; \
1696 CalcModulationDelays(State, moddelay, todo); \
1698 offset = State->Offset; \
1699 for(i = 0;i < todo;i++) \
1701 for(j = 0;j < 4;j++) \
1702 f[j] = DELAY_OUT_##T(&State->Delay, \
1703 offset-State->LateDelayTap[j][0], \
1704 offset-State->LateDelayTap[j][1], j, fade \
1705 ) * State->Late.DensityGain; \
1707 delay = offset - moddelay[i]; \
1708 for(j = 0;j < 4;j++) \
1709 f[j] += DELAY_OUT_##T(&State->Late.Delay, \
1710 delay-State->Late.Offset[j][0], \
1711 delay-State->Late.Offset[j][1], j, fade \
1712 ); \
1714 for(j = 0;j < 4;j++) \
1715 f[j] = LateT60Filter(j, f[j], State); \
1717 VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \
1718 &State->Late.VecAp); \
1720 for(j = 0;j < 4;j++) \
1721 out[j][i] = f[j]; \
1723 VectorReverse(f); \
1725 VectorPartialScatter(f, mixX, mixY); \
1727 DelayLineIn4(&State->Late.Delay, offset, f); \
1729 offset++; \
1730 fade += FadeStep; \
1733 DECL_TEMPLATE(Unfaded)
1734 DECL_TEMPLATE(Faded)
1735 #undef DECL_TEMPLATE
1737 typedef ALfloat (*ProcMethodType)(ALreverbState *State, const ALsizei todo, ALfloat fade,
1738 const ALfloat (*restrict input)[MAX_UPDATE_SAMPLES],
1739 ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]);
1741 /* Perform the non-EAX reverb pass on a given input sample, resulting in
1742 * four-channel output.
1744 static ALfloat VerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade,
1745 const ALfloat (*restrict input)[MAX_UPDATE_SAMPLES],
1746 ALfloat (*restrict early)[MAX_UPDATE_SAMPLES],
1747 ALfloat (*restrict late)[MAX_UPDATE_SAMPLES])
1749 ALsizei i, c;
1751 for(c = 0;c < 4;c++)
1753 /* Low-pass filter the incoming samples (use the early buffer as temp
1754 * storage).
1756 ALfilterState_process(&State->Filter[c].Lp, &early[0][0], input[c], todo);
1758 /* Feed the initial delay line. */
1759 for(i = 0;i < todo;i++)
1760 DelayLineIn(&State->Delay, State->Offset+i, c, early[0][i]);
1763 if(fade < 1.0f)
1765 /* Generate early reflections. */
1766 EarlyReflection_Faded(State, todo, fade, early);
1768 /* Generate late reverb. */
1769 LateReverb_Faded(State, todo, fade, late);
1770 fade = minf(1.0f, fade + todo*FadeStep);
1772 else
1774 /* Generate early reflections. */
1775 EarlyReflection_Unfaded(State, todo, fade, early);
1777 /* Generate late reverb. */
1778 LateReverb_Unfaded(State, todo, fade, late);
1781 /* Step all delays forward one sample. */
1782 State->Offset += todo;
1784 return fade;
1787 /* Perform the EAX reverb pass on a given input sample, resulting in four-
1788 * channel output.
1790 static ALfloat EAXVerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade,
1791 const ALfloat (*restrict input)[MAX_UPDATE_SAMPLES],
1792 ALfloat (*restrict early)[MAX_UPDATE_SAMPLES],
1793 ALfloat (*restrict late)[MAX_UPDATE_SAMPLES])
1795 ALsizei i, c;
1797 for(c = 0;c < 4;c++)
1799 /* Band-pass the incoming samples. Use the early output lines for temp
1800 * storage.
1802 ALfilterState_process(&State->Filter[c].Lp, early[0], input[c], todo);
1803 ALfilterState_process(&State->Filter[c].Hp, early[1], early[0], todo);
1805 /* Feed the initial delay line. */
1806 for(i = 0;i < todo;i++)
1807 DelayLineIn(&State->Delay, State->Offset+i, c, early[1][i]);
1810 if(fade < 1.0f)
1812 /* Generate early reflections. */
1813 EarlyReflection_Faded(State, todo, fade, early);
1815 /* Generate late reverb. */
1816 LateReverb_Faded(State, todo, fade, late);
1817 fade = minf(1.0f, fade + todo*FadeStep);
1819 else
1821 /* Generate early reflections. */
1822 EarlyReflection_Unfaded(State, todo, fade, early);
1824 /* Generate late reverb. */
1825 LateReverb_Unfaded(State, todo, fade, late);
1828 /* Step all delays forward. */
1829 State->Offset += todo;
1831 return fade;
1834 static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
1836 ProcMethodType ReverbProc = State->IsEax ? EAXVerbPass : VerbPass;
1837 ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples;
1838 ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples;
1839 ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples;
1840 ALsizei fadeCount = State->FadeCount;
1841 ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES;
1842 ALsizei base, c;
1844 /* Process reverb for these samples. */
1845 for(base = 0;base < SamplesToDo;)
1847 ALsizei todo = mini(SamplesToDo-base, MAX_UPDATE_SAMPLES);
1848 /* If cross-fading, don't do more samples than there are to fade. */
1849 if(FADE_SAMPLES-fadeCount > 0)
1850 todo = mini(todo, FADE_SAMPLES-fadeCount);
1852 /* Convert B-Format to A-Format for processing. */
1853 memset(afmt, 0, sizeof(*afmt)*4);
1854 for(c = 0;c < 4;c++)
1855 MixRowSamples(afmt[c], B2A.m[c],
1856 SamplesIn, MAX_EFFECT_CHANNELS, base, todo
1859 /* Process the samples for reverb. */
1860 fade = ReverbProc(State, todo, fade, afmt, early, late);
1861 if(UNEXPECTED(fadeCount < FADE_SAMPLES) && (fadeCount += todo) >= FADE_SAMPLES)
1863 /* Update the cross-fading delay line taps. */
1864 fadeCount = FADE_SAMPLES;
1865 fade = 1.0f;
1866 for(c = 0;c < 4;c++)
1868 State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1];
1869 State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1];
1870 State->Early.Offset[c][0] = State->Early.Offset[c][1];
1871 State->LateDelayTap[c][0] = State->LateDelayTap[c][1];
1872 State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1];
1873 State->Late.Offset[c][0] = State->Late.Offset[c][1];
1877 /* Mix the A-Format results to output, implicitly converting back to
1878 * B-Format.
1880 for(c = 0;c < 4;c++)
1881 MixSamples(early[c], NumChannels, SamplesOut,
1882 State->Early.CurrentGain[c], State->Early.PanGain[c],
1883 SamplesToDo-base, base, todo
1885 for(c = 0;c < 4;c++)
1886 MixSamples(late[c], NumChannels, SamplesOut,
1887 State->Late.CurrentGain[c], State->Late.PanGain[c],
1888 SamplesToDo-base, base, todo
1891 base += todo;
1893 State->FadeCount = fadeCount;
1897 typedef struct ALreverbStateFactory {
1898 DERIVE_FROM_TYPE(ALeffectStateFactory);
1899 } ALreverbStateFactory;
1901 static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(factory))
1903 ALreverbState *state;
1905 alcall_once(&mixfunc_inited, init_mixfunc);
1907 NEW_OBJ0(state, ALreverbState)();
1908 if(!state) return NULL;
1910 return STATIC_CAST(ALeffectState, state);
1913 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALreverbStateFactory);
1915 ALeffectStateFactory *ALreverbStateFactory_getFactory(void)
1917 static ALreverbStateFactory ReverbFactory = { { GET_VTABLE2(ALreverbStateFactory, ALeffectStateFactory) } };
1919 return STATIC_CAST(ALeffectStateFactory, &ReverbFactory);
1923 void ALeaxreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
1925 ALeffectProps *props = &effect->Props;
1926 switch(param)
1928 case AL_EAXREVERB_DECAY_HFLIMIT:
1929 if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT))
1930 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1931 props->Reverb.DecayHFLimit = val;
1932 break;
1934 default:
1935 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
1938 void ALeaxreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
1940 ALeaxreverb_setParami(effect, context, param, vals[0]);
1942 void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
1944 ALeffectProps *props = &effect->Props;
1945 switch(param)
1947 case AL_EAXREVERB_DENSITY:
1948 if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY))
1949 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1950 props->Reverb.Density = val;
1951 break;
1953 case AL_EAXREVERB_DIFFUSION:
1954 if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION))
1955 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1956 props->Reverb.Diffusion = val;
1957 break;
1959 case AL_EAXREVERB_GAIN:
1960 if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN))
1961 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1962 props->Reverb.Gain = val;
1963 break;
1965 case AL_EAXREVERB_GAINHF:
1966 if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF))
1967 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1968 props->Reverb.GainHF = val;
1969 break;
1971 case AL_EAXREVERB_GAINLF:
1972 if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF))
1973 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1974 props->Reverb.GainLF = val;
1975 break;
1977 case AL_EAXREVERB_DECAY_TIME:
1978 if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME))
1979 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1980 props->Reverb.DecayTime = val;
1981 break;
1983 case AL_EAXREVERB_DECAY_HFRATIO:
1984 if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO))
1985 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1986 props->Reverb.DecayHFRatio = val;
1987 break;
1989 case AL_EAXREVERB_DECAY_LFRATIO:
1990 if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO))
1991 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1992 props->Reverb.DecayLFRatio = val;
1993 break;
1995 case AL_EAXREVERB_REFLECTIONS_GAIN:
1996 if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN))
1997 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1998 props->Reverb.ReflectionsGain = val;
1999 break;
2001 case AL_EAXREVERB_REFLECTIONS_DELAY:
2002 if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY))
2003 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2004 props->Reverb.ReflectionsDelay = val;
2005 break;
2007 case AL_EAXREVERB_LATE_REVERB_GAIN:
2008 if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN))
2009 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2010 props->Reverb.LateReverbGain = val;
2011 break;
2013 case AL_EAXREVERB_LATE_REVERB_DELAY:
2014 if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY))
2015 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2016 props->Reverb.LateReverbDelay = val;
2017 break;
2019 case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
2020 if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF))
2021 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2022 props->Reverb.AirAbsorptionGainHF = val;
2023 break;
2025 case AL_EAXREVERB_ECHO_TIME:
2026 if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME))
2027 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2028 props->Reverb.EchoTime = val;
2029 break;
2031 case AL_EAXREVERB_ECHO_DEPTH:
2032 if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH))
2033 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2034 props->Reverb.EchoDepth = val;
2035 break;
2037 case AL_EAXREVERB_MODULATION_TIME:
2038 if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME))
2039 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2040 props->Reverb.ModulationTime = val;
2041 break;
2043 case AL_EAXREVERB_MODULATION_DEPTH:
2044 if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH))
2045 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2046 props->Reverb.ModulationDepth = val;
2047 break;
2049 case AL_EAXREVERB_HFREFERENCE:
2050 if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE))
2051 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2052 props->Reverb.HFReference = val;
2053 break;
2055 case AL_EAXREVERB_LFREFERENCE:
2056 if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE))
2057 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2058 props->Reverb.LFReference = val;
2059 break;
2061 case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
2062 if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR))
2063 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2064 props->Reverb.RoomRolloffFactor = val;
2065 break;
2067 default:
2068 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2071 void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
2073 ALeffectProps *props = &effect->Props;
2074 switch(param)
2076 case AL_EAXREVERB_REFLECTIONS_PAN:
2077 if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])))
2078 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2079 props->Reverb.ReflectionsPan[0] = vals[0];
2080 props->Reverb.ReflectionsPan[1] = vals[1];
2081 props->Reverb.ReflectionsPan[2] = vals[2];
2082 break;
2083 case AL_EAXREVERB_LATE_REVERB_PAN:
2084 if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])))
2085 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2086 props->Reverb.LateReverbPan[0] = vals[0];
2087 props->Reverb.LateReverbPan[1] = vals[1];
2088 props->Reverb.LateReverbPan[2] = vals[2];
2089 break;
2091 default:
2092 ALeaxreverb_setParamf(effect, context, param, vals[0]);
2093 break;
2097 void ALeaxreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
2099 const ALeffectProps *props = &effect->Props;
2100 switch(param)
2102 case AL_EAXREVERB_DECAY_HFLIMIT:
2103 *val = props->Reverb.DecayHFLimit;
2104 break;
2106 default:
2107 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2110 void ALeaxreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
2112 ALeaxreverb_getParami(effect, context, param, vals);
2114 void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
2116 const ALeffectProps *props = &effect->Props;
2117 switch(param)
2119 case AL_EAXREVERB_DENSITY:
2120 *val = props->Reverb.Density;
2121 break;
2123 case AL_EAXREVERB_DIFFUSION:
2124 *val = props->Reverb.Diffusion;
2125 break;
2127 case AL_EAXREVERB_GAIN:
2128 *val = props->Reverb.Gain;
2129 break;
2131 case AL_EAXREVERB_GAINHF:
2132 *val = props->Reverb.GainHF;
2133 break;
2135 case AL_EAXREVERB_GAINLF:
2136 *val = props->Reverb.GainLF;
2137 break;
2139 case AL_EAXREVERB_DECAY_TIME:
2140 *val = props->Reverb.DecayTime;
2141 break;
2143 case AL_EAXREVERB_DECAY_HFRATIO:
2144 *val = props->Reverb.DecayHFRatio;
2145 break;
2147 case AL_EAXREVERB_DECAY_LFRATIO:
2148 *val = props->Reverb.DecayLFRatio;
2149 break;
2151 case AL_EAXREVERB_REFLECTIONS_GAIN:
2152 *val = props->Reverb.ReflectionsGain;
2153 break;
2155 case AL_EAXREVERB_REFLECTIONS_DELAY:
2156 *val = props->Reverb.ReflectionsDelay;
2157 break;
2159 case AL_EAXREVERB_LATE_REVERB_GAIN:
2160 *val = props->Reverb.LateReverbGain;
2161 break;
2163 case AL_EAXREVERB_LATE_REVERB_DELAY:
2164 *val = props->Reverb.LateReverbDelay;
2165 break;
2167 case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
2168 *val = props->Reverb.AirAbsorptionGainHF;
2169 break;
2171 case AL_EAXREVERB_ECHO_TIME:
2172 *val = props->Reverb.EchoTime;
2173 break;
2175 case AL_EAXREVERB_ECHO_DEPTH:
2176 *val = props->Reverb.EchoDepth;
2177 break;
2179 case AL_EAXREVERB_MODULATION_TIME:
2180 *val = props->Reverb.ModulationTime;
2181 break;
2183 case AL_EAXREVERB_MODULATION_DEPTH:
2184 *val = props->Reverb.ModulationDepth;
2185 break;
2187 case AL_EAXREVERB_HFREFERENCE:
2188 *val = props->Reverb.HFReference;
2189 break;
2191 case AL_EAXREVERB_LFREFERENCE:
2192 *val = props->Reverb.LFReference;
2193 break;
2195 case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
2196 *val = props->Reverb.RoomRolloffFactor;
2197 break;
2199 default:
2200 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2203 void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
2205 const ALeffectProps *props = &effect->Props;
2206 switch(param)
2208 case AL_EAXREVERB_REFLECTIONS_PAN:
2209 vals[0] = props->Reverb.ReflectionsPan[0];
2210 vals[1] = props->Reverb.ReflectionsPan[1];
2211 vals[2] = props->Reverb.ReflectionsPan[2];
2212 break;
2213 case AL_EAXREVERB_LATE_REVERB_PAN:
2214 vals[0] = props->Reverb.LateReverbPan[0];
2215 vals[1] = props->Reverb.LateReverbPan[1];
2216 vals[2] = props->Reverb.LateReverbPan[2];
2217 break;
2219 default:
2220 ALeaxreverb_getParamf(effect, context, param, vals);
2221 break;
2225 DEFINE_ALEFFECT_VTABLE(ALeaxreverb);
2227 void ALreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
2229 ALeffectProps *props = &effect->Props;
2230 switch(param)
2232 case AL_REVERB_DECAY_HFLIMIT:
2233 if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT))
2234 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2235 props->Reverb.DecayHFLimit = val;
2236 break;
2238 default:
2239 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2242 void ALreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
2244 ALreverb_setParami(effect, context, param, vals[0]);
2246 void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
2248 ALeffectProps *props = &effect->Props;
2249 switch(param)
2251 case AL_REVERB_DENSITY:
2252 if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY))
2253 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2254 props->Reverb.Density = val;
2255 break;
2257 case AL_REVERB_DIFFUSION:
2258 if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION))
2259 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2260 props->Reverb.Diffusion = val;
2261 break;
2263 case AL_REVERB_GAIN:
2264 if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN))
2265 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2266 props->Reverb.Gain = val;
2267 break;
2269 case AL_REVERB_GAINHF:
2270 if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF))
2271 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2272 props->Reverb.GainHF = val;
2273 break;
2275 case AL_REVERB_DECAY_TIME:
2276 if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME))
2277 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2278 props->Reverb.DecayTime = val;
2279 break;
2281 case AL_REVERB_DECAY_HFRATIO:
2282 if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO))
2283 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2284 props->Reverb.DecayHFRatio = val;
2285 break;
2287 case AL_REVERB_REFLECTIONS_GAIN:
2288 if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN))
2289 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2290 props->Reverb.ReflectionsGain = val;
2291 break;
2293 case AL_REVERB_REFLECTIONS_DELAY:
2294 if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY))
2295 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2296 props->Reverb.ReflectionsDelay = val;
2297 break;
2299 case AL_REVERB_LATE_REVERB_GAIN:
2300 if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN))
2301 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2302 props->Reverb.LateReverbGain = val;
2303 break;
2305 case AL_REVERB_LATE_REVERB_DELAY:
2306 if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY))
2307 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2308 props->Reverb.LateReverbDelay = val;
2309 break;
2311 case AL_REVERB_AIR_ABSORPTION_GAINHF:
2312 if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF))
2313 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2314 props->Reverb.AirAbsorptionGainHF = val;
2315 break;
2317 case AL_REVERB_ROOM_ROLLOFF_FACTOR:
2318 if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR))
2319 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
2320 props->Reverb.RoomRolloffFactor = val;
2321 break;
2323 default:
2324 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2327 void ALreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
2329 ALreverb_setParamf(effect, context, param, vals[0]);
2332 void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
2334 const ALeffectProps *props = &effect->Props;
2335 switch(param)
2337 case AL_REVERB_DECAY_HFLIMIT:
2338 *val = props->Reverb.DecayHFLimit;
2339 break;
2341 default:
2342 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2345 void ALreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
2347 ALreverb_getParami(effect, context, param, vals);
2349 void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
2351 const ALeffectProps *props = &effect->Props;
2352 switch(param)
2354 case AL_REVERB_DENSITY:
2355 *val = props->Reverb.Density;
2356 break;
2358 case AL_REVERB_DIFFUSION:
2359 *val = props->Reverb.Diffusion;
2360 break;
2362 case AL_REVERB_GAIN:
2363 *val = props->Reverb.Gain;
2364 break;
2366 case AL_REVERB_GAINHF:
2367 *val = props->Reverb.GainHF;
2368 break;
2370 case AL_REVERB_DECAY_TIME:
2371 *val = props->Reverb.DecayTime;
2372 break;
2374 case AL_REVERB_DECAY_HFRATIO:
2375 *val = props->Reverb.DecayHFRatio;
2376 break;
2378 case AL_REVERB_REFLECTIONS_GAIN:
2379 *val = props->Reverb.ReflectionsGain;
2380 break;
2382 case AL_REVERB_REFLECTIONS_DELAY:
2383 *val = props->Reverb.ReflectionsDelay;
2384 break;
2386 case AL_REVERB_LATE_REVERB_GAIN:
2387 *val = props->Reverb.LateReverbGain;
2388 break;
2390 case AL_REVERB_LATE_REVERB_DELAY:
2391 *val = props->Reverb.LateReverbDelay;
2392 break;
2394 case AL_REVERB_AIR_ABSORPTION_GAINHF:
2395 *val = props->Reverb.AirAbsorptionGainHF;
2396 break;
2398 case AL_REVERB_ROOM_ROLLOFF_FACTOR:
2399 *val = props->Reverb.RoomRolloffFactor;
2400 break;
2402 default:
2403 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
2406 void ALreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
2408 ALreverb_getParamf(effect, context, param, vals);
2411 DEFINE_ALEFFECT_VTABLE(ALreverb);