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, 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
|