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.
This commit is contained in:
parent
f880f67049
commit
4a4442ad91
17
Alc/ALu.c
17
Alc/ALu.c
@ -1455,24 +1455,18 @@ static void ApplyLimiter(struct OutputLimiter *Limiter,
|
|||||||
{
|
{
|
||||||
ALfloat lastgain = Limiter->Gain;
|
ALfloat lastgain = Limiter->Gain;
|
||||||
ALsizei wpos = Limiter->Pos;
|
ALsizei wpos = Limiter->Pos;
|
||||||
ALfloat sum = 0.0f;
|
ALuint sum = Limiter->SquaredSum;
|
||||||
ALfloat gain;
|
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++)
|
for(i = 0;i < SamplesToDo;i++)
|
||||||
{
|
{
|
||||||
sum -= Limiter->Window[wpos];
|
sum -= Limiter->Window[wpos];
|
||||||
Limiter->Window[wpos] = Values[i];
|
Limiter->Window[wpos] = fastf2u(minf(Values[i]*65536.0f, LIMITER_VALUE_MAX));
|
||||||
sum += Values[i];
|
sum += Limiter->Window[wpos];
|
||||||
|
|
||||||
/* Clamp limiter range to 0dB...-80dB. */
|
/* 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)
|
if(lastgain >= gain)
|
||||||
lastgain = maxf(lastgain*AttackRate, gain);
|
lastgain = maxf(lastgain*AttackRate, gain);
|
||||||
else
|
else
|
||||||
@ -1485,6 +1479,7 @@ static void ApplyLimiter(struct OutputLimiter *Limiter,
|
|||||||
|
|
||||||
Limiter->Gain = lastgain;
|
Limiter->Gain = lastgain;
|
||||||
Limiter->Pos = wpos;
|
Limiter->Pos = wpos;
|
||||||
|
Limiter->SquaredSum = sum;
|
||||||
}
|
}
|
||||||
if(do_limit)
|
if(do_limit)
|
||||||
{
|
{
|
||||||
|
@ -299,9 +299,13 @@ void DeinitVoice(ALvoice *voice);
|
|||||||
|
|
||||||
#define LIMITER_WINDOW_SIZE (1<<7) /* 128 */
|
#define LIMITER_WINDOW_SIZE (1<<7) /* 128 */
|
||||||
#define LIMITER_WINDOW_MASK (LIMITER_WINDOW_SIZE-1)
|
#define LIMITER_WINDOW_MASK (LIMITER_WINDOW_SIZE-1)
|
||||||
|
#define LIMITER_VALUE_MAX (UINT_MAX / LIMITER_WINDOW_SIZE)
|
||||||
struct OutputLimiter {
|
struct OutputLimiter {
|
||||||
/* RMS detection window and the next write pos. */
|
/* RMS detection window, sum of values in the window, and the next write
|
||||||
alignas(16) ALfloat Window[LIMITER_WINDOW_SIZE];
|
* pos. Values are 16.16 fixed-point.
|
||||||
|
*/
|
||||||
|
ALuint Window[LIMITER_WINDOW_SIZE];
|
||||||
|
ALuint SquaredSum;
|
||||||
ALsizei Pos;
|
ALsizei Pos;
|
||||||
|
|
||||||
/* In milliseconds. */
|
/* In milliseconds. */
|
||||||
|
Loading…
Reference in New Issue
Block a user