blob: 7801196a4c6162909dd0d9dafbfd2389d496e8fd [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "modules/audio_processing/agc/legacy/digital_agc.h"
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +000016
niklase@google.com470e71d2011-07-07 08:21:25 +000017#include <string.h>
bjornv@webrtc.orgea297872014-09-23 11:21:39 +000018#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +000019#include <stdio.h>
20#endif
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +000021
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/checks.h"
23#include "modules/audio_processing/agc/legacy/gain_control.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000024
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;
minyuecac94aa2016-05-20 08:42:22 -070030// gains = round(2^16*10.^(0.05 * (MinGain + B * (
31// log(exp(-Knee*A)+exp(-Knee*B)) - log(1+exp(-Knee*B)) ) /
32// log(1/(1+exp(Knee*B))))));
niklase@google.com470e71d2011-07-07 08:21:25 +000033// fprintf(1, '\t%i, %i, %i, %i,\n', gains);
minyuecac94aa2016-05-20 08:42:22 -070034// % Matlab code for plotting the gain and input/output level characteristic
35// (copy/paste the following 3 lines):
niklase@google.com470e71d2011-07-07 08:21:25 +000036// in = 10*log10(lvl); out = 20*log10(gains/65536);
minyuecac94aa2016-05-20 08:42:22 -070037// subplot(121); plot(in, out); axis([-30, 0, -5, 20]); grid on; xlabel('Input
38// (dB)'); ylabel('Gain (dB)');
39// subplot(122); plot(in, in+out); axis([-30, 0, -30, 5]); grid on;
40// xlabel('Input (dB)'); ylabel('Output (dB)');
niklase@google.com470e71d2011-07-07 08:21:25 +000041// zoom on;
42
43// Generator table for y=log2(1+e^x) in Q8.
andrew@webrtc.orgd77a6612012-01-04 16:22:24 +000044enum { kGenFuncTableSize = 128 };
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000045static const uint16_t kGenFuncTable[kGenFuncTableSize] = {
minyuecac94aa2016-05-20 08:42:22 -070046 256, 485, 786, 1126, 1484, 1849, 2217, 2586, 2955, 3324, 3693,
47 4063, 4432, 4801, 5171, 5540, 5909, 6279, 6648, 7017, 7387, 7756,
48 8125, 8495, 8864, 9233, 9603, 9972, 10341, 10711, 11080, 11449, 11819,
49 12188, 12557, 12927, 13296, 13665, 14035, 14404, 14773, 15143, 15512, 15881,
50 16251, 16620, 16989, 17359, 17728, 18097, 18466, 18836, 19205, 19574, 19944,
51 20313, 20682, 21052, 21421, 21790, 22160, 22529, 22898, 23268, 23637, 24006,
52 24376, 24745, 25114, 25484, 25853, 26222, 26592, 26961, 27330, 27700, 28069,
53 28438, 28808, 29177, 29546, 29916, 30285, 30654, 31024, 31393, 31762, 32132,
54 32501, 32870, 33240, 33609, 33978, 34348, 34717, 35086, 35456, 35825, 36194,
55 36564, 36933, 37302, 37672, 38041, 38410, 38780, 39149, 39518, 39888, 40257,
56 40626, 40996, 41365, 41734, 42104, 42473, 42842, 43212, 43581, 43950, 44320,
57 44689, 45058, 45428, 45797, 46166, 46536, 46905};
niklase@google.com470e71d2011-07-07 08:21:25 +000058
minyuecac94aa2016-05-20 08:42:22 -070059static const int16_t kAvgDecayTime = 250; // frames; < 3000
niklase@google.com470e71d2011-07-07 08:21:25 +000060
minyuecac94aa2016-05-20 08:42:22 -070061int32_t WebRtcAgc_CalculateGainTable(int32_t* gainTable, // Q16
62 int16_t digCompGaindB, // Q0
63 int16_t targetLevelDbfs, // Q0
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000064 uint8_t limiterEnable,
minyuecac94aa2016-05-20 08:42:22 -070065 int16_t analogTarget) // Q0
niklase@google.com470e71d2011-07-07 08:21:25 +000066{
minyuecac94aa2016-05-20 08:42:22 -070067 // This function generates the compressor gain table used in the fixed digital
68 // part.
69 uint32_t tmpU32no1, tmpU32no2, absInLevel, logApprox;
70 int32_t inLevel, limiterLvl;
71 int32_t tmp32, tmp32no1, tmp32no2, numFIX, den, y32;
72 const uint16_t kLog10 = 54426; // log2(10) in Q14
73 const uint16_t kLog10_2 = 49321; // 10*log10(2) in Q14
74 const uint16_t kLogE_1 = 23637; // log2(e) in Q14
75 uint16_t constMaxGain;
76 uint16_t tmpU16, intPart, fracPart;
77 const int16_t kCompRatio = 3;
78 const int16_t kSoftLimiterLeft = 1;
79 int16_t limiterOffset = 0; // Limiter offset
80 int16_t limiterIdx, limiterLvlX;
81 int16_t constLinApprox, zeroGainLvl, maxGain, diffGain;
82 int16_t i, tmp16, tmp16no1;
83 int zeros, zerosScale;
niklase@google.com470e71d2011-07-07 08:21:25 +000084
minyuecac94aa2016-05-20 08:42:22 -070085 // Constants
86 // kLogE_1 = 23637; // log2(e) in Q14
87 // kLog10 = 54426; // log2(10) in Q14
88 // kLog10_2 = 49321; // 10*log10(2) in Q14
niklase@google.com470e71d2011-07-07 08:21:25 +000089
minyuecac94aa2016-05-20 08:42:22 -070090 // Calculate maximum digital gain and zero gain level
91 tmp32no1 = (digCompGaindB - analogTarget) * (kCompRatio - 1);
92 tmp16no1 = analogTarget - targetLevelDbfs;
93 tmp16no1 +=
94 WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
95 maxGain = WEBRTC_SPL_MAX(tmp16no1, (analogTarget - targetLevelDbfs));
96 tmp32no1 = maxGain * kCompRatio;
97 zeroGainLvl = digCompGaindB;
98 zeroGainLvl -= WebRtcSpl_DivW32W16ResW16(tmp32no1 + ((kCompRatio - 1) >> 1),
99 kCompRatio - 1);
100 if ((digCompGaindB <= analogTarget) && (limiterEnable)) {
101 zeroGainLvl += (analogTarget - digCompGaindB + kSoftLimiterLeft);
102 limiterOffset = 0;
103 }
104
105 // Calculate the difference between maximum gain and gain at 0dB0v:
106 // diffGain = maxGain + (compRatio-1)*zeroGainLvl/compRatio
107 // = (compRatio-1)*digCompGaindB/compRatio
108 tmp32no1 = digCompGaindB * (kCompRatio - 1);
109 diffGain =
110 WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
111 if (diffGain < 0 || diffGain >= kGenFuncTableSize) {
kwiberg1e8ed4a2016-08-26 04:33:34 -0700112 RTC_DCHECK(0);
minyuecac94aa2016-05-20 08:42:22 -0700113 return -1;
114 }
115
116 // Calculate the limiter level and index:
117 // limiterLvlX = analogTarget - limiterOffset
118 // limiterLvl = targetLevelDbfs + limiterOffset/compRatio
119 limiterLvlX = analogTarget - limiterOffset;
120 limiterIdx = 2 + WebRtcSpl_DivW32W16ResW16((int32_t)limiterLvlX * (1 << 13),
121 kLog10_2 / 2);
122 tmp16no1 =
123 WebRtcSpl_DivW32W16ResW16(limiterOffset + (kCompRatio >> 1), kCompRatio);
124 limiterLvl = targetLevelDbfs + tmp16no1;
125
126 // Calculate (through table lookup):
127 // constMaxGain = log2(1+2^(log2(e)*diffGain)); (in Q8)
128 constMaxGain = kGenFuncTable[diffGain]; // in Q8
129
130 // Calculate a parameter used to approximate the fractional part of 2^x with a
131 // piecewise linear function in Q14:
132 // constLinApprox = round(3/2*(4*(3-2*sqrt(2))/(log(2)^2)-0.5)*2^14);
133 constLinApprox = 22817; // in Q14
134
135 // Calculate a denominator used in the exponential part to convert from dB to
136 // linear scale:
137 // den = 20*constMaxGain (in Q8)
138 den = WEBRTC_SPL_MUL_16_U16(20, constMaxGain); // in Q8
139
140 for (i = 0; i < 32; i++) {
141 // Calculate scaled input level (compressor):
142 // inLevel =
143 // fix((-constLog10_2*(compRatio-1)*(1-i)+fix(compRatio/2))/compRatio)
144 tmp16 = (int16_t)((kCompRatio - 1) * (i - 1)); // Q0
145 tmp32 = WEBRTC_SPL_MUL_16_U16(tmp16, kLog10_2) + 1; // Q14
146 inLevel = WebRtcSpl_DivW32W16(tmp32, kCompRatio); // Q14
147
148 // Calculate diffGain-inLevel, to map using the genFuncTable
149 inLevel = (int32_t)diffGain * (1 << 14) - inLevel; // Q14
150
151 // Make calculations on abs(inLevel) and compensate for the sign afterwards.
152 absInLevel = (uint32_t)WEBRTC_SPL_ABS_W32(inLevel); // Q14
153
154 // LUT with interpolation
155 intPart = (uint16_t)(absInLevel >> 14);
156 fracPart =
157 (uint16_t)(absInLevel & 0x00003FFF); // extract the fractional part
158 tmpU16 = kGenFuncTable[intPart + 1] - kGenFuncTable[intPart]; // Q8
159 tmpU32no1 = tmpU16 * fracPart; // Q22
160 tmpU32no1 += (uint32_t)kGenFuncTable[intPart] << 14; // Q22
161 logApprox = tmpU32no1 >> 8; // Q14
162 // Compensate for negative exponent using the relation:
163 // log2(1 + 2^-x) = log2(1 + 2^x) - x
164 if (inLevel < 0) {
165 zeros = WebRtcSpl_NormU32(absInLevel);
166 zerosScale = 0;
167 if (zeros < 15) {
168 // Not enough space for multiplication
169 tmpU32no2 = absInLevel >> (15 - zeros); // Q(zeros-1)
170 tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no2, kLogE_1); // Q(zeros+13)
171 if (zeros < 9) {
172 zerosScale = 9 - zeros;
173 tmpU32no1 >>= zerosScale; // Q(zeros+13)
174 } else {
175 tmpU32no2 >>= zeros - 9; // Q22
176 }
177 } else {
178 tmpU32no2 = WEBRTC_SPL_UMUL_32_16(absInLevel, kLogE_1); // Q28
179 tmpU32no2 >>= 6; // Q22
180 }
181 logApprox = 0;
182 if (tmpU32no2 < tmpU32no1) {
183 logApprox = (tmpU32no1 - tmpU32no2) >> (8 - zerosScale); // Q14
184 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000185 }
minyuecac94aa2016-05-20 08:42:22 -0700186 numFIX = (maxGain * constMaxGain) * (1 << 6); // Q14
187 numFIX -= (int32_t)logApprox * diffGain; // Q14
niklase@google.com470e71d2011-07-07 08:21:25 +0000188
minyuecac94aa2016-05-20 08:42:22 -0700189 // Calculate ratio
190 // Shift |numFIX| as much as possible.
191 // Ensure we avoid wrap-around in |den| as well.
minyuefd634c42016-06-17 04:36:10 -0700192 if (numFIX > (den >> 8) || -numFIX > (den >> 8)) // |den| is Q8.
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 {
minyuecac94aa2016-05-20 08:42:22 -0700194 zeros = WebRtcSpl_NormW32(numFIX);
195 } else {
196 zeros = WebRtcSpl_NormW32(den) + 8;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 }
minyuecac94aa2016-05-20 08:42:22 -0700198 numFIX *= 1 << zeros; // Q(14+zeros)
niklase@google.com470e71d2011-07-07 08:21:25 +0000199
minyuecac94aa2016-05-20 08:42:22 -0700200 // Shift den so we end up in Qy1
minyuefd634c42016-06-17 04:36:10 -0700201 tmp32no1 = WEBRTC_SPL_SHIFT_W32(den, zeros - 9); // Q(zeros - 1)
202 y32 = numFIX / tmp32no1; // in Q15
203 // This is to do rounding in Q14.
204 y32 = y32 >= 0 ? (y32 + 1) >> 1 : -((-y32 + 1) >> 1);
205
minyuecac94aa2016-05-20 08:42:22 -0700206 if (limiterEnable && (i < limiterIdx)) {
207 tmp32 = WEBRTC_SPL_MUL_16_U16(i - 1, kLog10_2); // Q14
208 tmp32 -= limiterLvl * (1 << 14); // Q14
209 y32 = WebRtcSpl_DivW32W16(tmp32 + 10, 20);
210 }
211 if (y32 > 39000) {
212 tmp32 = (y32 >> 1) * kLog10 + 4096; // in Q27
213 tmp32 >>= 13; // In Q14.
214 } else {
215 tmp32 = y32 * kLog10 + 8192; // in Q28
216 tmp32 >>= 14; // In Q14.
217 }
218 tmp32 += 16 << 14; // in Q14 (Make sure final output is in Q16)
niklase@google.com470e71d2011-07-07 08:21:25 +0000219
minyuecac94aa2016-05-20 08:42:22 -0700220 // Calculate power
221 if (tmp32 > 0) {
222 intPart = (int16_t)(tmp32 >> 14);
223 fracPart = (uint16_t)(tmp32 & 0x00003FFF); // in Q14
224 if ((fracPart >> 13) != 0) {
225 tmp16 = (2 << 14) - constLinApprox;
226 tmp32no2 = (1 << 14) - fracPart;
227 tmp32no2 *= tmp16;
228 tmp32no2 >>= 13;
229 tmp32no2 = (1 << 14) - tmp32no2;
230 } else {
231 tmp16 = constLinApprox - (1 << 14);
232 tmp32no2 = (fracPart * tmp16) >> 13;
233 }
234 fracPart = (uint16_t)tmp32no2;
235 gainTable[i] =
236 (1 << intPart) + WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14);
237 } else {
238 gainTable[i] = 0;
239 }
240 }
241
242 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000243}
244
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000245int32_t WebRtcAgc_InitDigital(DigitalAgc* stt, int16_t agcMode) {
minyuecac94aa2016-05-20 08:42:22 -0700246 if (agcMode == kAgcModeFixedDigital) {
247 // start at minimum to find correct gain faster
248 stt->capacitorSlow = 0;
249 } else {
250 // start out with 0 dB gain
251 stt->capacitorSlow = 134217728; // (int32_t)(0.125f * 32768.0f * 32768.0f);
252 }
253 stt->capacitorFast = 0;
254 stt->gain = 65536;
255 stt->gatePrevious = 0;
256 stt->agcMode = agcMode;
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000257#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -0700258 stt->frameCounter = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000259#endif
260
minyuecac94aa2016-05-20 08:42:22 -0700261 // initialize VADs
262 WebRtcAgc_InitVad(&stt->vadNearend);
263 WebRtcAgc_InitVad(&stt->vadFarend);
niklase@google.com470e71d2011-07-07 08:21:25 +0000264
minyuecac94aa2016-05-20 08:42:22 -0700265 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266}
267
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000268int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* stt,
269 const int16_t* in_far,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700270 size_t nrSamples) {
kwiberg1e8ed4a2016-08-26 04:33:34 -0700271 RTC_DCHECK(stt);
minyuecac94aa2016-05-20 08:42:22 -0700272 // VAD for far end
273 WebRtcAgc_ProcessVad(&stt->vadFarend, in_far, nrSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000274
minyuecac94aa2016-05-20 08:42:22 -0700275 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000276}
277
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000278int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000279 const int16_t* const* in_near,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700280 size_t num_bands,
aluebs@webrtc.orgcf6d0b62014-12-16 20:56:09 +0000281 int16_t* const* out,
282 uint32_t FS,
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000283 int16_t lowlevelSignal) {
minyuecac94aa2016-05-20 08:42:22 -0700284 // array for gains (one value per ms, incl start & end)
285 int32_t gains[11];
niklase@google.com470e71d2011-07-07 08:21:25 +0000286
minyuecac94aa2016-05-20 08:42:22 -0700287 int32_t out_tmp, tmp32;
288 int32_t env[10];
289 int32_t max_nrg;
290 int32_t cur_level;
291 int32_t gain32, delta;
292 int16_t logratio;
293 int16_t lower_thr, upper_thr;
294 int16_t zeros = 0, zeros_fast, frac = 0;
295 int16_t decay;
296 int16_t gate, gain_adj;
297 int16_t k;
298 size_t n, i, L;
299 int16_t L2; // samples/subframe
niklase@google.com470e71d2011-07-07 08:21:25 +0000300
minyuecac94aa2016-05-20 08:42:22 -0700301 // determine number of samples per ms
302 if (FS == 8000) {
303 L = 8;
304 L2 = 3;
305 } else if (FS == 16000 || FS == 32000 || FS == 48000) {
306 L = 16;
307 L2 = 4;
308 } else {
309 return -1;
310 }
311
312 for (i = 0; i < num_bands; ++i) {
313 if (in_near[i] != out[i]) {
314 // Only needed if they don't already point to the same place.
315 memcpy(out[i], in_near[i], 10 * L * sizeof(in_near[i][0]));
316 }
317 }
318 // VAD for near end
319 logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, out[0], L * 10);
320
321 // Account for far end VAD
322 if (stt->vadFarend.counter > 10) {
323 tmp32 = 3 * logratio;
324 logratio = (int16_t)((tmp32 - stt->vadFarend.logRatio) >> 2);
325 }
326
327 // Determine decay factor depending on VAD
328 // upper_thr = 1.0f;
329 // lower_thr = 0.25f;
330 upper_thr = 1024; // Q10
331 lower_thr = 0; // Q10
332 if (logratio > upper_thr) {
333 // decay = -2^17 / DecayTime; -> -65
334 decay = -65;
335 } else if (logratio < lower_thr) {
336 decay = 0;
337 } else {
338 // decay = (int16_t)(((lower_thr - logratio)
339 // * (2^27/(DecayTime*(upper_thr-lower_thr)))) >> 10);
340 // SUBSTITUTED: 2^27/(DecayTime*(upper_thr-lower_thr)) -> 65
341 tmp32 = (lower_thr - logratio) * 65;
342 decay = (int16_t)(tmp32 >> 10);
343 }
344
345 // adjust decay factor for long silence (detected as low standard deviation)
346 // This is only done in the adaptive modes
347 if (stt->agcMode != kAgcModeFixedDigital) {
348 if (stt->vadNearend.stdLongTerm < 4000) {
349 decay = 0;
350 } else if (stt->vadNearend.stdLongTerm < 8096) {
351 // decay = (int16_t)(((stt->vadNearend.stdLongTerm - 4000) * decay) >>
352 // 12);
353 tmp32 = (stt->vadNearend.stdLongTerm - 4000) * decay;
354 decay = (int16_t)(tmp32 >> 12);
niklase@google.com470e71d2011-07-07 08:21:25 +0000355 }
356
minyuecac94aa2016-05-20 08:42:22 -0700357 if (lowlevelSignal != 0) {
358 decay = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000359 }
minyuecac94aa2016-05-20 08:42:22 -0700360 }
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000361#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -0700362 stt->frameCounter++;
363 fprintf(stt->logFile, "%5.2f\t%d\t%d\t%d\t", (float)(stt->frameCounter) / 100,
364 logratio, decay, stt->vadNearend.stdLongTerm);
niklase@google.com470e71d2011-07-07 08:21:25 +0000365#endif
minyuecac94aa2016-05-20 08:42:22 -0700366 // Find max amplitude per sub frame
367 // iterate over sub frames
368 for (k = 0; k < 10; k++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000369 // iterate over samples
minyuecac94aa2016-05-20 08:42:22 -0700370 max_nrg = 0;
371 for (n = 0; n < L; n++) {
372 int32_t nrg = out[0][k * L + n] * out[0][k * L + n];
373 if (nrg > max_nrg) {
374 max_nrg = nrg;
375 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000376 }
minyuecac94aa2016-05-20 08:42:22 -0700377 env[k] = max_nrg;
378 }
379
380 // Calculate gain per sub frame
381 gains[0] = stt->gain;
382 for (k = 0; k < 10; k++) {
383 // Fast envelope follower
384 // decay time = -131000 / -1000 = 131 (ms)
385 stt->capacitorFast =
386 AGC_SCALEDIFF32(-1000, stt->capacitorFast, stt->capacitorFast);
387 if (env[k] > stt->capacitorFast) {
388 stt->capacitorFast = env[k];
389 }
390 // Slow envelope follower
391 if (env[k] > stt->capacitorSlow) {
392 // increase capacitorSlow
393 stt->capacitorSlow = AGC_SCALEDIFF32(500, (env[k] - stt->capacitorSlow),
394 stt->capacitorSlow);
395 } else {
396 // decrease capacitorSlow
397 stt->capacitorSlow =
398 AGC_SCALEDIFF32(decay, stt->capacitorSlow, stt->capacitorSlow);
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 }
400
minyuecac94aa2016-05-20 08:42:22 -0700401 // use maximum of both capacitors as current level
402 if (stt->capacitorFast > stt->capacitorSlow) {
403 cur_level = stt->capacitorFast;
404 } else {
405 cur_level = stt->capacitorSlow;
406 }
407 // Translate signal level into gain, using a piecewise linear approximation
408 // find number of leading zeros
409 zeros = WebRtcSpl_NormU32((uint32_t)cur_level);
410 if (cur_level == 0) {
411 zeros = 31;
412 }
Alex Loikoc531af72017-10-24 10:41:48 +0200413 tmp32 = ((uint32_t)cur_level << zeros) & 0x7FFFFFFF;
minyuecac94aa2016-05-20 08:42:22 -0700414 frac = (int16_t)(tmp32 >> 19); // Q12.
Sam Zackrisson762289e2018-06-26 11:21:22 +0200415 // Interpolate between gainTable[zeros] and gainTable[zeros-1].
416 tmp32 = ((stt->gainTable[zeros - 1] - stt->gainTable[zeros]) *
417 (int64_t)frac) >> 12;
418 gains[k + 1] = stt->gainTable[zeros] + tmp32;
minyuecac94aa2016-05-20 08:42:22 -0700419#ifdef WEBRTC_AGC_DEBUG_DUMP
420 if (k == 0) {
421 fprintf(stt->logFile, "%d\t%d\t%d\t%d\t%d\n", env[0], cur_level,
422 stt->capacitorFast, stt->capacitorSlow, zeros);
423 }
424#endif
425 }
426
427 // Gate processing (lower gain during absence of speech)
428 zeros = (zeros << 9) - (frac >> 3);
429 // find number of leading zeros
430 zeros_fast = WebRtcSpl_NormU32((uint32_t)stt->capacitorFast);
431 if (stt->capacitorFast == 0) {
432 zeros_fast = 31;
433 }
Alex Loikoc531af72017-10-24 10:41:48 +0200434 tmp32 = ((uint32_t)stt->capacitorFast << zeros_fast) & 0x7FFFFFFF;
minyuecac94aa2016-05-20 08:42:22 -0700435 zeros_fast <<= 9;
436 zeros_fast -= (int16_t)(tmp32 >> 22);
437
438 gate = 1000 + zeros_fast - zeros - stt->vadNearend.stdShortTerm;
439
440 if (gate < 0) {
441 stt->gatePrevious = 0;
442 } else {
443 tmp32 = stt->gatePrevious * 7;
444 gate = (int16_t)((gate + tmp32) >> 3);
445 stt->gatePrevious = gate;
446 }
447 // gate < 0 -> no gate
448 // gate > 2500 -> max gate
449 if (gate > 0) {
450 if (gate < 2500) {
451 gain_adj = (2500 - gate) >> 5;
452 } else {
453 gain_adj = 0;
454 }
455 for (k = 0; k < 10; k++) {
456 if ((gains[k + 1] - stt->gainTable[0]) > 8388608) {
457 // To prevent wraparound
458 tmp32 = (gains[k + 1] - stt->gainTable[0]) >> 8;
459 tmp32 *= 178 + gain_adj;
460 } else {
461 tmp32 = (gains[k + 1] - stt->gainTable[0]) * (178 + gain_adj);
462 tmp32 >>= 8;
463 }
464 gains[k + 1] = stt->gainTable[0] + tmp32;
465 }
466 }
467
468 // Limit gain to avoid overload distortion
469 for (k = 0; k < 10; k++) {
Sam Zackrisson71729eb2018-07-09 16:06:28 +0200470 // Find a shift of gains[k + 1] such that it can be squared without
471 // overflow, but at least by 10 bits.
minyuecac94aa2016-05-20 08:42:22 -0700472 zeros = 10;
Sam Zackrisson71729eb2018-07-09 16:06:28 +0200473 if (gains[k + 1] > 47452159) {
minyuecac94aa2016-05-20 08:42:22 -0700474 zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]);
475 }
476 gain32 = (gains[k + 1] >> zeros) + 1;
477 gain32 *= gain32;
478 // check for overflow
479 while (AGC_MUL32((env[k] >> 12) + 1, gain32) >
480 WEBRTC_SPL_SHIFT_W32((int32_t)32767, 2 * (1 - zeros + 10))) {
481 // multiply by 253/256 ==> -0.1 dB
482 if (gains[k + 1] > 8388607) {
483 // Prevent wrap around
484 gains[k + 1] = (gains[k + 1] / 256) * 253;
485 } else {
486 gains[k + 1] = (gains[k + 1] * 253) / 256;
487 }
488 gain32 = (gains[k + 1] >> zeros) + 1;
489 gain32 *= gain32;
490 }
491 }
492 // gain reductions should be done 1 ms earlier than gain increases
493 for (k = 1; k < 10; k++) {
494 if (gains[k] > gains[k + 1]) {
495 gains[k] = gains[k + 1];
496 }
497 }
498 // save start gain for next frame
499 stt->gain = gains[10];
500
501 // Apply gain
502 // handle first sub frame separately
503 delta = (gains[1] - gains[0]) * (1 << (4 - L2));
504 gain32 = gains[0] * (1 << 4);
505 // iterate over samples
506 for (n = 0; n < L; n++) {
507 for (i = 0; i < num_bands; ++i) {
Sam Zackrisson46f858a2018-07-02 15:01:11 +0200508 out_tmp = (int64_t)out[i][n] * ((gain32 + 127) >> 7) >> 16;
minyuecac94aa2016-05-20 08:42:22 -0700509 if (out_tmp > 4095) {
510 out[i][n] = (int16_t)32767;
511 } else if (out_tmp < -4096) {
512 out[i][n] = (int16_t)-32768;
513 } else {
Sam Zackrisson46f858a2018-07-02 15:01:11 +0200514 tmp32 = ((int64_t)out[i][n] * (gain32 >> 4)) >> 16;
515 out[i][n] = (int16_t)tmp32;
minyuecac94aa2016-05-20 08:42:22 -0700516 }
517 }
minyuecac94aa2016-05-20 08:42:22 -0700518
519 gain32 += delta;
520 }
521 // iterate over subframes
522 for (k = 1; k < 10; k++) {
523 delta = (gains[k + 1] - gains[k]) * (1 << (4 - L2));
524 gain32 = gains[k] * (1 << 4);
525 // iterate over samples
526 for (n = 0; n < L; n++) {
527 for (i = 0; i < num_bands; ++i) {
peahfb2fa3f2017-09-13 06:28:16 -0700528 int64_t tmp64 = ((int64_t)(out[i][k * L + n])) * (gain32 >> 4);
529 tmp64 = tmp64 >> 16;
530 if (tmp64 > 32767) {
531 out[i][k * L + n] = 32767;
532 }
533 else if (tmp64 < -32768) {
534 out[i][k * L + n] = -32768;
535 }
536 else {
537 out[i][k * L + n] = (int16_t)(tmp64);
538 }
minyuecac94aa2016-05-20 08:42:22 -0700539 }
540 gain32 += delta;
541 }
542 }
543
544 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000545}
546
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000547void WebRtcAgc_InitVad(AgcVad* state) {
minyuecac94aa2016-05-20 08:42:22 -0700548 int16_t k;
niklase@google.com470e71d2011-07-07 08:21:25 +0000549
minyuecac94aa2016-05-20 08:42:22 -0700550 state->HPstate = 0; // state of high pass filter
551 state->logRatio = 0; // log( P(active) / P(inactive) )
552 // average input level (Q10)
553 state->meanLongTerm = 15 << 10;
niklase@google.com470e71d2011-07-07 08:21:25 +0000554
minyuecac94aa2016-05-20 08:42:22 -0700555 // variance of input level (Q8)
556 state->varianceLongTerm = 500 << 8;
niklase@google.com470e71d2011-07-07 08:21:25 +0000557
minyuecac94aa2016-05-20 08:42:22 -0700558 state->stdLongTerm = 0; // standard deviation of input level in dB
559 // short-term average input level (Q10)
560 state->meanShortTerm = 15 << 10;
niklase@google.com470e71d2011-07-07 08:21:25 +0000561
minyuecac94aa2016-05-20 08:42:22 -0700562 // short-term variance of input level (Q8)
563 state->varianceShortTerm = 500 << 8;
niklase@google.com470e71d2011-07-07 08:21:25 +0000564
minyuecac94aa2016-05-20 08:42:22 -0700565 state->stdShortTerm =
566 0; // short-term standard deviation of input level in dB
567 state->counter = 3; // counts updates
568 for (k = 0; k < 8; k++) {
569 // downsampling filter
570 state->downState[k] = 0;
571 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000572}
573
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000574int16_t WebRtcAgc_ProcessVad(AgcVad* state, // (i) VAD state
575 const int16_t* in, // (i) Speech signal
minyuecac94aa2016-05-20 08:42:22 -0700576 size_t nrSamples) // (i) number of samples
niklase@google.com470e71d2011-07-07 08:21:25 +0000577{
Alex Loikoc7b18fe2017-10-27 14:57:38 +0200578 uint32_t nrg;
579 int32_t out, tmp32, tmp32b;
minyuecac94aa2016-05-20 08:42:22 -0700580 uint16_t tmpU16;
581 int16_t k, subfr, tmp16;
582 int16_t buf1[8];
583 int16_t buf2[4];
584 int16_t HPstate;
585 int16_t zeros, dB;
niklase@google.com470e71d2011-07-07 08:21:25 +0000586
minyuecac94aa2016-05-20 08:42:22 -0700587 // process in 10 sub frames of 1 ms (to save on memory)
588 nrg = 0;
589 HPstate = state->HPstate;
590 for (subfr = 0; subfr < 10; subfr++) {
591 // downsample to 4 kHz
592 if (nrSamples == 160) {
593 for (k = 0; k < 8; k++) {
594 tmp32 = (int32_t)in[2 * k] + (int32_t)in[2 * k + 1];
595 tmp32 >>= 1;
596 buf1[k] = (int16_t)tmp32;
597 }
598 in += 16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000599
minyuecac94aa2016-05-20 08:42:22 -0700600 WebRtcSpl_DownsampleBy2(buf1, 8, buf2, state->downState);
601 } else {
602 WebRtcSpl_DownsampleBy2(in, 8, buf2, state->downState);
603 in += 8;
niklase@google.com470e71d2011-07-07 08:21:25 +0000604 }
605
minyuecac94aa2016-05-20 08:42:22 -0700606 // high pass filter and compute energy
607 for (k = 0; k < 4; k++) {
608 out = buf2[k] + HPstate;
609 tmp32 = 600 * out;
610 HPstate = (int16_t)((tmp32 >> 10) - buf2[k]);
Alex Loiko7cfbf3a2017-11-07 16:34:32 +0100611
612 // Add 'out * out / 2**6' to 'nrg' in a non-overflowing
613 // way. Guaranteed to work as long as 'out * out / 2**6' fits in
614 // an int32_t.
615 nrg += out * (out / (1 << 6));
616 nrg += out * (out % (1 << 6)) / (1 << 6);
niklase@google.com470e71d2011-07-07 08:21:25 +0000617 }
minyuecac94aa2016-05-20 08:42:22 -0700618 }
619 state->HPstate = HPstate;
niklase@google.com470e71d2011-07-07 08:21:25 +0000620
minyuecac94aa2016-05-20 08:42:22 -0700621 // find number of leading zeros
622 if (!(0xFFFF0000 & nrg)) {
623 zeros = 16;
624 } else {
625 zeros = 0;
626 }
627 if (!(0xFF000000 & (nrg << zeros))) {
628 zeros += 8;
629 }
630 if (!(0xF0000000 & (nrg << zeros))) {
631 zeros += 4;
632 }
633 if (!(0xC0000000 & (nrg << zeros))) {
634 zeros += 2;
635 }
636 if (!(0x80000000 & (nrg << zeros))) {
637 zeros += 1;
638 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000639
minyuecac94aa2016-05-20 08:42:22 -0700640 // energy level (range {-32..30}) (Q10)
Alex Loikob9f53612017-10-24 09:58:00 +0200641 dB = (15 - zeros) * (1 << 11);
niklase@google.com470e71d2011-07-07 08:21:25 +0000642
minyuecac94aa2016-05-20 08:42:22 -0700643 // Update statistics
niklase@google.com470e71d2011-07-07 08:21:25 +0000644
minyuecac94aa2016-05-20 08:42:22 -0700645 if (state->counter < kAvgDecayTime) {
646 // decay time = AvgDecTime * 10 ms
647 state->counter++;
648 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000649
minyuecac94aa2016-05-20 08:42:22 -0700650 // update short-term estimate of mean energy level (Q10)
651 tmp32 = state->meanShortTerm * 15 + dB;
652 state->meanShortTerm = (int16_t)(tmp32 >> 4);
niklase@google.com470e71d2011-07-07 08:21:25 +0000653
minyuecac94aa2016-05-20 08:42:22 -0700654 // update short-term estimate of variance in energy level (Q8)
655 tmp32 = (dB * dB) >> 12;
656 tmp32 += state->varianceShortTerm * 15;
657 state->varianceShortTerm = tmp32 / 16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000658
minyuecac94aa2016-05-20 08:42:22 -0700659 // update short-term estimate of standard deviation in energy level (Q10)
660 tmp32 = state->meanShortTerm * state->meanShortTerm;
661 tmp32 = (state->varianceShortTerm << 12) - tmp32;
662 state->stdShortTerm = (int16_t)WebRtcSpl_Sqrt(tmp32);
niklase@google.com470e71d2011-07-07 08:21:25 +0000663
minyuecac94aa2016-05-20 08:42:22 -0700664 // update long-term estimate of mean energy level (Q10)
665 tmp32 = state->meanLongTerm * state->counter + dB;
666 state->meanLongTerm =
667 WebRtcSpl_DivW32W16ResW16(tmp32, WebRtcSpl_AddSatW16(state->counter, 1));
niklase@google.com470e71d2011-07-07 08:21:25 +0000668
minyuecac94aa2016-05-20 08:42:22 -0700669 // update long-term estimate of variance in energy level (Q8)
670 tmp32 = (dB * dB) >> 12;
671 tmp32 += state->varianceLongTerm * state->counter;
672 state->varianceLongTerm =
673 WebRtcSpl_DivW32W16(tmp32, WebRtcSpl_AddSatW16(state->counter, 1));
niklase@google.com470e71d2011-07-07 08:21:25 +0000674
minyuecac94aa2016-05-20 08:42:22 -0700675 // update long-term estimate of standard deviation in energy level (Q10)
676 tmp32 = state->meanLongTerm * state->meanLongTerm;
677 tmp32 = (state->varianceLongTerm << 12) - tmp32;
678 state->stdLongTerm = (int16_t)WebRtcSpl_Sqrt(tmp32);
679
680 // update voice activity measure (Q10)
681 tmp16 = 3 << 12;
682 // TODO(bjornv): (dB - state->meanLongTerm) can overflow, e.g., in
683 // ApmTest.Process unit test. Previously the macro WEBRTC_SPL_MUL_16_16()
684 // was used, which did an intermediate cast to (int16_t), hence losing
685 // significant bits. This cause logRatio to max out positive, rather than
686 // negative. This is a bug, but has very little significance.
687 tmp32 = tmp16 * (int16_t)(dB - state->meanLongTerm);
688 tmp32 = WebRtcSpl_DivW32W16(tmp32, state->stdLongTerm);
689 tmpU16 = (13 << 12);
690 tmp32b = WEBRTC_SPL_MUL_16_U16(state->logRatio, tmpU16);
691 tmp32 += tmp32b >> 10;
692
693 state->logRatio = (int16_t)(tmp32 >> 6);
694
695 // limit
696 if (state->logRatio > 2048) {
697 state->logRatio = 2048;
698 }
699 if (state->logRatio < -2048) {
700 state->logRatio = -2048;
701 }
702
703 return state->logRatio; // Q10
niklase@google.com470e71d2011-07-07 08:21:25 +0000704}