diff options
author | Chris Robinson <[email protected]> | 2017-05-09 11:50:25 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2017-05-09 11:56:03 -0700 |
commit | a2c25378a970792461c961054e2b47cd3a086e05 (patch) | |
tree | 58faea77675124e906d5059a5e833f86c821cee4 | |
parent | 4a4442ad91d34964b1d695381fafbdef07bb14ce (diff) |
Reduce LIMITER_VALUE_MAX
The previous value couldn't actually be expressed as a float and got rounded up
to the next whole number value, leaving the potential for an overrun in the
squared sum.
-rw-r--r-- | Alc/ALu.c | 18 | ||||
-rw-r--r-- | OpenAL32/Include/alu.h | 2 |
2 files changed, 13 insertions, 7 deletions
@@ -1427,6 +1427,8 @@ static void UpdateContextSources(ALCcontext *ctx, const struct ALeffectslotArray } +static_assert(LIMITER_VALUE_MAX < (UINT_MAX/LIMITER_WINDOW_SIZE), "LIMITER_VALUE_MAX is too big"); + static void ApplyLimiter(struct OutputLimiter *Limiter, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALsizei NumChans, const ALfloat AttackRate, const ALfloat ReleaseRate, @@ -1446,8 +1448,8 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, { for(i = 0;i < SamplesToDo;i++) { - ALfloat amp_sqr = OutBuffer[c][i] * OutBuffer[c][i]; - Values[i] = maxf(Values[i], amp_sqr); + ALfloat amp = OutBuffer[c][i]; + Values[i] = maxf(Values[i], amp*amp); } } @@ -1456,7 +1458,7 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, ALfloat lastgain = Limiter->Gain; ALsizei wpos = Limiter->Pos; ALuint sum = Limiter->SquaredSum; - ALfloat gain; + ALfloat gain, rms; for(i = 0;i < SamplesToDo;i++) { @@ -1464,9 +1466,13 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, 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((ALfloat)sum / ((ALfloat)LIMITER_WINDOW_SIZE*65536.0f)), - 1.0f, 1000.0f); + rms = sqrtf((ALfloat)sum / ((ALfloat)LIMITER_WINDOW_SIZE*65536.0f)); + + /* Clamp the minimum RMS to 0dB. The uint used for the squared sum + * inherently limits the maximum RMS to about 21dB, thus the gain + * ranges from 0dB to -21dB. + */ + gain = 1.0f / maxf(rms, 1.0f); if(lastgain >= gain) lastgain = maxf(lastgain*AttackRate, gain); else diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8ac25e35..30b245a5 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -299,7 +299,7 @@ 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) +#define LIMITER_VALUE_MAX (1<<24) /* 16777216 */ struct OutputLimiter { /* RMS detection window, sum of values in the window, and the next write * pos. Values are 16.16 fixed-point. |