Improve ambient gain calculations
[openal-soft.git] / Alc / effects / reverb.c
blob9170e1c98a6e52a9b3311dfda9df877be983aef0
1 /**
2 * Reverb for the OpenAL cross platform audio library
3 * Copyright (C) 2008-2009 by 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"
35 typedef struct DelayLine
37 // The delay lines use sample lengths that are powers of 2 to allow the
38 // use of bit-masking instead of a modulus for wrapping.
39 ALuint Mask;
40 ALfloat *Line;
41 } DelayLine;
43 typedef struct ALreverbState {
44 DERIVE_FROM_TYPE(ALeffectState);
46 ALboolean IsEax;
48 // All delay lines are allocated as a single buffer to reduce memory
49 // fragmentation and management code.
50 ALfloat *SampleBuffer;
51 ALuint TotalSamples;
53 // Master effect filters
54 ALfilterState LpFilter;
55 ALfilterState HpFilter; // EAX only
57 struct {
58 // Modulator delay line.
59 DelayLine Delay;
61 // The vibrato time is tracked with an index over a modulus-wrapped
62 // range (in samples).
63 ALuint Index;
64 ALuint Range;
66 // The depth of frequency change (also in samples) and its filter.
67 ALfloat Depth;
68 ALfloat Coeff;
69 ALfloat Filter;
70 } Mod;
72 // Initial effect delay.
73 DelayLine Delay;
74 // The tap points for the initial delay. First tap goes to early
75 // reflections, the last to late reverb.
76 ALuint DelayTap[2];
78 struct {
79 // Output gain for early reflections.
80 ALfloat Gain;
82 // Early reflections are done with 4 delay lines.
83 ALfloat Coeff[4];
84 DelayLine Delay[4];
85 ALuint Offset[4];
87 // The gain for each output channel based on 3D panning (only for the
88 // EAX path).
89 ALfloat PanGain[MAX_OUTPUT_CHANNELS];
90 } Early;
92 // Decorrelator delay line.
93 DelayLine Decorrelator;
94 // There are actually 4 decorrelator taps, but the first occurs at the
95 // initial sample.
96 ALuint DecoTap[3];
98 struct {
99 // Output gain for late reverb.
100 ALfloat Gain;
102 // Attenuation to compensate for the modal density and decay rate of
103 // the late lines.
104 ALfloat DensityGain;
106 // The feed-back and feed-forward all-pass coefficient.
107 ALfloat ApFeedCoeff;
109 // Mixing matrix coefficient.
110 ALfloat MixCoeff;
112 // Late reverb has 4 parallel all-pass filters.
113 ALfloat ApCoeff[4];
114 DelayLine ApDelay[4];
115 ALuint ApOffset[4];
117 // In addition to 4 cyclical delay lines.
118 ALfloat Coeff[4];
119 DelayLine Delay[4];
120 ALuint Offset[4];
122 // The cyclical delay lines are 1-pole low-pass filtered.
123 ALfloat LpCoeff[4];
124 ALfloat LpSample[4];
126 // The gain for each output channel based on 3D panning (only for the
127 // EAX path).
128 ALfloat PanGain[MAX_OUTPUT_CHANNELS];
129 } Late;
131 struct {
132 // Attenuation to compensate for the modal density and decay rate of
133 // the echo line.
134 ALfloat DensityGain;
136 // Echo delay and all-pass lines.
137 DelayLine Delay;
138 DelayLine ApDelay;
140 ALfloat Coeff;
141 ALfloat ApFeedCoeff;
142 ALfloat ApCoeff;
144 ALuint Offset;
145 ALuint ApOffset;
147 // The echo line is 1-pole low-pass filtered.
148 ALfloat LpCoeff;
149 ALfloat LpSample;
151 // Echo mixing coefficients.
152 ALfloat MixCoeff[2];
153 } Echo;
155 // The current read offset for all delay lines.
156 ALuint Offset;
158 // The gain for each output channel (non-EAX path only; aliased from
159 // Late.PanGain)
160 ALfloat *Gain;
162 /* Temporary storage used when processing, before deinterlacing. */
163 ALfloat ReverbSamples[BUFFERSIZE][4];
164 ALfloat EarlySamples[BUFFERSIZE][4];
165 } ALreverbState;
167 /* This is a user config option for modifying the overall output of the reverb
168 * effect.
170 ALfloat ReverbBoost = 1.0f;
172 /* Specifies whether to use a standard reverb effect in place of EAX reverb */
173 ALboolean EmulateEAXReverb = AL_FALSE;
175 /* This coefficient is used to define the maximum frequency range controlled
176 * by the modulation depth. The current value of 0.1 will allow it to swing
177 * from 0.9x to 1.1x. This value must be below 1. At 1 it will cause the
178 * sampler to stall on the downswing, and above 1 it will cause it to sample
179 * backwards.
181 static const ALfloat MODULATION_DEPTH_COEFF = 0.1f;
183 /* A filter is used to avoid the terrible distortion caused by changing
184 * modulation time and/or depth. To be consistent across different sample
185 * rates, the coefficient must be raised to a constant divided by the sample
186 * rate: coeff^(constant / rate).
188 static const ALfloat MODULATION_FILTER_COEFF = 0.048f;
189 static const ALfloat MODULATION_FILTER_CONST = 100000.0f;
191 // When diffusion is above 0, an all-pass filter is used to take the edge off
192 // the echo effect. It uses the following line length (in seconds).
193 static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f;
195 // Input into the late reverb is decorrelated between four channels. Their
196 // timings are dependent on a fraction and multiplier. See the
197 // UpdateDecorrelator() routine for the calculations involved.
198 static const ALfloat DECO_FRACTION = 0.15f;
199 static const ALfloat DECO_MULTIPLIER = 2.0f;
201 // All delay line lengths are specified in seconds.
203 // The lengths of the early delay lines.
204 static const ALfloat EARLY_LINE_LENGTH[4] =
206 0.0015f, 0.0045f, 0.0135f, 0.0405f
209 // The lengths of the late all-pass delay lines.
210 static const ALfloat ALLPASS_LINE_LENGTH[4] =
212 0.0151f, 0.0167f, 0.0183f, 0.0200f,
215 // The lengths of the late cyclical delay lines.
216 static const ALfloat LATE_LINE_LENGTH[4] =
218 0.0211f, 0.0311f, 0.0461f, 0.0680f
221 // The late cyclical delay lines have a variable length dependent on the
222 // effect's density parameter (inverted for some reason) and this multiplier.
223 static const ALfloat LATE_LINE_MULTIPLIER = 4.0f;
226 // Basic delay line input/output routines.
227 static inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
229 return Delay->Line[offset&Delay->Mask];
232 static inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
234 Delay->Line[offset&Delay->Mask] = in;
237 // Attenuated delay line output routine.
238 static inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff)
240 return coeff * Delay->Line[offset&Delay->Mask];
243 // Basic attenuated all-pass input/output routine.
244 static inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
246 ALfloat out, feed;
248 out = DelayLineOut(Delay, outOffset);
249 feed = feedCoeff * in;
250 DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in);
252 // The time-based attenuation is only applied to the delay output to
253 // keep it from affecting the feed-back path (which is already controlled
254 // by the all-pass feed coefficient).
255 return (coeff * out) - feed;
258 // Given an input sample, this function produces modulation for the late
259 // reverb.
260 static inline ALfloat EAXModulation(ALreverbState *State, ALfloat in)
262 ALfloat sinus, frac;
263 ALuint offset;
264 ALfloat out0, out1;
266 // Calculate the sinus rythm (dependent on modulation time and the
267 // sampling rate). The center of the sinus is moved to reduce the delay
268 // of the effect when the time or depth are low.
269 sinus = 1.0f - cosf(F_2PI * State->Mod.Index / State->Mod.Range);
271 // The depth determines the range over which to read the input samples
272 // from, so it must be filtered to reduce the distortion caused by even
273 // small parameter changes.
274 State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth,
275 State->Mod.Coeff);
277 // Calculate the read offset and fraction between it and the next sample.
278 frac = (1.0f + (State->Mod.Filter * sinus));
279 offset = fastf2u(frac);
280 frac -= offset;
282 // Get the two samples crossed by the offset, and feed the delay line
283 // with the next input sample.
284 out0 = DelayLineOut(&State->Mod.Delay, State->Offset - offset);
285 out1 = DelayLineOut(&State->Mod.Delay, State->Offset - offset - 1);
286 DelayLineIn(&State->Mod.Delay, State->Offset, in);
288 // Step the modulation index forward, keeping it bound to its range.
289 State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range;
291 // The output is obtained by linearly interpolating the two samples that
292 // were acquired above.
293 return lerp(out0, out1, frac);
296 // Delay line output routine for early reflections.
297 static inline ALfloat EarlyDelayLineOut(ALreverbState *State, ALuint index)
299 return AttenuatedDelayLineOut(&State->Early.Delay[index],
300 State->Offset - State->Early.Offset[index],
301 State->Early.Coeff[index]);
304 // Given an input sample, this function produces four-channel output for the
305 // early reflections.
306 static inline ALvoid EarlyReflection(ALreverbState *State, ALfloat in, ALfloat *restrict out)
308 ALfloat d[4], v, f[4];
310 // Obtain the decayed results of each early delay line.
311 d[0] = EarlyDelayLineOut(State, 0);
312 d[1] = EarlyDelayLineOut(State, 1);
313 d[2] = EarlyDelayLineOut(State, 2);
314 d[3] = EarlyDelayLineOut(State, 3);
316 /* The following uses a lossless scattering junction from waveguide
317 * theory. It actually amounts to a householder mixing matrix, which
318 * will produce a maximally diffuse response, and means this can probably
319 * be considered a simple feed-back delay network (FDN).
321 * ---
323 * v = 2/N / d_i
324 * ---
325 * i=1
327 v = (d[0] + d[1] + d[2] + d[3]) * 0.5f;
328 // The junction is loaded with the input here.
329 v += in;
331 // Calculate the feed values for the delay lines.
332 f[0] = v - d[0];
333 f[1] = v - d[1];
334 f[2] = v - d[2];
335 f[3] = v - d[3];
337 // Re-feed the delay lines.
338 DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]);
339 DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]);
340 DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]);
341 DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]);
343 // Output the results of the junction for all four channels.
344 out[0] = State->Early.Gain * f[0];
345 out[1] = State->Early.Gain * f[1];
346 out[2] = State->Early.Gain * f[2];
347 out[3] = State->Early.Gain * f[3];
350 // All-pass input/output routine for late reverb.
351 static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint index, ALfloat in)
353 return AllpassInOut(&State->Late.ApDelay[index],
354 State->Offset - State->Late.ApOffset[index],
355 State->Offset, in, State->Late.ApFeedCoeff,
356 State->Late.ApCoeff[index]);
359 // Delay line output routine for late reverb.
360 static inline ALfloat LateDelayLineOut(ALreverbState *State, ALuint index)
362 return AttenuatedDelayLineOut(&State->Late.Delay[index],
363 State->Offset - State->Late.Offset[index],
364 State->Late.Coeff[index]);
367 // Low-pass filter input/output routine for late reverb.
368 static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALfloat in)
370 in = lerp(in, State->Late.LpSample[index], State->Late.LpCoeff[index]);
371 State->Late.LpSample[index] = in;
372 return in;
375 // Given four decorrelated input samples, this function produces four-channel
376 // output for the late reverb.
377 static inline ALvoid LateReverb(ALreverbState *State, const ALfloat *restrict in, ALfloat *restrict out)
379 ALfloat d[4], f[4];
381 // Obtain the decayed results of the cyclical delay lines, and add the
382 // corresponding input channels. Then pass the results through the
383 // low-pass filters.
385 // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and back
386 // to 0.
387 d[0] = LateLowPassInOut(State, 2, in[2] + LateDelayLineOut(State, 2));
388 d[1] = LateLowPassInOut(State, 0, in[0] + LateDelayLineOut(State, 0));
389 d[2] = LateLowPassInOut(State, 3, in[3] + LateDelayLineOut(State, 3));
390 d[3] = LateLowPassInOut(State, 1, in[1] + LateDelayLineOut(State, 1));
392 // To help increase diffusion, run each line through an all-pass filter.
393 // When there is no diffusion, the shortest all-pass filter will feed the
394 // shortest delay line.
395 d[0] = LateAllPassInOut(State, 0, d[0]);
396 d[1] = LateAllPassInOut(State, 1, d[1]);
397 d[2] = LateAllPassInOut(State, 2, d[2]);
398 d[3] = LateAllPassInOut(State, 3, d[3]);
400 /* Late reverb is done with a modified feed-back delay network (FDN)
401 * topology. Four input lines are each fed through their own all-pass
402 * filter and then into the mixing matrix. The four outputs of the
403 * mixing matrix are then cycled back to the inputs. Each output feeds
404 * a different input to form a circlular feed cycle.
406 * The mixing matrix used is a 4D skew-symmetric rotation matrix derived
407 * using a single unitary rotational parameter:
409 * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
410 * [ -a, d, c, -b ]
411 * [ -b, -c, d, a ]
412 * [ -c, b, -a, d ]
414 * The rotation is constructed from the effect's diffusion parameter,
415 * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
416 * with differing signs, and d is the coefficient x. The matrix is thus:
418 * [ x, y, -y, y ] n = sqrt(matrix_order - 1)
419 * [ -y, x, y, y ] t = diffusion_parameter * atan(n)
420 * [ y, -y, x, y ] x = cos(t)
421 * [ -y, -y, -y, x ] y = sin(t) / n
423 * To reduce the number of multiplies, the x coefficient is applied with
424 * the cyclical delay line coefficients. Thus only the y coefficient is
425 * applied when mixing, and is modified to be: y / x.
427 f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3]));
428 f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3]));
429 f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3]));
430 f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] ));
432 // Output the results of the matrix for all four channels, attenuated by
433 // the late reverb gain (which is attenuated by the 'x' mix coefficient).
434 out[0] = State->Late.Gain * f[0];
435 out[1] = State->Late.Gain * f[1];
436 out[2] = State->Late.Gain * f[2];
437 out[3] = State->Late.Gain * f[3];
439 // Re-feed the cyclical delay lines.
440 DelayLineIn(&State->Late.Delay[0], State->Offset, f[0]);
441 DelayLineIn(&State->Late.Delay[1], State->Offset, f[1]);
442 DelayLineIn(&State->Late.Delay[2], State->Offset, f[2]);
443 DelayLineIn(&State->Late.Delay[3], State->Offset, f[3]);
446 // Given an input sample, this function mixes echo into the four-channel late
447 // reverb.
448 static inline ALvoid EAXEcho(ALreverbState *State, ALfloat in, ALfloat *restrict late)
450 ALfloat out, feed;
452 // Get the latest attenuated echo sample for output.
453 feed = AttenuatedDelayLineOut(&State->Echo.Delay,
454 State->Offset - State->Echo.Offset,
455 State->Echo.Coeff);
457 // Mix the output into the late reverb channels.
458 out = State->Echo.MixCoeff[0] * feed;
459 late[0] = (State->Echo.MixCoeff[1] * late[0]) + out;
460 late[1] = (State->Echo.MixCoeff[1] * late[1]) + out;
461 late[2] = (State->Echo.MixCoeff[1] * late[2]) + out;
462 late[3] = (State->Echo.MixCoeff[1] * late[3]) + out;
464 // Mix the energy-attenuated input with the output and pass it through
465 // the echo low-pass filter.
466 feed += State->Echo.DensityGain * in;
467 feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff);
468 State->Echo.LpSample = feed;
470 // Then the echo all-pass filter.
471 feed = AllpassInOut(&State->Echo.ApDelay,
472 State->Offset - State->Echo.ApOffset,
473 State->Offset, feed, State->Echo.ApFeedCoeff,
474 State->Echo.ApCoeff);
476 // Feed the delay with the mixed and filtered sample.
477 DelayLineIn(&State->Echo.Delay, State->Offset, feed);
480 // Perform the non-EAX reverb pass on a given input sample, resulting in
481 // four-channel output.
482 static inline ALvoid VerbPass(ALreverbState *State, ALfloat in, ALfloat *restrict out)
484 ALfloat feed, late[4], taps[4];
486 // Filter the incoming sample.
487 in = ALfilterState_processSingle(&State->LpFilter, in);
489 // Feed the initial delay line.
490 DelayLineIn(&State->Delay, State->Offset, in);
492 // Calculate the early reflection from the first delay tap.
493 in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
494 EarlyReflection(State, in, out);
496 // Feed the decorrelator from the energy-attenuated output of the second
497 // delay tap.
498 in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
499 feed = in * State->Late.DensityGain;
500 DelayLineIn(&State->Decorrelator, State->Offset, feed);
502 // Calculate the late reverb from the decorrelator taps.
503 taps[0] = feed;
504 taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
505 taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
506 taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
507 LateReverb(State, taps, late);
509 // Mix early reflections and late reverb.
510 out[0] += late[0];
511 out[1] += late[1];
512 out[2] += late[2];
513 out[3] += late[3];
515 // Step all delays forward one sample.
516 State->Offset++;
519 // Perform the EAX reverb pass on a given input sample, resulting in four-
520 // channel output.
521 static inline ALvoid EAXVerbPass(ALreverbState *State, ALfloat in, ALfloat *restrict early, ALfloat *restrict late)
523 ALfloat feed, taps[4];
525 // Low-pass filter the incoming sample.
526 in = ALfilterState_processSingle(&State->LpFilter, in);
527 in = ALfilterState_processSingle(&State->HpFilter, in);
529 // Perform any modulation on the input.
530 in = EAXModulation(State, in);
532 // Feed the initial delay line.
533 DelayLineIn(&State->Delay, State->Offset, in);
535 // Calculate the early reflection from the first delay tap.
536 in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
537 EarlyReflection(State, in, early);
539 // Feed the decorrelator from the energy-attenuated output of the second
540 // delay tap.
541 in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
542 feed = in * State->Late.DensityGain;
543 DelayLineIn(&State->Decorrelator, State->Offset, feed);
545 // Calculate the late reverb from the decorrelator taps.
546 taps[0] = feed;
547 taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
548 taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
549 taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
550 LateReverb(State, taps, late);
552 // Calculate and mix in any echo.
553 EAXEcho(State, in, late);
555 // Step all delays forward one sample.
556 State->Offset++;
559 static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
561 ALfloat (*restrict out)[4] = State->ReverbSamples;
562 ALuint index, c;
564 /* Process reverb for these samples. */
565 for(index = 0;index < SamplesToDo;index++)
566 VerbPass(State, SamplesIn[index], out[index]);
568 for(c = 0;c < NumChannels;c++)
570 ALfloat gain = State->Gain[c];
571 if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
572 continue;
574 for(index = 0;index < SamplesToDo;index++)
575 SamplesOut[c][index] += gain * out[index][c&3];
579 static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
581 ALfloat (*restrict early)[4] = State->EarlySamples;
582 ALfloat (*restrict late)[4] = State->ReverbSamples;
583 ALuint index, c;
585 /* Process reverb for these samples. */
586 for(index = 0;index < SamplesToDo;index++)
587 EAXVerbPass(State, SamplesIn[index], early[index], late[index]);
589 for(c = 0;c < NumChannels;c++)
591 ALfloat earlyGain, lateGain;
593 earlyGain = State->Early.PanGain[c];
594 if(fabsf(earlyGain) > GAIN_SILENCE_THRESHOLD)
596 for(index = 0;index < SamplesToDo;index++)
597 SamplesOut[c][index] += earlyGain*early[index][c&3];
599 lateGain = State->Late.PanGain[c];
600 if(fabsf(lateGain) > GAIN_SILENCE_THRESHOLD)
602 for(index = 0;index < SamplesToDo;index++)
603 SamplesOut[c][index] += lateGain*late[index][c&3];
608 static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
610 if(State->IsEax)
611 ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
612 else
613 ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
616 // Given the allocated sample buffer, this function updates each delay line
617 // offset.
618 static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay)
620 Delay->Line = &sampleBuffer[(ptrdiff_t)Delay->Line];
623 // Calculate the length of a delay line and store its mask and offset.
624 static ALuint CalcLineLength(ALfloat length, ptrdiff_t offset, ALuint frequency, DelayLine *Delay)
626 ALuint samples;
628 // All line lengths are powers of 2, calculated from their lengths, with
629 // an additional sample in case of rounding errors.
630 samples = NextPowerOf2(fastf2u(length * frequency) + 1);
631 // All lines share a single sample buffer.
632 Delay->Mask = samples - 1;
633 Delay->Line = (ALfloat*)offset;
634 // Return the sample count for accumulation.
635 return samples;
638 /* Calculates the delay line metrics and allocates the shared sample buffer
639 * for all lines given the sample rate (frequency). If an allocation failure
640 * occurs, it returns AL_FALSE.
642 static ALboolean AllocLines(ALuint frequency, ALreverbState *State)
644 ALuint totalSamples, index;
645 ALfloat length;
646 ALfloat *newBuffer = NULL;
648 // All delay line lengths are calculated to accomodate the full range of
649 // lengths given their respective paramters.
650 totalSamples = 0;
652 /* The modulator's line length is calculated from the maximum modulation
653 * time and depth coefficient, and halfed for the low-to-high frequency
654 * swing. An additional sample is added to keep it stable when there is no
655 * modulation.
657 length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f) +
658 (1.0f / frequency);
659 totalSamples += CalcLineLength(length, totalSamples, frequency,
660 &State->Mod.Delay);
662 // The initial delay is the sum of the reflections and late reverb
663 // delays.
664 length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
665 AL_EAXREVERB_MAX_LATE_REVERB_DELAY;
666 totalSamples += CalcLineLength(length, totalSamples, frequency,
667 &State->Delay);
669 // The early reflection lines.
670 for(index = 0;index < 4;index++)
671 totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples,
672 frequency, &State->Early.Delay[index]);
674 // The decorrelator line is calculated from the lowest reverb density (a
675 // parameter value of 1).
676 length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) *
677 LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER);
678 totalSamples += CalcLineLength(length, totalSamples, frequency,
679 &State->Decorrelator);
681 // The late all-pass lines.
682 for(index = 0;index < 4;index++)
683 totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples,
684 frequency, &State->Late.ApDelay[index]);
686 // The late delay lines are calculated from the lowest reverb density.
687 for(index = 0;index < 4;index++)
689 length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER);
690 totalSamples += CalcLineLength(length, totalSamples, frequency,
691 &State->Late.Delay[index]);
694 // The echo all-pass and delay lines.
695 totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples,
696 frequency, &State->Echo.ApDelay);
697 totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples,
698 frequency, &State->Echo.Delay);
700 if(totalSamples != State->TotalSamples)
702 TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency);
703 newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples);
704 if(newBuffer == NULL)
705 return AL_FALSE;
706 State->SampleBuffer = newBuffer;
707 State->TotalSamples = totalSamples;
710 // Update all delays to reflect the new sample buffer.
711 RealizeLineOffset(State->SampleBuffer, &State->Delay);
712 RealizeLineOffset(State->SampleBuffer, &State->Decorrelator);
713 for(index = 0;index < 4;index++)
715 RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]);
716 RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]);
717 RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]);
719 RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay);
720 RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay);
721 RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay);
723 // Clear the sample buffer.
724 for(index = 0;index < State->TotalSamples;index++)
725 State->SampleBuffer[index] = 0.0f;
727 return AL_TRUE;
730 static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device)
732 ALuint frequency = Device->Frequency, index;
734 // Allocate the delay lines.
735 if(!AllocLines(frequency, State))
736 return AL_FALSE;
738 // Calculate the modulation filter coefficient. Notice that the exponent
739 // is calculated given the current sample rate. This ensures that the
740 // resulting filter response over time is consistent across all sample
741 // rates.
742 State->Mod.Coeff = powf(MODULATION_FILTER_COEFF,
743 MODULATION_FILTER_CONST / frequency);
745 // The early reflection and late all-pass filter line lengths are static,
746 // so their offsets only need to be calculated once.
747 for(index = 0;index < 4;index++)
749 State->Early.Offset[index] = fastf2u(EARLY_LINE_LENGTH[index] *
750 frequency);
751 State->Late.ApOffset[index] = fastf2u(ALLPASS_LINE_LENGTH[index] *
752 frequency);
755 // The echo all-pass filter line length is static, so its offset only
756 // needs to be calculated once.
757 State->Echo.ApOffset = fastf2u(ECHO_ALLPASS_LENGTH * frequency);
759 return AL_TRUE;
762 // Calculate a decay coefficient given the length of each cycle and the time
763 // until the decay reaches -60 dB.
764 static inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime)
766 return powf(0.001f/*-60 dB*/, length/decayTime);
769 // Calculate a decay length from a coefficient and the time until the decay
770 // reaches -60 dB.
771 static inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime)
773 return log10f(coeff) * decayTime / log10f(0.001f)/*-60 dB*/;
776 // Calculate an attenuation to be applied to the input of any echo models to
777 // compensate for modal density and decay time.
778 static inline ALfloat CalcDensityGain(ALfloat a)
780 /* The energy of a signal can be obtained by finding the area under the
781 * squared signal. This takes the form of Sum(x_n^2), where x is the
782 * amplitude for the sample n.
784 * Decaying feedback matches exponential decay of the form Sum(a^n),
785 * where a is the attenuation coefficient, and n is the sample. The area
786 * under this decay curve can be calculated as: 1 / (1 - a).
788 * Modifying the above equation to find the squared area under the curve
789 * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be
790 * calculated by inverting the square root of this approximation,
791 * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2).
793 return sqrtf(1.0f - (a * a));
796 // Calculate the mixing matrix coefficients given a diffusion factor.
797 static inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y)
799 ALfloat n, t;
801 // The matrix is of order 4, so n is sqrt (4 - 1).
802 n = sqrtf(3.0f);
803 t = diffusion * atanf(n);
805 // Calculate the first mixing matrix coefficient.
806 *x = cosf(t);
807 // Calculate the second mixing matrix coefficient.
808 *y = sinf(t) / n;
811 // Calculate the limited HF ratio for use with the late reverb low-pass
812 // filters.
813 static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime)
815 ALfloat limitRatio;
817 /* Find the attenuation due to air absorption in dB (converting delay
818 * time to meters using the speed of sound). Then reversing the decay
819 * equation, solve for HF ratio. The delay length is cancelled out of
820 * the equation, so it can be calculated once for all lines.
822 limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) *
823 SPEEDOFSOUNDMETRESPERSEC);
824 /* Using the limit calculated above, apply the upper bound to the HF
825 * ratio. Also need to limit the result to a minimum of 0.1, just like the
826 * HF ratio parameter. */
827 return clampf(limitRatio, 0.1f, hfRatio);
830 // Calculate the coefficient for a HF (and eventually LF) decay damping
831 // filter.
832 static inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw)
834 ALfloat coeff, g;
836 // Eventually this should boost the high frequencies when the ratio
837 // exceeds 1.
838 coeff = 0.0f;
839 if (hfRatio < 1.0f)
841 // Calculate the low-pass coefficient by dividing the HF decay
842 // coefficient by the full decay coefficient.
843 g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff;
845 // Damping is done with a 1-pole filter, so g needs to be squared.
846 g *= g;
847 if(g < 0.9999f) /* 1-epsilon */
849 /* Be careful with gains < 0.001, as that causes the coefficient
850 * head towards 1, which will flatten the signal. */
851 g = maxf(g, 0.001f);
852 coeff = (1 - g*cw - sqrtf(2*g*(1-cw) - g*g*(1 - cw*cw))) /
853 (1 - g);
856 // Very low decay times will produce minimal output, so apply an
857 // upper bound to the coefficient.
858 coeff = minf(coeff, 0.98f);
860 return coeff;
863 // Update the EAX modulation index, range, and depth. Keep in mind that this
864 // kind of vibrato is additive and not multiplicative as one may expect. The
865 // downswing will sound stronger than the upswing.
866 static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALreverbState *State)
868 ALuint range;
870 /* Modulation is calculated in two parts.
872 * The modulation time effects the sinus applied to the change in
873 * frequency. An index out of the current time range (both in samples)
874 * is incremented each sample. The range is bound to a reasonable
875 * minimum (1 sample) and when the timing changes, the index is rescaled
876 * to the new range (to keep the sinus consistent).
878 range = maxu(fastf2u(modTime*frequency), 1);
879 State->Mod.Index = (ALuint)(State->Mod.Index * (ALuint64)range /
880 State->Mod.Range);
881 State->Mod.Range = range;
883 /* The modulation depth effects the amount of frequency change over the
884 * range of the sinus. It needs to be scaled by the modulation time so
885 * that a given depth produces a consistent change in frequency over all
886 * ranges of time. Since the depth is applied to a sinus value, it needs
887 * to be halfed once for the sinus range and again for the sinus swing
888 * in time (half of it is spent decreasing the frequency, half is spent
889 * increasing it).
891 State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f /
892 2.0f * frequency;
895 // Update the offsets for the initial effect delay line.
896 static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALreverbState *State)
898 // Calculate the initial delay taps.
899 State->DelayTap[0] = fastf2u(earlyDelay * frequency);
900 State->DelayTap[1] = fastf2u((earlyDelay + lateDelay) * frequency);
903 // Update the early reflections gain and line coefficients.
904 static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALreverbState *State)
906 ALuint index;
908 // Calculate the early reflections gain (from the master effect gain, and
909 // reflections gain parameters) with a constant attenuation of 0.5.
910 State->Early.Gain = 0.5f * reverbGain * earlyGain;
912 // Calculate the gain (coefficient) for each early delay line using the
913 // late delay time. This expands the early reflections to the start of
914 // the late reverb.
915 for(index = 0;index < 4;index++)
916 State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index],
917 lateDelay);
920 // Update the offsets for the decorrelator line.
921 static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbState *State)
923 ALuint index;
924 ALfloat length;
926 /* The late reverb inputs are decorrelated to smooth the reverb tail and
927 * reduce harsh echos. The first tap occurs immediately, while the
928 * remaining taps are delayed by multiples of a fraction of the smallest
929 * cyclical delay time.
931 * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay
933 for(index = 0;index < 3;index++)
935 length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) *
936 LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER));
937 State->DecoTap[index] = fastf2u(length * frequency);
941 // Update the late reverb gains, line lengths, and line coefficients.
942 static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State)
944 ALfloat length;
945 ALuint index;
947 /* Calculate the late reverb gain (from the master effect gain, and late
948 * reverb gain parameters). Since the output is tapped prior to the
949 * application of the next delay line coefficients, this gain needs to be
950 * attenuated by the 'x' mixing matrix coefficient as well.
952 State->Late.Gain = reverbGain * lateGain * xMix;
954 /* To compensate for changes in modal density and decay time of the late
955 * reverb signal, the input is attenuated based on the maximal energy of
956 * the outgoing signal. This approximation is used to keep the apparent
957 * energy of the signal equal for all ranges of density and decay time.
959 * The average length of the cyclcical delay lines is used to calculate
960 * the attenuation coefficient.
962 length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] +
963 LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f;
964 length *= 1.0f + (density * LATE_LINE_MULTIPLIER);
965 State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length,
966 decayTime));
968 // Calculate the all-pass feed-back and feed-forward coefficient.
969 State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f);
971 for(index = 0;index < 4;index++)
973 // Calculate the gain (coefficient) for each all-pass line.
974 State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index],
975 decayTime);
977 // Calculate the length (in seconds) of each cyclical delay line.
978 length = LATE_LINE_LENGTH[index] * (1.0f + (density *
979 LATE_LINE_MULTIPLIER));
981 // Calculate the delay offset for each cyclical delay line.
982 State->Late.Offset[index] = fastf2u(length * frequency);
984 // Calculate the gain (coefficient) for each cyclical line.
985 State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime);
987 // Calculate the damping coefficient for each low-pass filter.
988 State->Late.LpCoeff[index] =
989 CalcDampingCoeff(hfRatio, length, decayTime,
990 State->Late.Coeff[index], cw);
992 // Attenuate the cyclical line coefficients by the mixing coefficient
993 // (x).
994 State->Late.Coeff[index] *= xMix;
998 // Update the echo gain, line offset, line coefficients, and mixing
999 // coefficients.
1000 static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State)
1002 // Update the offset and coefficient for the echo delay line.
1003 State->Echo.Offset = fastf2u(echoTime * frequency);
1005 // Calculate the decay coefficient for the echo line.
1006 State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime);
1008 // Calculate the energy-based attenuation coefficient for the echo delay
1009 // line.
1010 State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff);
1012 // Calculate the echo all-pass feed coefficient.
1013 State->Echo.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f);
1015 // Calculate the echo all-pass attenuation coefficient.
1016 State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime);
1018 // Calculate the damping coefficient for each low-pass filter.
1019 State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime,
1020 State->Echo.Coeff, cw);
1022 /* Calculate the echo mixing coefficients. The first is applied to the
1023 * echo itself. The second is used to attenuate the late reverb when
1024 * echo depth is high and diffusion is low, so the echo is slightly
1025 * stronger than the decorrelated echos in the reverb tail.
1027 State->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth;
1028 State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion));
1031 // Update the early and late 3D panning gains.
1032 static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State)
1034 ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1], -ReflectionsPan[2] };
1035 ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1], -LateReverbPan[2] };
1036 ALfloat AmbientGains[MAX_OUTPUT_CHANNELS];
1037 ALfloat DirGains[MAX_OUTPUT_CHANNELS];
1038 ALfloat length, invlen;
1039 ALuint i;
1041 ComputeAmbientGains(Device, 1.4142f, AmbientGains);
1043 length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2];
1044 if(!(length > FLT_EPSILON))
1046 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
1047 State->Early.PanGain[i] = AmbientGains[i] * Gain;
1049 else
1051 invlen = 1.0f / sqrtf(length);
1052 earlyPan[0] *= invlen;
1053 earlyPan[1] *= invlen;
1054 earlyPan[2] *= invlen;
1056 length = minf(length, 1.0f);
1057 ComputeDirectionalGains(Device, earlyPan, 1.4142f, DirGains);
1058 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
1059 State->Early.PanGain[i] = lerp(AmbientGains[i], DirGains[i], length) * Gain;
1062 length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2];
1063 if(!(length > FLT_EPSILON))
1065 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
1066 State->Late.PanGain[i] = AmbientGains[i] * Gain;
1068 else
1070 invlen = 1.0f / sqrtf(length);
1071 latePan[0] *= invlen;
1072 latePan[1] *= invlen;
1073 latePan[2] *= invlen;
1075 length = minf(length, 1.0f);
1076 ComputeDirectionalGains(Device, latePan, 1.4142f, DirGains);
1077 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
1078 State->Late.PanGain[i] = lerp(AmbientGains[i], DirGains[i], length) * Gain;
1082 static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, const ALeffectslot *Slot)
1084 ALuint frequency = Device->Frequency;
1085 ALfloat lfscale, hfscale, hfRatio;
1086 ALfloat cw, x, y;
1088 if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb)
1089 State->IsEax = AL_TRUE;
1090 else if(Slot->EffectType == AL_EFFECT_REVERB || EmulateEAXReverb)
1091 State->IsEax = AL_FALSE;
1093 // Calculate the master low-pass filter (from the master effect HF gain).
1094 if(State->IsEax)
1096 hfscale = Slot->EffectProps.Reverb.HFReference / frequency;
1097 ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
1098 Slot->EffectProps.Reverb.GainHF,
1099 hfscale, 0.0f);
1100 lfscale = Slot->EffectProps.Reverb.LFReference / frequency;
1101 ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf,
1102 Slot->EffectProps.Reverb.GainLF,
1103 lfscale, 0.0f);
1105 else
1107 hfscale = LOWPASSFREQREF / frequency;
1108 ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
1109 Slot->EffectProps.Reverb.GainHF,
1110 hfscale, 0.0f);
1113 if(State->IsEax)
1115 // Update the modulator line.
1116 UpdateModulator(Slot->EffectProps.Reverb.ModulationTime,
1117 Slot->EffectProps.Reverb.ModulationDepth,
1118 frequency, State);
1121 // Update the initial effect delay.
1122 UpdateDelayLine(Slot->EffectProps.Reverb.ReflectionsDelay,
1123 Slot->EffectProps.Reverb.LateReverbDelay,
1124 frequency, State);
1126 // Update the early lines.
1127 UpdateEarlyLines(Slot->EffectProps.Reverb.Gain,
1128 Slot->EffectProps.Reverb.ReflectionsGain,
1129 Slot->EffectProps.Reverb.LateReverbDelay, State);
1131 // Update the decorrelator.
1132 UpdateDecorrelator(Slot->EffectProps.Reverb.Density, frequency, State);
1134 // Get the mixing matrix coefficients (x and y).
1135 CalcMatrixCoeffs(Slot->EffectProps.Reverb.Diffusion, &x, &y);
1136 // Then divide x into y to simplify the matrix calculation.
1137 State->Late.MixCoeff = y / x;
1139 // If the HF limit parameter is flagged, calculate an appropriate limit
1140 // based on the air absorption parameter.
1141 hfRatio = Slot->EffectProps.Reverb.DecayHFRatio;
1142 if(Slot->EffectProps.Reverb.DecayHFLimit &&
1143 Slot->EffectProps.Reverb.AirAbsorptionGainHF < 1.0f)
1144 hfRatio = CalcLimitedHfRatio(hfRatio,
1145 Slot->EffectProps.Reverb.AirAbsorptionGainHF,
1146 Slot->EffectProps.Reverb.DecayTime);
1148 cw = cosf(F_2PI * hfscale);
1149 // Update the late lines.
1150 UpdateLateLines(Slot->EffectProps.Reverb.Gain, Slot->EffectProps.Reverb.LateReverbGain,
1151 x, Slot->EffectProps.Reverb.Density, Slot->EffectProps.Reverb.DecayTime,
1152 Slot->EffectProps.Reverb.Diffusion, hfRatio, cw, frequency, State);
1154 if(State->IsEax)
1156 // Update the echo line.
1157 UpdateEchoLine(Slot->EffectProps.Reverb.Gain, Slot->EffectProps.Reverb.LateReverbGain,
1158 Slot->EffectProps.Reverb.EchoTime, Slot->EffectProps.Reverb.DecayTime,
1159 Slot->EffectProps.Reverb.Diffusion, Slot->EffectProps.Reverb.EchoDepth,
1160 hfRatio, cw, frequency, State);
1162 // Update early and late 3D panning.
1163 Update3DPanning(Device, Slot->EffectProps.Reverb.ReflectionsPan,
1164 Slot->EffectProps.Reverb.LateReverbPan,
1165 Slot->Gain * ReverbBoost, State);
1167 else
1169 /* Update channel gains */
1170 ComputeAmbientGains(Device, Slot->Gain*1.4142f, State->Gain);
1175 static ALvoid ALreverbState_Destruct(ALreverbState *State)
1177 free(State->SampleBuffer);
1178 State->SampleBuffer = NULL;
1181 DECLARE_DEFAULT_ALLOCATORS(ALreverbState)
1183 DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState);
1186 typedef struct ALreverbStateFactory {
1187 DERIVE_FROM_TYPE(ALeffectStateFactory);
1188 } ALreverbStateFactory;
1190 static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(factory))
1192 ALreverbState *state;
1193 ALuint index;
1195 state = ALreverbState_New(sizeof(*state));
1196 if(!state) return NULL;
1197 SET_VTABLE2(ALreverbState, ALeffectState, state);
1199 state->TotalSamples = 0;
1200 state->SampleBuffer = NULL;
1202 ALfilterState_clear(&state->LpFilter);
1203 ALfilterState_clear(&state->HpFilter);
1205 state->Mod.Delay.Mask = 0;
1206 state->Mod.Delay.Line = NULL;
1207 state->Mod.Index = 0;
1208 state->Mod.Range = 1;
1209 state->Mod.Depth = 0.0f;
1210 state->Mod.Coeff = 0.0f;
1211 state->Mod.Filter = 0.0f;
1213 state->Delay.Mask = 0;
1214 state->Delay.Line = NULL;
1215 state->DelayTap[0] = 0;
1216 state->DelayTap[1] = 0;
1218 state->Early.Gain = 0.0f;
1219 for(index = 0;index < 4;index++)
1221 state->Early.Coeff[index] = 0.0f;
1222 state->Early.Delay[index].Mask = 0;
1223 state->Early.Delay[index].Line = NULL;
1224 state->Early.Offset[index] = 0;
1227 state->Decorrelator.Mask = 0;
1228 state->Decorrelator.Line = NULL;
1229 state->DecoTap[0] = 0;
1230 state->DecoTap[1] = 0;
1231 state->DecoTap[2] = 0;
1233 state->Late.Gain = 0.0f;
1234 state->Late.DensityGain = 0.0f;
1235 state->Late.ApFeedCoeff = 0.0f;
1236 state->Late.MixCoeff = 0.0f;
1237 for(index = 0;index < 4;index++)
1239 state->Late.ApCoeff[index] = 0.0f;
1240 state->Late.ApDelay[index].Mask = 0;
1241 state->Late.ApDelay[index].Line = NULL;
1242 state->Late.ApOffset[index] = 0;
1244 state->Late.Coeff[index] = 0.0f;
1245 state->Late.Delay[index].Mask = 0;
1246 state->Late.Delay[index].Line = NULL;
1247 state->Late.Offset[index] = 0;
1249 state->Late.LpCoeff[index] = 0.0f;
1250 state->Late.LpSample[index] = 0.0f;
1253 for(index = 0;index < MAX_OUTPUT_CHANNELS;index++)
1255 state->Early.PanGain[index] = 0.0f;
1256 state->Late.PanGain[index] = 0.0f;
1259 state->Echo.DensityGain = 0.0f;
1260 state->Echo.Delay.Mask = 0;
1261 state->Echo.Delay.Line = NULL;
1262 state->Echo.ApDelay.Mask = 0;
1263 state->Echo.ApDelay.Line = NULL;
1264 state->Echo.Coeff = 0.0f;
1265 state->Echo.ApFeedCoeff = 0.0f;
1266 state->Echo.ApCoeff = 0.0f;
1267 state->Echo.Offset = 0;
1268 state->Echo.ApOffset = 0;
1269 state->Echo.LpCoeff = 0.0f;
1270 state->Echo.LpSample = 0.0f;
1271 state->Echo.MixCoeff[0] = 0.0f;
1272 state->Echo.MixCoeff[1] = 0.0f;
1274 state->Offset = 0;
1276 state->Gain = state->Late.PanGain;
1278 return STATIC_CAST(ALeffectState, state);
1281 DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALreverbStateFactory);
1283 ALeffectStateFactory *ALreverbStateFactory_getFactory(void)
1285 static ALreverbStateFactory ReverbFactory = { { GET_VTABLE2(ALreverbStateFactory, ALeffectStateFactory) } };
1287 return STATIC_CAST(ALeffectStateFactory, &ReverbFactory);
1291 void ALeaxreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
1293 ALeffectProps *props = &effect->Props;
1294 switch(param)
1296 case AL_EAXREVERB_DECAY_HFLIMIT:
1297 if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT))
1298 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1299 props->Reverb.DecayHFLimit = val;
1300 break;
1302 default:
1303 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
1306 void ALeaxreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
1308 ALeaxreverb_setParami(effect, context, param, vals[0]);
1310 void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
1312 ALeffectProps *props = &effect->Props;
1313 switch(param)
1315 case AL_EAXREVERB_DENSITY:
1316 if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY))
1317 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1318 props->Reverb.Density = val;
1319 break;
1321 case AL_EAXREVERB_DIFFUSION:
1322 if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION))
1323 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1324 props->Reverb.Diffusion = val;
1325 break;
1327 case AL_EAXREVERB_GAIN:
1328 if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN))
1329 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1330 props->Reverb.Gain = val;
1331 break;
1333 case AL_EAXREVERB_GAINHF:
1334 if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF))
1335 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1336 props->Reverb.GainHF = val;
1337 break;
1339 case AL_EAXREVERB_GAINLF:
1340 if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF))
1341 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1342 props->Reverb.GainLF = val;
1343 break;
1345 case AL_EAXREVERB_DECAY_TIME:
1346 if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME))
1347 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1348 props->Reverb.DecayTime = val;
1349 break;
1351 case AL_EAXREVERB_DECAY_HFRATIO:
1352 if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO))
1353 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1354 props->Reverb.DecayHFRatio = val;
1355 break;
1357 case AL_EAXREVERB_DECAY_LFRATIO:
1358 if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO))
1359 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1360 props->Reverb.DecayLFRatio = val;
1361 break;
1363 case AL_EAXREVERB_REFLECTIONS_GAIN:
1364 if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN))
1365 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1366 props->Reverb.ReflectionsGain = val;
1367 break;
1369 case AL_EAXREVERB_REFLECTIONS_DELAY:
1370 if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY))
1371 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1372 props->Reverb.ReflectionsDelay = val;
1373 break;
1375 case AL_EAXREVERB_LATE_REVERB_GAIN:
1376 if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN))
1377 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1378 props->Reverb.LateReverbGain = val;
1379 break;
1381 case AL_EAXREVERB_LATE_REVERB_DELAY:
1382 if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY))
1383 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1384 props->Reverb.LateReverbDelay = val;
1385 break;
1387 case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
1388 if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF))
1389 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1390 props->Reverb.AirAbsorptionGainHF = val;
1391 break;
1393 case AL_EAXREVERB_ECHO_TIME:
1394 if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME))
1395 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1396 props->Reverb.EchoTime = val;
1397 break;
1399 case AL_EAXREVERB_ECHO_DEPTH:
1400 if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH))
1401 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1402 props->Reverb.EchoDepth = val;
1403 break;
1405 case AL_EAXREVERB_MODULATION_TIME:
1406 if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME))
1407 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1408 props->Reverb.ModulationTime = val;
1409 break;
1411 case AL_EAXREVERB_MODULATION_DEPTH:
1412 if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH))
1413 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1414 props->Reverb.ModulationDepth = val;
1415 break;
1417 case AL_EAXREVERB_HFREFERENCE:
1418 if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE))
1419 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1420 props->Reverb.HFReference = val;
1421 break;
1423 case AL_EAXREVERB_LFREFERENCE:
1424 if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE))
1425 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1426 props->Reverb.LFReference = val;
1427 break;
1429 case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
1430 if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR))
1431 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1432 props->Reverb.RoomRolloffFactor = val;
1433 break;
1435 default:
1436 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
1439 void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
1441 ALeffectProps *props = &effect->Props;
1442 switch(param)
1444 case AL_EAXREVERB_REFLECTIONS_PAN:
1445 if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])))
1446 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1447 LockContext(context);
1448 props->Reverb.ReflectionsPan[0] = vals[0];
1449 props->Reverb.ReflectionsPan[1] = vals[1];
1450 props->Reverb.ReflectionsPan[2] = vals[2];
1451 UnlockContext(context);
1452 break;
1453 case AL_EAXREVERB_LATE_REVERB_PAN:
1454 if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])))
1455 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1456 LockContext(context);
1457 props->Reverb.LateReverbPan[0] = vals[0];
1458 props->Reverb.LateReverbPan[1] = vals[1];
1459 props->Reverb.LateReverbPan[2] = vals[2];
1460 UnlockContext(context);
1461 break;
1463 default:
1464 ALeaxreverb_setParamf(effect, context, param, vals[0]);
1465 break;
1469 void ALeaxreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
1471 const ALeffectProps *props = &effect->Props;
1472 switch(param)
1474 case AL_EAXREVERB_DECAY_HFLIMIT:
1475 *val = props->Reverb.DecayHFLimit;
1476 break;
1478 default:
1479 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
1482 void ALeaxreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
1484 ALeaxreverb_getParami(effect, context, param, vals);
1486 void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
1488 const ALeffectProps *props = &effect->Props;
1489 switch(param)
1491 case AL_EAXREVERB_DENSITY:
1492 *val = props->Reverb.Density;
1493 break;
1495 case AL_EAXREVERB_DIFFUSION:
1496 *val = props->Reverb.Diffusion;
1497 break;
1499 case AL_EAXREVERB_GAIN:
1500 *val = props->Reverb.Gain;
1501 break;
1503 case AL_EAXREVERB_GAINHF:
1504 *val = props->Reverb.GainHF;
1505 break;
1507 case AL_EAXREVERB_GAINLF:
1508 *val = props->Reverb.GainLF;
1509 break;
1511 case AL_EAXREVERB_DECAY_TIME:
1512 *val = props->Reverb.DecayTime;
1513 break;
1515 case AL_EAXREVERB_DECAY_HFRATIO:
1516 *val = props->Reverb.DecayHFRatio;
1517 break;
1519 case AL_EAXREVERB_DECAY_LFRATIO:
1520 *val = props->Reverb.DecayLFRatio;
1521 break;
1523 case AL_EAXREVERB_REFLECTIONS_GAIN:
1524 *val = props->Reverb.ReflectionsGain;
1525 break;
1527 case AL_EAXREVERB_REFLECTIONS_DELAY:
1528 *val = props->Reverb.ReflectionsDelay;
1529 break;
1531 case AL_EAXREVERB_LATE_REVERB_GAIN:
1532 *val = props->Reverb.LateReverbGain;
1533 break;
1535 case AL_EAXREVERB_LATE_REVERB_DELAY:
1536 *val = props->Reverb.LateReverbDelay;
1537 break;
1539 case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
1540 *val = props->Reverb.AirAbsorptionGainHF;
1541 break;
1543 case AL_EAXREVERB_ECHO_TIME:
1544 *val = props->Reverb.EchoTime;
1545 break;
1547 case AL_EAXREVERB_ECHO_DEPTH:
1548 *val = props->Reverb.EchoDepth;
1549 break;
1551 case AL_EAXREVERB_MODULATION_TIME:
1552 *val = props->Reverb.ModulationTime;
1553 break;
1555 case AL_EAXREVERB_MODULATION_DEPTH:
1556 *val = props->Reverb.ModulationDepth;
1557 break;
1559 case AL_EAXREVERB_HFREFERENCE:
1560 *val = props->Reverb.HFReference;
1561 break;
1563 case AL_EAXREVERB_LFREFERENCE:
1564 *val = props->Reverb.LFReference;
1565 break;
1567 case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
1568 *val = props->Reverb.RoomRolloffFactor;
1569 break;
1571 default:
1572 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
1575 void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
1577 const ALeffectProps *props = &effect->Props;
1578 switch(param)
1580 case AL_EAXREVERB_REFLECTIONS_PAN:
1581 LockContext(context);
1582 vals[0] = props->Reverb.ReflectionsPan[0];
1583 vals[1] = props->Reverb.ReflectionsPan[1];
1584 vals[2] = props->Reverb.ReflectionsPan[2];
1585 UnlockContext(context);
1586 break;
1587 case AL_EAXREVERB_LATE_REVERB_PAN:
1588 LockContext(context);
1589 vals[0] = props->Reverb.LateReverbPan[0];
1590 vals[1] = props->Reverb.LateReverbPan[1];
1591 vals[2] = props->Reverb.LateReverbPan[2];
1592 UnlockContext(context);
1593 break;
1595 default:
1596 ALeaxreverb_getParamf(effect, context, param, vals);
1597 break;
1601 DEFINE_ALEFFECT_VTABLE(ALeaxreverb);
1603 void ALreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
1605 ALeffectProps *props = &effect->Props;
1606 switch(param)
1608 case AL_REVERB_DECAY_HFLIMIT:
1609 if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT))
1610 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1611 props->Reverb.DecayHFLimit = val;
1612 break;
1614 default:
1615 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
1618 void ALreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
1620 ALreverb_setParami(effect, context, param, vals[0]);
1622 void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
1624 ALeffectProps *props = &effect->Props;
1625 switch(param)
1627 case AL_REVERB_DENSITY:
1628 if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY))
1629 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1630 props->Reverb.Density = val;
1631 break;
1633 case AL_REVERB_DIFFUSION:
1634 if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION))
1635 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1636 props->Reverb.Diffusion = val;
1637 break;
1639 case AL_REVERB_GAIN:
1640 if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN))
1641 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1642 props->Reverb.Gain = val;
1643 break;
1645 case AL_REVERB_GAINHF:
1646 if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF))
1647 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1648 props->Reverb.GainHF = val;
1649 break;
1651 case AL_REVERB_DECAY_TIME:
1652 if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME))
1653 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1654 props->Reverb.DecayTime = val;
1655 break;
1657 case AL_REVERB_DECAY_HFRATIO:
1658 if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO))
1659 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1660 props->Reverb.DecayHFRatio = val;
1661 break;
1663 case AL_REVERB_REFLECTIONS_GAIN:
1664 if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN))
1665 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1666 props->Reverb.ReflectionsGain = val;
1667 break;
1669 case AL_REVERB_REFLECTIONS_DELAY:
1670 if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY))
1671 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1672 props->Reverb.ReflectionsDelay = val;
1673 break;
1675 case AL_REVERB_LATE_REVERB_GAIN:
1676 if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN))
1677 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1678 props->Reverb.LateReverbGain = val;
1679 break;
1681 case AL_REVERB_LATE_REVERB_DELAY:
1682 if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY))
1683 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1684 props->Reverb.LateReverbDelay = val;
1685 break;
1687 case AL_REVERB_AIR_ABSORPTION_GAINHF:
1688 if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF))
1689 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1690 props->Reverb.AirAbsorptionGainHF = val;
1691 break;
1693 case AL_REVERB_ROOM_ROLLOFF_FACTOR:
1694 if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR))
1695 SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
1696 props->Reverb.RoomRolloffFactor = val;
1697 break;
1699 default:
1700 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
1703 void ALreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
1705 ALreverb_setParamf(effect, context, param, vals[0]);
1708 void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
1710 const ALeffectProps *props = &effect->Props;
1711 switch(param)
1713 case AL_REVERB_DECAY_HFLIMIT:
1714 *val = props->Reverb.DecayHFLimit;
1715 break;
1717 default:
1718 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
1721 void ALreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
1723 ALreverb_getParami(effect, context, param, vals);
1725 void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
1727 const ALeffectProps *props = &effect->Props;
1728 switch(param)
1730 case AL_REVERB_DENSITY:
1731 *val = props->Reverb.Density;
1732 break;
1734 case AL_REVERB_DIFFUSION:
1735 *val = props->Reverb.Diffusion;
1736 break;
1738 case AL_REVERB_GAIN:
1739 *val = props->Reverb.Gain;
1740 break;
1742 case AL_REVERB_GAINHF:
1743 *val = props->Reverb.GainHF;
1744 break;
1746 case AL_REVERB_DECAY_TIME:
1747 *val = props->Reverb.DecayTime;
1748 break;
1750 case AL_REVERB_DECAY_HFRATIO:
1751 *val = props->Reverb.DecayHFRatio;
1752 break;
1754 case AL_REVERB_REFLECTIONS_GAIN:
1755 *val = props->Reverb.ReflectionsGain;
1756 break;
1758 case AL_REVERB_REFLECTIONS_DELAY:
1759 *val = props->Reverb.ReflectionsDelay;
1760 break;
1762 case AL_REVERB_LATE_REVERB_GAIN:
1763 *val = props->Reverb.LateReverbGain;
1764 break;
1766 case AL_REVERB_LATE_REVERB_DELAY:
1767 *val = props->Reverb.LateReverbDelay;
1768 break;
1770 case AL_REVERB_AIR_ABSORPTION_GAINHF:
1771 *val = props->Reverb.AirAbsorptionGainHF;
1772 break;
1774 case AL_REVERB_ROOM_ROLLOFF_FACTOR:
1775 *val = props->Reverb.RoomRolloffFactor;
1776 break;
1778 default:
1779 SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
1782 void ALreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
1784 ALreverb_getParamf(effect, context, param, vals);
1787 DEFINE_ALEFFECT_VTABLE(ALreverb);