diff options
Diffstat (limited to 'Alc')
-rw-r--r-- | Alc/effects/reverb.c | 168 |
1 files changed, 86 insertions, 82 deletions
diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 472037ba..b4961ce8 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -49,6 +49,13 @@ ALfloat ReverbBoost = 1.0f; */ #define FADE_SAMPLES 128 +/* The number of spatialized lines or channels to process. Four channels allows + * for a 3D A-Format response. NOTE: This can't be changed without taking care + * of the conversion matrices, and a few places where the length arrays are + * assumed to have 4 elements. + */ +#define NUM_LINES 4 + static RowMixerFunc MixRowSamples = MixRow_C; @@ -137,7 +144,7 @@ static const ALfloat LINE_MULTIPLIER = 9.0f; * Assuming an average of 5m (up to 50m with the density multiplier), we get * the following taps: */ -static const ALfloat EARLY_TAP_LENGTHS[4] = +static const ALfloat EARLY_TAP_LENGTHS[NUM_LINES] = { 0.000000e+0f, 1.010676e-3f, 2.126553e-3f, 3.358580e-3f }; @@ -148,7 +155,7 @@ static const ALfloat EARLY_TAP_LENGTHS[4] = * * Where a is the approximate maximum all-pass cycle limit (20). */ -static const ALfloat EARLY_ALLPASS_LENGTHS[4] = +static const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES] = { 4.854840e-4f, 5.360178e-4f, 5.918117e-4f, 6.534130e-4f }; @@ -175,7 +182,7 @@ static const ALfloat EARLY_ALLPASS_LENGTHS[4] = * * Using an average dimension of 5m, we get: */ -static const ALfloat EARLY_LINE_LENGTHS[4] = +static const ALfloat EARLY_LINE_LENGTHS[NUM_LINES] = { 2.992520e-3f, 5.456575e-3f, 7.688329e-3f, 9.709681e-3f }; @@ -184,7 +191,7 @@ static const ALfloat EARLY_LINE_LENGTHS[4] = * * A_i = (5 / 3) L_i / r_1 */ -static const ALfloat LATE_ALLPASS_LENGTHS[4] = +static const ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES] = { 8.091400e-4f, 1.019453e-3f, 1.407968e-3f, 1.618280e-3f }; @@ -204,7 +211,7 @@ static const ALfloat LATE_ALLPASS_LENGTHS[4] = * * For our 5m average room, we get: */ -static const ALfloat LATE_LINE_LENGTHS[4] = +static const ALfloat LATE_LINE_LENGTHS[NUM_LINES] = { 9.709681e-3f, 1.223343e-2f, 1.689561e-2f, 1.941936e-2f }; @@ -222,12 +229,12 @@ typedef struct DelayLineI { * of 2 to allow the use of bit-masking instead of a modulus for wrapping. */ ALsizei Mask; - ALfloat (*Line)[4]; + ALfloat (*Line)[NUM_LINES]; } DelayLineI; typedef struct VecAllpass { DelayLineI Delay; - ALsizei Offset[4][2]; + ALsizei Offset[NUM_LINES][2]; } VecAllpass; typedef struct ALreverbState { @@ -243,18 +250,18 @@ typedef struct ALreverbState { struct { ALfilterState Lp; ALfilterState Hp; /* EAX only */ - } Filter[4]; + } Filter[NUM_LINES]; /* Core delay line (early reflections and late reverb tap from this). */ DelayLineI Delay; /* Tap points for early reflection delay. */ - ALsizei EarlyDelayTap[4][2]; - ALfloat EarlyDelayCoeff[4]; + ALsizei EarlyDelayTap[NUM_LINES][2]; + ALfloat EarlyDelayCoeff[NUM_LINES]; /* Tap points for late reverb feed and delay. */ ALsizei LateFeedTap; - ALsizei LateDelayTap[4][2]; + ALsizei LateDelayTap[NUM_LINES][2]; /* The feed-back and feed-forward all-pass coefficient. */ ALfloat ApFeedCoeff; @@ -274,12 +281,12 @@ typedef struct ALreverbState { * reflections. */ DelayLineI Delay; - ALsizei Offset[4][2]; - ALfloat Coeff[4]; + ALsizei Offset[NUM_LINES][2]; + ALfloat Coeff[NUM_LINES]; /* The gain for each output channel based on 3D panning. */ - ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; + ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; + ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; } Early; struct { @@ -302,7 +309,7 @@ typedef struct ALreverbState { /* A recursive delay line is used fill in the reverb tail. */ DelayLineI Delay; - ALsizei Offset[4][2]; + ALsizei Offset[NUM_LINES][2]; /* T60 decay filters are used to simulate absorption. */ struct { @@ -312,7 +319,7 @@ typedef struct ALreverbState { * last output sample. */ ALfloat States[2][2]; - } Filters[4]; + } Filters[NUM_LINES]; /* A Gerzon vector all-pass filter is used to simulate diffusion. */ VecAllpass VecAp; @@ -329,10 +336,10 @@ typedef struct ALreverbState { ALsizei Offset; /* Temporary storage used when processing. */ - alignas(16) ALsizei ModulationDelays[4][MAX_UPDATE_SAMPLES][2]; - alignas(16) ALfloat AFormatSamples[4][MAX_UPDATE_SAMPLES]; - alignas(16) ALfloat ReverbSamples[4][MAX_UPDATE_SAMPLES]; - alignas(16) ALfloat EarlySamples[4][MAX_UPDATE_SAMPLES]; + alignas(16) ALsizei ModulationDelays[NUM_LINES][MAX_UPDATE_SAMPLES][2]; + alignas(16) ALfloat AFormatSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat ReverbSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat EarlySamples[NUM_LINES][MAX_UPDATE_SAMPLES]; } ALreverbState; static ALvoid ALreverbState_Destruct(ALreverbState *State); @@ -353,7 +360,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->TotalSamples = 0; state->SampleBuffer = NULL; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { ALfilterState_clear(&state->Filter[i].Lp); ALfilterState_clear(&state->Filter[i].Hp); @@ -362,7 +369,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Delay.Mask = 0; state->Delay.Line = NULL; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { state->EarlyDelayTap[i][0] = 0; state->EarlyDelayTap[i][1] = 0; @@ -371,7 +378,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->LateFeedTap = 0; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { state->LateDelayTap[i][0] = 0; state->LateDelayTap[i][1] = 0; @@ -385,7 +392,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.VecAp.Delay.Line = NULL; state->Early.Delay.Mask = 0; state->Early.Delay.Line = NULL; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { state->Early.VecAp.Offset[i][0] = 0; state->Early.VecAp.Offset[i][1] = 0; @@ -406,7 +413,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.Delay.Line = NULL; state->Late.VecAp.Delay.Mask = 0; state->Late.VecAp.Delay.Line = NULL; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { state->Late.Offset[i][0] = 0; state->Late.Offset[i][1] = 0; @@ -425,7 +432,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.Filters[i].States[1][1] = 0.0f; } - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) { @@ -459,9 +466,9 @@ static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay) { union { ALfloat *f; - ALfloat (*f4)[4]; + ALfloat (*f4)[NUM_LINES]; } u; - u.f = &sampleBuffer[(ptrdiff_t)Delay->Line * 4]; + u.f = &sampleBuffer[(ptrdiff_t)Delay->Line * NUM_LINES]; Delay->Line = u.f4; } @@ -479,7 +486,7 @@ static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const /* All lines share a single sample buffer. */ Delay->Mask = samples - 1; - Delay->Line = (ALfloat(*)[4])offset; + Delay->Line = (ALfloat(*)[NUM_LINES])offset; /* Return the sample count for accumulation. */ return samples; @@ -509,35 +516,34 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) * largest late tap width. Finally, it must also be extended by the * update size (MAX_UPDATE_SAMPLES) for block processing. */ - length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS[3]*multiplier + + length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + - (LATE_LINE_LENGTHS[3] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; + (LATE_LINE_LENGTHS[NUM_LINES-1] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, &State->Delay); /* The early vector all-pass line. */ - length = EARLY_ALLPASS_LENGTHS[3] * multiplier; + length = EARLY_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Early.VecAp.Delay); /* The early reflection line. */ - length = EARLY_LINE_LENGTHS[3] * multiplier; + length = EARLY_LINE_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Early.Delay); /* The late vector all-pass line. */ - length = LATE_ALLPASS_LENGTHS[3] * multiplier; + length = LATE_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &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 * modulation-related delay. The modulator's delay is calculated from the - * maximum modulation time and depth coefficient, and halved for the low- - * to-high frequency swing. + * depth coefficient. */ - length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[3]*multiplier) + - AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f; + length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[NUM_LINES-1]*multiplier) + + MODULATION_DEPTH_COEFF; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Late.Delay); @@ -546,7 +552,7 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) ALfloat *newBuffer; TRACE("New reverb buffer length: %ux4 samples\n", totalSamples); - newBuffer = al_calloc(16, sizeof(ALfloat[4]) * totalSamples); + newBuffer = al_calloc(16, sizeof(ALfloat[NUM_LINES]) * totalSamples); if(!newBuffer) return AL_FALSE; al_free(State->SampleBuffer); @@ -581,7 +587,7 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev /* The late feed taps are set a fixed position past the latest delay tap. */ State->LateFeedTap = fastf2i((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + - EARLY_TAP_LENGTHS[3]*multiplier) * + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * frequency); return AL_TRUE; @@ -1038,7 +1044,7 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, * delay path and offsets that would continue the propagation naturally * into the late lines. */ - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier; State->EarlyDelayTap[i][1] = fastf2i(length * frequency); @@ -1059,7 +1065,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c multiplier = 1.0f + density*LINE_MULTIPLIER; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { /* Calculate the length (in seconds) of each all-pass line. */ length = EARLY_ALLPASS_LENGTHS[i] * multiplier; @@ -1112,7 +1118,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co bandWeights[2]*hfDecayTime) / F_TAU) ); - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { /* Calculate the length (in seconds) of each all-pass line. */ length = LATE_ALLPASS_LENGTHS[i] * multiplier; @@ -1277,7 +1283,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte gainlf = maxf(props->Reverb.GainLF, 0.001f); ALfilterState_setParams(&State->Filter[0].Hp, ALfilterType_LowShelf, gainlf, lf0norm, calc_rcpQ_from_slope(gainlf, 1.0f)); - for(i = 1;i < 4;i++) + for(i = 1;i < NUM_LINES;i++) { ALfilterState_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); ALfilterState_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp); @@ -1332,7 +1338,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte props->Reverb.LateReverbGain, State); /* Determine if delay-line cross-fading is required. */ - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { if((State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0]) || (State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0]) || @@ -1375,20 +1381,20 @@ static inline ALvoid DelayLineIn(DelayLineI *Delay, const ALsizei offset, const Delay->Line[offset&Delay->Mask][c] = in; } -static inline ALvoid DelayLineIn4(DelayLineI *Delay, ALsizei offset, const ALfloat in[4]) +static inline ALvoid DelayLineIn4(DelayLineI *Delay, ALsizei offset, const ALfloat in[NUM_LINES]) { ALsizei i; offset &= Delay->Mask; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) Delay->Line[offset][i] = in[i]; } -static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const ALfloat in[4]) +static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const ALfloat in[NUM_LINES]) { ALsizei i; offset &= Delay->Mask; - for(i = 0;i < 4;i++) - Delay->Line[offset][i] = in[3-i]; + for(i = 0;i < NUM_LINES;i++) + Delay->Line[offset][i] = in[NUM_LINES-1-i]; } static void CalcModulationDelays(ALreverbState *State, @@ -1399,7 +1405,7 @@ static void CalcModulationDelays(ALreverbState *State, ALsizei index, c, i; ALfloat sinus; - for(c = 0;c < 4;c++) + for(c = 0;c < NUM_LINES;c++) { ALsizei offset0 = offsets[c][0] << FRACTIONBITS; ALsizei offset1 = offsets[c][1] << FRACTIONBITS; @@ -1483,13 +1489,13 @@ static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \ const ALfloat yCoeff, const ALfloat mu, \ VecAllpass *Vap) \ { \ - ALfloat f[4], fs[4]; \ + ALfloat f[NUM_LINES], fs[NUM_LINES]; \ ALfloat input; \ ALsizei i; \ \ (void)mu; /* Ignore for Unfaded. */ \ \ - for(i = 0;i < 4;i++) \ + for(i = 0;i < NUM_LINES;i++) \ { \ input = vec[i]; \ vec[i] = T##DelayLineOut(&Vap->Delay, offset-Vap->Offset[i][0], \ @@ -1509,10 +1515,9 @@ DECL_TEMPLATE(Faded) /* A helper to reverse vector components. */ static inline void VectorReverse(ALfloat *restrict out, const ALfloat *restrict in) { - out[0] = in[3]; - out[1] = in[2]; - out[2] = in[1]; - out[3] = in[0]; + ALsizei i; + for(i = 0;i < NUM_LINES;i++) + out[i] = in[NUM_LINES-1-i]; } /* This generates early reflections. @@ -1543,12 +1548,12 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ const ALfloat apFeedCoeff = State->ApFeedCoeff; \ const ALfloat mixX = State->MixX; \ const ALfloat mixY = State->MixY; \ - ALfloat f[4], fr[4]; \ + ALfloat f[NUM_LINES], fr[NUM_LINES]; \ ALsizei i, j; \ \ for(i = 0;i < todo;i++) \ { \ - for(j = 0;j < 4;j++) \ + for(j = 0;j < NUM_LINES;j++) \ f[j] = T##DelayLineOut(&State->Delay, \ offset-State->EarlyDelayTap[j][0], \ offset-State->EarlyDelayTap[j][1], j, fade \ @@ -1559,13 +1564,13 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ \ DelayLineIn4Rev(&State->Early.Delay, offset, f); \ \ - for(j = 0;j < 4;j++) \ + for(j = 0;j < NUM_LINES;j++) \ f[j] += T##DelayLineOut(&State->Early.Delay, \ offset-State->Early.Offset[j][0], \ offset-State->Early.Offset[j][1], j, fade \ ) * State->Early.Coeff[j]; \ \ - for(j = 0;j < 4;j++) \ + for(j = 0;j < NUM_LINES;j++) \ out[j][i] = f[j]; \ \ VectorReverse(fr, f); \ @@ -1631,21 +1636,21 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat offset = State->Offset; for(i = 0;i < todo;i++) { - ALfloat f[4], fr[4]; + ALfloat f[NUM_LINES], fr[NUM_LINES]; - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) f[j] = FadedDelayLineOut(&State->Delay, - offset-State->LateDelayTap[j][0], - offset-State->LateDelayTap[j][1], j, fade + offset - State->LateDelayTap[j][0], + offset - State->LateDelayTap[j][1], j, fade ) * State->Late.DensityGain; - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) f[j] += FadedDelayLineOut(&State->Late.Delay, offset - State->Late.Offset[j][0], offset - State->Late.Offset[j][1], j, fade ); - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) f[j] = LateT60Filter( State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].States[0], State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].States[1], @@ -1654,7 +1659,7 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat VectorAllpass_Faded(f, offset, apFeedCoeff, mixX, mixY, fade, &State->Late.VecAp); - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) out[j][i] = f[j]; VectorReverse(fr, f); @@ -1681,17 +1686,16 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo offset = State->Offset; for(i = 0;i < todo;i++) { - ALfloat f[4], fr[4]; + ALfloat f[NUM_LINES], fr[NUM_LINES]; - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) f[j] = DelayLineOut(&State->Delay, offset-State->LateDelayTap[j][0], j) * State->Late.DensityGain; - for(j = 0;j < 4;j++) - f[j] += DelayLineOut(&State->Late.Delay, - offset - State->Late.Offset[j][0], j); + for(j = 0;j < NUM_LINES;j++) + f[j] += DelayLineOut(&State->Late.Delay, offset-State->Late.Offset[j][0], j); - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) f[j] = LateT60Filter( State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].States[0], State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].States[1], @@ -1700,7 +1704,7 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo VectorAllpass_Unfaded(f, offset, apFeedCoeff, mixX, mixY, fade, &State->Late.VecAp); - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) out[j][i] = f[j]; VectorReverse(fr, f); @@ -1730,14 +1734,14 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c todo = mini(todo, FADE_SAMPLES-fadeCount); /* Convert B-Format to A-Format for processing. */ - memset(afmt, 0, sizeof(*afmt)*4); - for(c = 0;c < 4;c++) + memset(afmt, 0, sizeof(*afmt)*NUM_LINES); + for(c = 0;c < NUM_LINES;c++) MixRowSamples(afmt[c], B2A.m[c], SamplesIn, MAX_EFFECT_CHANNELS, base, todo ); /* Process the samples for reverb. */ - for(c = 0;c < 4;c++) + for(c = 0;c < NUM_LINES;c++) { /* Band-pass the incoming samples. Use the early output lines for * temp storage. @@ -1776,7 +1780,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c /* Update the cross-fading delay line taps. */ fadeCount = FADE_SAMPLES; fade = 1.0f; - for(c = 0;c < 4;c++) + 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]; @@ -1791,12 +1795,12 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c /* Mix the A-Format results to output, implicitly converting back to * B-Format. */ - for(c = 0;c < 4;c++) + for(c = 0;c < NUM_LINES;c++) MixSamples(early[c], NumChannels, SamplesOut, State->Early.CurrentGain[c], State->Early.PanGain[c], SamplesToDo-base, base, todo ); - for(c = 0;c < 4;c++) + for(c = 0;c < NUM_LINES;c++) MixSamples(late[c], NumChannels, SamplesOut, State->Late.CurrentGain[c], State->Late.PanGain[c], SamplesToDo-base, base, todo |