1 /*
2 * Copyright (C) 2004-2010 NXP Software
3 * Copyright (C) 2010 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /****************************************************************************************/
19 /* */
20 /* Includes */
21 /* */
22 /****************************************************************************************/
23
24 #include "AGC.h"
25 #include "ScalarArithmetic.h"
26
27 /****************************************************************************************/
28 /* */
29 /* Defines */
30 /* */
31 /****************************************************************************************/
32
33 #define VOL_TC_SHIFT 21 /* As a power of 2 */
34 #define DECAY_SHIFT 10 /* As a power of 2 */
35 #define VOL_TC_FLOAT 2.0f /* As a power of 2 */
36 #define DECAY_FAC_FLOAT 64.0f /* As a power of 2 */
37
38 /****************************************************************************************/
39 /* */
40 /* FUNCTION: AGC_MIX_VOL_2St1Mon_D32_WRA */
41 /* */
42 /* DESCRIPTION: */
43 /* Apply AGC and mix signals */
44 /* */
45 /* */
46 /* StSrc ------------------| */
47 /* | */
48 /* ______ _|_ ________ */
49 /* | | | | | | */
50 /* MonoSrc -->| AGC |---->| + |----->| Volume |------------------------------+---> */
51 /* | Gain | |___| | Gain | | */
52 /* |______| |________| | */
53 /* /|\ __________ ________ | */
54 /* | | | | | | */
55 /* |-------------------------------| AGC Gain |<--| Peak |<--| */
56 /* | Update | | Detect | */
57 /* |__________| |________| */
58 /* */
59 /* */
60 /* PARAMETERS: */
61 /* pInstance Instance pointer */
62 /* pStereoIn Stereo source */
63 /* pMonoIn Mono band pass source */
64 /* pStereoOut Stereo destination */
65 /* */
66 /* RETURNS: */
67 /* Void */
68 /* */
69 /* NOTES: */
70 /* */
71 /****************************************************************************************/
AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t * pInstance,const LVM_FLOAT * pStSrc,const LVM_FLOAT * pMonoSrc,LVM_FLOAT * pDst,LVM_UINT16 NumSamples)72 void AGC_MIX_VOL_2St1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t *pInstance, /* Instance pointer */
73 const LVM_FLOAT *pStSrc, /* Stereo source */
74 const LVM_FLOAT *pMonoSrc, /* Mono source */
75 LVM_FLOAT *pDst, /* Stereo destination */
76 LVM_UINT16 NumSamples) /* Number of samples */
77 {
78
79 /*
80 * General variables
81 */
82 LVM_UINT16 i; /* Sample index */
83 LVM_FLOAT Left; /* Left sample */
84 LVM_FLOAT Right; /* Right sample */
85 LVM_FLOAT Mono; /* Mono sample */
86 LVM_FLOAT AbsPeak; /* Absolute peak signal */
87 LVM_FLOAT AGC_Mult; /* Short AGC gain */
88 LVM_FLOAT Vol_Mult; /* Short volume */
89
90 /*
91 * Instance control variables
92 */
93 LVM_FLOAT AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */
94 LVM_FLOAT AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */
95 LVM_FLOAT AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */
96 LVM_FLOAT AGC_Decay = (pInstance->AGC_Decay * (1 << (DECAY_SHIFT)));/* Decay scaler */
97 LVM_FLOAT AGC_Target = pInstance->AGC_Target; /* Get the target level */
98 LVM_FLOAT Vol_Current = pInstance->Volume; /* Actual volume setting */
99 LVM_FLOAT Vol_Target = pInstance->Target; /* Target volume setting */
100 LVM_FLOAT Vol_TC = pInstance->VolumeTC; /* Time constant */
101
102 /*
103 * Process on a sample by sample basis
104 */
105 for (i = 0; i < NumSamples; i++) /* For each sample */
106 {
107
108 /*
109 * Get the short scalers
110 */
111 AGC_Mult = (LVM_FLOAT)(AGC_Gain); /* Get the short AGC gain */
112 Vol_Mult = (LVM_FLOAT)(Vol_Current); /* Get the short volume gain */
113
114 /*
115 * Get the input samples
116 */
117 Left = *pStSrc++; /* Get the left sample */
118 Right = *pStSrc++; /* Get the right sample */
119 Mono = *pMonoSrc++; /* Get the mono sample */
120
121 /*
122 * Apply the AGC gain to the mono input and mix with the stereo signal
123 */
124 Left += (Mono * AGC_Mult); /* Mix in the mono signal */
125 Right += (Mono * AGC_Mult);
126
127 /*
128 * Apply the volume and write to the output stream
129 */
130 Left = Left * Vol_Mult;
131 Right = Right * Vol_Mult;
132 *pDst++ = Left; /* Save the results */
133 *pDst++ = Right;
134
135 /*
136 * Update the AGC gain
137 */
138 AbsPeak = Abs_Float(Left) > Abs_Float(Right) ? Abs_Float(Left) : Abs_Float(Right);
139 if (AbsPeak > AGC_Target)
140 {
141 /*
142 * The signal is too large so decrease the gain
143 */
144 AGC_Gain = AGC_Gain * AGC_Attack;
145 }
146 else
147 {
148 /*
149 * The signal is too small so increase the gain
150 */
151 if (AGC_Gain > AGC_MaxGain)
152 {
153 AGC_Gain -= (AGC_Decay);
154 }
155 else
156 {
157 AGC_Gain += (AGC_Decay);
158 }
159 }
160
161 /*
162 * Update the gain
163 */
164 Vol_Current += (Vol_Target - Vol_Current) * ((LVM_FLOAT)Vol_TC / VOL_TC_FLOAT);
165 }
166
167 /*
168 * Update the parameters
169 */
170 pInstance->Volume = Vol_Current; /* Actual volume setting */
171 pInstance->AGC_Gain = AGC_Gain;
172
173 return;
174 }
175 #ifdef SUPPORT_MC
176 /****************************************************************************************/
177 /* */
178 /* FUNCTION: AGC_MIX_VOL_Mc1Mon_D32_WRA */
179 /* */
180 /* DESCRIPTION: */
181 /* Apply AGC and mix signals */
182 /* */
183 /* */
184 /* McSrc ------------------| */
185 /* | */
186 /* ______ _|_ ________ */
187 /* | | | | | | */
188 /* MonoSrc -->| AGC |---->| + |----->| Volume |------------------------------+---> */
189 /* | Gain | |___| | Gain | | */
190 /* |______| |________| | */
191 /* /|\ __________ ________ | */
192 /* | | | | | | */
193 /* |-------------------------------| AGC Gain |<--| Peak |<--| */
194 /* | Update | | Detect | */
195 /* |__________| |________| */
196 /* */
197 /* */
198 /* PARAMETERS: */
199 /* pInstance Instance pointer */
200 /* pMcSrc Multichannel source */
201 /* pMonoSrc Mono band pass source */
202 /* pDst Multichannel destination */
203 /* NrFrames Number of frames */
204 /* NrChannels Number of channels */
205 /* */
206 /* RETURNS: */
207 /* Void */
208 /* */
209 /* NOTES: */
210 /* */
211 /****************************************************************************************/
AGC_MIX_VOL_Mc1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t * pInstance,const LVM_FLOAT * pMcSrc,const LVM_FLOAT * pMonoSrc,LVM_FLOAT * pDst,LVM_UINT16 NrFrames,LVM_UINT16 NrChannels)212 void AGC_MIX_VOL_Mc1Mon_D32_WRA(AGC_MIX_VOL_2St1Mon_FLOAT_t *pInstance,
213 const LVM_FLOAT *pMcSrc,
214 const LVM_FLOAT *pMonoSrc,
215 LVM_FLOAT *pDst,
216 LVM_UINT16 NrFrames,
217 LVM_UINT16 NrChannels)
218 {
219
220 /*
221 * General variables
222 */
223 LVM_UINT16 i, jj; /* Sample index */
224 LVM_FLOAT SampleVal; /* Sample value */
225 LVM_FLOAT Mono; /* Mono sample */
226 LVM_FLOAT AbsPeak; /* Absolute peak signal */
227 LVM_FLOAT AGC_Mult; /* Short AGC gain */
228 LVM_FLOAT Vol_Mult; /* Short volume */
229
230 /*
231 * Instance control variables
232 */
233 LVM_FLOAT AGC_Gain = pInstance->AGC_Gain; /* Get the current AGC gain */
234 LVM_FLOAT AGC_MaxGain = pInstance->AGC_MaxGain; /* Get maximum AGC gain */
235 LVM_FLOAT AGC_Attack = pInstance->AGC_Attack; /* Attack scaler */
236 /* Decay scaler */
237 LVM_FLOAT AGC_Decay = (pInstance->AGC_Decay * (1 << (DECAY_SHIFT)));
238 LVM_FLOAT AGC_Target = pInstance->AGC_Target; /* Get the target level */
239 LVM_FLOAT Vol_Current = pInstance->Volume; /* Actual volume setting */
240 LVM_FLOAT Vol_Target = pInstance->Target; /* Target volume setting */
241 LVM_FLOAT Vol_TC = pInstance->VolumeTC; /* Time constant */
242
243 /*
244 * Process on a sample by sample basis
245 */
246 for (i = 0; i < NrFrames; i++) /* For each frame */
247 {
248
249 /*
250 * Get the scalers
251 */
252 AGC_Mult = (LVM_FLOAT)(AGC_Gain); /* Get the AGC gain */
253 Vol_Mult = (LVM_FLOAT)(Vol_Current); /* Get the volume gain */
254
255 AbsPeak = 0.0f;
256 /*
257 * Get the input samples
258 */
259 for (jj = 0; jj < NrChannels; jj++)
260 {
261 SampleVal = *pMcSrc++; /* Get the sample value of jj Channel*/
262 Mono = *pMonoSrc; /* Get the mono sample */
263
264 /*
265 * Apply the AGC gain to the mono input and mix with the input signal
266 */
267 SampleVal += (Mono * AGC_Mult); /* Mix in the mono signal */
268
269 /*
270 * Apply the volume and write to the output stream
271 */
272 SampleVal = SampleVal * Vol_Mult;
273
274 *pDst++ = SampleVal; /* Save the results */
275
276 /*
277 * Update the AGC gain
278 */
279 AbsPeak = Abs_Float(SampleVal) > AbsPeak ? Abs_Float(SampleVal) : AbsPeak;
280 }
281 if (AbsPeak > AGC_Target)
282 {
283 /*
284 * The signal is too large so decrease the gain
285 */
286 AGC_Gain = AGC_Gain * AGC_Attack;
287 }
288 else
289 {
290 /*
291 * The signal is too small so increase the gain
292 */
293 if (AGC_Gain > AGC_MaxGain)
294 {
295 AGC_Gain -= (AGC_Decay);
296 }
297 else
298 {
299 AGC_Gain += (AGC_Decay);
300 }
301 }
302 pMonoSrc++;
303 /*
304 * Update the gain
305 */
306 Vol_Current += (Vol_Target - Vol_Current) * ((LVM_FLOAT)Vol_TC / VOL_TC_FLOAT);
307 }
308
309 /*
310 * Update the parameters
311 */
312 pInstance->Volume = Vol_Current; /* Actual volume setting */
313 pInstance->AGC_Gain = AGC_Gain;
314
315 return;
316 }
317 #endif /*SUPPORT_MC*/
318