winamp/Src/external_dependencies/openmpt-trunk/sounddsp/AGC.cpp

142 lines
3.2 KiB
C++

/*
* AGC.cpp
* -------
* Purpose: Automatic Gain Control
* Notes : Ugh... This should really be removed at some point.
* Authors: Olivier Lapicque
* OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
#include "stdafx.h"
#include "../sounddsp/AGC.h"
OPENMPT_NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////////////
// Automatic Gain Control
#ifndef NO_AGC
#define AGC_PRECISION 10
#define AGC_UNITY (1 << AGC_PRECISION)
// Limiter
#define MIXING_LIMITMAX (0x08100000)
#define MIXING_LIMITMIN (-MIXING_LIMITMAX)
static UINT ProcessAGC(int *pBuffer, int *pRearBuffer, std::size_t nSamples, std::size_t nChannels, int nAGC)
{
if(nChannels == 1)
{
while(nSamples--)
{
int val = (int)(((int64)*pBuffer * (int32)nAGC) >> AGC_PRECISION);
if(val < MIXING_LIMITMIN || val > MIXING_LIMITMAX) nAGC--;
*pBuffer = val;
pBuffer++;
}
} else
{
if(nChannels == 2)
{
while(nSamples--)
{
int fl = (int)(((int64)pBuffer[0] * (int32)nAGC) >> AGC_PRECISION);
int fr = (int)(((int64)pBuffer[1] * (int32)nAGC) >> AGC_PRECISION);
bool dec = false;
dec = dec || (fl < MIXING_LIMITMIN || fl > MIXING_LIMITMAX);
dec = dec || (fr < MIXING_LIMITMIN || fr > MIXING_LIMITMAX);
if(dec) nAGC--;
pBuffer[0] = fl;
pBuffer[1] = fr;
pBuffer += 2;
}
} else if(nChannels == 4)
{
while(nSamples--)
{
int fl = (int)(((int64)pBuffer[0] * (int32)nAGC) >> AGC_PRECISION);
int fr = (int)(((int64)pBuffer[1] * (int32)nAGC) >> AGC_PRECISION);
int rl = (int)(((int64)pRearBuffer[0] * (int32)nAGC) >> AGC_PRECISION);
int rr = (int)(((int64)pRearBuffer[1] * (int32)nAGC) >> AGC_PRECISION);
bool dec = false;
dec = dec || (fl < MIXING_LIMITMIN || fl > MIXING_LIMITMAX);
dec = dec || (fr < MIXING_LIMITMIN || fr > MIXING_LIMITMAX);
dec = dec || (rl < MIXING_LIMITMIN || rl > MIXING_LIMITMAX);
dec = dec || (rr < MIXING_LIMITMIN || rr > MIXING_LIMITMAX);
if(dec) nAGC--;
pBuffer[0] = fl;
pBuffer[1] = fr;
pRearBuffer[0] = rl;
pRearBuffer[1] = rr;
pBuffer += 2;
pRearBuffer += 2;
}
}
}
return nAGC;
}
CAGC::CAGC()
{
Initialize(true, 44100);
}
void CAGC::Process(int *MixSoundBuffer, int *RearSoundBuffer, std::size_t count, std::size_t nChannels)
{
UINT agc = ProcessAGC(MixSoundBuffer, RearSoundBuffer, count, nChannels, m_nAGC);
// Some kind custom law, so that the AGC stays quite stable, but slowly
// goes back up if the sound level stays below a level inversely proportional
// to the AGC level. (J'me comprends)
if((agc >= m_nAGC) && (m_nAGC < AGC_UNITY))
{
m_nAGCRecoverCount += count;
if(m_nAGCRecoverCount >= m_Timeout)
{
m_nAGCRecoverCount = 0;
m_nAGC++;
}
} else
{
m_nAGC = agc;
m_nAGCRecoverCount = 0;
}
}
void CAGC::Adjust(UINT oldVol, UINT newVol)
{
m_nAGC = m_nAGC * oldVol / newVol;
if (m_nAGC > AGC_UNITY) m_nAGC = AGC_UNITY;
}
void CAGC::Initialize(bool bReset, DWORD MixingFreq)
{
if(bReset)
{
m_nAGC = AGC_UNITY;
m_nAGCRecoverCount = 0;
}
m_Timeout = (MixingFreq >> (AGC_PRECISION-8)) >> 1;
}
#else
MPT_MSVC_WORKAROUND_LNK4221(AGC)
#endif // NO_AGC
OPENMPT_NAMESPACE_END