1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
/*
* 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, 48000);
}
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
|