/* * 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