diff options
author | Chris Robinson <[email protected]> | 2018-08-05 00:45:13 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2018-08-05 00:45:13 -0700 |
commit | 4aa029183b8fcdf16f43ee953cab809c9274eebd (patch) | |
tree | 648a35c65cb9b0552282f96dc1b819a149ba5804 /Alc/effects | |
parent | 3f165040e2e7880c36f431bce4af13b64b2692d6 (diff) |
Apply the reverb's T60 filter in groups of samples
The late reverb line lengths are long enough to ensure a single process loop
won't rely on reading samples it wrote in the same call. So we can safely read
in all samples we need from the feedback buffer up front, then more efficiently
filter them.
Diffstat (limited to 'Alc/effects')
-rw-r--r-- | Alc/effects/reverb.c | 132 |
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; |