blob: 662e88b6e788bdc98c0f1d55ac38de1e38e94950 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
bjornv@webrtc.org0c6f9312012-01-30 09:39:08 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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/* analog_agc.c
12 *
13 * Using a feedback system, determines an appropriate analog volume level
14 * given an input signal and current volume level. Targets a conservative
15 * signal level and is intended for use with a digital AGC to apply
16 * additional gain.
17 *
18 */
19
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/audio_processing/agc/legacy/analog_agc.h"
bjornv@webrtc.orgb395a5e2014-12-16 10:38:10 +000021
niklase@google.com470e71d2011-07-07 08:21:25 +000022#include <stdlib.h>
bjornv@webrtc.orgea297872014-09-23 11:21:39 +000023#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +000024#include <stdio.h>
25#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000026
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "rtc_base/checks.h"
kwiberg1e8ed4a2016-08-26 04:33:34 -070028
niklase@google.com470e71d2011-07-07 08:21:25 +000029/* The slope of in Q13*/
minyuecac94aa2016-05-20 08:42:22 -070030static const int16_t kSlope1[8] = {21793, 12517, 7189, 4129,
31 2372, 1362, 472, 78};
niklase@google.com470e71d2011-07-07 08:21:25 +000032
33/* The offset in Q14 */
minyuecac94aa2016-05-20 08:42:22 -070034static const int16_t kOffset1[8] = {25395, 23911, 22206, 20737,
35 19612, 18805, 17951, 17367};
niklase@google.com470e71d2011-07-07 08:21:25 +000036
37/* The slope of in Q13*/
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000038static const int16_t kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337};
niklase@google.com470e71d2011-07-07 08:21:25 +000039
40/* The offset in Q14 */
minyuecac94aa2016-05-20 08:42:22 -070041static const int16_t kOffset2[8] = {18432, 18379, 18290, 18177,
42 18052, 17920, 17670, 17286};
niklase@google.com470e71d2011-07-07 08:21:25 +000043
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000044static const int16_t kMuteGuardTimeMs = 8000;
45static const int16_t kInitCheck = 42;
Peter Kastingdce40cf2015-08-24 14:52:23 -070046static const size_t kNumSubframes = 10;
niklase@google.com470e71d2011-07-07 08:21:25 +000047
48/* Default settings if config is not used */
49#define AGC_DEFAULT_TARGET_LEVEL 3
50#define AGC_DEFAULT_COMP_GAIN 9
minyuecac94aa2016-05-20 08:42:22 -070051/* This is the target level for the analog part in ENV scale. To convert to RMS
52 * scale you
niklase@google.com470e71d2011-07-07 08:21:25 +000053 * have to add OFFSET_ENV_TO_RMS.
54 */
55#define ANALOG_TARGET_LEVEL 11
minyuecac94aa2016-05-20 08:42:22 -070056#define ANALOG_TARGET_LEVEL_2 5 // ANALOG_TARGET_LEVEL / 2
57/* Offset between RMS scale (analog part) and ENV scale (digital part). This
58 * value actually
59 * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future
60 * replace it with
niklase@google.com470e71d2011-07-07 08:21:25 +000061 * a table.
62 */
63#define OFFSET_ENV_TO_RMS 9
minyuecac94aa2016-05-20 08:42:22 -070064/* The reference input level at which the digital part gives an output of
65 * targetLevelDbfs
66 * (desired level) if we have no compression gain. This level should be set high
67 * enough not
niklase@google.com470e71d2011-07-07 08:21:25 +000068 * to compress the peaks due to the dynamics.
69 */
70#define DIGITAL_REF_AT_0_COMP_GAIN 4
71/* Speed of reference level decrease.
72 */
73#define DIFF_REF_TO_ANALOG 5
74
75#ifdef MIC_LEVEL_FEEDBACK
76#define NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET 7
77#endif
78/* Size of analog gain table */
79#define GAIN_TBL_LEN 32
80/* Matlab code:
81 * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12));
82 */
83/* Q12 */
minyuecac94aa2016-05-20 08:42:22 -070084static const uint16_t kGainTableAnalog[GAIN_TBL_LEN] = {
85 4096, 4251, 4412, 4579, 4752, 4932, 5118, 5312, 5513, 5722, 5938,
86 6163, 6396, 6638, 6889, 7150, 7420, 7701, 7992, 8295, 8609, 8934,
87 9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953};
niklase@google.com470e71d2011-07-07 08:21:25 +000088
89/* Gain/Suppression tables for virtual Mic (in Q10) */
minyuecac94aa2016-05-20 08:42:22 -070090static const uint16_t kGainTableVirtualMic[128] = {
91 1052, 1081, 1110, 1141, 1172, 1204, 1237, 1271, 1305, 1341, 1378,
92 1416, 1454, 1494, 1535, 1577, 1620, 1664, 1710, 1757, 1805, 1854,
93 1905, 1957, 2010, 2065, 2122, 2180, 2239, 2301, 2364, 2428, 2495,
94 2563, 2633, 2705, 2779, 2855, 2933, 3013, 3096, 3180, 3267, 3357,
95 3449, 3543, 3640, 3739, 3842, 3947, 4055, 4166, 4280, 4397, 4517,
96 4640, 4767, 4898, 5032, 5169, 5311, 5456, 5605, 5758, 5916, 6078,
97 6244, 6415, 6590, 6770, 6956, 7146, 7341, 7542, 7748, 7960, 8178,
98 8402, 8631, 8867, 9110, 9359, 9615, 9878, 10148, 10426, 10711, 11004,
99 11305, 11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807,
100 15212, 15628, 16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923,
101 20468, 21028, 21603, 22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808,
102 27541, 28295, 29069, 29864, 30681, 31520, 32382};
103static const uint16_t kSuppressionTableVirtualMic[128] = {
104 1024, 1006, 988, 970, 952, 935, 918, 902, 886, 870, 854, 839, 824, 809, 794,
105 780, 766, 752, 739, 726, 713, 700, 687, 675, 663, 651, 639, 628, 616, 605,
106 594, 584, 573, 563, 553, 543, 533, 524, 514, 505, 496, 487, 478, 470, 461,
107 453, 445, 437, 429, 421, 414, 406, 399, 392, 385, 378, 371, 364, 358, 351,
108 345, 339, 333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278, 273, 268,
109 263, 258, 254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204,
110 200, 197, 193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155,
111 153, 150, 147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118,
112 116, 114, 112, 110, 108, 106, 104, 102};
niklase@google.com470e71d2011-07-07 08:21:25 +0000113
114/* Table for target energy levels. Values in Q(-7)
115 * Matlab code
minyuecac94aa2016-05-20 08:42:22 -0700116 * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n',
117 * round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */
niklase@google.com470e71d2011-07-07 08:21:25 +0000118
minyuecac94aa2016-05-20 08:42:22 -0700119static const int32_t kTargetLevelTable[64] = {
120 134209536, 106606424, 84680493, 67264106, 53429779, 42440782, 33711911,
121 26778323, 21270778, 16895980, 13420954, 10660642, 8468049, 6726411,
122 5342978, 4244078, 3371191, 2677832, 2127078, 1689598, 1342095,
123 1066064, 846805, 672641, 534298, 424408, 337119, 267783,
124 212708, 168960, 134210, 106606, 84680, 67264, 53430,
125 42441, 33712, 26778, 21271, 16896, 13421, 10661,
126 8468, 6726, 5343, 4244, 3371, 2678, 2127,
127 1690, 1342, 1066, 847, 673, 534, 424,
128 337, 268, 213, 169, 134, 107, 85,
129 67};
niklase@google.com470e71d2011-07-07 08:21:25 +0000130
minyuecac94aa2016-05-20 08:42:22 -0700131int WebRtcAgc_AddMic(void* state,
132 int16_t* const* in_mic,
133 size_t num_bands,
134 size_t samples) {
135 int32_t nrg, max_nrg, sample, tmp32;
136 int32_t* ptr;
137 uint16_t targetGainIdx, gain;
138 size_t i;
139 int16_t n, L, tmp16, tmp_speech[16];
140 LegacyAgc* stt;
141 stt = (LegacyAgc*)state;
niklase@google.com470e71d2011-07-07 08:21:25 +0000142
minyuecac94aa2016-05-20 08:42:22 -0700143 if (stt->fs == 8000) {
144 L = 8;
145 if (samples != 80) {
146 return -1;
147 }
148 } else {
149 L = 16;
150 if (samples != 160) {
151 return -1;
152 }
153 }
154
155 /* apply slowly varying digital gain */
156 if (stt->micVol > stt->maxAnalog) {
157 /* |maxLevel| is strictly >= |micVol|, so this condition should be
158 * satisfied here, ensuring there is no divide-by-zero. */
kwiberg1e8ed4a2016-08-26 04:33:34 -0700159 RTC_DCHECK_GT(stt->maxLevel, stt->maxAnalog);
minyuecac94aa2016-05-20 08:42:22 -0700160
161 /* Q1 */
162 tmp16 = (int16_t)(stt->micVol - stt->maxAnalog);
163 tmp32 = (GAIN_TBL_LEN - 1) * tmp16;
164 tmp16 = (int16_t)(stt->maxLevel - stt->maxAnalog);
165 targetGainIdx = tmp32 / tmp16;
kwiberg1e8ed4a2016-08-26 04:33:34 -0700166 RTC_DCHECK_LT(targetGainIdx, GAIN_TBL_LEN);
minyuecac94aa2016-05-20 08:42:22 -0700167
168 /* Increment through the table towards the target gain.
169 * If micVol drops below maxAnalog, we allow the gain
170 * to be dropped immediately. */
171 if (stt->gainTableIdx < targetGainIdx) {
172 stt->gainTableIdx++;
173 } else if (stt->gainTableIdx > targetGainIdx) {
174 stt->gainTableIdx--;
175 }
176
177 /* Q12 */
178 gain = kGainTableAnalog[stt->gainTableIdx];
179
180 for (i = 0; i < samples; i++) {
181 size_t j;
182 for (j = 0; j < num_bands; ++j) {
183 sample = (in_mic[j][i] * gain) >> 12;
184 if (sample > 32767) {
185 in_mic[j][i] = 32767;
186 } else if (sample < -32768) {
187 in_mic[j][i] = -32768;
188 } else {
189 in_mic[j][i] = (int16_t)sample;
niklase@google.com470e71d2011-07-07 08:21:25 +0000190 }
minyuecac94aa2016-05-20 08:42:22 -0700191 }
192 }
193 } else {
194 stt->gainTableIdx = 0;
195 }
196
197 /* compute envelope */
198 if (stt->inQueue > 0) {
199 ptr = stt->env[1];
200 } else {
201 ptr = stt->env[0];
202 }
203
204 for (i = 0; i < kNumSubframes; i++) {
205 /* iterate over samples */
206 max_nrg = 0;
207 for (n = 0; n < L; n++) {
208 nrg = in_mic[0][i * L + n] * in_mic[0][i * L + n];
209 if (nrg > max_nrg) {
210 max_nrg = nrg;
211 }
212 }
213 ptr[i] = max_nrg;
214 }
215
216 /* compute energy */
217 if (stt->inQueue > 0) {
218 ptr = stt->Rxx16w32_array[1];
219 } else {
220 ptr = stt->Rxx16w32_array[0];
221 }
222
223 for (i = 0; i < kNumSubframes / 2; i++) {
224 if (stt->fs == 16000) {
225 WebRtcSpl_DownsampleBy2(&in_mic[0][i * 32], 32, tmp_speech,
226 stt->filterState);
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000227 } else {
minyuecac94aa2016-05-20 08:42:22 -0700228 memcpy(tmp_speech, &in_mic[0][i * 16], 16 * sizeof(short));
niklase@google.com470e71d2011-07-07 08:21:25 +0000229 }
minyuecac94aa2016-05-20 08:42:22 -0700230 /* Compute energy in blocks of 16 samples */
231 ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4);
232 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000233
minyuecac94aa2016-05-20 08:42:22 -0700234 /* update queue information */
235 if (stt->inQueue == 0) {
236 stt->inQueue = 1;
237 } else {
238 stt->inQueue = 2;
239 }
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +0000240
minyuecac94aa2016-05-20 08:42:22 -0700241 /* call VAD (use low band only) */
242 WebRtcAgc_ProcessVad(&stt->vadMic, in_mic[0], samples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000243
minyuecac94aa2016-05-20 08:42:22 -0700244 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245}
246
minyuecac94aa2016-05-20 08:42:22 -0700247int WebRtcAgc_AddFarend(void* state, const int16_t* in_far, size_t samples) {
peah4d291f72015-11-16 23:52:25 -0800248 LegacyAgc* stt = (LegacyAgc*)state;
249
minyuecac94aa2016-05-20 08:42:22 -0700250 int err = WebRtcAgc_GetAddFarendError(state, samples);
peah4d291f72015-11-16 23:52:25 -0800251
minyuecac94aa2016-05-20 08:42:22 -0700252 if (err != 0)
253 return err;
peah4d291f72015-11-16 23:52:25 -0800254
minyuecac94aa2016-05-20 08:42:22 -0700255 return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples);
peah4d291f72015-11-16 23:52:25 -0800256}
257
minyuecac94aa2016-05-20 08:42:22 -0700258int WebRtcAgc_GetAddFarendError(void* state, size_t samples) {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000259 LegacyAgc* stt;
260 stt = (LegacyAgc*)state;
niklase@google.com470e71d2011-07-07 08:21:25 +0000261
peah4d291f72015-11-16 23:52:25 -0800262 if (stt == NULL)
263 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000264
peah4d291f72015-11-16 23:52:25 -0800265 if (stt->fs == 8000) {
266 if (samples != 80)
267 return -1;
268 } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) {
269 if (samples != 160)
270 return -1;
271 } else {
272 return -1;
273 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000274
peah4d291f72015-11-16 23:52:25 -0800275 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000276}
277
minyuecac94aa2016-05-20 08:42:22 -0700278int WebRtcAgc_VirtualMic(void* agcInst,
279 int16_t* const* in_near,
280 size_t num_bands,
281 size_t samples,
282 int32_t micLevelIn,
283 int32_t* micLevelOut) {
284 int32_t tmpFlt, micLevelTmp, gainIdx;
285 uint16_t gain;
286 size_t ii, j;
287 LegacyAgc* stt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000288
minyuecac94aa2016-05-20 08:42:22 -0700289 uint32_t nrg;
290 size_t sampleCntr;
291 uint32_t frameNrg = 0;
292 uint32_t frameNrgLimit = 5500;
293 int16_t numZeroCrossing = 0;
294 const int16_t kZeroCrossingLowLim = 15;
295 const int16_t kZeroCrossingHighLim = 20;
niklase@google.com470e71d2011-07-07 08:21:25 +0000296
minyuecac94aa2016-05-20 08:42:22 -0700297 stt = (LegacyAgc*)agcInst;
niklase@google.com470e71d2011-07-07 08:21:25 +0000298
minyuecac94aa2016-05-20 08:42:22 -0700299 /*
300 * Before applying gain decide if this is a low-level signal.
301 * The idea is that digital AGC will not adapt to low-level
302 * signals.
303 */
304 if (stt->fs != 8000) {
305 frameNrgLimit = frameNrgLimit << 1;
306 }
307
308 frameNrg = (uint32_t)(in_near[0][0] * in_near[0][0]);
309 for (sampleCntr = 1; sampleCntr < samples; sampleCntr++) {
310 // increment frame energy if it is less than the limit
311 // the correct value of the energy is not important
312 if (frameNrg < frameNrgLimit) {
313 nrg = (uint32_t)(in_near[0][sampleCntr] * in_near[0][sampleCntr]);
314 frameNrg += nrg;
niklase@google.com470e71d2011-07-07 08:21:25 +0000315 }
316
minyuecac94aa2016-05-20 08:42:22 -0700317 // Count the zero crossings
318 numZeroCrossing +=
319 ((in_near[0][sampleCntr] ^ in_near[0][sampleCntr - 1]) < 0);
320 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000321
minyuecac94aa2016-05-20 08:42:22 -0700322 if ((frameNrg < 500) || (numZeroCrossing <= 5)) {
323 stt->lowLevelSignal = 1;
324 } else if (numZeroCrossing <= kZeroCrossingLowLim) {
325 stt->lowLevelSignal = 0;
326 } else if (frameNrg <= frameNrgLimit) {
327 stt->lowLevelSignal = 1;
328 } else if (numZeroCrossing >= kZeroCrossingHighLim) {
329 stt->lowLevelSignal = 1;
330 } else {
331 stt->lowLevelSignal = 0;
332 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000333
minyuecac94aa2016-05-20 08:42:22 -0700334 micLevelTmp = micLevelIn << stt->scale;
335 /* Set desired level */
336 gainIdx = stt->micVol;
337 if (stt->micVol > stt->maxAnalog) {
338 gainIdx = stt->maxAnalog;
339 }
340 if (micLevelTmp != stt->micRef) {
341 /* Something has happened with the physical level, restart. */
342 stt->micRef = micLevelTmp;
343 stt->micVol = 127;
344 *micLevelOut = 127;
345 stt->micGainIdx = 127;
346 gainIdx = 127;
347 }
348 /* Pre-process the signal to emulate the microphone level. */
349 /* Take one step at a time in the gain table. */
350 if (gainIdx > 127) {
351 gain = kGainTableVirtualMic[gainIdx - 128];
352 } else {
353 gain = kSuppressionTableVirtualMic[127 - gainIdx];
354 }
355 for (ii = 0; ii < samples; ii++) {
356 tmpFlt = (in_near[0][ii] * gain) >> 10;
357 if (tmpFlt > 32767) {
358 tmpFlt = 32767;
359 gainIdx--;
360 if (gainIdx >= 127) {
361 gain = kGainTableVirtualMic[gainIdx - 127];
362 } else {
niklase@google.com470e71d2011-07-07 08:21:25 +0000363 gain = kSuppressionTableVirtualMic[127 - gainIdx];
minyuecac94aa2016-05-20 08:42:22 -0700364 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 }
minyuecac94aa2016-05-20 08:42:22 -0700366 if (tmpFlt < -32768) {
367 tmpFlt = -32768;
368 gainIdx--;
369 if (gainIdx >= 127) {
370 gain = kGainTableVirtualMic[gainIdx - 127];
371 } else {
372 gain = kSuppressionTableVirtualMic[127 - gainIdx];
373 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000374 }
minyuecac94aa2016-05-20 08:42:22 -0700375 in_near[0][ii] = (int16_t)tmpFlt;
376 for (j = 1; j < num_bands; ++j) {
377 tmpFlt = (in_near[j][ii] * gain) >> 10;
378 if (tmpFlt > 32767) {
379 tmpFlt = 32767;
380 }
381 if (tmpFlt < -32768) {
382 tmpFlt = -32768;
383 }
384 in_near[j][ii] = (int16_t)tmpFlt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000385 }
minyuecac94aa2016-05-20 08:42:22 -0700386 }
387 /* Set the level we (finally) used */
388 stt->micGainIdx = gainIdx;
389 // *micLevelOut = stt->micGainIdx;
390 *micLevelOut = stt->micGainIdx >> stt->scale;
391 /* Add to Mic as if it was the output from a true microphone */
392 if (WebRtcAgc_AddMic(agcInst, in_near, num_bands, samples) != 0) {
393 return -1;
394 }
395 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000396}
397
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000398void WebRtcAgc_UpdateAgcThresholds(LegacyAgc* stt) {
minyuecac94aa2016-05-20 08:42:22 -0700399 int16_t tmp16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000400#ifdef MIC_LEVEL_FEEDBACK
minyuecac94aa2016-05-20 08:42:22 -0700401 int zeros;
niklase@google.com470e71d2011-07-07 08:21:25 +0000402
minyuecac94aa2016-05-20 08:42:22 -0700403 if (stt->micLvlSat) {
404 /* Lower the analog target level since we have reached its maximum */
405 zeros = WebRtcSpl_NormW32(stt->Rxx160_LPw32);
406 stt->targetIdxOffset = (3 * zeros - stt->targetIdx - 2) / 4;
407 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000408#endif
409
minyuecac94aa2016-05-20 08:42:22 -0700410 /* Set analog target level in envelope dBOv scale */
411 tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2;
412 tmp16 = WebRtcSpl_DivW32W16ResW16((int32_t)tmp16, ANALOG_TARGET_LEVEL);
413 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16;
414 if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN) {
415 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN;
416 }
417 if (stt->agcMode == kAgcModeFixedDigital) {
418 /* Adjust for different parameter interpretation in FixedDigital mode */
419 stt->analogTarget = stt->compressionGaindB;
420 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000421#ifdef MIC_LEVEL_FEEDBACK
minyuecac94aa2016-05-20 08:42:22 -0700422 stt->analogTarget += stt->targetIdxOffset;
niklase@google.com470e71d2011-07-07 08:21:25 +0000423#endif
minyuecac94aa2016-05-20 08:42:22 -0700424 /* Since the offset between RMS and ENV is not constant, we should make this
425 * into a
426 * table, but for now, we'll stick with a constant, tuned for the chosen
427 * analog
428 * target level.
429 */
430 stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000431#ifdef MIC_LEVEL_FEEDBACK
minyuecac94aa2016-05-20 08:42:22 -0700432 stt->targetIdx += stt->targetIdxOffset;
niklase@google.com470e71d2011-07-07 08:21:25 +0000433#endif
minyuecac94aa2016-05-20 08:42:22 -0700434 /* Analog adaptation limits */
435 /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */
436 stt->analogTargetLevel =
437 RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */
438 stt->startUpperLimit =
439 RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 1]; /* -19 dBov */
440 stt->startLowerLimit =
441 RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 1]; /* -21 dBov */
442 stt->upperPrimaryLimit =
443 RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 2]; /* -18 dBov */
444 stt->lowerPrimaryLimit =
445 RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 2]; /* -22 dBov */
446 stt->upperSecondaryLimit =
447 RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 5]; /* -15 dBov */
448 stt->lowerSecondaryLimit =
449 RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 5]; /* -25 dBov */
450 stt->upperLimit = stt->startUpperLimit;
451 stt->lowerLimit = stt->startLowerLimit;
niklase@google.com470e71d2011-07-07 08:21:25 +0000452}
453
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000454void WebRtcAgc_SaturationCtrl(LegacyAgc* stt,
455 uint8_t* saturated,
456 int32_t* env) {
minyuecac94aa2016-05-20 08:42:22 -0700457 int16_t i, tmpW16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000458
minyuecac94aa2016-05-20 08:42:22 -0700459 /* Check if the signal is saturated */
460 for (i = 0; i < 10; i++) {
461 tmpW16 = (int16_t)(env[i] >> 20);
462 if (tmpW16 > 875) {
463 stt->envSum += tmpW16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000464 }
minyuecac94aa2016-05-20 08:42:22 -0700465 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000466
minyuecac94aa2016-05-20 08:42:22 -0700467 if (stt->envSum > 25000) {
468 *saturated = 1;
469 stt->envSum = 0;
470 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000471
minyuecac94aa2016-05-20 08:42:22 -0700472 /* stt->envSum *= 0.99; */
473 stt->envSum = (int16_t)((stt->envSum * 32440) >> 15);
niklase@google.com470e71d2011-07-07 08:21:25 +0000474}
475
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000476void WebRtcAgc_ZeroCtrl(LegacyAgc* stt, int32_t* inMicLevel, int32_t* env) {
minyuecac94aa2016-05-20 08:42:22 -0700477 int16_t i;
minyuefd634c42016-06-17 04:36:10 -0700478 int64_t tmp = 0;
minyuecac94aa2016-05-20 08:42:22 -0700479 int32_t midVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000480
minyuecac94aa2016-05-20 08:42:22 -0700481 /* Is the input signal zero? */
482 for (i = 0; i < 10; i++) {
minyuefd634c42016-06-17 04:36:10 -0700483 tmp += env[i];
minyuecac94aa2016-05-20 08:42:22 -0700484 }
485
486 /* Each block is allowed to have a few non-zero
487 * samples.
488 */
minyuefd634c42016-06-17 04:36:10 -0700489 if (tmp < 500) {
minyuecac94aa2016-05-20 08:42:22 -0700490 stt->msZero += 10;
491 } else {
492 stt->msZero = 0;
493 }
494
495 if (stt->muteGuardMs > 0) {
496 stt->muteGuardMs -= 10;
497 }
498
499 if (stt->msZero > 500) {
500 stt->msZero = 0;
501
502 /* Increase microphone level only if it's less than 50% */
503 midVal = (stt->maxAnalog + stt->minLevel + 1) / 2;
504 if (*inMicLevel < midVal) {
505 /* *inMicLevel *= 1.1; */
506 *inMicLevel = (1126 * *inMicLevel) >> 10;
507 /* Reduces risk of a muted mic repeatedly triggering excessive levels due
508 * to zero signal detection. */
509 *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax);
510 stt->micVol = *inMicLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 }
512
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000513#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -0700514 fprintf(stt->fpt,
515 "\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold,"
516 " micVol: %d\n",
517 stt->fcount, stt->micVol);
niklase@google.com470e71d2011-07-07 08:21:25 +0000518#endif
519
minyuecac94aa2016-05-20 08:42:22 -0700520 stt->activeSpeech = 0;
521 stt->Rxx16_LPw32Max = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000522
minyuecac94aa2016-05-20 08:42:22 -0700523 /* The AGC has a tendency (due to problems with the VAD parameters), to
524 * vastly increase the volume after a muting event. This timer prevents
525 * upwards adaptation for a short period. */
526 stt->muteGuardMs = kMuteGuardTimeMs;
527 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000528}
529
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000530void WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc* stt) {
minyuecac94aa2016-05-20 08:42:22 -0700531 /* Check if the near end speaker is inactive.
532 * If that is the case the VAD threshold is
533 * increased since the VAD speech model gets
534 * more sensitive to any sound after a long
535 * silence.
536 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000537
minyuecac94aa2016-05-20 08:42:22 -0700538 int32_t tmp32;
539 int16_t vadThresh;
niklase@google.com470e71d2011-07-07 08:21:25 +0000540
minyuecac94aa2016-05-20 08:42:22 -0700541 if (stt->vadMic.stdLongTerm < 2500) {
542 stt->vadThreshold = 1500;
543 } else {
544 vadThresh = kNormalVadThreshold;
545 if (stt->vadMic.stdLongTerm < 4500) {
546 /* Scale between min and max threshold */
547 vadThresh += (4500 - stt->vadMic.stdLongTerm) / 2;
niklase@google.com470e71d2011-07-07 08:21:25 +0000548 }
minyuecac94aa2016-05-20 08:42:22 -0700549
550 /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */
551 tmp32 = vadThresh + 31 * stt->vadThreshold;
552 stt->vadThreshold = (int16_t)(tmp32 >> 5);
553 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000554}
555
minyuecac94aa2016-05-20 08:42:22 -0700556void WebRtcAgc_ExpCurve(int16_t volume, int16_t* index) {
557 // volume in Q14
558 // index in [0-7]
559 /* 8 different curves */
560 if (volume > 5243) {
561 if (volume > 7864) {
562 if (volume > 12124) {
563 *index = 7;
564 } else {
565 *index = 6;
566 }
567 } else {
568 if (volume > 6554) {
569 *index = 5;
570 } else {
571 *index = 4;
572 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000573 }
minyuecac94aa2016-05-20 08:42:22 -0700574 } else {
575 if (volume > 2621) {
576 if (volume > 3932) {
577 *index = 3;
578 } else {
579 *index = 2;
580 }
581 } else {
582 if (volume > 1311) {
583 *index = 1;
584 } else {
585 *index = 0;
586 }
587 }
588 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000589}
590
minyuecac94aa2016-05-20 08:42:22 -0700591int32_t WebRtcAgc_ProcessAnalog(void* state,
592 int32_t inMicLevel,
593 int32_t* outMicLevel,
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000594 int16_t vadLogRatio,
minyuecac94aa2016-05-20 08:42:22 -0700595 int16_t echo,
596 uint8_t* saturationWarning) {
597 uint32_t tmpU32;
598 int32_t Rxx16w32, tmp32;
599 int32_t inMicLevelTmp, lastMicVol;
600 int16_t i;
601 uint8_t saturated = 0;
602 LegacyAgc* stt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000603
minyuecac94aa2016-05-20 08:42:22 -0700604 stt = (LegacyAgc*)state;
605 inMicLevelTmp = inMicLevel << stt->scale;
niklase@google.com470e71d2011-07-07 08:21:25 +0000606
minyuecac94aa2016-05-20 08:42:22 -0700607 if (inMicLevelTmp > stt->maxAnalog) {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000608#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -0700609 fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n",
610 stt->fcount);
niklase@google.com470e71d2011-07-07 08:21:25 +0000611#endif
minyuecac94aa2016-05-20 08:42:22 -0700612 return -1;
613 } else if (inMicLevelTmp < stt->minLevel) {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000614#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -0700615 fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n",
616 stt->fcount);
niklase@google.com470e71d2011-07-07 08:21:25 +0000617#endif
minyuecac94aa2016-05-20 08:42:22 -0700618 return -1;
619 }
620
621 if (stt->firstCall == 0) {
622 int32_t tmpVol;
623 stt->firstCall = 1;
624 tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
625 tmpVol = (stt->minLevel + tmp32);
626
627 /* If the mic level is very low at start, increase it! */
628 if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog)) {
629 inMicLevelTmp = tmpVol;
niklase@google.com470e71d2011-07-07 08:21:25 +0000630 }
minyuecac94aa2016-05-20 08:42:22 -0700631 stt->micVol = inMicLevelTmp;
632 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000633
minyuecac94aa2016-05-20 08:42:22 -0700634 /* Set the mic level to the previous output value if there is digital input
635 * gain */
636 if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog)) {
637 inMicLevelTmp = stt->micVol;
638 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000639
minyuecac94aa2016-05-20 08:42:22 -0700640 /* If the mic level was manually changed to a very low value raise it! */
641 if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput)) {
642 tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
643 inMicLevelTmp = (stt->minLevel + tmp32);
644 stt->micVol = inMicLevelTmp;
niklase@google.com470e71d2011-07-07 08:21:25 +0000645#ifdef MIC_LEVEL_FEEDBACK
minyuecac94aa2016-05-20 08:42:22 -0700646// stt->numBlocksMicLvlSat = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000647#endif
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000648#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -0700649 fprintf(stt->fpt,
650 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual"
651 " decrease, raise vol\n",
652 stt->fcount);
niklase@google.com470e71d2011-07-07 08:21:25 +0000653#endif
minyuecac94aa2016-05-20 08:42:22 -0700654 }
655
656 if (inMicLevelTmp != stt->micVol) {
657 if (inMicLevel == stt->lastInMicLevel) {
658 // We requested a volume adjustment, but it didn't occur. This is
659 // probably due to a coarse quantization of the volume slider.
660 // Restore the requested value to prevent getting stuck.
661 inMicLevelTmp = stt->micVol;
662 } else {
663 // As long as the value changed, update to match.
664 stt->micVol = inMicLevelTmp;
niklase@google.com470e71d2011-07-07 08:21:25 +0000665 }
minyuecac94aa2016-05-20 08:42:22 -0700666 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000667
minyuecac94aa2016-05-20 08:42:22 -0700668 if (inMicLevelTmp > stt->maxLevel) {
669 // Always allow the user to raise the volume above the maxLevel.
670 stt->maxLevel = inMicLevelTmp;
671 }
672
673 // Store last value here, after we've taken care of manual updates etc.
674 stt->lastInMicLevel = inMicLevel;
675 lastMicVol = stt->micVol;
676
677 /* Checks if the signal is saturated. Also a check if individual samples
678 * are larger than 12000 is done. If they are the counter for increasing
679 * the volume level is set to -100ms
680 */
681 WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
682
683 /* The AGC is always allowed to lower the level if the signal is saturated */
684 if (saturated == 1) {
685 /* Lower the recording level
686 * Rxx160_LP is adjusted down because it is so slow it could
687 * cause the AGC to make wrong decisions. */
688 /* stt->Rxx160_LPw32 *= 0.875; */
689 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 8) * 7;
690
691 stt->zeroCtrlMax = stt->micVol;
692
693 /* stt->micVol *= 0.903; */
694 tmp32 = inMicLevelTmp - stt->minLevel;
695 tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32));
696 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
697 if (stt->micVol > lastMicVol - 2) {
698 stt->micVol = lastMicVol - 2;
niklase@google.com470e71d2011-07-07 08:21:25 +0000699 }
minyuecac94aa2016-05-20 08:42:22 -0700700 inMicLevelTmp = stt->micVol;
niklase@google.com470e71d2011-07-07 08:21:25 +0000701
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000702#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -0700703 fprintf(stt->fpt,
704 "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
705 stt->fcount, stt->micVol);
niklase@google.com470e71d2011-07-07 08:21:25 +0000706#endif
707
minyuecac94aa2016-05-20 08:42:22 -0700708 if (stt->micVol < stt->minOutput) {
709 *saturationWarning = 1;
710 }
711
712 /* Reset counter for decrease of volume level to avoid
713 * decreasing too much. The saturation control can still
714 * lower the level if needed. */
715 stt->msTooHigh = -100;
716
717 /* Enable the control mechanism to ensure that our measure,
718 * Rxx160_LP, is in the correct range. This must be done since
719 * the measure is very slow. */
720 stt->activeSpeech = 0;
721 stt->Rxx16_LPw32Max = 0;
722
723 /* Reset to initial values */
724 stt->msecSpeechInnerChange = kMsecSpeechInner;
725 stt->msecSpeechOuterChange = kMsecSpeechOuter;
726 stt->changeToSlowMode = 0;
727
728 stt->muteGuardMs = 0;
729
730 stt->upperLimit = stt->startUpperLimit;
731 stt->lowerLimit = stt->startLowerLimit;
732#ifdef MIC_LEVEL_FEEDBACK
733// stt->numBlocksMicLvlSat = 0;
734#endif
735 }
736
737 /* Check if the input speech is zero. If so the mic volume
738 * is increased. On some computers the input is zero up as high
739 * level as 17% */
740 WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
741
742 /* Check if the near end speaker is inactive.
743 * If that is the case the VAD threshold is
744 * increased since the VAD speech model gets
745 * more sensitive to any sound after a long
746 * silence.
747 */
748 WebRtcAgc_SpeakerInactiveCtrl(stt);
749
750 for (i = 0; i < 5; i++) {
751 /* Computed on blocks of 16 samples */
752
753 Rxx16w32 = stt->Rxx16w32_array[0][i];
754
755 /* Rxx160w32 in Q(-7) */
756 tmp32 = (Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos]) >> 3;
757 stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
758 stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
759
760 /* Circular buffer */
761 stt->Rxx16pos++;
762 if (stt->Rxx16pos == RXX_BUFFER_LEN) {
763 stt->Rxx16pos = 0;
764 }
765
766 /* Rxx16_LPw32 in Q(-4) */
767 tmp32 = (Rxx16w32 - stt->Rxx16_LPw32) >> kAlphaShortTerm;
768 stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
769
770 if (vadLogRatio > stt->vadThreshold) {
771 /* Speech detected! */
772
773 /* Check if Rxx160_LP is in the correct range. If
774 * it is too high/low then we set it to the maximum of
775 * Rxx16_LPw32 during the first 200ms of speech.
776 */
777 if (stt->activeSpeech < 250) {
778 stt->activeSpeech += 2;
779
780 if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max) {
781 stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
niklase@google.com470e71d2011-07-07 08:21:25 +0000782 }
minyuecac94aa2016-05-20 08:42:22 -0700783 } else if (stt->activeSpeech == 250) {
784 stt->activeSpeech += 2;
785 tmp32 = stt->Rxx16_LPw32Max >> 3;
786 stt->Rxx160_LPw32 = tmp32 * RXX_BUFFER_LEN;
787 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000788
minyuecac94aa2016-05-20 08:42:22 -0700789 tmp32 = (stt->Rxx160w32 - stt->Rxx160_LPw32) >> kAlphaLongTerm;
790 stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
niklase@google.com470e71d2011-07-07 08:21:25 +0000791
minyuecac94aa2016-05-20 08:42:22 -0700792 if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit) {
793 stt->msTooHigh += 2;
794 stt->msTooLow = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000795 stt->changeToSlowMode = 0;
796
minyuecac94aa2016-05-20 08:42:22 -0700797 if (stt->msTooHigh > stt->msecSpeechOuterChange) {
798 stt->msTooHigh = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000799
minyuecac94aa2016-05-20 08:42:22 -0700800 /* Lower the recording level */
801 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
802 tmp32 = stt->Rxx160_LPw32 >> 6;
803 stt->Rxx160_LPw32 = tmp32 * 53;
804
805 /* Reduce the max gain to avoid excessive oscillation
806 * (but never drop below the maximum analog level).
807 */
808 stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
809 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
810
811 stt->zeroCtrlMax = stt->micVol;
812
813 /* 0.95 in Q15 */
814 tmp32 = inMicLevelTmp - stt->minLevel;
815 tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32));
816 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
817 if (stt->micVol > lastMicVol - 1) {
818 stt->micVol = lastMicVol - 1;
819 }
820 inMicLevelTmp = stt->micVol;
821
822 /* Enable the control mechanism to ensure that our measure,
823 * Rxx160_LP, is in the correct range.
824 */
825 stt->activeSpeech = 0;
826 stt->Rxx16_LPw32Max = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000827#ifdef MIC_LEVEL_FEEDBACK
minyuecac94aa2016-05-20 08:42:22 -0700828// stt->numBlocksMicLvlSat = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000829#endif
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000830#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -0700831 fprintf(stt->fpt,
832 "\tAGC->ProcessAnalog, frame %d: measure >"
833 " 2ndUpperLim, micVol = %d, maxLevel = %d\n",
834 stt->fcount, stt->micVol, stt->maxLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000835#endif
836 }
minyuecac94aa2016-05-20 08:42:22 -0700837 } else if (stt->Rxx160_LPw32 > stt->upperLimit) {
838 stt->msTooHigh += 2;
839 stt->msTooLow = 0;
840 stt->changeToSlowMode = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000841
minyuecac94aa2016-05-20 08:42:22 -0700842 if (stt->msTooHigh > stt->msecSpeechInnerChange) {
843 /* Lower the recording level */
844 stt->msTooHigh = 0;
845 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
846 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 53;
847
848 /* Reduce the max gain to avoid excessive oscillation
849 * (but never drop below the maximum analog level).
850 */
851 stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
852 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
853
854 stt->zeroCtrlMax = stt->micVol;
855
856 /* 0.965 in Q15 */
857 tmp32 = inMicLevelTmp - stt->minLevel;
858 tmpU32 =
859 WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel));
860 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
861 if (stt->micVol > lastMicVol - 1) {
862 stt->micVol = lastMicVol - 1;
863 }
864 inMicLevelTmp = stt->micVol;
865
866#ifdef MIC_LEVEL_FEEDBACK
867// stt->numBlocksMicLvlSat = 0;
868#endif
869#ifdef WEBRTC_AGC_DEBUG_DUMP
870 fprintf(stt->fpt,
871 "\tAGC->ProcessAnalog, frame %d: measure >"
872 " UpperLim, micVol = %d, maxLevel = %d\n",
873 stt->fcount, stt->micVol, stt->maxLevel);
874#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000875 }
minyuecac94aa2016-05-20 08:42:22 -0700876 } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit) {
877 stt->msTooHigh = 0;
878 stt->changeToSlowMode = 0;
879 stt->msTooLow += 2;
880
881 if (stt->msTooLow > stt->msecSpeechOuterChange) {
882 /* Raise the recording level */
883 int16_t index, weightFIX;
884 int16_t volNormFIX = 16384; // =1 in Q14.
885
886 stt->msTooLow = 0;
887
888 /* Normalize the volume level */
889 tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
890 if (stt->maxInit != stt->minLevel) {
891 volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
892 }
893
894 /* Find correct curve */
895 WebRtcAgc_ExpCurve(volNormFIX, &index);
896
897 /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05
898 */
899 weightFIX =
900 kOffset1[index] - (int16_t)((kSlope1[index] * volNormFIX) >> 13);
901
902 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
903 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
904
905 tmp32 = inMicLevelTmp - stt->minLevel;
906 tmpU32 =
907 ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
908 stt->micVol = (tmpU32 >> 14) + stt->minLevel;
909 if (stt->micVol < lastMicVol + 2) {
910 stt->micVol = lastMicVol + 2;
911 }
912
913 inMicLevelTmp = stt->micVol;
914
915#ifdef MIC_LEVEL_FEEDBACK
916 /* Count ms in level saturation */
917 // if (stt->micVol > stt->maxAnalog) {
918 if (stt->micVol > 150) {
919 /* mic level is saturated */
920 stt->numBlocksMicLvlSat++;
921 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
922 }
923#endif
924#ifdef WEBRTC_AGC_DEBUG_DUMP
925 fprintf(stt->fpt,
926 "\tAGC->ProcessAnalog, frame %d: measure <"
927 " 2ndLowerLim, micVol = %d\n",
928 stt->fcount, stt->micVol);
929#endif
930 }
931 } else if (stt->Rxx160_LPw32 < stt->lowerLimit) {
932 stt->msTooHigh = 0;
933 stt->changeToSlowMode = 0;
934 stt->msTooLow += 2;
935
936 if (stt->msTooLow > stt->msecSpeechInnerChange) {
937 /* Raise the recording level */
938 int16_t index, weightFIX;
939 int16_t volNormFIX = 16384; // =1 in Q14.
940
941 stt->msTooLow = 0;
942
943 /* Normalize the volume level */
944 tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
945 if (stt->maxInit != stt->minLevel) {
946 volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
947 }
948
949 /* Find correct curve */
950 WebRtcAgc_ExpCurve(volNormFIX, &index);
951
952 /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1
953 */
954 weightFIX =
955 kOffset2[index] - (int16_t)((kSlope2[index] * volNormFIX) >> 13);
956
957 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
958 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
959
960 tmp32 = inMicLevelTmp - stt->minLevel;
961 tmpU32 =
962 ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
963 stt->micVol = (tmpU32 >> 14) + stt->minLevel;
964 if (stt->micVol < lastMicVol + 1) {
965 stt->micVol = lastMicVol + 1;
966 }
967
968 inMicLevelTmp = stt->micVol;
969
970#ifdef MIC_LEVEL_FEEDBACK
971 /* Count ms in level saturation */
972 // if (stt->micVol > stt->maxAnalog) {
973 if (stt->micVol > 150) {
974 /* mic level is saturated */
975 stt->numBlocksMicLvlSat++;
976 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
977 }
978#endif
979#ifdef WEBRTC_AGC_DEBUG_DUMP
980 fprintf(stt->fpt,
981 "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol "
982 "= %d\n",
983 stt->fcount, stt->micVol);
984#endif
985 }
986 } else {
987 /* The signal is inside the desired range which is:
988 * lowerLimit < Rxx160_LP/640 < upperLimit
989 */
990 if (stt->changeToSlowMode > 4000) {
991 stt->msecSpeechInnerChange = 1000;
992 stt->msecSpeechOuterChange = 500;
993 stt->upperLimit = stt->upperPrimaryLimit;
994 stt->lowerLimit = stt->lowerPrimaryLimit;
995 } else {
996 stt->changeToSlowMode += 2; // in milliseconds
997 }
998 stt->msTooLow = 0;
999 stt->msTooHigh = 0;
1000
1001 stt->micVol = inMicLevelTmp;
1002 }
1003#ifdef MIC_LEVEL_FEEDBACK
1004 if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET) {
1005 stt->micLvlSat = 1;
1006 fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel,
1007 stt->targetIdx);
1008 WebRtcAgc_UpdateAgcThresholds(stt);
1009 WebRtcAgc_CalculateGainTable(
1010 &(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
1011 stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget);
1012 stt->numBlocksMicLvlSat = 0;
1013 stt->micLvlSat = 0;
1014 fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset);
1015 fprintf(stderr, "target after = %d (%d)\n", stt->analogTargetLevel,
1016 stt->targetIdx);
1017 }
1018#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001019 }
minyuecac94aa2016-05-20 08:42:22 -07001020 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001021
minyuecac94aa2016-05-20 08:42:22 -07001022 /* Ensure gain is not increased in presence of echo or after a mute event
1023 * (but allow the zeroCtrl() increase on the frame of a mute detection).
1024 */
1025 if (echo == 1 ||
1026 (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs)) {
1027 if (stt->micVol > lastMicVol) {
1028 stt->micVol = lastMicVol;
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 }
minyuecac94aa2016-05-20 08:42:22 -07001030 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001031
minyuecac94aa2016-05-20 08:42:22 -07001032 /* limit the gain */
1033 if (stt->micVol > stt->maxLevel) {
1034 stt->micVol = stt->maxLevel;
1035 } else if (stt->micVol < stt->minOutput) {
1036 stt->micVol = stt->minOutput;
1037 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001038
minyuecac94aa2016-05-20 08:42:22 -07001039 *outMicLevel = WEBRTC_SPL_MIN(stt->micVol, stt->maxAnalog) >> stt->scale;
1040
1041 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001042}
1043
minyuecac94aa2016-05-20 08:42:22 -07001044int WebRtcAgc_Process(void* agcInst,
1045 const int16_t* const* in_near,
1046 size_t num_bands,
1047 size_t samples,
1048 int16_t* const* out,
1049 int32_t inMicLevel,
1050 int32_t* outMicLevel,
1051 int16_t echo,
1052 uint8_t* saturationWarning) {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +00001053 LegacyAgc* stt;
niklase@google.com470e71d2011-07-07 08:21:25 +00001054
pbos@webrtc.orge468bc92014-12-18 09:11:33 +00001055 stt = (LegacyAgc*)agcInst;
niklase@google.com470e71d2011-07-07 08:21:25 +00001056
minyuecac94aa2016-05-20 08:42:22 -07001057 //
1058 if (stt == NULL) {
1059 return -1;
1060 }
1061 //
1062
1063 if (stt->fs == 8000) {
1064 if (samples != 80) {
1065 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001066 }
minyuecac94aa2016-05-20 08:42:22 -07001067 } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) {
1068 if (samples != 160) {
1069 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001070 }
minyuecac94aa2016-05-20 08:42:22 -07001071 } else {
1072 return -1;
1073 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001074
minyuecac94aa2016-05-20 08:42:22 -07001075 *saturationWarning = 0;
1076 // TODO(minyue): PUT IN RANGE CHECKING FOR INPUT LEVELS
1077 *outMicLevel = inMicLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001078
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001079#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -07001080 stt->fcount++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001081#endif
1082
minyuecac94aa2016-05-20 08:42:22 -07001083 if (WebRtcAgc_ProcessDigital(&stt->digitalAgc, in_near, num_bands, out,
1084 stt->fs, stt->lowLevelSignal) == -1) {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001085#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -07001086 fprintf(stt->fpt, "AGC->Process, frame %d: Error from DigAGC\n\n",
1087 stt->fcount);
niklase@google.com470e71d2011-07-07 08:21:25 +00001088#endif
minyuecac94aa2016-05-20 08:42:22 -07001089 return -1;
1090 }
1091 if (stt->agcMode < kAgcModeFixedDigital &&
1092 (stt->lowLevelSignal == 0 || stt->agcMode != kAgcModeAdaptiveDigital)) {
1093 if (WebRtcAgc_ProcessAnalog(agcInst, inMicLevel, outMicLevel,
1094 stt->vadMic.logRatio, echo,
1095 saturationWarning) == -1) {
1096 return -1;
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001097 }
minyuecac94aa2016-05-20 08:42:22 -07001098 }
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001099#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -07001100 fprintf(stt->agcLog, "%5d\t%d\t%d\t%d\t%d\n", stt->fcount, inMicLevel,
1101 *outMicLevel, stt->maxLevel, stt->micVol);
niklase@google.com470e71d2011-07-07 08:21:25 +00001102#endif
1103
minyuecac94aa2016-05-20 08:42:22 -07001104 /* update queue */
1105 if (stt->inQueue > 1) {
1106 memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t));
1107 memcpy(stt->Rxx16w32_array[0], stt->Rxx16w32_array[1], 5 * sizeof(int32_t));
1108 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001109
minyuecac94aa2016-05-20 08:42:22 -07001110 if (stt->inQueue > 0) {
1111 stt->inQueue--;
1112 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001113
minyuecac94aa2016-05-20 08:42:22 -07001114 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001115}
1116
pbos@webrtc.orge468bc92014-12-18 09:11:33 +00001117int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) {
1118 LegacyAgc* stt;
1119 stt = (LegacyAgc*)agcInst;
niklase@google.com470e71d2011-07-07 08:21:25 +00001120
minyuecac94aa2016-05-20 08:42:22 -07001121 if (stt == NULL) {
1122 return -1;
1123 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001124
minyuecac94aa2016-05-20 08:42:22 -07001125 if (stt->initFlag != kInitCheck) {
1126 stt->lastError = AGC_UNINITIALIZED_ERROR;
1127 return -1;
1128 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001129
minyuecac94aa2016-05-20 08:42:22 -07001130 if (agcConfig.limiterEnable != kAgcFalse &&
1131 agcConfig.limiterEnable != kAgcTrue) {
1132 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1133 return -1;
1134 }
1135 stt->limiterEnable = agcConfig.limiterEnable;
1136 stt->compressionGaindB = agcConfig.compressionGaindB;
1137 if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31)) {
1138 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1139 return -1;
1140 }
1141 stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
niklase@google.com470e71d2011-07-07 08:21:25 +00001142
minyuecac94aa2016-05-20 08:42:22 -07001143 if (stt->agcMode == kAgcModeFixedDigital) {
1144 /* Adjust for different parameter interpretation in FixedDigital mode */
1145 stt->compressionGaindB += agcConfig.targetLevelDbfs;
1146 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001147
minyuecac94aa2016-05-20 08:42:22 -07001148 /* Update threshold levels for analog adaptation */
1149 WebRtcAgc_UpdateAgcThresholds(stt);
niklase@google.com470e71d2011-07-07 08:21:25 +00001150
minyuecac94aa2016-05-20 08:42:22 -07001151 /* Recalculate gain table */
1152 if (WebRtcAgc_CalculateGainTable(
1153 &(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
1154 stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1) {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001155#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -07001156 fprintf(stt->fpt, "AGC->set_config, frame %d: Error from calcGainTable\n\n",
1157 stt->fcount);
niklase@google.com470e71d2011-07-07 08:21:25 +00001158#endif
minyuecac94aa2016-05-20 08:42:22 -07001159 return -1;
1160 }
1161 /* Store the config in a WebRtcAgcConfig */
1162 stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
1163 stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
1164 stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
niklase@google.com470e71d2011-07-07 08:21:25 +00001165
minyuecac94aa2016-05-20 08:42:22 -07001166 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001167}
1168
pbos@webrtc.orge468bc92014-12-18 09:11:33 +00001169int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config) {
1170 LegacyAgc* stt;
1171 stt = (LegacyAgc*)agcInst;
niklase@google.com470e71d2011-07-07 08:21:25 +00001172
minyuecac94aa2016-05-20 08:42:22 -07001173 if (stt == NULL) {
1174 return -1;
1175 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001176
minyuecac94aa2016-05-20 08:42:22 -07001177 if (config == NULL) {
1178 stt->lastError = AGC_NULL_POINTER_ERROR;
1179 return -1;
1180 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001181
minyuecac94aa2016-05-20 08:42:22 -07001182 if (stt->initFlag != kInitCheck) {
1183 stt->lastError = AGC_UNINITIALIZED_ERROR;
1184 return -1;
1185 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001186
minyuecac94aa2016-05-20 08:42:22 -07001187 config->limiterEnable = stt->usedConfig.limiterEnable;
1188 config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
1189 config->compressionGaindB = stt->usedConfig.compressionGaindB;
niklase@google.com470e71d2011-07-07 08:21:25 +00001190
minyuecac94aa2016-05-20 08:42:22 -07001191 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001192}
1193
Bjorn Volcker9345e862015-06-10 21:43:36 +02001194void* WebRtcAgc_Create() {
1195 LegacyAgc* stt = malloc(sizeof(LegacyAgc));
niklase@google.com470e71d2011-07-07 08:21:25 +00001196
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001197#ifdef WEBRTC_AGC_DEBUG_DUMP
Bjorn Volcker9345e862015-06-10 21:43:36 +02001198 stt->fpt = fopen("./agc_test_log.txt", "wt");
1199 stt->agcLog = fopen("./agc_debug_log.txt", "wt");
1200 stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
niklase@google.com470e71d2011-07-07 08:21:25 +00001201#endif
1202
Bjorn Volcker9345e862015-06-10 21:43:36 +02001203 stt->initFlag = 0;
1204 stt->lastError = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001205
Bjorn Volcker9345e862015-06-10 21:43:36 +02001206 return stt;
niklase@google.com470e71d2011-07-07 08:21:25 +00001207}
1208
minyuecac94aa2016-05-20 08:42:22 -07001209void WebRtcAgc_Free(void* state) {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +00001210 LegacyAgc* stt;
niklase@google.com470e71d2011-07-07 08:21:25 +00001211
pbos@webrtc.orge468bc92014-12-18 09:11:33 +00001212 stt = (LegacyAgc*)state;
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001213#ifdef WEBRTC_AGC_DEBUG_DUMP
Bjorn Volckerf6a99e62015-04-10 07:56:57 +02001214 fclose(stt->fpt);
1215 fclose(stt->agcLog);
1216 fclose(stt->digitalAgc.logFile);
niklase@google.com470e71d2011-07-07 08:21:25 +00001217#endif
Bjorn Volckerf6a99e62015-04-10 07:56:57 +02001218 free(stt);
niklase@google.com470e71d2011-07-07 08:21:25 +00001219}
1220
1221/* minLevel - Minimum volume level
1222 * maxLevel - Maximum volume level
1223 */
minyuecac94aa2016-05-20 08:42:22 -07001224int WebRtcAgc_Init(void* agcInst,
1225 int32_t minLevel,
1226 int32_t maxLevel,
1227 int16_t agcMode,
1228 uint32_t fs) {
1229 int32_t max_add, tmp32;
1230 int16_t i;
1231 int tmpNorm;
1232 LegacyAgc* stt;
niklase@google.com470e71d2011-07-07 08:21:25 +00001233
minyuecac94aa2016-05-20 08:42:22 -07001234 /* typecast state pointer */
1235 stt = (LegacyAgc*)agcInst;
niklase@google.com470e71d2011-07-07 08:21:25 +00001236
minyuecac94aa2016-05-20 08:42:22 -07001237 if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0) {
1238 stt->lastError = AGC_UNINITIALIZED_ERROR;
1239 return -1;
1240 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001241
minyuecac94aa2016-05-20 08:42:22 -07001242 /* Analog AGC variables */
1243 stt->envSum = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001244
minyuecac94aa2016-05-20 08:42:22 -07001245/* mode = 0 - Only saturation protection
1246 * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3
1247 * dBOv)]
1248 * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3
1249 * dBOv)]
1250 * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
1251 */
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001252#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -07001253 stt->fcount = 0;
1254 fprintf(stt->fpt, "AGC->Init\n");
niklase@google.com470e71d2011-07-07 08:21:25 +00001255#endif
minyuecac94aa2016-05-20 08:42:22 -07001256 if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital) {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001257#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -07001258 fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
niklase@google.com470e71d2011-07-07 08:21:25 +00001259#endif
minyuecac94aa2016-05-20 08:42:22 -07001260 return -1;
1261 }
1262 stt->agcMode = agcMode;
1263 stt->fs = fs;
niklase@google.com470e71d2011-07-07 08:21:25 +00001264
minyuecac94aa2016-05-20 08:42:22 -07001265 /* initialize input VAD */
1266 WebRtcAgc_InitVad(&stt->vadMic);
niklase@google.com470e71d2011-07-07 08:21:25 +00001267
minyuecac94aa2016-05-20 08:42:22 -07001268 /* If the volume range is smaller than 0-256 then
1269 * the levels are shifted up to Q8-domain */
1270 tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
1271 stt->scale = tmpNorm - 23;
1272 if (stt->scale < 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001273 stt->scale = 0;
minyuecac94aa2016-05-20 08:42:22 -07001274 }
1275 // TODO(bjornv): Investigate if we really need to scale up a small range now
1276 // when we have
1277 // a guard against zero-increments. For now, we do not support scale up (scale
1278 // = 0).
1279 stt->scale = 0;
1280 maxLevel <<= stt->scale;
1281 minLevel <<= stt->scale;
niklase@google.com470e71d2011-07-07 08:21:25 +00001282
minyuecac94aa2016-05-20 08:42:22 -07001283 /* Make minLevel and maxLevel static in AdaptiveDigital */
1284 if (stt->agcMode == kAgcModeAdaptiveDigital) {
1285 minLevel = 0;
1286 maxLevel = 255;
1287 stt->scale = 0;
1288 }
1289 /* The maximum supplemental volume range is based on a vague idea
1290 * of how much lower the gain will be than the real analog gain. */
1291 max_add = (maxLevel - minLevel) / 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001292
minyuecac94aa2016-05-20 08:42:22 -07001293 /* Minimum/maximum volume level that can be set */
1294 stt->minLevel = minLevel;
1295 stt->maxAnalog = maxLevel;
1296 stt->maxLevel = maxLevel + max_add;
1297 stt->maxInit = stt->maxLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001298
minyuecac94aa2016-05-20 08:42:22 -07001299 stt->zeroCtrlMax = stt->maxAnalog;
1300 stt->lastInMicLevel = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001301
minyuecac94aa2016-05-20 08:42:22 -07001302 /* Initialize micVol parameter */
1303 stt->micVol = stt->maxAnalog;
1304 if (stt->agcMode == kAgcModeAdaptiveDigital) {
1305 stt->micVol = 127; /* Mid-point of mic level */
1306 }
1307 stt->micRef = stt->micVol;
1308 stt->micGainIdx = 127;
niklase@google.com470e71d2011-07-07 08:21:25 +00001309#ifdef MIC_LEVEL_FEEDBACK
minyuecac94aa2016-05-20 08:42:22 -07001310 stt->numBlocksMicLvlSat = 0;
1311 stt->micLvlSat = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001312#endif
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001313#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -07001314 fprintf(stt->fpt, "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
1315 stt->minLevel, stt->maxAnalog, stt->maxLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001316#endif
1317
minyuecac94aa2016-05-20 08:42:22 -07001318 /* Minimum output volume is 4% higher than the available lowest volume level
1319 */
1320 tmp32 = ((stt->maxLevel - stt->minLevel) * 10) >> 8;
1321 stt->minOutput = (stt->minLevel + tmp32);
niklase@google.com470e71d2011-07-07 08:21:25 +00001322
minyuecac94aa2016-05-20 08:42:22 -07001323 stt->msTooLow = 0;
1324 stt->msTooHigh = 0;
1325 stt->changeToSlowMode = 0;
1326 stt->firstCall = 0;
1327 stt->msZero = 0;
1328 stt->muteGuardMs = 0;
1329 stt->gainTableIdx = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001330
minyuecac94aa2016-05-20 08:42:22 -07001331 stt->msecSpeechInnerChange = kMsecSpeechInner;
1332 stt->msecSpeechOuterChange = kMsecSpeechOuter;
niklase@google.com470e71d2011-07-07 08:21:25 +00001333
minyuecac94aa2016-05-20 08:42:22 -07001334 stt->activeSpeech = 0;
1335 stt->Rxx16_LPw32Max = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001336
minyuecac94aa2016-05-20 08:42:22 -07001337 stt->vadThreshold = kNormalVadThreshold;
1338 stt->inActive = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001339
minyuecac94aa2016-05-20 08:42:22 -07001340 for (i = 0; i < RXX_BUFFER_LEN; i++) {
1341 stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
1342 }
1343 stt->Rxx160w32 =
1344 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
niklase@google.com470e71d2011-07-07 08:21:25 +00001345
minyuecac94aa2016-05-20 08:42:22 -07001346 stt->Rxx16pos = 0;
1347 stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */
niklase@google.com470e71d2011-07-07 08:21:25 +00001348
minyuecac94aa2016-05-20 08:42:22 -07001349 for (i = 0; i < 5; i++) {
1350 stt->Rxx16w32_array[0][i] = 0;
1351 }
1352 for (i = 0; i < 10; i++) {
1353 stt->env[0][i] = 0;
1354 stt->env[1][i] = 0;
1355 }
1356 stt->inQueue = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001357
1358#ifdef MIC_LEVEL_FEEDBACK
minyuecac94aa2016-05-20 08:42:22 -07001359 stt->targetIdxOffset = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001360#endif
1361
minyuecac94aa2016-05-20 08:42:22 -07001362 WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
niklase@google.com470e71d2011-07-07 08:21:25 +00001363
minyuecac94aa2016-05-20 08:42:22 -07001364 stt->initFlag = kInitCheck;
1365 // Default config settings.
1366 stt->defaultConfig.limiterEnable = kAgcTrue;
1367 stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
1368 stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
niklase@google.com470e71d2011-07-07 08:21:25 +00001369
minyuecac94aa2016-05-20 08:42:22 -07001370 if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1) {
1371 stt->lastError = AGC_UNSPECIFIED_ERROR;
1372 return -1;
1373 }
1374 stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value
niklase@google.com470e71d2011-07-07 08:21:25 +00001375
minyuecac94aa2016-05-20 08:42:22 -07001376 stt->lowLevelSignal = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001377
minyuecac94aa2016-05-20 08:42:22 -07001378 /* Only positive values are allowed that are not too large */
1379 if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000)) {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001380#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -07001381 fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
niklase@google.com470e71d2011-07-07 08:21:25 +00001382#endif
minyuecac94aa2016-05-20 08:42:22 -07001383 return -1;
1384 } else {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001385#ifdef WEBRTC_AGC_DEBUG_DUMP
minyuecac94aa2016-05-20 08:42:22 -07001386 fprintf(stt->fpt, "\n");
niklase@google.com470e71d2011-07-07 08:21:25 +00001387#endif
minyuecac94aa2016-05-20 08:42:22 -07001388 return 0;
1389 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001390}