aboutsummaryrefslogtreecommitdiffstats
path: root/Alc
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2017-05-13 15:45:05 -0700
committerChris Robinson <[email protected]>2017-05-13 15:45:05 -0700
commit0b66b2bbe798f7e9bca3fb101ff72d06334124ee (patch)
tree7af5cb84c124a201ab918ce0af750bd5640a7e3b /Alc
parent87d4710bc4f980663fa8ca67a9ef416aa56b2a93 (diff)
Replace 4 separate all-passes with one vector all-pass
Each 4 related all-passes now share a structure with one delay line, which uses an interleaved sample history. Also fixes some potential rounding problems for delay lines with interleaved samples.
Diffstat (limited to 'Alc')
-rw-r--r--Alc/effects/reverb.c100
1 files changed, 47 insertions, 53 deletions
diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c
index c1b0369b..92698bd4 100644
--- a/Alc/effects/reverb.c
+++ b/Alc/effects/reverb.c
@@ -67,10 +67,10 @@ typedef struct DelayLine {
ALfloat *Line;
} DelayLine;
-typedef struct Allpass {
+typedef struct VecAllpass {
DelayLine Delay;
- ALsizei Offset[2];
-} Allpass;
+ ALsizei Offset[4][2];
+} VecAllpass;
typedef struct ALreverbState {
DERIVE_FROM_TYPE(ALeffectState);
@@ -112,7 +112,7 @@ typedef struct ALreverbState {
* diffusion. The spread from this filter also helps smooth out the
* reverb tail.
*/
- Allpass Ap[4];
+ VecAllpass VecAp;
/* Echo lines are used to complete the second half of the early
* reflections.
@@ -161,7 +161,7 @@ typedef struct ALreverbState {
} Filters[4];
/* A Gerzon vector all-pass filter is used to simulate diffusion. */
- Allpass Ap[4];
+ VecAllpass VecAp;
/* The gain for each output channel based on 3D panning. */
ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS];
@@ -228,12 +228,12 @@ static void ALreverbState_Construct(ALreverbState *state)
state->MixX = 0.0f;
state->MixY = 0.0f;
+ state->Early.VecAp.Delay.Mask = 0;
+ state->Early.VecAp.Delay.Line = NULL;
for(i = 0;i < 4;i++)
{
- state->Early.Ap[i].Delay.Mask = 0;
- state->Early.Ap[i].Delay.Line = NULL;
- state->Early.Ap[i].Offset[0] = 0;
- state->Early.Ap[i].Offset[1] = 0;
+ state->Early.VecAp.Offset[i][0] = 0;
+ state->Early.VecAp.Offset[i][1] = 0;
state->Early.Delay[i].Mask = 0;
state->Early.Delay[i].Line = NULL;
state->Early.Offset[i][0] = 0;
@@ -249,12 +249,12 @@ static void ALreverbState_Construct(ALreverbState *state)
state->Late.DensityGain = 0.0f;
+ state->Late.VecAp.Delay.Mask = 0;
+ state->Late.VecAp.Delay.Line = NULL;
for(i = 0;i < 4;i++)
{
- state->Late.Ap[i].Delay.Mask = 0;
- state->Late.Ap[i].Delay.Line = NULL;
- state->Late.Ap[i].Offset[0] = 0;
- state->Late.Ap[i].Offset[1] = 0;
+ state->Late.VecAp.Offset[i][0] = 0;
+ state->Late.VecAp.Offset[i][1] = 0;
state->Late.Delay[i].Mask = 0;
state->Late.Delay[i].Line = NULL;
@@ -501,15 +501,15 @@ static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay)
/* Calculate the length of a delay line and store its mask and offset. */
static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALuint frequency,
- const ALuint extra, DelayLine *Delay)
+ const ALuint extra, const ALuint splmult, DelayLine *Delay)
{
ALuint samples;
- /* All line lengths are powers of 2, calculated from their lengths, with
- * an additional sample in case of rounding errors.
+ /* All line lengths are powers of 2, calculated from their lengths in
+ * seconds, rounded up.
*/
- samples = fastf2u(length*frequency) + extra;
- samples = NextPowerOf2(samples + 1);
+ samples = fastf2u(ceilf(length*frequency));
+ samples = NextPowerOf2((samples+extra) * splmult);
/* All lines share a single sample buffer. */
Delay->Mask = samples - 1;
@@ -546,32 +546,28 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State)
/* Multiply length by 4, since we're storing 4 interleaved channels in the
* main delay line.
*/
- totalSamples += CalcLineLength(length*4, totalSamples, frequency,
- MAX_UPDATE_SAMPLES*4, &State->Delay);
+ totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, 4,
+ &State->Delay);
- /* The early all-pass lines. */
- for(i = 0;i < 4;i++)
- {
- length = EARLY_ALLPASS_LENGTHS[i] * multiplier;
- totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
- &State->Early.Ap[i].Delay);
- }
+ /* The early all-pass line. Multiply by 4, for 4 interleaved channels. */
+ length = (EARLY_ALLPASS_LENGTHS[0]+EARLY_ALLPASS_LENGTHS[1]+
+ EARLY_ALLPASS_LENGTHS[2]+EARLY_ALLPASS_LENGTHS[3]) * multiplier;
+ totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 4,
+ &State->Early.VecAp.Delay);
/* The early reflection lines. */
for(i = 0;i < 4;i++)
{
length = EARLY_LINE_LENGTHS[i] * multiplier;
- totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
+ totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 1,
&State->Early.Delay[i]);
}
- /* The late vector all-pass lines. */
- for(i = 0;i < 4;i++)
- {
- length = LATE_ALLPASS_LENGTHS[i] * multiplier;
- totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
- &State->Late.Ap[i].Delay);
- }
+ /* The late vector all-pass line. Multiply by 4, for 4 interleaved channels. */
+ length = (LATE_ALLPASS_LENGTHS[0]+LATE_ALLPASS_LENGTHS[1]+
+ LATE_ALLPASS_LENGTHS[2]+LATE_ALLPASS_LENGTHS[3]) * multiplier;
+ totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 4,
+ &State->Late.VecAp.Delay);
/* The late delay lines are calculated from the larger of the maximum
* density line length or the maximum echo time, and includes the maximum
@@ -583,7 +579,7 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State)
{
length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[i]*multiplier) +
AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f;
- totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
+ totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 1,
&State->Late.Delay[i]);
}
@@ -602,14 +598,12 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State)
/* Update all delays to reflect the new sample buffer. */
RealizeLineOffset(State->SampleBuffer, &State->Delay);
+ RealizeLineOffset(State->SampleBuffer, &State->Early.VecAp.Delay);
for(i = 0;i < 4;i++)
- {
- RealizeLineOffset(State->SampleBuffer, &State->Early.Ap[i].Delay);
RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[i]);
-
- RealizeLineOffset(State->SampleBuffer, &State->Late.Ap[i].Delay);
+ RealizeLineOffset(State->SampleBuffer, &State->Late.VecAp.Delay);
+ for(i = 0;i < 4;i++)
RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[i]);
- }
/* Clear the sample buffer. */
for(i = 0;i < State->TotalSamples;i++)
@@ -1129,7 +1123,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c
length = EARLY_ALLPASS_LENGTHS[i] * multiplier;
/* Calculate the delay offset for each all-pass line. */
- State->Early.Ap[i].Offset[1] = fastf2u(length * frequency);
+ State->Early.VecAp.Offset[i][1] = fastf2i(length * frequency);
/* Calculate the length (in seconds) of each delay line. */
length = EARLY_LINE_LENGTHS[i] * multiplier;
@@ -1182,7 +1176,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co
length = LATE_ALLPASS_LENGTHS[i] * multiplier;
/* Calculate the delay offset for each all-pass line. */
- State->Late.Ap[i].Offset[1] = fastf2u(length * frequency);
+ State->Late.VecAp.Offset[i][1] = fastf2i(length * frequency);
/* Calculate the length (in seconds) of each delay line. This also
* applies the echo transformation. As the EAX echo depth approaches
@@ -1409,10 +1403,10 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device
for(i = 0;i < 4;i++)
{
if((State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0]) ||
- (State->Early.Ap[i].Offset[1] != State->Early.Ap[i].Offset[0]) ||
+ (State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0]) ||
(State->Early.Offset[i][1] != State->Early.Offset[i][0]) ||
(State->LateDelayTap[i][1] != State->LateDelayTap[i][0]) ||
- (State->Late.Ap[i].Offset[1] != State->Late.Ap[i].Offset[0]) ||
+ (State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0]) ||
(State->Late.Offset[i][1] != State->Late.Offset[i][0]))
{
State->FadeCount = 0;
@@ -1540,7 +1534,7 @@ static inline void VectorPartialScatter(ALfloat *restrict vec, const ALfloat xCo
static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \
const ALfloat feedCoeff, const ALfloat xCoeff, \
const ALfloat yCoeff, const ALfloat mu, \
- Allpass Ap[4]) \
+ VecAllpass *Vap) \
{ \
ALfloat input; \
ALfloat f[4]; \
@@ -1551,8 +1545,8 @@ static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \
for(i = 0;i < 4;i++) \
{ \
input = vec[i]; \
- vec[i] = DELAY_OUT_##T(&Ap[i].Delay, offset-Ap[i].Offset[0], \
- offset-Ap[i].Offset[1], mu) - \
+ vec[i] = DELAY_OUT_##T(&Vap->Delay, (offset-Vap->Offset[i][0])*4 + i, \
+ (offset-Vap->Offset[i][1])*4 + i, mu) - \
feedCoeff*input; \
f[i] = input + feedCoeff*vec[i]; \
} \
@@ -1560,7 +1554,7 @@ static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \
VectorPartialScatter(f, xCoeff, yCoeff); \
\
for(i = 0;i < 4;i++) \
- DelayLineIn(&Ap[i].Delay, offset, f[i]); \
+ DelayLineIn(&Vap->Delay, offset*4 + i, f[i]); \
}
DECL_TEMPLATE(Unfaded)
DECL_TEMPLATE(Faded)
@@ -1617,7 +1611,7 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \
) * State->EarlyDelayCoeff[j]; \
\
VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \
- State->Early.Ap); \
+ &State->Early.VecAp); \
\
for(j = 0;j < 4;j++) \
DelayLineIn(&State->Early.Delay[j], offset, f[3 - j]); \
@@ -1737,7 +1731,7 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \
f[j] = LateT60Filter(j, f[j], State); \
\
VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \
- State->Late.Ap); \
+ &State->Late.VecAp); \
\
for(j = 0;j < 4;j++) \
out[j][i] = f[j]; \
@@ -1889,10 +1883,10 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c
for(c = 0;c < 4;c++)
{
State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1];
- State->Early.Ap[c].Offset[0] = State->Early.Ap[c].Offset[1];
+ State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1];
State->Early.Offset[c][0] = State->Early.Offset[c][1];
State->LateDelayTap[c][0] = State->LateDelayTap[c][1];
- State->Late.Ap[c].Offset[0] = State->Late.Ap[c].Offset[1];
+ State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1];
State->Late.Offset[c][0] = State->Late.Offset[c][1];
}
}