blob: e0c076650f7ba4e175179c34fe64fdf09aed8206 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_processing/agc/legacy/digital_agc.h"
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +000012
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <string.h>
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +000014
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "modules/audio_processing/agc/legacy/gain_control.h"
Per Åhgren5b139d62020-03-20 15:50:14 +010016#include "rtc_base/checks.h"
17
18namespace webrtc {
19
20namespace {
niklase@google.com470e71d2011-07-07 08:21:25 +000021
22// To generate the gaintable, copy&paste the following lines to a Matlab window:
23// MaxGain = 6; MinGain = 0; CompRatio = 3; Knee = 1;
24// zeros = 0:31; lvl = 2.^(1-zeros);
25// A = -10*log10(lvl) * (CompRatio - 1) / CompRatio;
26// B = MaxGain - MinGain;
minyuecac94aa2016-05-20 08:42:22 -070027// gains = round(2^16*10.^(0.05 * (MinGain + B * (
28// log(exp(-Knee*A)+exp(-Knee*B)) - log(1+exp(-Knee*B)) ) /
29// log(1/(1+exp(Knee*B))))));
niklase@google.com470e71d2011-07-07 08:21:25 +000030// fprintf(1, '\t%i, %i, %i, %i,\n', gains);
minyuecac94aa2016-05-20 08:42:22 -070031// % Matlab code for plotting the gain and input/output level characteristic
32// (copy/paste the following 3 lines):
niklase@google.com470e71d2011-07-07 08:21:25 +000033// in = 10*log10(lvl); out = 20*log10(gains/65536);
minyuecac94aa2016-05-20 08:42:22 -070034// subplot(121); plot(in, out); axis([-30, 0, -5, 20]); grid on; xlabel('Input
35// (dB)'); ylabel('Gain (dB)');
36// subplot(122); plot(in, in+out); axis([-30, 0, -30, 5]); grid on;
37// xlabel('Input (dB)'); ylabel('Output (dB)');
niklase@google.com470e71d2011-07-07 08:21:25 +000038// zoom on;
39
40// Generator table for y=log2(1+e^x) in Q8.
andrew@webrtc.orgd77a6612012-01-04 16:22:24 +000041enum { kGenFuncTableSize = 128 };
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000042static const uint16_t kGenFuncTable[kGenFuncTableSize] = {
minyuecac94aa2016-05-20 08:42:22 -070043 256, 485, 786, 1126, 1484, 1849, 2217, 2586, 2955, 3324, 3693,
44 4063, 4432, 4801, 5171, 5540, 5909, 6279, 6648, 7017, 7387, 7756,
45 8125, 8495, 8864, 9233, 9603, 9972, 10341, 10711, 11080, 11449, 11819,
46 12188, 12557, 12927, 13296, 13665, 14035, 14404, 14773, 15143, 15512, 15881,
47 16251, 16620, 16989, 17359, 17728, 18097, 18466, 18836, 19205, 19574, 19944,
48 20313, 20682, 21052, 21421, 21790, 22160, 22529, 22898, 23268, 23637, 24006,
49 24376, 24745, 25114, 25484, 25853, 26222, 26592, 26961, 27330, 27700, 28069,
50 28438, 28808, 29177, 29546, 29916, 30285, 30654, 31024, 31393, 31762, 32132,
51 32501, 32870, 33240, 33609, 33978, 34348, 34717, 35086, 35456, 35825, 36194,
52 36564, 36933, 37302, 37672, 38041, 38410, 38780, 39149, 39518, 39888, 40257,
53 40626, 40996, 41365, 41734, 42104, 42473, 42842, 43212, 43581, 43950, 44320,
54 44689, 45058, 45428, 45797, 46166, 46536, 46905};
niklase@google.com470e71d2011-07-07 08:21:25 +000055
minyuecac94aa2016-05-20 08:42:22 -070056static const int16_t kAvgDecayTime = 250; // frames; < 3000
niklase@google.com470e71d2011-07-07 08:21:25 +000057
Per Åhgren5b139d62020-03-20 15:50:14 +010058// the 32 most significant bits of A(19) * B(26) >> 13
59#define AGC_MUL32(A, B) (((B) >> 13) * (A) + (((0x00001FFF & (B)) * (A)) >> 13))
60// C + the 32 most significant bits of A * B
61#define AGC_SCALEDIFF32(A, B, C) \
62 ((C) + ((B) >> 16) * (A) + (((0x0000FFFF & (B)) * (A)) >> 16))
63
64} // namespace
65
minyuecac94aa2016-05-20 08:42:22 -070066int32_t WebRtcAgc_CalculateGainTable(int32_t* gainTable, // Q16
67 int16_t digCompGaindB, // Q0
68 int16_t targetLevelDbfs, // Q0
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000069 uint8_t limiterEnable,
Per Åhgren5b139d62020-03-20 15:50:14 +010070 int16_t analogTarget) { // Q0
minyuecac94aa2016-05-20 08:42:22 -070071 // This function generates the compressor gain table used in the fixed digital
72 // part.
73 uint32_t tmpU32no1, tmpU32no2, absInLevel, logApprox;
74 int32_t inLevel, limiterLvl;
75 int32_t tmp32, tmp32no1, tmp32no2, numFIX, den, y32;
76 const uint16_t kLog10 = 54426; // log2(10) in Q14
77 const uint16_t kLog10_2 = 49321; // 10*log10(2) in Q14
78 const uint16_t kLogE_1 = 23637; // log2(e) in Q14
79 uint16_t constMaxGain;
80 uint16_t tmpU16, intPart, fracPart;
81 const int16_t kCompRatio = 3;
minyuecac94aa2016-05-20 08:42:22 -070082 int16_t limiterOffset = 0; // Limiter offset
83 int16_t limiterIdx, limiterLvlX;
Peter Kasting55ec1a42021-07-27 17:14:26 -070084 int16_t constLinApprox, maxGain, diffGain;
minyuecac94aa2016-05-20 08:42:22 -070085 int16_t i, tmp16, tmp16no1;
86 int zeros, zerosScale;
niklase@google.com470e71d2011-07-07 08:21:25 +000087
minyuecac94aa2016-05-20 08:42:22 -070088 // Constants
89 // kLogE_1 = 23637; // log2(e) in Q14
90 // kLog10 = 54426; // log2(10) in Q14
91 // kLog10_2 = 49321; // 10*log10(2) in Q14
niklase@google.com470e71d2011-07-07 08:21:25 +000092
minyuecac94aa2016-05-20 08:42:22 -070093 // Calculate maximum digital gain and zero gain level
94 tmp32no1 = (digCompGaindB - analogTarget) * (kCompRatio - 1);
95 tmp16no1 = analogTarget - targetLevelDbfs;
96 tmp16no1 +=
97 WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
98 maxGain = WEBRTC_SPL_MAX(tmp16no1, (analogTarget - targetLevelDbfs));
99 tmp32no1 = maxGain * kCompRatio;
minyuecac94aa2016-05-20 08:42:22 -0700100 if ((digCompGaindB <= analogTarget) && (limiterEnable)) {
minyuecac94aa2016-05-20 08:42:22 -0700101 limiterOffset = 0;
102 }
103
Peter Kasting55ec1a42021-07-27 17:14:26 -0700104 // Calculate the difference between maximum gain and gain at 0dB0v
minyuecac94aa2016-05-20 08:42:22 -0700105 tmp32no1 = digCompGaindB * (kCompRatio - 1);
106 diffGain =
107 WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
108 if (diffGain < 0 || diffGain >= kGenFuncTableSize) {
kwiberg1e8ed4a2016-08-26 04:33:34 -0700109 RTC_DCHECK(0);
minyuecac94aa2016-05-20 08:42:22 -0700110 return -1;
111 }
112
113 // Calculate the limiter level and index:
114 // limiterLvlX = analogTarget - limiterOffset
115 // limiterLvl = targetLevelDbfs + limiterOffset/compRatio
116 limiterLvlX = analogTarget - limiterOffset;
117 limiterIdx = 2 + WebRtcSpl_DivW32W16ResW16((int32_t)limiterLvlX * (1 << 13),
118 kLog10_2 / 2);
119 tmp16no1 =
120 WebRtcSpl_DivW32W16ResW16(limiterOffset + (kCompRatio >> 1), kCompRatio);
121 limiterLvl = targetLevelDbfs + tmp16no1;
122
123 // Calculate (through table lookup):
124 // constMaxGain = log2(1+2^(log2(e)*diffGain)); (in Q8)
125 constMaxGain = kGenFuncTable[diffGain]; // in Q8
126
127 // Calculate a parameter used to approximate the fractional part of 2^x with a
128 // piecewise linear function in Q14:
129 // constLinApprox = round(3/2*(4*(3-2*sqrt(2))/(log(2)^2)-0.5)*2^14);
130 constLinApprox = 22817; // in Q14
131
132 // Calculate a denominator used in the exponential part to convert from dB to
133 // linear scale:
134 // den = 20*constMaxGain (in Q8)
135 den = WEBRTC_SPL_MUL_16_U16(20, constMaxGain); // in Q8
136
137 for (i = 0; i < 32; i++) {
138 // Calculate scaled input level (compressor):
139 // inLevel =
140 // fix((-constLog10_2*(compRatio-1)*(1-i)+fix(compRatio/2))/compRatio)
141 tmp16 = (int16_t)((kCompRatio - 1) * (i - 1)); // Q0
142 tmp32 = WEBRTC_SPL_MUL_16_U16(tmp16, kLog10_2) + 1; // Q14
143 inLevel = WebRtcSpl_DivW32W16(tmp32, kCompRatio); // Q14
144
145 // Calculate diffGain-inLevel, to map using the genFuncTable
146 inLevel = (int32_t)diffGain * (1 << 14) - inLevel; // Q14
147
148 // Make calculations on abs(inLevel) and compensate for the sign afterwards.
149 absInLevel = (uint32_t)WEBRTC_SPL_ABS_W32(inLevel); // Q14
150
151 // LUT with interpolation
152 intPart = (uint16_t)(absInLevel >> 14);
153 fracPart =
154 (uint16_t)(absInLevel & 0x00003FFF); // extract the fractional part
155 tmpU16 = kGenFuncTable[intPart + 1] - kGenFuncTable[intPart]; // Q8
156 tmpU32no1 = tmpU16 * fracPart; // Q22
157 tmpU32no1 += (uint32_t)kGenFuncTable[intPart] << 14; // Q22
158 logApprox = 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 zeros = WebRtcSpl_NormU32(absInLevel);
163 zerosScale = 0;
164 if (zeros < 15) {
165 // Not enough space for multiplication
166 tmpU32no2 = absInLevel >> (15 - zeros); // Q(zeros-1)
167 tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no2, kLogE_1); // Q(zeros+13)
168 if (zeros < 9) {
169 zerosScale = 9 - zeros;
170 tmpU32no1 >>= zerosScale; // Q(zeros+13)
171 } else {
172 tmpU32no2 >>= zeros - 9; // Q22
173 }
174 } else {
175 tmpU32no2 = WEBRTC_SPL_UMUL_32_16(absInLevel, kLogE_1); // Q28
176 tmpU32no2 >>= 6; // Q22
177 }
178 logApprox = 0;
179 if (tmpU32no2 < tmpU32no1) {
180 logApprox = (tmpU32no1 - tmpU32no2) >> (8 - zerosScale); // Q14
181 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000182 }
minyuecac94aa2016-05-20 08:42:22 -0700183 numFIX = (maxGain * constMaxGain) * (1 << 6); // Q14
184 numFIX -= (int32_t)logApprox * diffGain; // Q14
niklase@google.com470e71d2011-07-07 08:21:25 +0000185
minyuecac94aa2016-05-20 08:42:22 -0700186 // Calculate ratio
187 // Shift |numFIX| as much as possible.
188 // Ensure we avoid wrap-around in |den| as well.
Per Åhgren5b139d62020-03-20 15:50:14 +0100189 if (numFIX > (den >> 8) || -numFIX > (den >> 8)) { // |den| is Q8.
minyuecac94aa2016-05-20 08:42:22 -0700190 zeros = WebRtcSpl_NormW32(numFIX);
191 } else {
192 zeros = WebRtcSpl_NormW32(den) + 8;
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 }
minyuecac94aa2016-05-20 08:42:22 -0700194 numFIX *= 1 << zeros; // Q(14+zeros)
niklase@google.com470e71d2011-07-07 08:21:25 +0000195
minyuecac94aa2016-05-20 08:42:22 -0700196 // Shift den so we end up in Qy1
minyuefd634c42016-06-17 04:36:10 -0700197 tmp32no1 = WEBRTC_SPL_SHIFT_W32(den, zeros - 9); // Q(zeros - 1)
Per Åhgren5b139d62020-03-20 15:50:14 +0100198 y32 = numFIX / tmp32no1; // in Q15
minyuefd634c42016-06-17 04:36:10 -0700199 // This is to do rounding in Q14.
200 y32 = y32 >= 0 ? (y32 + 1) >> 1 : -((-y32 + 1) >> 1);
201
minyuecac94aa2016-05-20 08:42:22 -0700202 if (limiterEnable && (i < limiterIdx)) {
203 tmp32 = WEBRTC_SPL_MUL_16_U16(i - 1, kLog10_2); // Q14
204 tmp32 -= limiterLvl * (1 << 14); // Q14
205 y32 = WebRtcSpl_DivW32W16(tmp32 + 10, 20);
206 }
207 if (y32 > 39000) {
208 tmp32 = (y32 >> 1) * kLog10 + 4096; // in Q27
209 tmp32 >>= 13; // In Q14.
210 } else {
211 tmp32 = y32 * kLog10 + 8192; // in Q28
212 tmp32 >>= 14; // In Q14.
213 }
214 tmp32 += 16 << 14; // in Q14 (Make sure final output is in Q16)
niklase@google.com470e71d2011-07-07 08:21:25 +0000215
minyuecac94aa2016-05-20 08:42:22 -0700216 // Calculate power
217 if (tmp32 > 0) {
218 intPart = (int16_t)(tmp32 >> 14);
219 fracPart = (uint16_t)(tmp32 & 0x00003FFF); // in Q14
220 if ((fracPart >> 13) != 0) {
221 tmp16 = (2 << 14) - constLinApprox;
222 tmp32no2 = (1 << 14) - fracPart;
223 tmp32no2 *= tmp16;
224 tmp32no2 >>= 13;
225 tmp32no2 = (1 << 14) - tmp32no2;
226 } else {
227 tmp16 = constLinApprox - (1 << 14);
228 tmp32no2 = (fracPart * tmp16) >> 13;
229 }
230 fracPart = (uint16_t)tmp32no2;
231 gainTable[i] =
232 (1 << intPart) + WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14);
233 } else {
234 gainTable[i] = 0;
235 }
236 }
237
238 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000239}
240
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000241int32_t WebRtcAgc_InitDigital(DigitalAgc* stt, int16_t agcMode) {
minyuecac94aa2016-05-20 08:42:22 -0700242 if (agcMode == kAgcModeFixedDigital) {
243 // start at minimum to find correct gain faster
244 stt->capacitorSlow = 0;
245 } else {
246 // start out with 0 dB gain
247 stt->capacitorSlow = 134217728; // (int32_t)(0.125f * 32768.0f * 32768.0f);
248 }
249 stt->capacitorFast = 0;
250 stt->gain = 65536;
251 stt->gatePrevious = 0;
252 stt->agcMode = agcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
minyuecac94aa2016-05-20 08:42:22 -0700254 // initialize VADs
255 WebRtcAgc_InitVad(&stt->vadNearend);
256 WebRtcAgc_InitVad(&stt->vadFarend);
niklase@google.com470e71d2011-07-07 08:21:25 +0000257
minyuecac94aa2016-05-20 08:42:22 -0700258 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000259}
260
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000261int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* stt,
262 const int16_t* in_far,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700263 size_t nrSamples) {
kwiberg1e8ed4a2016-08-26 04:33:34 -0700264 RTC_DCHECK(stt);
minyuecac94aa2016-05-20 08:42:22 -0700265 // VAD for far end
266 WebRtcAgc_ProcessVad(&stt->vadFarend, in_far, nrSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000267
minyuecac94aa2016-05-20 08:42:22 -0700268 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000269}
270
Per Åhgren77dc1992019-11-23 00:14:31 +0100271// Gains is an 11 element long array (one value per ms, incl start & end).
272int32_t WebRtcAgc_ComputeDigitalGains(DigitalAgc* stt,
273 const int16_t* const* in_near,
274 size_t num_bands,
275 uint32_t FS,
276 int16_t lowlevelSignal,
277 int32_t gains[11]) {
278 int32_t tmp32;
minyuecac94aa2016-05-20 08:42:22 -0700279 int32_t env[10];
280 int32_t max_nrg;
281 int32_t cur_level;
Per Åhgren77dc1992019-11-23 00:14:31 +0100282 int32_t gain32;
minyuecac94aa2016-05-20 08:42:22 -0700283 int16_t logratio;
284 int16_t lower_thr, upper_thr;
285 int16_t zeros = 0, zeros_fast, frac = 0;
286 int16_t decay;
287 int16_t gate, gain_adj;
288 int16_t k;
Per Åhgren77dc1992019-11-23 00:14:31 +0100289 size_t n, L;
niklase@google.com470e71d2011-07-07 08:21:25 +0000290
minyuecac94aa2016-05-20 08:42:22 -0700291 // determine number of samples per ms
292 if (FS == 8000) {
293 L = 8;
minyuecac94aa2016-05-20 08:42:22 -0700294 } else if (FS == 16000 || FS == 32000 || FS == 48000) {
295 L = 16;
minyuecac94aa2016-05-20 08:42:22 -0700296 } else {
297 return -1;
298 }
299
minyuecac94aa2016-05-20 08:42:22 -0700300 // VAD for near end
Per Åhgren77dc1992019-11-23 00:14:31 +0100301 logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, in_near[0], L * 10);
minyuecac94aa2016-05-20 08:42:22 -0700302
303 // Account for far end VAD
304 if (stt->vadFarend.counter > 10) {
305 tmp32 = 3 * logratio;
306 logratio = (int16_t)((tmp32 - stt->vadFarend.logRatio) >> 2);
307 }
308
309 // Determine decay factor depending on VAD
310 // upper_thr = 1.0f;
311 // lower_thr = 0.25f;
312 upper_thr = 1024; // Q10
313 lower_thr = 0; // Q10
314 if (logratio > upper_thr) {
315 // decay = -2^17 / DecayTime; -> -65
316 decay = -65;
317 } else if (logratio < lower_thr) {
318 decay = 0;
319 } else {
320 // decay = (int16_t)(((lower_thr - logratio)
321 // * (2^27/(DecayTime*(upper_thr-lower_thr)))) >> 10);
322 // SUBSTITUTED: 2^27/(DecayTime*(upper_thr-lower_thr)) -> 65
323 tmp32 = (lower_thr - logratio) * 65;
324 decay = (int16_t)(tmp32 >> 10);
325 }
326
327 // adjust decay factor for long silence (detected as low standard deviation)
328 // This is only done in the adaptive modes
329 if (stt->agcMode != kAgcModeFixedDigital) {
330 if (stt->vadNearend.stdLongTerm < 4000) {
331 decay = 0;
332 } else if (stt->vadNearend.stdLongTerm < 8096) {
333 // decay = (int16_t)(((stt->vadNearend.stdLongTerm - 4000) * decay) >>
334 // 12);
335 tmp32 = (stt->vadNearend.stdLongTerm - 4000) * decay;
336 decay = (int16_t)(tmp32 >> 12);
niklase@google.com470e71d2011-07-07 08:21:25 +0000337 }
338
minyuecac94aa2016-05-20 08:42:22 -0700339 if (lowlevelSignal != 0) {
340 decay = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000341 }
minyuecac94aa2016-05-20 08:42:22 -0700342 }
minyuecac94aa2016-05-20 08:42:22 -0700343 // Find max amplitude per sub frame
344 // iterate over sub frames
345 for (k = 0; k < 10; k++) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000346 // iterate over samples
minyuecac94aa2016-05-20 08:42:22 -0700347 max_nrg = 0;
348 for (n = 0; n < L; n++) {
Per Åhgren77dc1992019-11-23 00:14:31 +0100349 int32_t nrg = in_near[0][k * L + n] * in_near[0][k * L + n];
minyuecac94aa2016-05-20 08:42:22 -0700350 if (nrg > max_nrg) {
351 max_nrg = nrg;
352 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000353 }
minyuecac94aa2016-05-20 08:42:22 -0700354 env[k] = max_nrg;
355 }
356
357 // Calculate gain per sub frame
358 gains[0] = stt->gain;
359 for (k = 0; k < 10; k++) {
360 // Fast envelope follower
361 // decay time = -131000 / -1000 = 131 (ms)
362 stt->capacitorFast =
363 AGC_SCALEDIFF32(-1000, stt->capacitorFast, stt->capacitorFast);
364 if (env[k] > stt->capacitorFast) {
365 stt->capacitorFast = env[k];
366 }
367 // Slow envelope follower
368 if (env[k] > stt->capacitorSlow) {
369 // increase capacitorSlow
370 stt->capacitorSlow = AGC_SCALEDIFF32(500, (env[k] - stt->capacitorSlow),
371 stt->capacitorSlow);
372 } else {
373 // decrease capacitorSlow
374 stt->capacitorSlow =
375 AGC_SCALEDIFF32(decay, stt->capacitorSlow, stt->capacitorSlow);
niklase@google.com470e71d2011-07-07 08:21:25 +0000376 }
377
minyuecac94aa2016-05-20 08:42:22 -0700378 // use maximum of both capacitors as current level
379 if (stt->capacitorFast > stt->capacitorSlow) {
380 cur_level = stt->capacitorFast;
381 } else {
382 cur_level = stt->capacitorSlow;
383 }
384 // Translate signal level into gain, using a piecewise linear approximation
385 // find number of leading zeros
386 zeros = WebRtcSpl_NormU32((uint32_t)cur_level);
387 if (cur_level == 0) {
388 zeros = 31;
389 }
Alex Loikoc531af72017-10-24 10:41:48 +0200390 tmp32 = ((uint32_t)cur_level << zeros) & 0x7FFFFFFF;
minyuecac94aa2016-05-20 08:42:22 -0700391 frac = (int16_t)(tmp32 >> 19); // Q12.
Sam Zackrisson762289e2018-06-26 11:21:22 +0200392 // Interpolate between gainTable[zeros] and gainTable[zeros-1].
Per Åhgren5b139d62020-03-20 15:50:14 +0100393 tmp32 =
394 ((stt->gainTable[zeros - 1] - stt->gainTable[zeros]) * (int64_t)frac) >>
395 12;
Sam Zackrisson762289e2018-06-26 11:21:22 +0200396 gains[k + 1] = stt->gainTable[zeros] + tmp32;
minyuecac94aa2016-05-20 08:42:22 -0700397 }
398
399 // Gate processing (lower gain during absence of speech)
400 zeros = (zeros << 9) - (frac >> 3);
401 // find number of leading zeros
402 zeros_fast = WebRtcSpl_NormU32((uint32_t)stt->capacitorFast);
403 if (stt->capacitorFast == 0) {
404 zeros_fast = 31;
405 }
Alex Loikoc531af72017-10-24 10:41:48 +0200406 tmp32 = ((uint32_t)stt->capacitorFast << zeros_fast) & 0x7FFFFFFF;
minyuecac94aa2016-05-20 08:42:22 -0700407 zeros_fast <<= 9;
408 zeros_fast -= (int16_t)(tmp32 >> 22);
409
410 gate = 1000 + zeros_fast - zeros - stt->vadNearend.stdShortTerm;
411
412 if (gate < 0) {
413 stt->gatePrevious = 0;
414 } else {
415 tmp32 = stt->gatePrevious * 7;
416 gate = (int16_t)((gate + tmp32) >> 3);
417 stt->gatePrevious = gate;
418 }
419 // gate < 0 -> no gate
420 // gate > 2500 -> max gate
421 if (gate > 0) {
422 if (gate < 2500) {
423 gain_adj = (2500 - gate) >> 5;
424 } else {
425 gain_adj = 0;
426 }
427 for (k = 0; k < 10; k++) {
428 if ((gains[k + 1] - stt->gainTable[0]) > 8388608) {
429 // To prevent wraparound
430 tmp32 = (gains[k + 1] - stt->gainTable[0]) >> 8;
431 tmp32 *= 178 + gain_adj;
432 } else {
433 tmp32 = (gains[k + 1] - stt->gainTable[0]) * (178 + gain_adj);
434 tmp32 >>= 8;
435 }
436 gains[k + 1] = stt->gainTable[0] + tmp32;
437 }
438 }
439
440 // Limit gain to avoid overload distortion
441 for (k = 0; k < 10; k++) {
Sam Zackrisson71729eb2018-07-09 16:06:28 +0200442 // Find a shift of gains[k + 1] such that it can be squared without
443 // overflow, but at least by 10 bits.
minyuecac94aa2016-05-20 08:42:22 -0700444 zeros = 10;
Sam Zackrisson71729eb2018-07-09 16:06:28 +0200445 if (gains[k + 1] > 47452159) {
minyuecac94aa2016-05-20 08:42:22 -0700446 zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]);
447 }
448 gain32 = (gains[k + 1] >> zeros) + 1;
449 gain32 *= gain32;
450 // check for overflow
451 while (AGC_MUL32((env[k] >> 12) + 1, gain32) >
452 WEBRTC_SPL_SHIFT_W32((int32_t)32767, 2 * (1 - zeros + 10))) {
453 // multiply by 253/256 ==> -0.1 dB
454 if (gains[k + 1] > 8388607) {
455 // Prevent wrap around
456 gains[k + 1] = (gains[k + 1] / 256) * 253;
457 } else {
458 gains[k + 1] = (gains[k + 1] * 253) / 256;
459 }
460 gain32 = (gains[k + 1] >> zeros) + 1;
461 gain32 *= gain32;
462 }
463 }
464 // gain reductions should be done 1 ms earlier than gain increases
465 for (k = 1; k < 10; k++) {
466 if (gains[k] > gains[k + 1]) {
467 gains[k] = gains[k + 1];
468 }
469 }
470 // save start gain for next frame
471 stt->gain = gains[10];
472
Per Åhgren77dc1992019-11-23 00:14:31 +0100473 return 0;
474}
475
Per Åhgren5b139d62020-03-20 15:50:14 +0100476int32_t WebRtcAgc_ApplyDigitalGains(const int32_t gains[11],
477 size_t num_bands,
478 uint32_t FS,
479 const int16_t* const* in_near,
Per Åhgren77dc1992019-11-23 00:14:31 +0100480 int16_t* const* out) {
minyuecac94aa2016-05-20 08:42:22 -0700481 // Apply gain
482 // handle first sub frame separately
Per Åhgren77dc1992019-11-23 00:14:31 +0100483 size_t L;
484 int16_t L2; // samples/subframe
485
486 // determine number of samples per ms
487 if (FS == 8000) {
488 L = 8;
489 L2 = 3;
490 } else if (FS == 16000 || FS == 32000 || FS == 48000) {
491 L = 16;
492 L2 = 4;
493 } else {
494 return -1;
495 }
496
497 for (size_t i = 0; i < num_bands; ++i) {
498 if (in_near[i] != out[i]) {
499 // Only needed if they don't already point to the same place.
500 memcpy(out[i], in_near[i], 10 * L * sizeof(in_near[i][0]));
501 }
502 }
503
minyuecac94aa2016-05-20 08:42:22 -0700504 // iterate over samples
Per Åhgren77dc1992019-11-23 00:14:31 +0100505 int32_t delta = (gains[1] - gains[0]) * (1 << (4 - L2));
506 int32_t gain32 = gains[0] * (1 << 4);
507 for (size_t n = 0; n < L; n++) {
508 for (size_t i = 0; i < num_bands; ++i) {
509 int32_t out_tmp = (int64_t)out[i][n] * ((gain32 + 127) >> 7) >> 16;
minyuecac94aa2016-05-20 08:42:22 -0700510 if (out_tmp > 4095) {
511 out[i][n] = (int16_t)32767;
512 } else if (out_tmp < -4096) {
513 out[i][n] = (int16_t)-32768;
514 } else {
Per Åhgren77dc1992019-11-23 00:14:31 +0100515 int32_t tmp32 = ((int64_t)out[i][n] * (gain32 >> 4)) >> 16;
Sam Zackrisson46f858a2018-07-02 15:01:11 +0200516 out[i][n] = (int16_t)tmp32;
minyuecac94aa2016-05-20 08:42:22 -0700517 }
518 }
minyuecac94aa2016-05-20 08:42:22 -0700519
520 gain32 += delta;
521 }
522 // iterate over subframes
Per Åhgren77dc1992019-11-23 00:14:31 +0100523 for (int k = 1; k < 10; k++) {
minyuecac94aa2016-05-20 08:42:22 -0700524 delta = (gains[k + 1] - gains[k]) * (1 << (4 - L2));
525 gain32 = gains[k] * (1 << 4);
526 // iterate over samples
Per Åhgren77dc1992019-11-23 00:14:31 +0100527 for (size_t n = 0; n < L; n++) {
528 for (size_t i = 0; i < num_bands; ++i) {
peahfb2fa3f2017-09-13 06:28:16 -0700529 int64_t tmp64 = ((int64_t)(out[i][k * L + n])) * (gain32 >> 4);
530 tmp64 = tmp64 >> 16;
531 if (tmp64 > 32767) {
532 out[i][k * L + n] = 32767;
Per Åhgren5b139d62020-03-20 15:50:14 +0100533 } else if (tmp64 < -32768) {
peahfb2fa3f2017-09-13 06:28:16 -0700534 out[i][k * L + n] = -32768;
Per Åhgren5b139d62020-03-20 15:50:14 +0100535 } else {
peahfb2fa3f2017-09-13 06:28:16 -0700536 out[i][k * L + n] = (int16_t)(tmp64);
537 }
minyuecac94aa2016-05-20 08:42:22 -0700538 }
539 gain32 += delta;
540 }
541 }
minyuecac94aa2016-05-20 08:42:22 -0700542 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000543}
544
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000545void WebRtcAgc_InitVad(AgcVad* state) {
minyuecac94aa2016-05-20 08:42:22 -0700546 int16_t k;
niklase@google.com470e71d2011-07-07 08:21:25 +0000547
minyuecac94aa2016-05-20 08:42:22 -0700548 state->HPstate = 0; // state of high pass filter
549 state->logRatio = 0; // log( P(active) / P(inactive) )
550 // average input level (Q10)
551 state->meanLongTerm = 15 << 10;
niklase@google.com470e71d2011-07-07 08:21:25 +0000552
minyuecac94aa2016-05-20 08:42:22 -0700553 // variance of input level (Q8)
554 state->varianceLongTerm = 500 << 8;
niklase@google.com470e71d2011-07-07 08:21:25 +0000555
minyuecac94aa2016-05-20 08:42:22 -0700556 state->stdLongTerm = 0; // standard deviation of input level in dB
557 // short-term average input level (Q10)
558 state->meanShortTerm = 15 << 10;
niklase@google.com470e71d2011-07-07 08:21:25 +0000559
minyuecac94aa2016-05-20 08:42:22 -0700560 // short-term variance of input level (Q8)
561 state->varianceShortTerm = 500 << 8;
niklase@google.com470e71d2011-07-07 08:21:25 +0000562
minyuecac94aa2016-05-20 08:42:22 -0700563 state->stdShortTerm =
564 0; // short-term standard deviation of input level in dB
565 state->counter = 3; // counts updates
566 for (k = 0; k < 8; k++) {
567 // downsampling filter
568 state->downState[k] = 0;
569 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000570}
571
Per Åhgren5b139d62020-03-20 15:50:14 +0100572int16_t WebRtcAgc_ProcessVad(AgcVad* state, // (i) VAD state
573 const int16_t* in, // (i) Speech signal
574 size_t nrSamples) { // (i) number of samples
Alex Loikoc7b18fe2017-10-27 14:57:38 +0200575 uint32_t nrg;
576 int32_t out, tmp32, tmp32b;
minyuecac94aa2016-05-20 08:42:22 -0700577 uint16_t tmpU16;
578 int16_t k, subfr, tmp16;
579 int16_t buf1[8];
580 int16_t buf2[4];
581 int16_t HPstate;
582 int16_t zeros, dB;
Alex Loikoe714ed62018-07-19 13:08:23 +0200583 int64_t tmp64;
niklase@google.com470e71d2011-07-07 08:21:25 +0000584
minyuecac94aa2016-05-20 08:42:22 -0700585 // process in 10 sub frames of 1 ms (to save on memory)
586 nrg = 0;
587 HPstate = state->HPstate;
588 for (subfr = 0; subfr < 10; subfr++) {
589 // downsample to 4 kHz
590 if (nrSamples == 160) {
591 for (k = 0; k < 8; k++) {
592 tmp32 = (int32_t)in[2 * k] + (int32_t)in[2 * k + 1];
593 tmp32 >>= 1;
594 buf1[k] = (int16_t)tmp32;
595 }
596 in += 16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000597
minyuecac94aa2016-05-20 08:42:22 -0700598 WebRtcSpl_DownsampleBy2(buf1, 8, buf2, state->downState);
599 } else {
600 WebRtcSpl_DownsampleBy2(in, 8, buf2, state->downState);
601 in += 8;
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 }
603
minyuecac94aa2016-05-20 08:42:22 -0700604 // high pass filter and compute energy
605 for (k = 0; k < 4; k++) {
606 out = buf2[k] + HPstate;
607 tmp32 = 600 * out;
608 HPstate = (int16_t)((tmp32 >> 10) - buf2[k]);
Alex Loiko7cfbf3a2017-11-07 16:34:32 +0100609
610 // Add 'out * out / 2**6' to 'nrg' in a non-overflowing
611 // way. Guaranteed to work as long as 'out * out / 2**6' fits in
612 // an int32_t.
613 nrg += out * (out / (1 << 6));
614 nrg += out * (out % (1 << 6)) / (1 << 6);
niklase@google.com470e71d2011-07-07 08:21:25 +0000615 }
minyuecac94aa2016-05-20 08:42:22 -0700616 }
617 state->HPstate = HPstate;
niklase@google.com470e71d2011-07-07 08:21:25 +0000618
minyuecac94aa2016-05-20 08:42:22 -0700619 // find number of leading zeros
620 if (!(0xFFFF0000 & nrg)) {
621 zeros = 16;
622 } else {
623 zeros = 0;
624 }
625 if (!(0xFF000000 & (nrg << zeros))) {
626 zeros += 8;
627 }
628 if (!(0xF0000000 & (nrg << zeros))) {
629 zeros += 4;
630 }
631 if (!(0xC0000000 & (nrg << zeros))) {
632 zeros += 2;
633 }
634 if (!(0x80000000 & (nrg << zeros))) {
635 zeros += 1;
636 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000637
minyuecac94aa2016-05-20 08:42:22 -0700638 // energy level (range {-32..30}) (Q10)
Alex Loikob9f53612017-10-24 09:58:00 +0200639 dB = (15 - zeros) * (1 << 11);
niklase@google.com470e71d2011-07-07 08:21:25 +0000640
minyuecac94aa2016-05-20 08:42:22 -0700641 // Update statistics
niklase@google.com470e71d2011-07-07 08:21:25 +0000642
minyuecac94aa2016-05-20 08:42:22 -0700643 if (state->counter < kAvgDecayTime) {
644 // decay time = AvgDecTime * 10 ms
645 state->counter++;
646 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000647
minyuecac94aa2016-05-20 08:42:22 -0700648 // update short-term estimate of mean energy level (Q10)
649 tmp32 = state->meanShortTerm * 15 + dB;
650 state->meanShortTerm = (int16_t)(tmp32 >> 4);
niklase@google.com470e71d2011-07-07 08:21:25 +0000651
minyuecac94aa2016-05-20 08:42:22 -0700652 // update short-term estimate of variance in energy level (Q8)
653 tmp32 = (dB * dB) >> 12;
654 tmp32 += state->varianceShortTerm * 15;
655 state->varianceShortTerm = tmp32 / 16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000656
minyuecac94aa2016-05-20 08:42:22 -0700657 // update short-term estimate of standard deviation in energy level (Q10)
658 tmp32 = state->meanShortTerm * state->meanShortTerm;
659 tmp32 = (state->varianceShortTerm << 12) - tmp32;
660 state->stdShortTerm = (int16_t)WebRtcSpl_Sqrt(tmp32);
niklase@google.com470e71d2011-07-07 08:21:25 +0000661
minyuecac94aa2016-05-20 08:42:22 -0700662 // update long-term estimate of mean energy level (Q10)
663 tmp32 = state->meanLongTerm * state->counter + dB;
664 state->meanLongTerm =
665 WebRtcSpl_DivW32W16ResW16(tmp32, WebRtcSpl_AddSatW16(state->counter, 1));
niklase@google.com470e71d2011-07-07 08:21:25 +0000666
minyuecac94aa2016-05-20 08:42:22 -0700667 // update long-term estimate of variance in energy level (Q8)
668 tmp32 = (dB * dB) >> 12;
669 tmp32 += state->varianceLongTerm * state->counter;
670 state->varianceLongTerm =
671 WebRtcSpl_DivW32W16(tmp32, WebRtcSpl_AddSatW16(state->counter, 1));
niklase@google.com470e71d2011-07-07 08:21:25 +0000672
minyuecac94aa2016-05-20 08:42:22 -0700673 // update long-term estimate of standard deviation in energy level (Q10)
674 tmp32 = state->meanLongTerm * state->meanLongTerm;
675 tmp32 = (state->varianceLongTerm << 12) - tmp32;
676 state->stdLongTerm = (int16_t)WebRtcSpl_Sqrt(tmp32);
677
678 // update voice activity measure (Q10)
679 tmp16 = 3 << 12;
680 // TODO(bjornv): (dB - state->meanLongTerm) can overflow, e.g., in
681 // ApmTest.Process unit test. Previously the macro WEBRTC_SPL_MUL_16_16()
682 // was used, which did an intermediate cast to (int16_t), hence losing
683 // significant bits. This cause logRatio to max out positive, rather than
684 // negative. This is a bug, but has very little significance.
685 tmp32 = tmp16 * (int16_t)(dB - state->meanLongTerm);
686 tmp32 = WebRtcSpl_DivW32W16(tmp32, state->stdLongTerm);
687 tmpU16 = (13 << 12);
688 tmp32b = WEBRTC_SPL_MUL_16_U16(state->logRatio, tmpU16);
Alex Loikoe714ed62018-07-19 13:08:23 +0200689 tmp64 = tmp32;
690 tmp64 += tmp32b >> 10;
691 tmp64 >>= 6;
minyuecac94aa2016-05-20 08:42:22 -0700692
693 // limit
Alex Loikoe714ed62018-07-19 13:08:23 +0200694 if (tmp64 > 2048) {
695 tmp64 = 2048;
696 } else if (tmp64 < -2048) {
697 tmp64 = -2048;
minyuecac94aa2016-05-20 08:42:22 -0700698 }
Alex Loikoe714ed62018-07-19 13:08:23 +0200699 state->logRatio = (int16_t)tmp64;
minyuecac94aa2016-05-20 08:42:22 -0700700
701 return state->logRatio; // Q10
niklase@google.com470e71d2011-07-07 08:21:25 +0000702}
Per Åhgren5b139d62020-03-20 15:50:14 +0100703
704} // namespace webrtc