From 4a4442ad91d34964b1d695381fafbdef07bb14ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 May 2017 16:23:16 -0700 Subject: Store the output limiter values as fixed-point integers This helps keep the squared sum stable over larger updates, also avoiding the need to keep recalculating it. --- Alc/ALu.c | 17 ++++++----------- OpenAL32/Include/alu.h | 8 ++++++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 8d9356c5..b8c93c69 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1455,24 +1455,18 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, { ALfloat lastgain = Limiter->Gain; ALsizei wpos = Limiter->Pos; - ALfloat sum = 0.0f; + ALuint sum = Limiter->SquaredSum; ALfloat gain; - /* Unfortunately we can't store the running sum due to fp inaccuracies - * causing it to drift over time. So we need to recalculate it every - * once in a while (i.e. every invocation). - */ - for(i = 0;i < LIMITER_WINDOW_SIZE;i++) - sum += Limiter->Window[i]; - for(i = 0;i < SamplesToDo;i++) { sum -= Limiter->Window[wpos]; - Limiter->Window[wpos] = Values[i]; - sum += Values[i]; + Limiter->Window[wpos] = fastf2u(minf(Values[i]*65536.0f, LIMITER_VALUE_MAX)); + sum += Limiter->Window[wpos]; /* Clamp limiter range to 0dB...-80dB. */ - gain = 1.0f / clampf(sqrtf(sum / (ALfloat)LIMITER_WINDOW_SIZE), 1.0f, 1000.0f); + gain = 1.0f / clampf(sqrtf((ALfloat)sum / ((ALfloat)LIMITER_WINDOW_SIZE*65536.0f)), + 1.0f, 1000.0f); if(lastgain >= gain) lastgain = maxf(lastgain*AttackRate, gain); else @@ -1485,6 +1479,7 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, Limiter->Gain = lastgain; Limiter->Pos = wpos; + Limiter->SquaredSum = sum; } if(do_limit) { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 6fdbac6f..8ac25e35 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -299,9 +299,13 @@ void DeinitVoice(ALvoice *voice); #define LIMITER_WINDOW_SIZE (1<<7) /* 128 */ #define LIMITER_WINDOW_MASK (LIMITER_WINDOW_SIZE-1) +#define LIMITER_VALUE_MAX (UINT_MAX / LIMITER_WINDOW_SIZE) struct OutputLimiter { - /* RMS detection window and the next write pos. */ - alignas(16) ALfloat Window[LIMITER_WINDOW_SIZE]; + /* RMS detection window, sum of values in the window, and the next write + * pos. Values are 16.16 fixed-point. + */ + ALuint Window[LIMITER_WINDOW_SIZE]; + ALuint SquaredSum; ALsizei Pos; /* In milliseconds. */ -- cgit v1.2.3