kobodl/sound/a_limiter.c
Ville Lindholm dbc223eb84
Initial commit
Import existing source tree; original VCS history is no longer available.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-28 16:35:31 +03:00

141 lines
3.4 KiB
C

/*(LGPL)
---------------------------------------------------------------------------
a_limiter.h - Simple limiter
---------------------------------------------------------------------------
* Copyright (C) 2001, 2002, David Olofson
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include "a_limiter.h"
#include "a_types.h"
int lim_open(limiter_t *lim, int samplerate)
{
lim->samplerate = samplerate;
lim_control(lim, LIM_THRESHOLD, 32768);
lim_control(lim, LIM_RELEASE, 300000);
lim->peak = (unsigned)(32768<<8);
lim->attenuation = 0;
return 0;
}
void lim_close(limiter_t *lim)
{
/* Nothing to destruct */
}
void lim_control(limiter_t *lim, int param, int value)
{
switch(param)
{
case LIM_THRESHOLD:
lim->threshold = (unsigned)(value << 8);
if(lim->threshold < 256)
lim->threshold = 256;
break;
case LIM_RELEASE:
if(lim->samplerate < 1)
lim->samplerate = 44100;
lim->release = (value << 8) / lim->samplerate;
break;
}
}
void lims_process(limiter_t *lim, int *in, int *out, unsigned frames)
{
unsigned i;
frames <<= 1;
for(i = 0; i < frames; i += 2)
{
int gain;
int lp = abs(in[i]) << 8;
int rp = abs(in[i+1]) << 8;
unsigned maxp = (unsigned)(lp > rp ? lp : rp);
if(maxp > lim->peak)
{
lim->peak = maxp;
gain = (32767<<16) / ((lim->peak+255)>>8);
}
else
{
gain = (32767<<16) / ((lim->peak+255)>>8);
lim->peak -= lim->release;
if(lim->peak < lim->threshold)
lim->peak = lim->threshold;
}
#ifdef A_USE_INT64
out[i] = (Sint64)in[i] * (Sint64)gain >> 16;
out[i+1] = (Sint64)in[i+1] * (Sint64)gain >> 16;
#else
if(gain < 8192)
{
out[i] = in[i] * gain >> 16;
out[i+1] = in[i+1] * gain >> 16;
}
else
{
out[i] = in[i] * (gain>>4) >> 12;
out[i+1] = in[i+1] * (gain>>4) >> 12;
}
#endif
}
lim->attenuation = (lim->peak - lim->threshold) >> 8;
}
void limss_process(limiter_t *lim, int *in, int *out, unsigned frames)
{
unsigned i;
frames <<= 1;
for(i = 0; i < frames; i += 2)
{
int gain;
int lp = abs(in[i]);
int rp = abs(in[i+1]);
unsigned maxp = (unsigned)(lp > rp ? lp : rp);
unsigned p = maxp << 8;
p += (maxp - abs(lp - rp)) << 7;
if(p > lim->peak)
{
lim->peak = p;
gain = (32767<<16) / ((lim->peak+255)>>8);
}
else
{
gain = (32767<<16) / ((lim->peak+255)>>8);
lim->peak -= lim->release;
if(lim->peak < lim->threshold)
lim->peak = lim->threshold;
}
#ifdef A_USE_INT64
out[i] = (Sint64)in[i] * (Sint64)gain >> 16;
out[i+1] = (Sint64)in[i+1] * (Sint64)gain >> 16;
#else
if(gain < 8192)
{
out[i] = in[i] * gain >> 16;
out[i+1] = in[i+1] * gain >> 16;
}
else
{
out[i] = in[i] * (gain>>4) >> 12;
out[i+1] = in[i+1] * (gain>>4) >> 12;
}
#endif
}
lim->attenuation = (lim->peak - lim->threshold) >> 8;
}