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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
29 #include "alAuxEffectSlot.h"
34 #define aluSqrt(x) ((ALfloat)sqrtf((float)(x)))
36 #define aluSqrt(x) ((ALfloat)sqrt((double)(x)))
40 #if defined(max) && !defined(__max)
43 #if defined(min) && !defined(__min)
48 #define M_PI 3.14159265358979323846 /* pi */
51 typedef struct DelayLine
53 // The delay lines use sample lengths that are powers of 2 to allow
54 // bitmasking instead of modulus wrapping.
61 // All delay lines are allocated as a single buffer to reduce memory
62 // fragmentation and management code.
63 ALfloat
*SampleBuffer
;
64 // Master effect gain.
66 // Initial effect delay and decorrelation.
68 // The tap points for the initial delay. First tap goes to early
69 // reflections, the last four decorrelate to late reverb.
72 // Gain for early reflections.
74 // Early reflections are done with 4 delay lines.
80 // Gain for late reverb.
82 // Attenuation to compensate for modal density and decay rate.
84 // The feed-back and feed-forward all-pass coefficient.
86 // Mixing matrix coefficient.
88 // Late reverb has 4 parallel all-pass filters.
92 // In addition to 4 cyclical delay lines.
96 // The cyclical delay lines are low-pass filtered.
97 ALfloat LpCoeff
[4][2];
100 // The current read offset for all delay lines.
104 // All delay line lengths are specified in seconds.
106 // The lengths of the early delay lines.
107 static const ALfloat EARLY_LINE_LENGTH
[4] =
109 0.0015f
, 0.0045f
, 0.0135f
, 0.0405f
112 // The lengths of the late all-pass delay lines.
113 static const ALfloat ALLPASS_LINE_LENGTH
[4] =
115 0.0151f
, 0.0167f
, 0.0183f
, 0.0200f
,
118 // The lengths of the late cyclical delay lines.
119 static const ALfloat LATE_LINE_LENGTH
[4] =
121 0.0211f
, 0.0311f
, 0.0461f
, 0.0680f
124 // The late cyclical delay lines have a variable length dependent on the
125 // effect's density parameter (inverted for some reason) and this multiplier.
126 static const ALfloat LATE_LINE_MULTIPLIER
= 4.0f
;
128 // Input into the late reverb is decorrelated between four channels. Their
129 // timings are dependent on a fraction and multiplier. See VerbUpdate() for
130 // the calculations involved.
131 static const ALfloat DECO_FRACTION
= 1.0f
/ 32.0f
;
132 static const ALfloat DECO_MULTIPLIER
= 2.0f
;
134 // The maximum length of initial delay for the master delay line (a sum of
135 // the maximum early reflection and late reverb delays).
136 static const ALfloat MASTER_LINE_LENGTH
= 0.3f
+ 0.1f
;
138 // Find the next power of 2. Actually, this will return the input value if
139 // it is already a power of 2.
140 static ALuint
NextPowerOf2(ALuint value
)
156 // Basic delay line input/output routines.
157 static __inline ALfloat
DelayLineOut(DelayLine
*Delay
, ALuint offset
)
159 return Delay
->Line
[offset
&Delay
->Mask
];
162 static __inline ALvoid
DelayLineIn(DelayLine
*Delay
, ALuint offset
, ALfloat in
)
164 Delay
->Line
[offset
&Delay
->Mask
] = in
;
167 // Delay line output routine for early reflections.
168 static __inline ALfloat
EarlyDelayLineOut(ALverbState
*State
, ALuint index
)
170 return State
->Early
.Coeff
[index
] *
171 DelayLineOut(&State
->Early
.Delay
[index
],
172 State
->Offset
- State
->Early
.Offset
[index
]);
175 // Given an input sample, this function produces stereo output for early
177 static __inline ALvoid
EarlyReflection(ALverbState
*State
, ALfloat in
, ALfloat
*out
)
179 ALfloat d
[4], v
, f
[4];
181 // Obtain the decayed results of each early delay line.
182 d
[0] = EarlyDelayLineOut(State
, 0);
183 d
[1] = EarlyDelayLineOut(State
, 1);
184 d
[2] = EarlyDelayLineOut(State
, 2);
185 d
[3] = EarlyDelayLineOut(State
, 3);
187 /* The following uses a lossless scattering junction from waveguide
188 * theory. It actually amounts to a householder mixing matrix, which
189 * will produce a maximally diffuse response, and means this can probably
190 * be considered a simple feedback delay network (FDN).
198 v
= (d
[0] + d
[1] + d
[2] + d
[3]) * 0.5f
;
199 // The junction is loaded with the input here.
202 // Calculate the feed values for the delay lines.
208 // Refeed the delay lines.
209 DelayLineIn(&State
->Early
.Delay
[0], State
->Offset
, f
[0]);
210 DelayLineIn(&State
->Early
.Delay
[1], State
->Offset
, f
[1]);
211 DelayLineIn(&State
->Early
.Delay
[2], State
->Offset
, f
[2]);
212 DelayLineIn(&State
->Early
.Delay
[3], State
->Offset
, f
[3]);
214 // To decorrelate the output for stereo separation, the two outputs are
215 // obtained from the inner delay lines.
216 // Output is instant by using the inputs to them instead of taking the
217 // result of the two delay lines directly (f[0] and f[3] instead of d[1]
219 out
[0] = State
->Early
.Gain
* f
[0];
220 out
[1] = State
->Early
.Gain
* f
[3];
223 // All-pass input/output routine for late reverb.
224 static __inline ALfloat
LateAllPassInOut(ALverbState
*State
, ALuint index
, ALfloat in
)
228 out
= State
->Late
.ApCoeff
[index
] *
229 DelayLineOut(&State
->Late
.ApDelay
[index
],
230 State
->Offset
- State
->Late
.ApOffset
[index
]);
231 out
-= (State
->Late
.ApFeedCoeff
* in
);
232 DelayLineIn(&State
->Late
.ApDelay
[index
], State
->Offset
,
233 (State
->Late
.ApFeedCoeff
* out
) + in
);
237 // Delay line output routine for late reverb.
238 static __inline ALfloat
LateDelayLineOut(ALverbState
*State
, ALuint index
)
240 return State
->Late
.Coeff
[index
] *
241 DelayLineOut(&State
->Late
.Delay
[index
],
242 State
->Offset
- State
->Late
.Offset
[index
]);
245 // Low-pass filter input/output routine for late reverb.
246 static __inline ALfloat
LateLowPassInOut(ALverbState
*State
, ALuint index
, ALfloat in
)
248 State
->Late
.LpSample
[index
] = (State
->Late
.LpCoeff
[index
][0] * in
) +
249 (State
->Late
.LpCoeff
[index
][1] * State
->Late
.LpSample
[index
]);
250 return State
->Late
.LpSample
[index
];
253 // Given four decorrelated input samples, this function produces stereo
254 // output for late reverb.
255 static __inline ALvoid
LateReverb(ALverbState
*State
, ALfloat
*in
, ALfloat
*out
)
259 // Obtain the decayed results of the cyclical delay lines, and add the
260 // corresponding input channels attenuated by density. Then pass the
261 // results through the low-pass filters.
262 d
[0] = LateLowPassInOut(State
, 0, (State
->Late
.DensityGain
* in
[0]) +
263 LateDelayLineOut(State
, 0));
264 d
[1] = LateLowPassInOut(State
, 1, (State
->Late
.DensityGain
* in
[1]) +
265 LateDelayLineOut(State
, 1));
266 d
[2] = LateLowPassInOut(State
, 2, (State
->Late
.DensityGain
* in
[2]) +
267 LateDelayLineOut(State
, 2));
268 d
[3] = LateLowPassInOut(State
, 3, (State
->Late
.DensityGain
* in
[3]) +
269 LateDelayLineOut(State
, 3));
271 // To help increase diffusion, run each line through an all-pass filter.
272 // The order of the all-pass filters is selected so that the shortest
273 // all-pass filter will feed the shortest delay line.
274 d
[0] = LateAllPassInOut(State
, 1, d
[0]);
275 d
[1] = LateAllPassInOut(State
, 3, d
[1]);
276 d
[2] = LateAllPassInOut(State
, 0, d
[2]);
277 d
[3] = LateAllPassInOut(State
, 2, d
[3]);
279 /* Late reverb is done with a modified feedback delay network (FDN)
280 * topology. Four input lines are each fed through their own all-pass
281 * filter and then into the mixing matrix. The four outputs of the
282 * mixing matrix are then cycled back to the inputs. Each output feeds
283 * a different input to form a circlular feed cycle.
285 * The mixing matrix used is a 4D skew-symmetric rotation matrix derived
286 * using a single unitary rotational parameter:
288 * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
293 * The rotation is constructed from the effect's diffusion parameter,
294 * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
295 * with differing signs, and d is the coefficient x. The matrix is thus:
297 * [ x, y, -y, y ] x = 1 - (0.5 diffusion^3)
298 * [ -y, x, y, y ] y = sqrt((1 - x^2) / 3)
302 * To reduce the number of multiplies, the x coefficient is applied with
303 * the cyclical delay line coefficients. Thus only the y coefficient is
304 * applied when mixing, and is modified to be: y / x.
306 f
[0] = d
[0] + (State
->Late
.MixCoeff
* ( d
[1] - d
[2] + d
[3]));
307 f
[1] = d
[1] + (State
->Late
.MixCoeff
* (-d
[0] + d
[2] + d
[3]));
308 f
[2] = d
[2] + (State
->Late
.MixCoeff
* ( d
[0] - d
[1] + d
[3]));
309 f
[3] = d
[3] + (State
->Late
.MixCoeff
* (-d
[0] - d
[1] - d
[2]));
311 // Output is tapped at the input to the shortest two cyclical delay
312 // lines, attenuated by the late reverb gain (which is attenuated by the
313 // mixing coefficient x).
314 out
[0] = State
->Late
.Gain
* f
[0];
315 out
[1] = State
->Late
.Gain
* f
[1];
317 // The delay lines are fed circularly in the order:
318 // 0 -> 1 -> 3 -> 2 -> 0 ...
319 DelayLineIn(&State
->Late
.Delay
[0], State
->Offset
, f
[2]);
320 DelayLineIn(&State
->Late
.Delay
[1], State
->Offset
, f
[0]);
321 DelayLineIn(&State
->Late
.Delay
[2], State
->Offset
, f
[3]);
322 DelayLineIn(&State
->Late
.Delay
[3], State
->Offset
, f
[1]);
325 // This creates the reverb state. It should be called only when the reverb
326 // effect is loaded into a slot that doesn't already have a reverb effect.
327 ALverbState
*VerbCreate(ALCcontext
*Context
)
329 ALverbState
*State
= NULL
;
330 ALuint samples
, length
[13], totalLength
, index
;
332 State
= malloc(sizeof(ALverbState
));
336 // All line lengths are powers of 2, calculated from their lengths, with
337 // an additional sample in case of rounding errors.
339 // See VerbUpdate() for an explanation of the additional calculation
340 // added to the master line length.
342 ((MASTER_LINE_LENGTH
+
343 (LATE_LINE_LENGTH
[0] * (1.0f
+ LATE_LINE_MULTIPLIER
) *
344 (DECO_FRACTION
* ((DECO_MULTIPLIER
* DECO_MULTIPLIER
*
345 DECO_MULTIPLIER
) - 1.0f
)))) *
346 Context
->Frequency
) + 1;
347 length
[0] = NextPowerOf2(samples
);
348 totalLength
= length
[0];
349 for(index
= 0;index
< 4;index
++)
351 samples
= (ALuint
)(EARLY_LINE_LENGTH
[index
] * Context
->Frequency
) + 1;
352 length
[1 + index
] = NextPowerOf2(samples
);
353 totalLength
+= length
[1 + index
];
355 for(index
= 0;index
< 4;index
++)
357 samples
= (ALuint
)(ALLPASS_LINE_LENGTH
[index
] * Context
->Frequency
) + 1;
358 length
[5 + index
] = NextPowerOf2(samples
);
359 totalLength
+= length
[5 + index
];
361 for(index
= 0;index
< 4;index
++)
363 samples
= (ALuint
)(LATE_LINE_LENGTH
[index
] *
364 (1.0f
+ LATE_LINE_MULTIPLIER
) * Context
->Frequency
) + 1;
365 length
[9 + index
] = NextPowerOf2(samples
);
366 totalLength
+= length
[9 + index
];
369 // All lines share a single sample buffer.
370 State
->SampleBuffer
= malloc(totalLength
* sizeof(ALfloat
));
371 if(!State
->SampleBuffer
)
376 for(index
= 0; index
< totalLength
;index
++)
377 State
->SampleBuffer
[index
] = 0.0f
;
379 // Each one has its mask and start address calculated one time.
381 State
->Delay
.Mask
= length
[0] - 1;
382 State
->Delay
.Line
= &State
->SampleBuffer
[0];
383 totalLength
= length
[0];
391 State
->Early
.Gain
= 0.0f
;
392 for(index
= 0;index
< 4;index
++)
394 State
->Early
.Coeff
[index
] = 0.0f
;
395 State
->Early
.Delay
[index
].Mask
= length
[1 + index
] - 1;
396 State
->Early
.Delay
[index
].Line
= &State
->SampleBuffer
[totalLength
];
397 totalLength
+= length
[1 + index
];
399 // The early delay lines have their read offsets calculated once.
400 State
->Early
.Offset
[index
] = (ALuint
)(EARLY_LINE_LENGTH
[index
] *
404 State
->Late
.Gain
= 0.0f
;
405 State
->Late
.DensityGain
= 0.0f
;
406 State
->Late
.ApFeedCoeff
= 0.0f
;
407 State
->Late
.MixCoeff
= 0.0f
;
409 for(index
= 0;index
< 4;index
++)
411 State
->Late
.ApCoeff
[index
] = 0.0f
;
412 State
->Late
.ApDelay
[index
].Mask
= length
[5 + index
] - 1;
413 State
->Late
.ApDelay
[index
].Line
= &State
->SampleBuffer
[totalLength
];
414 totalLength
+= length
[5 + index
];
416 // The late all-pass lines have their read offsets calculated once.
417 State
->Late
.ApOffset
[index
] = (ALuint
)(ALLPASS_LINE_LENGTH
[index
] *
421 for(index
= 0;index
< 4;index
++)
423 State
->Late
.Coeff
[index
] = 0.0f
;
424 State
->Late
.Delay
[index
].Mask
= length
[9 + index
] - 1;
425 State
->Late
.Delay
[index
].Line
= &State
->SampleBuffer
[totalLength
];
426 totalLength
+= length
[9 + index
];
428 State
->Late
.Offset
[index
] = 0;
430 State
->Late
.LpCoeff
[index
][0] = 0.0f
;
431 State
->Late
.LpCoeff
[index
][1] = 0.0f
;
432 State
->Late
.LpSample
[index
] = 0.0f
;
439 // This destroys the reverb state. It should be called only when the effect
440 // slot has a different (or no) effect loaded over the reverb effect.
441 ALvoid
VerbDestroy(ALverbState
*State
)
445 free(State
->SampleBuffer
);
446 State
->SampleBuffer
= NULL
;
451 // This updates the reverb state. This is called any time the reverb effect
452 // is loaded into a slot.
453 ALvoid
VerbUpdate(ALCcontext
*Context
, ALeffectslot
*Slot
, ALeffect
*Effect
)
455 ALverbState
*State
= Slot
->ReverbState
;
457 ALfloat length
, mixCoeff
, cw
, g
, lpCoeff
;
458 ALfloat hfRatio
= Effect
->Reverb
.DecayHFRatio
;
460 // Calculate the master gain (from the slot and master effect gain).
461 State
->Gain
= Slot
->Gain
* Effect
->Reverb
.Gain
;
463 // Calculate the initial delay taps.
464 length
= Effect
->Reverb
.ReflectionsDelay
;
465 State
->Tap
[0] = (ALuint
)(length
* Context
->Frequency
);
467 length
+= Effect
->Reverb
.LateReverbDelay
;
469 /* The four inputs to the late reverb are decorrelated to smooth the
470 * initial reverb and reduce harsh echos. The timings are calculated as
471 * multiples of a fraction of the smallest cyclical delay time. This
472 * result is then adjusted so that the first tap occurs immediately (all
473 * taps are reduced by the shortest fraction).
475 * offset[index] = ((FRACTION MULTIPLIER^index) - 1) delay
477 for(index
= 0;index
< 4;index
++)
479 length
+= LATE_LINE_LENGTH
[0] *
480 (1.0f
+ (Effect
->Reverb
.Density
* LATE_LINE_MULTIPLIER
)) *
481 (DECO_FRACTION
* (pow(DECO_MULTIPLIER
, (ALfloat
)index
) - 1.0f
));
482 State
->Tap
[1 + index
] = (ALuint
)(length
* Context
->Frequency
);
485 // Set the early reflections gain.
486 State
->Early
.Gain
= Effect
->Reverb
.ReflectionsGain
;
488 // Calculate the gain (coefficient) for each early delay line.
489 for(index
= 0;index
< 4;index
++)
490 State
->Early
.Coeff
[index
] = pow(10.0f
, EARLY_LINE_LENGTH
[index
] /
491 Effect
->Reverb
.LateReverbDelay
*
494 // Calculate the first mixing matrix coefficient (x).
495 mixCoeff
= 1.0f
- (0.5f
* pow(Effect
->Reverb
.Diffusion
, 3.0f
));
497 // Set the late reverb gain. Since the output is tapped prior to the
498 // application of the delay line coefficients, this gain needs to be
499 // attenuated by the mix coefficient from above.
500 State
->Late
.Gain
= Effect
->Reverb
.LateReverbGain
* mixCoeff
;
502 /* To compensate for changes in modal density and decay time of the late
503 * reverb signal, the input is attenuated based on the maximal energy of
504 * the outgoing signal. This is calculated as the ratio between a
505 * reference value and the current approximation of energy for the output
508 * Reverb output matches exponential decay of the form Sum(a^n), where a
509 * is the attenuation coefficient, and n is the sample ranging from 0 to
510 * infinity. The signal energy can thus be approximated using the area
511 * under this curve, calculated as: 1 / (1 - a).
513 * The reference energy is calculated from a signal at the lowest (effect
514 * at 1.0) density with a decay time of one second.
516 * The coefficient is calculated as the average length of the cyclical
517 * delay lines. This produces a better result than calculating the gain
518 * for each line individually (most likely a side effect of diffusion).
520 * The final result is the square root of the ratio bound to a maximum
521 * value of 1 (no amplification) and attenuated by 1 / sqrt(2) to
522 * compensate for the four decorrelated inputs.
524 length
= (LATE_LINE_LENGTH
[0] + LATE_LINE_LENGTH
[1] +
525 LATE_LINE_LENGTH
[2] + LATE_LINE_LENGTH
[3]);
526 g
= length
* (1.0f
+ LATE_LINE_MULTIPLIER
) * 0.25f
;
527 g
= pow(10.0f
, g
* -60.0f
/ 20.0f
);
528 g
= 1.0f
/ (1.0f
- (g
*g
));
529 length
*= 1.0f
+ (Effect
->Reverb
.Density
* LATE_LINE_MULTIPLIER
) * 0.25f
;
530 length
= pow(10.0f
, length
/ Effect
->Reverb
.DecayTime
* -60.0f
/ 20.0f
);
531 length
= 1.0f
/ (1.0f
- (length
*length
));
532 State
->Late
.DensityGain
= 0.707106f
* __min(aluSqrt(g
/ length
), 1.0f
);
534 // Calculate the all-pass feed-back and feed-forward coefficient.
535 State
->Late
.ApFeedCoeff
= 0.6f
* pow(Effect
->Reverb
.Diffusion
, 3.0f
);
537 // Calculate the mixing matrix coefficient (y / x).
538 g
= aluSqrt((1.0f
- (mixCoeff
* mixCoeff
)) / 3.0f
);
539 State
->Late
.MixCoeff
= g
/ mixCoeff
;
541 for(index
= 0;index
< 4;index
++)
543 // Calculate the gain (coefficient) for each all-pass line.
544 State
->Late
.ApCoeff
[index
] = pow(10.0f
, ALLPASS_LINE_LENGTH
[index
] /
545 Effect
->Reverb
.DecayTime
*
549 // If the HF limit parameter is flagged, calculate an appropriate limit
550 // based on the air absorption parameter.
551 if(Effect
->Reverb
.DecayHFLimit
&& Effect
->Reverb
.AirAbsorptionGainHF
< 1.0f
)
555 // For each of the cyclical delays, find the attenuation due to air
556 // absorption in dB (converting delay time to meters using the speed
557 // of sound). Then reversing the decay equation, solve for HF ratio.
558 // The delay length is cancelled out of the equation, so it can be
559 // calculated once for all lines.
560 limitRatio
= 1.0f
/ (log10(Effect
->Reverb
.AirAbsorptionGainHF
) *
561 SPEEDOFSOUNDMETRESPERSEC
*
562 Effect
->Reverb
.DecayTime
/ -60.0f
* 20.0f
);
563 // Need to limit the result to a minimum of 0.1, just like the HF
565 limitRatio
= __max(limitRatio
, 0.1f
);
567 // Using the limit calculated above, apply the upper bound to the
569 hfRatio
= __min(hfRatio
, limitRatio
);
572 // Calculate the filter frequency for low-pass or high-pass depending on
573 // whether the HF ratio is above 1.
574 cw
= 2.0f
* M_PI
* LOWPASSFREQCUTOFF
/ Context
->Frequency
;
579 for(index
= 0;index
< 4;index
++)
581 // Calculate the length (in seconds) of each cyclical delay line.
582 length
= LATE_LINE_LENGTH
[index
] * (1.0f
+ (Effect
->Reverb
.Density
*
583 LATE_LINE_MULTIPLIER
));
584 // Calculate the delay offset for the cyclical delay lines.
585 State
->Late
.Offset
[index
] = (ALuint
)(length
* Context
->Frequency
);
587 // Calculate the gain (coefficient) for each cyclical line.
588 State
->Late
.Coeff
[index
] = pow(10.0f
, length
/ Effect
->Reverb
.DecayTime
*
591 // Calculate the decay equation for each low-pass filter.
592 g
= pow(10.0f
, length
/ (Effect
->Reverb
.DecayTime
* hfRatio
) *
595 g
= State
->Late
.Coeff
[index
] / g
;
597 g
= g
/ State
->Late
.Coeff
[index
];
601 // Calculate the gain (coefficient) for each low-pass filter.
603 if(g
< 0.9999f
) // 1-epsilon
604 lpCoeff
= (1 - g
*cw
- aluSqrt(2*g
*(1-cw
) - g
*g
*(1 - cw
*cw
))) / (1 - g
);
606 // Very low decay times will produce minimal output, so apply an
607 // upper bound to the coefficient.
608 lpCoeff
= __min(lpCoeff
, 0.98f
);
610 // Calculate the filter coefficients for high-pass or low-pass
611 // dependent on HF ratio being above 1.
613 State
->Late
.LpCoeff
[index
][0] = 1.0f
+ lpCoeff
;
614 State
->Late
.LpCoeff
[index
][1] = -lpCoeff
;
616 State
->Late
.LpCoeff
[index
][0] = 1.0f
- lpCoeff
;
617 State
->Late
.LpCoeff
[index
][1] = lpCoeff
;
620 // Attenuate the cyclical line coefficients by the mixing coefficient
622 State
->Late
.Coeff
[index
] *= mixCoeff
;
626 // This processes the reverb state, given the input samples and an output
628 ALvoid
VerbProcess(ALverbState
*State
, ALuint SamplesToDo
, const ALfloat
*SamplesIn
, ALfloat (*SamplesOut
)[OUTPUTCHANNELS
])
631 ALfloat in
[4], early
[2], late
[2], out
[2];
633 for(index
= 0;index
< SamplesToDo
;index
++)
635 // Feed the initial delay line.
636 DelayLineIn(&State
->Delay
, State
->Offset
, SamplesIn
[index
]);
638 // Calculate the early reflection from the first delay tap.
639 in
[0] = DelayLineOut(&State
->Delay
, State
->Offset
- State
->Tap
[0]);
640 EarlyReflection(State
, in
[0], early
);
642 // Calculate the late reverb from the last four delay taps.
643 in
[0] = DelayLineOut(&State
->Delay
, State
->Offset
- State
->Tap
[1]);
644 in
[1] = DelayLineOut(&State
->Delay
, State
->Offset
- State
->Tap
[2]);
645 in
[2] = DelayLineOut(&State
->Delay
, State
->Offset
- State
->Tap
[3]);
646 in
[3] = DelayLineOut(&State
->Delay
, State
->Offset
- State
->Tap
[4]);
647 LateReverb(State
, in
, late
);
649 // Mix early reflections and late reverb.
650 out
[0] = State
->Gain
* (early
[0] + late
[0]);
651 out
[1] = State
->Gain
* (early
[1] + late
[1]);
653 // Step all delays forward one sample.
656 // Output the results.
657 SamplesOut
[index
][FRONT_LEFT
] += out
[0];
658 SamplesOut
[index
][FRONT_RIGHT
] += out
[1];
659 SamplesOut
[index
][SIDE_LEFT
] += out
[0];
660 SamplesOut
[index
][SIDE_RIGHT
] += out
[1];
661 SamplesOut
[index
][BACK_LEFT
] += out
[0];
662 SamplesOut
[index
][BACK_RIGHT
] += out
[1];