aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/effects
diff options
context:
space:
mode:
Diffstat (limited to 'Alc/effects')
-rw-r--r--Alc/effects/reverb.c132
1 files changed, 78 insertions, 54 deletions
diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c
index 3e157cbc..7ef95cf3 100644
--- a/Alc/effects/reverb.c
+++ b/Alc/effects/reverb.c
@@ -317,7 +317,7 @@ typedef struct ALreverbState {
ALsizei Offset;
/* Temporary storage used when processing. */
- alignas(16) ALfloat AFormatSamples[NUM_LINES][MAX_UPDATE_SAMPLES];
+ alignas(16) ALfloat TempSamples[NUM_LINES][MAX_UPDATE_SAMPLES];
alignas(16) ALfloat MixSamples[NUM_LINES][MAX_UPDATE_SAMPLES];
} ALreverbState;
@@ -1035,6 +1035,11 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co
/* Calculate the delay offset for each delay line. */
Late->Offset[i][1] = float2int(length*frequency + 0.5f);
+ /* Late reverb is processed in chunks, so ensure the feedback delays
+ * are long enough to avoid needing to read what's written in a given
+ * update.
+ */
+ assert(Late->Offset[i][1] >= MAX_UPDATE_SAMPLES);
/* Approximate the absorption that the vector all-pass would exhibit
* given the current diffusion so we don't have to process a full T60
@@ -1434,25 +1439,33 @@ DECL_TEMPLATE(Unfaded)
DECL_TEMPLATE(Faded)
#undef DECL_TEMPLATE
-/* Applies a first order filter section. */
-static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat *restrict coeffs,
- ALfloat *restrict state)
-{
- ALfloat out = coeffs[0]*in + *state;
- *state = coeffs[1]*in + coeffs[2]*out;
- return out;
-}
-
/* Applies the two T60 damping filter sections. */
-static inline void LateT60Filter(ALfloat *restrict out, const ALfloat *restrict in,
- T60Filter *filter)
+static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, T60Filter *filter)
{
+ const ALfloat hfb0 = filter->HFCoeffs[0];
+ const ALfloat hfb1 = filter->HFCoeffs[1];
+ const ALfloat hfa1 = filter->HFCoeffs[2];
+ const ALfloat lfb0 = filter->LFCoeffs[0];
+ const ALfloat lfb1 = filter->LFCoeffs[1];
+ const ALfloat lfa1 = filter->LFCoeffs[2];
+ ALfloat hfz = filter->HFState;
+ ALfloat lfz = filter->LFState;
ALsizei i;
- for(i = 0;i < NUM_LINES;i++)
- out[i] = FirstOrderFilter(
- FirstOrderFilter(in[i], filter[i].HFCoeffs, &filter[i].HFState),
- filter[i].LFCoeffs, &filter[i].LFState
- );
+
+ for(i = 0;i < todo;i++)
+ {
+ ALfloat in = samples[i];
+ ALfloat out = in*hfb0 + hfz;
+ hfz = in*hfb1 + out*hfa1;
+
+ in = out;
+ out = in*lfb0 + lfz;
+ lfz = in*lfb1 + out*lfa1;
+
+ samples[i] = out;
+ }
+ filter->HFState = hfz;
+ filter->LFState = lfz;
}
/* This generates the reverb tail using a modified feed-back delay network
@@ -1474,30 +1487,39 @@ static void LateReverb_##T(ALreverbState *State, const ALsizei todo, \
ALfloat fade, \
ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) \
{ \
+ ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; \
const ALfloat apFeedCoeff = State->ApFeedCoeff; \
const ALfloat mixX = State->MixX; \
const ALfloat mixY = State->MixY; \
ALsizei offset; \
ALsizei i, j; \
\
+ for(j = 0;j < NUM_LINES;j++) \
+ { \
+ ALfloat fader = fade; \
+ offset = State->Offset; \
+ for(i = 0;i < todo;i++) \
+ { \
+ temps[j][i] = T##DelayLineOut(&State->Delay, \
+ offset - State->LateDelayTap[j][0], \
+ offset - State->LateDelayTap[j][1], j, fader \
+ ) + T##DelayLineOut(&State->Late.Delay, \
+ offset - State->Late.Offset[j][0], \
+ offset - State->Late.Offset[j][1], j, fader \
+ ); \
+ ++offset; \
+ fader += FadeStep; \
+ } \
+ LateT60Filter(temps[j], todo, &State->Late.T60[j]); \
+ } \
+ \
offset = State->Offset; \
for(i = 0;i < todo;i++) \
{ \
ALfloat f[NUM_LINES], fr[NUM_LINES]; \
- \
for(j = 0;j < NUM_LINES;j++) \
- f[j] = T##DelayLineOut(&State->Delay, \
- offset - State->LateDelayTap[j][0], \
- offset - State->LateDelayTap[j][1], j, fade \
- ); \
+ fr[j] = temps[j][i]; \
\
- for(j = 0;j < NUM_LINES;j++) \
- f[j] += T##DelayLineOut(&State->Late.Delay, \
- offset - State->Late.Offset[j][0], \
- offset - State->Late.Offset[j][1], j, fade \
- ); \
- \
- LateT60Filter(fr, f, State->Late.T60); \
VectorAllpass_##T(f, fr, offset, apFeedCoeff, mixX, mixY, fade, \
&State->Late.VecAp); \
\
@@ -1518,7 +1540,7 @@ DECL_TEMPLATE(Faded)
static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
- ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples;
+ ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->TempSamples;
ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES] = State->MixSamples;
ALsizei fadeCount = State->FadeCount;
ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES;
@@ -1550,10 +1572,10 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c
DelayLineIn(&State->Delay, State->Offset, c, samples[1], todo);
}
- if(UNLIKELY(fadeCount < FADE_SAMPLES))
+ if(LIKELY(fadeCount >= FADE_SAMPLES))
{
- /* Generate early reflections. */
- EarlyReflection_Faded(State, todo, fade, samples);
+ /* Generate and mix early reflections. */
+ EarlyReflection_Unfaded(State, todo, fade, samples);
/* Mix the A-Format results to output, implicitly converting back
* to B-Format.
*/
@@ -1564,8 +1586,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c
);
/* Generate and mix late reverb. */
- LateReverb_Faded(State, todo, fade, samples);
- fade = minf(1.0f, fade + todo*FadeStep);
+ LateReverb_Unfaded(State, todo, fade, samples);
for(c = 0;c < NUM_LINES;c++)
MixSamples(samples[c], NumChannels, SamplesOut,
State->Late.CurrentGain[c], State->Late.PanGain[c],
@@ -1574,8 +1595,8 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c
}
else
{
- /* Generate and mix early reflections. */
- EarlyReflection_Unfaded(State, todo, fade, samples);
+ /* Generate early reflections. */
+ EarlyReflection_Faded(State, todo, fade, samples);
for(c = 0;c < NUM_LINES;c++)
MixSamples(samples[c], NumChannels, SamplesOut,
State->Early.CurrentGain[c], State->Early.PanGain[c],
@@ -1583,33 +1604,36 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c
);
/* Generate and mix late reverb. */
- LateReverb_Unfaded(State, todo, fade, samples);
+ LateReverb_Faded(State, todo, fade, samples);
for(c = 0;c < NUM_LINES;c++)
MixSamples(samples[c], NumChannels, SamplesOut,
State->Late.CurrentGain[c], State->Late.PanGain[c],
SamplesToDo-base, base, todo
);
- }
-
- /* Step all delays forward. */
- State->Offset += todo;
- if(UNLIKELY(fadeCount < FADE_SAMPLES) && (fadeCount += todo) >= FADE_SAMPLES)
- {
- /* Update the cross-fading delay line taps. */
- fadeCount = FADE_SAMPLES;
- fade = 1.0f;
- for(c = 0;c < NUM_LINES;c++)
+ /* Step fading forward. */
+ fade += todo*FadeStep;
+ fadeCount += todo;
+ if(LIKELY(fadeCount >= FADE_SAMPLES))
{
- State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][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.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1];
- State->Late.Offset[c][0] = State->Late.Offset[c][1];
+ /* Update the cross-fading delay line taps. */
+ fadeCount = FADE_SAMPLES;
+ fade = 1.0f;
+ for(c = 0;c < NUM_LINES;c++)
+ {
+ State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][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.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1];
+ State->Late.Offset[c][0] = State->Late.Offset[c][1];
+ }
}
}
+ /* Step all delays forward. */
+ State->Offset += todo;
+
base += todo;
}
State->FadeCount = fadeCount;