blob: 3b4b39b9cc808ba0a9b21583bfdb8c7269217f11 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11/* digital_agc.c
12 *
13 */
14
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +000015#include "digital_agc.h"
16
17#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000018#include <string.h>
19#ifdef AGC_DEBUG
20#include <stdio.h>
21#endif
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +000022
niklase@google.com470e71d2011-07-07 08:21:25 +000023#include "gain_control.h"
24
25// To generate the gaintable, copy&paste the following lines to a Matlab window:
26// MaxGain = 6; MinGain = 0; CompRatio = 3; Knee = 1;
27// zeros = 0:31; lvl = 2.^(1-zeros);
28// A = -10*log10(lvl) * (CompRatio - 1) / CompRatio;
29// B = MaxGain - MinGain;
30// gains = round(2^16*10.^(0.05 * (MinGain + B * ( log(exp(-Knee*A)+exp(-Knee*B)) - log(1+exp(-Knee*B)) ) / log(1/(1+exp(Knee*B))))));
31// fprintf(1, '\t%i, %i, %i, %i,\n', gains);
32// % Matlab code for plotting the gain and input/output level characteristic (copy/paste the following 3 lines):
33// in = 10*log10(lvl); out = 20*log10(gains/65536);
34// subplot(121); plot(in, out); axis([-30, 0, -5, 20]); grid on; xlabel('Input (dB)'); ylabel('Gain (dB)');
35// subplot(122); plot(in, in+out); axis([-30, 0, -30, 5]); grid on; xlabel('Input (dB)'); ylabel('Output (dB)');
36// zoom on;
37
38// Generator table for y=log2(1+e^x) in Q8.
andrew@webrtc.orgd77a6612012-01-04 16:22:24 +000039enum { kGenFuncTableSize = 128 };
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +000040static const WebRtc_UWord16 kGenFuncTable[kGenFuncTableSize] = {
niklase@google.com470e71d2011-07-07 08:21:25 +000041 256, 485, 786, 1126, 1484, 1849, 2217, 2586,
42 2955, 3324, 3693, 4063, 4432, 4801, 5171, 5540,
43 5909, 6279, 6648, 7017, 7387, 7756, 8125, 8495,
44 8864, 9233, 9603, 9972, 10341, 10711, 11080, 11449,
45 11819, 12188, 12557, 12927, 13296, 13665, 14035, 14404,
46 14773, 15143, 15512, 15881, 16251, 16620, 16989, 17359,
47 17728, 18097, 18466, 18836, 19205, 19574, 19944, 20313,
48 20682, 21052, 21421, 21790, 22160, 22529, 22898, 23268,
49 23637, 24006, 24376, 24745, 25114, 25484, 25853, 26222,
50 26592, 26961, 27330, 27700, 28069, 28438, 28808, 29177,
51 29546, 29916, 30285, 30654, 31024, 31393, 31762, 32132,
52 32501, 32870, 33240, 33609, 33978, 34348, 34717, 35086,
53 35456, 35825, 36194, 36564, 36933, 37302, 37672, 38041,
54 38410, 38780, 39149, 39518, 39888, 40257, 40626, 40996,
55 41365, 41734, 42104, 42473, 42842, 43212, 43581, 43950,
56 44320, 44689, 45058, 45428, 45797, 46166, 46536, 46905
57};
58
59static const WebRtc_Word16 kAvgDecayTime = 250; // frames; < 3000
60
61WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16
62 WebRtc_Word16 digCompGaindB, // Q0
63 WebRtc_Word16 targetLevelDbfs,// Q0
64 WebRtc_UWord8 limiterEnable,
65 WebRtc_Word16 analogTarget) // Q0
66{
67 // This function generates the compressor gain table used in the fixed digital part.
68 WebRtc_UWord32 tmpU32no1, tmpU32no2, absInLevel, logApprox;
69 WebRtc_Word32 inLevel, limiterLvl;
70 WebRtc_Word32 tmp32, tmp32no1, tmp32no2, numFIX, den, y32;
71 const WebRtc_UWord16 kLog10 = 54426; // log2(10) in Q14
72 const WebRtc_UWord16 kLog10_2 = 49321; // 10*log10(2) in Q14
73 const WebRtc_UWord16 kLogE_1 = 23637; // log2(e) in Q14
74 WebRtc_UWord16 constMaxGain;
75 WebRtc_UWord16 tmpU16, intPart, fracPart;
76 const WebRtc_Word16 kCompRatio = 3;
77 const WebRtc_Word16 kSoftLimiterLeft = 1;
78 WebRtc_Word16 limiterOffset = 0; // Limiter offset
79 WebRtc_Word16 limiterIdx, limiterLvlX;
80 WebRtc_Word16 constLinApprox, zeroGainLvl, maxGain, diffGain;
81 WebRtc_Word16 i, tmp16, tmp16no1;
82 int zeros, zerosScale;
83
84 // Constants
85// kLogE_1 = 23637; // log2(e) in Q14
86// kLog10 = 54426; // log2(10) in Q14
87// kLog10_2 = 49321; // 10*log10(2) in Q14
88
89 // Calculate maximum digital gain and zero gain level
90 tmp32no1 = WEBRTC_SPL_MUL_16_16(digCompGaindB - analogTarget, kCompRatio - 1);
91 tmp16no1 = analogTarget - targetLevelDbfs;
92 tmp16no1 += WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
93 maxGain = WEBRTC_SPL_MAX(tmp16no1, (analogTarget - targetLevelDbfs));
94 tmp32no1 = WEBRTC_SPL_MUL_16_16(maxGain, kCompRatio);
95 zeroGainLvl = digCompGaindB;
96 zeroGainLvl -= WebRtcSpl_DivW32W16ResW16(tmp32no1 + ((kCompRatio - 1) >> 1),
97 kCompRatio - 1);
98 if ((digCompGaindB <= analogTarget) && (limiterEnable))
99 {
100 zeroGainLvl += (analogTarget - digCompGaindB + kSoftLimiterLeft);
101 limiterOffset = 0;
102 }
103
104 // Calculate the difference between maximum gain and gain at 0dB0v:
105 // diffGain = maxGain + (compRatio-1)*zeroGainLvl/compRatio
106 // = (compRatio-1)*digCompGaindB/compRatio
107 tmp32no1 = WEBRTC_SPL_MUL_16_16(digCompGaindB, kCompRatio - 1);
108 diffGain = WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +0000109 if (diffGain < 0 || diffGain >= kGenFuncTableSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000110 {
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +0000111 assert(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000112 return -1;
113 }
114
115 // Calculate the limiter level and index:
116 // limiterLvlX = analogTarget - limiterOffset
117 // limiterLvl = targetLevelDbfs + limiterOffset/compRatio
118 limiterLvlX = analogTarget - limiterOffset;
119 limiterIdx = 2
120 + WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)limiterLvlX, 13),
121 WEBRTC_SPL_RSHIFT_U16(kLog10_2, 1));
122 tmp16no1 = WebRtcSpl_DivW32W16ResW16(limiterOffset + (kCompRatio >> 1), kCompRatio);
123 limiterLvl = targetLevelDbfs + tmp16no1;
124
125 // Calculate (through table lookup):
126 // constMaxGain = log2(1+2^(log2(e)*diffGain)); (in Q8)
127 constMaxGain = kGenFuncTable[diffGain]; // in Q8
128
129 // Calculate a parameter used to approximate the fractional part of 2^x with a
130 // piecewise linear function in Q14:
131 // constLinApprox = round(3/2*(4*(3-2*sqrt(2))/(log(2)^2)-0.5)*2^14);
132 constLinApprox = 22817; // in Q14
133
134 // Calculate a denominator used in the exponential part to convert from dB to linear scale:
135 // den = 20*constMaxGain (in Q8)
136 den = WEBRTC_SPL_MUL_16_U16(20, constMaxGain); // in Q8
137
138 for (i = 0; i < 32; i++)
139 {
140 // Calculate scaled input level (compressor):
141 // inLevel = fix((-constLog10_2*(compRatio-1)*(1-i)+fix(compRatio/2))/compRatio)
142 tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(kCompRatio - 1, i - 1); // Q0
143 tmp32 = WEBRTC_SPL_MUL_16_U16(tmp16, kLog10_2) + 1; // Q14
144 inLevel = WebRtcSpl_DivW32W16(tmp32, kCompRatio); // Q14
145
146 // Calculate diffGain-inLevel, to map using the genFuncTable
147 inLevel = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)diffGain, 14) - inLevel; // Q14
148
149 // Make calculations on abs(inLevel) and compensate for the sign afterwards.
150 absInLevel = (WebRtc_UWord32)WEBRTC_SPL_ABS_W32(inLevel); // Q14
151
152 // LUT with interpolation
153 intPart = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_U32(absInLevel, 14);
154 fracPart = (WebRtc_UWord16)(absInLevel & 0x00003FFF); // extract the fractional part
155 tmpU16 = kGenFuncTable[intPart + 1] - kGenFuncTable[intPart]; // Q8
156 tmpU32no1 = WEBRTC_SPL_UMUL_16_16(tmpU16, fracPart); // Q22
157 tmpU32no1 += WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)kGenFuncTable[intPart], 14); // Q22
158 logApprox = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 8); // Q14
159 // Compensate for negative exponent using the relation:
160 // log2(1 + 2^-x) = log2(1 + 2^x) - x
161 if (inLevel < 0)
162 {
163 zeros = WebRtcSpl_NormU32(absInLevel);
164 zerosScale = 0;
165 if (zeros < 15)
166 {
167 // Not enough space for multiplication
168 tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(absInLevel, 15 - zeros); // Q(zeros-1)
169 tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no2, kLogE_1); // Q(zeros+13)
170 if (zeros < 9)
171 {
172 tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 9 - zeros); // Q(zeros+13)
173 zerosScale = 9 - zeros;
174 } else
175 {
176 tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, zeros - 9); // Q22
177 }
178 } else
179 {
180 tmpU32no2 = WEBRTC_SPL_UMUL_32_16(absInLevel, kLogE_1); // Q28
181 tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 6); // Q22
182 }
183 logApprox = 0;
184 if (tmpU32no2 < tmpU32no1)
185 {
186 logApprox = WEBRTC_SPL_RSHIFT_U32(tmpU32no1 - tmpU32no2, 8 - zerosScale); //Q14
187 }
188 }
189 numFIX = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_U16(maxGain, constMaxGain), 6); // Q14
190 numFIX -= WEBRTC_SPL_MUL_32_16((WebRtc_Word32)logApprox, diffGain); // Q14
191
192 // Calculate ratio
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +0000193 // Shift |numFIX| as much as possible.
194 // Ensure we avoid wrap-around in |den| as well.
195 if (numFIX > (den >> 8)) // |den| is Q8.
196 {
197 zeros = WebRtcSpl_NormW32(numFIX);
198 } else
199 {
200 zeros = WebRtcSpl_NormW32(den) + 8;
201 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 numFIX = WEBRTC_SPL_LSHIFT_W32(numFIX, zeros); // Q(14+zeros)
203
204 // Shift den so we end up in Qy1
205 tmp32no1 = WEBRTC_SPL_SHIFT_W32(den, zeros - 8); // Q(zeros)
206 if (numFIX < 0)
207 {
208 numFIX -= WEBRTC_SPL_RSHIFT_W32(tmp32no1, 1);
209 } else
210 {
211 numFIX += WEBRTC_SPL_RSHIFT_W32(tmp32no1, 1);
212 }
213 y32 = WEBRTC_SPL_DIV(numFIX, tmp32no1); // in Q14
214 if (limiterEnable && (i < limiterIdx))
215 {
216 tmp32 = WEBRTC_SPL_MUL_16_U16(i - 1, kLog10_2); // Q14
217 tmp32 -= WEBRTC_SPL_LSHIFT_W32(limiterLvl, 14); // Q14
218 y32 = WebRtcSpl_DivW32W16(tmp32 + 10, 20);
219 }
220 if (y32 > 39000)
221 {
222 tmp32 = WEBRTC_SPL_MUL(y32 >> 1, kLog10) + 4096; // in Q27
223 tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 13); // in Q14
224 } else
225 {
226 tmp32 = WEBRTC_SPL_MUL(y32, kLog10) + 8192; // in Q28
227 tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 14); // in Q14
228 }
229 tmp32 += WEBRTC_SPL_LSHIFT_W32(16, 14); // in Q14 (Make sure final output is in Q16)
230
231 // Calculate power
232 if (tmp32 > 0)
233 {
234 intPart = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 14);
235 fracPart = (WebRtc_UWord16)(tmp32 & 0x00003FFF); // in Q14
236 if (WEBRTC_SPL_RSHIFT_W32(fracPart, 13))
237 {
238 tmp16 = WEBRTC_SPL_LSHIFT_W16(2, 14) - constLinApprox;
239 tmp32no2 = WEBRTC_SPL_LSHIFT_W32(1, 14) - fracPart;
240 tmp32no2 = WEBRTC_SPL_MUL_32_16(tmp32no2, tmp16);
241 tmp32no2 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, 13);
242 tmp32no2 = WEBRTC_SPL_LSHIFT_W32(1, 14) - tmp32no2;
243 } else
244 {
245 tmp16 = constLinApprox - WEBRTC_SPL_LSHIFT_W16(1, 14);
246 tmp32no2 = WEBRTC_SPL_MUL_32_16(fracPart, tmp16);
247 tmp32no2 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, 13);
248 }
249 fracPart = (WebRtc_UWord16)tmp32no2;
250 gainTable[i] = WEBRTC_SPL_LSHIFT_W32(1, intPart)
251 + WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14);
252 } else
253 {
254 gainTable[i] = 0;
255 }
256 }
257
258 return 0;
259}
260
261WebRtc_Word32 WebRtcAgc_InitDigital(DigitalAgc_t *stt, WebRtc_Word16 agcMode)
262{
263
264 if (agcMode == kAgcModeFixedDigital)
265 {
266 // start at minimum to find correct gain faster
267 stt->capacitorSlow = 0;
268 } else
269 {
270 // start out with 0 dB gain
271 stt->capacitorSlow = 134217728; // (WebRtc_Word32)(0.125f * 32768.0f * 32768.0f);
272 }
273 stt->capacitorFast = 0;
274 stt->gain = 65536;
275 stt->gatePrevious = 0;
276 stt->agcMode = agcMode;
277#ifdef AGC_DEBUG
278 stt->frameCounter = 0;
279#endif
280
281 // initialize VADs
282 WebRtcAgc_InitVad(&stt->vadNearend);
283 WebRtcAgc_InitVad(&stt->vadFarend);
284
285 return 0;
286}
287
288WebRtc_Word32 WebRtcAgc_AddFarendToDigital(DigitalAgc_t *stt, const WebRtc_Word16 *in_far,
289 WebRtc_Word16 nrSamples)
290{
291 // Check for valid pointer
292 if (&stt->vadFarend == NULL)
293 {
294 return -1;
295 }
296
297 // VAD for far end
298 WebRtcAgc_ProcessVad(&stt->vadFarend, in_far, nrSamples);
299
300 return 0;
301}
302
303WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *in_near,
304 const WebRtc_Word16 *in_near_H, WebRtc_Word16 *out,
305 WebRtc_Word16 *out_H, WebRtc_UWord32 FS,
306 WebRtc_Word16 lowlevelSignal)
307{
308 // array for gains (one value per ms, incl start & end)
309 WebRtc_Word32 gains[11];
310
311 WebRtc_Word32 out_tmp, tmp32;
312 WebRtc_Word32 env[10];
313 WebRtc_Word32 nrg, max_nrg;
314 WebRtc_Word32 cur_level;
315 WebRtc_Word32 gain32, delta;
316 WebRtc_Word16 logratio;
317 WebRtc_Word16 lower_thr, upper_thr;
318 WebRtc_Word16 zeros, zeros_fast, frac;
319 WebRtc_Word16 decay;
320 WebRtc_Word16 gate, gain_adj;
321 WebRtc_Word16 k, n;
322 WebRtc_Word16 L, L2; // samples/subframe
323
324 // determine number of samples per ms
325 if (FS == 8000)
326 {
327 L = 8;
328 L2 = 3;
329 } else if (FS == 16000)
330 {
331 L = 16;
332 L2 = 4;
333 } else if (FS == 32000)
334 {
335 L = 16;
336 L2 = 4;
337 } else
338 {
339 return -1;
340 }
341
andrew@webrtc.org64235092011-08-19 21:22:08 +0000342 // TODO(andrew): again, we don't need input and output pointers...
343 if (in_near != out)
344 {
345 // Only needed if they don't already point to the same place.
346 memcpy(out, in_near, 10 * L * sizeof(WebRtc_Word16));
347 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000348 if (FS == 32000)
349 {
andrew@webrtc.org64235092011-08-19 21:22:08 +0000350 if (in_near_H != out_H)
351 {
352 memcpy(out_H, in_near_H, 10 * L * sizeof(WebRtc_Word16));
353 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000354 }
355 // VAD for near end
356 logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, out, L * 10);
357
358 // Account for far end VAD
359 if (stt->vadFarend.counter > 10)
360 {
361 tmp32 = WEBRTC_SPL_MUL_16_16(3, logratio);
362 logratio = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 - stt->vadFarend.logRatio, 2);
363 }
364
365 // Determine decay factor depending on VAD
366 // upper_thr = 1.0f;
367 // lower_thr = 0.25f;
368 upper_thr = 1024; // Q10
369 lower_thr = 0; // Q10
370 if (logratio > upper_thr)
371 {
372 // decay = -2^17 / DecayTime; -> -65
373 decay = -65;
374 } else if (logratio < lower_thr)
375 {
376 decay = 0;
377 } else
378 {
379 // decay = (WebRtc_Word16)(((lower_thr - logratio)
380 // * (2^27/(DecayTime*(upper_thr-lower_thr)))) >> 10);
381 // SUBSTITUTED: 2^27/(DecayTime*(upper_thr-lower_thr)) -> 65
382 tmp32 = WEBRTC_SPL_MUL_16_16((lower_thr - logratio), 65);
383 decay = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 10);
384 }
385
386 // adjust decay factor for long silence (detected as low standard deviation)
387 // This is only done in the adaptive modes
388 if (stt->agcMode != kAgcModeFixedDigital)
389 {
390 if (stt->vadNearend.stdLongTerm < 4000)
391 {
392 decay = 0;
393 } else if (stt->vadNearend.stdLongTerm < 8096)
394 {
395 // decay = (WebRtc_Word16)(((stt->vadNearend.stdLongTerm - 4000) * decay) >> 12);
396 tmp32 = WEBRTC_SPL_MUL_16_16((stt->vadNearend.stdLongTerm - 4000), decay);
397 decay = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 12);
398 }
399
400 if (lowlevelSignal != 0)
401 {
402 decay = 0;
403 }
404 }
405#ifdef AGC_DEBUG
406 stt->frameCounter++;
407 fprintf(stt->logFile, "%5.2f\t%d\t%d\t%d\t", (float)(stt->frameCounter) / 100, logratio, decay, stt->vadNearend.stdLongTerm);
408#endif
409 // Find max amplitude per sub frame
410 // iterate over sub frames
411 for (k = 0; k < 10; k++)
412 {
413 // iterate over samples
414 max_nrg = 0;
415 for (n = 0; n < L; n++)
416 {
417 nrg = WEBRTC_SPL_MUL_16_16(out[k * L + n], out[k * L + n]);
418 if (nrg > max_nrg)
419 {
420 max_nrg = nrg;
421 }
422 }
423 env[k] = max_nrg;
424 }
425
426 // Calculate gain per sub frame
427 gains[0] = stt->gain;
428 for (k = 0; k < 10; k++)
429 {
430 // Fast envelope follower
431 // decay time = -131000 / -1000 = 131 (ms)
432 stt->capacitorFast = AGC_SCALEDIFF32(-1000, stt->capacitorFast, stt->capacitorFast);
433 if (env[k] > stt->capacitorFast)
434 {
435 stt->capacitorFast = env[k];
436 }
437 // Slow envelope follower
438 if (env[k] > stt->capacitorSlow)
439 {
440 // increase capacitorSlow
441 stt->capacitorSlow
442 = AGC_SCALEDIFF32(500, (env[k] - stt->capacitorSlow), stt->capacitorSlow);
443 } else
444 {
445 // decrease capacitorSlow
446 stt->capacitorSlow
447 = AGC_SCALEDIFF32(decay, stt->capacitorSlow, stt->capacitorSlow);
448 }
449
450 // use maximum of both capacitors as current level
451 if (stt->capacitorFast > stt->capacitorSlow)
452 {
453 cur_level = stt->capacitorFast;
454 } else
455 {
456 cur_level = stt->capacitorSlow;
457 }
458 // Translate signal level into gain, using a piecewise linear approximation
459 // find number of leading zeros
460 zeros = WebRtcSpl_NormU32((WebRtc_UWord32)cur_level);
461 if (cur_level == 0)
462 {
463 zeros = 31;
464 }
465 tmp32 = (WEBRTC_SPL_LSHIFT_W32(cur_level, zeros) & 0x7FFFFFFF);
466 frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 19); // Q12
467 tmp32 = WEBRTC_SPL_MUL((stt->gainTable[zeros-1] - stt->gainTable[zeros]), frac);
468 gains[k + 1] = stt->gainTable[zeros] + WEBRTC_SPL_RSHIFT_W32(tmp32, 12);
469#ifdef AGC_DEBUG
470 if (k == 0)
471 {
472 fprintf(stt->logFile, "%d\t%d\t%d\t%d\t%d\n", env[0], cur_level, stt->capacitorFast, stt->capacitorSlow, zeros);
473 }
474#endif
475 }
476
477 // Gate processing (lower gain during absence of speech)
478 zeros = WEBRTC_SPL_LSHIFT_W16(zeros, 9) - WEBRTC_SPL_RSHIFT_W16(frac, 3);
479 // find number of leading zeros
480 zeros_fast = WebRtcSpl_NormU32((WebRtc_UWord32)stt->capacitorFast);
481 if (stt->capacitorFast == 0)
482 {
483 zeros_fast = 31;
484 }
485 tmp32 = (WEBRTC_SPL_LSHIFT_W32(stt->capacitorFast, zeros_fast) & 0x7FFFFFFF);
486 zeros_fast = WEBRTC_SPL_LSHIFT_W16(zeros_fast, 9);
487 zeros_fast -= (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 22);
488
489 gate = 1000 + zeros_fast - zeros - stt->vadNearend.stdShortTerm;
490
491 if (gate < 0)
492 {
493 stt->gatePrevious = 0;
494 } else
495 {
496 tmp32 = WEBRTC_SPL_MUL_16_16(stt->gatePrevious, 7);
497 gate = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)gate + tmp32, 3);
498 stt->gatePrevious = gate;
499 }
500 // gate < 0 -> no gate
501 // gate > 2500 -> max gate
502 if (gate > 0)
503 {
504 if (gate < 2500)
505 {
506 gain_adj = WEBRTC_SPL_RSHIFT_W16(2500 - gate, 5);
507 } else
508 {
509 gain_adj = 0;
510 }
511 for (k = 0; k < 10; k++)
512 {
513 if ((gains[k + 1] - stt->gainTable[0]) > 8388608)
514 {
515 // To prevent wraparound
516 tmp32 = WEBRTC_SPL_RSHIFT_W32((gains[k+1] - stt->gainTable[0]), 8);
517 tmp32 = WEBRTC_SPL_MUL(tmp32, (178 + gain_adj));
518 } else
519 {
520 tmp32 = WEBRTC_SPL_MUL((gains[k+1] - stt->gainTable[0]), (178 + gain_adj));
521 tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 8);
522 }
523 gains[k + 1] = stt->gainTable[0] + tmp32;
524 }
525 }
526
527 // Limit gain to avoid overload distortion
528 for (k = 0; k < 10; k++)
529 {
530 // To prevent wrap around
531 zeros = 10;
532 if (gains[k + 1] > 47453132)
533 {
534 zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]);
535 }
536 gain32 = WEBRTC_SPL_RSHIFT_W32(gains[k+1], zeros) + 1;
537 gain32 = WEBRTC_SPL_MUL(gain32, gain32);
538 // check for overflow
539 while (AGC_MUL32(WEBRTC_SPL_RSHIFT_W32(env[k], 12) + 1, gain32)
540 > WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)32767, 2 * (1 - zeros + 10)))
541 {
542 // multiply by 253/256 ==> -0.1 dB
543 if (gains[k + 1] > 8388607)
544 {
545 // Prevent wrap around
546 gains[k + 1] = WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(gains[k+1], 8), 253);
547 } else
548 {
549 gains[k + 1] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(gains[k+1], 253), 8);
550 }
551 gain32 = WEBRTC_SPL_RSHIFT_W32(gains[k+1], zeros) + 1;
552 gain32 = WEBRTC_SPL_MUL(gain32, gain32);
553 }
554 }
555 // gain reductions should be done 1 ms earlier than gain increases
556 for (k = 1; k < 10; k++)
557 {
558 if (gains[k] > gains[k + 1])
559 {
560 gains[k] = gains[k + 1];
561 }
562 }
563 // save start gain for next frame
564 stt->gain = gains[10];
565
566 // Apply gain
567 // handle first sub frame separately
568 delta = WEBRTC_SPL_LSHIFT_W32(gains[1] - gains[0], (4 - L2));
569 gain32 = WEBRTC_SPL_LSHIFT_W32(gains[0], 4);
570 // iterate over samples
571 for (n = 0; n < L; n++)
572 {
573 // For lower band
574 tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out[n], WEBRTC_SPL_RSHIFT_W32(gain32 + 127, 7));
575 out_tmp = WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
576 if (out_tmp > 4095)
577 {
578 out[n] = (WebRtc_Word16)32767;
579 } else if (out_tmp < -4096)
580 {
581 out[n] = (WebRtc_Word16)-32768;
582 } else
583 {
584 tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out[n], WEBRTC_SPL_RSHIFT_W32(gain32, 4));
585 out[n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
586 }
587 // For higher band
588 if (FS == 32000)
589 {
590 tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out_H[n],
591 WEBRTC_SPL_RSHIFT_W32(gain32 + 127, 7));
592 out_tmp = WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
593 if (out_tmp > 4095)
594 {
595 out_H[n] = (WebRtc_Word16)32767;
596 } else if (out_tmp < -4096)
597 {
598 out_H[n] = (WebRtc_Word16)-32768;
599 } else
600 {
601 tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out_H[n],
602 WEBRTC_SPL_RSHIFT_W32(gain32, 4));
603 out_H[n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
604 }
605 }
606 //
607
608 gain32 += delta;
609 }
610 // iterate over subframes
611 for (k = 1; k < 10; k++)
612 {
613 delta = WEBRTC_SPL_LSHIFT_W32(gains[k+1] - gains[k], (4 - L2));
614 gain32 = WEBRTC_SPL_LSHIFT_W32(gains[k], 4);
615 // iterate over samples
616 for (n = 0; n < L; n++)
617 {
618 // For lower band
619 tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out[k * L + n],
620 WEBRTC_SPL_RSHIFT_W32(gain32, 4));
621 out[k * L + n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
622 // For higher band
623 if (FS == 32000)
624 {
625 tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out_H[k * L + n],
626 WEBRTC_SPL_RSHIFT_W32(gain32, 4));
627 out_H[k * L + n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
628 }
629 gain32 += delta;
630 }
631 }
632
633 return 0;
634}
635
636void WebRtcAgc_InitVad(AgcVad_t *state)
637{
638 WebRtc_Word16 k;
639
640 state->HPstate = 0; // state of high pass filter
641 state->logRatio = 0; // log( P(active) / P(inactive) )
642 // average input level (Q10)
643 state->meanLongTerm = WEBRTC_SPL_LSHIFT_W16(15, 10);
644
645 // variance of input level (Q8)
646 state->varianceLongTerm = WEBRTC_SPL_LSHIFT_W32(500, 8);
647
648 state->stdLongTerm = 0; // standard deviation of input level in dB
649 // short-term average input level (Q10)
650 state->meanShortTerm = WEBRTC_SPL_LSHIFT_W16(15, 10);
651
652 // short-term variance of input level (Q8)
653 state->varianceShortTerm = WEBRTC_SPL_LSHIFT_W32(500, 8);
654
655 state->stdShortTerm = 0; // short-term standard deviation of input level in dB
656 state->counter = 3; // counts updates
657 for (k = 0; k < 8; k++)
658 {
659 // downsampling filter
660 state->downState[k] = 0;
661 }
662}
663
664WebRtc_Word16 WebRtcAgc_ProcessVad(AgcVad_t *state, // (i) VAD state
665 const WebRtc_Word16 *in, // (i) Speech signal
666 WebRtc_Word16 nrSamples) // (i) number of samples
667{
668 WebRtc_Word32 out, nrg, tmp32, tmp32b;
669 WebRtc_UWord16 tmpU16;
670 WebRtc_Word16 k, subfr, tmp16;
671 WebRtc_Word16 buf1[8];
672 WebRtc_Word16 buf2[4];
673 WebRtc_Word16 HPstate;
674 WebRtc_Word16 zeros, dB;
niklase@google.com470e71d2011-07-07 08:21:25 +0000675
676 // process in 10 sub frames of 1 ms (to save on memory)
677 nrg = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000678 HPstate = state->HPstate;
679 for (subfr = 0; subfr < 10; subfr++)
680 {
681 // downsample to 4 kHz
682 if (nrSamples == 160)
683 {
684 for (k = 0; k < 8; k++)
685 {
686 tmp32 = (WebRtc_Word32)in[2 * k] + (WebRtc_Word32)in[2 * k + 1];
687 tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 1);
688 buf1[k] = (WebRtc_Word16)tmp32;
689 }
690 in += 16;
691
692 WebRtcSpl_DownsampleBy2(buf1, 8, buf2, state->downState);
693 } else
694 {
695 WebRtcSpl_DownsampleBy2(in, 8, buf2, state->downState);
696 in += 8;
697 }
698
699 // high pass filter and compute energy
700 for (k = 0; k < 4; k++)
701 {
702 out = buf2[k] + HPstate;
703 tmp32 = WEBRTC_SPL_MUL(600, out);
704 HPstate = (WebRtc_Word16)(WEBRTC_SPL_RSHIFT_W32(tmp32, 10) - buf2[k]);
705 tmp32 = WEBRTC_SPL_MUL(out, out);
706 nrg += WEBRTC_SPL_RSHIFT_W32(tmp32, 6);
707 }
708 }
709 state->HPstate = HPstate;
710
711 // find number of leading zeros
712 if (!(0xFFFF0000 & nrg))
713 {
714 zeros = 16;
715 } else
716 {
717 zeros = 0;
718 }
719 if (!(0xFF000000 & (nrg << zeros)))
720 {
721 zeros += 8;
722 }
723 if (!(0xF0000000 & (nrg << zeros)))
724 {
725 zeros += 4;
726 }
727 if (!(0xC0000000 & (nrg << zeros)))
728 {
729 zeros += 2;
730 }
731 if (!(0x80000000 & (nrg << zeros)))
732 {
733 zeros += 1;
734 }
735
736 // energy level (range {-32..30}) (Q10)
737 dB = WEBRTC_SPL_LSHIFT_W16(15 - zeros, 11);
738
739 // Update statistics
740
741 if (state->counter < kAvgDecayTime)
742 {
743 // decay time = AvgDecTime * 10 ms
744 state->counter++;
745 }
746
747 // update short-term estimate of mean energy level (Q10)
748 tmp32 = (WEBRTC_SPL_MUL_16_16(state->meanShortTerm, 15) + (WebRtc_Word32)dB);
749 state->meanShortTerm = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 4);
750
751 // update short-term estimate of variance in energy level (Q8)
752 tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(dB, dB), 12);
753 tmp32 += WEBRTC_SPL_MUL(state->varianceShortTerm, 15);
754 state->varianceShortTerm = WEBRTC_SPL_RSHIFT_W32(tmp32, 4);
755
756 // update short-term estimate of standard deviation in energy level (Q10)
757 tmp32 = WEBRTC_SPL_MUL_16_16(state->meanShortTerm, state->meanShortTerm);
758 tmp32 = WEBRTC_SPL_LSHIFT_W32(state->varianceShortTerm, 12) - tmp32;
759 state->stdShortTerm = (WebRtc_Word16)WebRtcSpl_Sqrt(tmp32);
760
761 // update long-term estimate of mean energy level (Q10)
762 tmp32 = WEBRTC_SPL_MUL_16_16(state->meanLongTerm, state->counter) + (WebRtc_Word32)dB;
763 state->meanLongTerm = WebRtcSpl_DivW32W16ResW16(tmp32,
764 WEBRTC_SPL_ADD_SAT_W16(state->counter, 1));
765
766 // update long-term estimate of variance in energy level (Q8)
767 tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(dB, dB), 12);
768 tmp32 += WEBRTC_SPL_MUL(state->varianceLongTerm, state->counter);
769 state->varianceLongTerm = WebRtcSpl_DivW32W16(tmp32,
770 WEBRTC_SPL_ADD_SAT_W16(state->counter, 1));
771
772 // update long-term estimate of standard deviation in energy level (Q10)
773 tmp32 = WEBRTC_SPL_MUL_16_16(state->meanLongTerm, state->meanLongTerm);
774 tmp32 = WEBRTC_SPL_LSHIFT_W32(state->varianceLongTerm, 12) - tmp32;
775 state->stdLongTerm = (WebRtc_Word16)WebRtcSpl_Sqrt(tmp32);
776
777 // update voice activity measure (Q10)
778 tmp16 = WEBRTC_SPL_LSHIFT_W16(3, 12);
779 tmp32 = WEBRTC_SPL_MUL_16_16(tmp16, (dB - state->meanLongTerm));
780 tmp32 = WebRtcSpl_DivW32W16(tmp32, state->stdLongTerm);
781 tmpU16 = WEBRTC_SPL_LSHIFT_U16((WebRtc_UWord16)13, 12);
782 tmp32b = WEBRTC_SPL_MUL_16_U16(state->logRatio, tmpU16);
783 tmp32 += WEBRTC_SPL_RSHIFT_W32(tmp32b, 10);
784
785 state->logRatio = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 6);
786
787 // limit
788 if (state->logRatio > 2048)
789 {
790 state->logRatio = 2048;
791 }
792 if (state->logRatio < -2048)
793 {
794 state->logRatio = -2048;
795 }
796
797 return state->logRatio; // Q10
798}