1 /*
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 
15 #include "digital_agc.h"
16 
17 #include <assert.h>
18 #include <string.h>
19 #ifdef AGC_DEBUG
20 #include <stdio.h>
21 #endif
22 
23 #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.
39 enum { kGenFuncTableSize = 128 };
40 static const WebRtc_UWord16 kGenFuncTable[kGenFuncTableSize] = {
41           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 
59 static const WebRtc_Word16 kAvgDecayTime = 250; // frames; < 3000
60 
WebRtcAgc_CalculateGainTable(WebRtc_Word32 * gainTable,WebRtc_Word16 digCompGaindB,WebRtc_Word16 targetLevelDbfs,WebRtc_UWord8 limiterEnable,WebRtc_Word16 analogTarget)61 WebRtc_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);
109     if (diffGain < 0 || diffGain >= kGenFuncTableSize)
110     {
111         assert(0);
112         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
193         // 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         }
202         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 
WebRtcAgc_InitDigital(DigitalAgc_t * stt,WebRtc_Word16 agcMode)261 WebRtc_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 
WebRtcAgc_AddFarendToDigital(DigitalAgc_t * stt,const WebRtc_Word16 * in_far,WebRtc_Word16 nrSamples)288 WebRtc_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 
WebRtcAgc_ProcessDigital(DigitalAgc_t * stt,const WebRtc_Word16 * in_near,const WebRtc_Word16 * in_near_H,WebRtc_Word16 * out,WebRtc_Word16 * out_H,WebRtc_UWord32 FS,WebRtc_Word16 lowlevelSignal)303 WebRtc_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 
342     // 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     }
348     if (FS == 32000)
349     {
350         if (in_near_H != out_H)
351         {
352             memcpy(out_H, in_near_H, 10 * L * sizeof(WebRtc_Word16));
353         }
354     }
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 
WebRtcAgc_InitVad(AgcVad_t * state)636 void 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 
WebRtcAgc_ProcessVad(AgcVad_t * state,const WebRtc_Word16 * in,WebRtc_Word16 nrSamples)664 WebRtc_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;
675 
676     // process in 10 sub frames of 1 ms (to save on memory)
677     nrg = 0;
678     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 }
799