blob: 4f110cc2092296036802bf8ca42dd5412182eee7 [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
20#include <assert.h>
21#include <stdlib.h>
22#ifdef AGC_DEBUG //test log
23#include <stdio.h>
24#endif
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000025#include "webrtc/modules/audio_processing/agc/analog_agc.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000026
27/* The slope of in Q13*/
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000028static const int16_t kSlope1[8] = {21793, 12517, 7189, 4129, 2372, 1362, 472, 78};
niklase@google.com470e71d2011-07-07 08:21:25 +000029
30/* The offset in Q14 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000031static const int16_t kOffset1[8] = {25395, 23911, 22206, 20737, 19612, 18805, 17951,
niklase@google.com470e71d2011-07-07 08:21:25 +000032 17367};
33
34/* The slope of in Q13*/
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000035static const int16_t kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337};
niklase@google.com470e71d2011-07-07 08:21:25 +000036
37/* The offset in Q14 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000038static const int16_t kOffset2[8] = {18432, 18379, 18290, 18177, 18052, 17920, 17670,
niklase@google.com470e71d2011-07-07 08:21:25 +000039 17286};
40
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000041static const int16_t kMuteGuardTimeMs = 8000;
42static const int16_t kInitCheck = 42;
niklase@google.com470e71d2011-07-07 08:21:25 +000043
44/* Default settings if config is not used */
45#define AGC_DEFAULT_TARGET_LEVEL 3
46#define AGC_DEFAULT_COMP_GAIN 9
47/* This is the target level for the analog part in ENV scale. To convert to RMS scale you
48 * have to add OFFSET_ENV_TO_RMS.
49 */
50#define ANALOG_TARGET_LEVEL 11
51#define ANALOG_TARGET_LEVEL_2 5 // ANALOG_TARGET_LEVEL / 2
52/* Offset between RMS scale (analog part) and ENV scale (digital part). This value actually
53 * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future replace it with
54 * a table.
55 */
56#define OFFSET_ENV_TO_RMS 9
57/* The reference input level at which the digital part gives an output of targetLevelDbfs
58 * (desired level) if we have no compression gain. This level should be set high enough not
59 * to compress the peaks due to the dynamics.
60 */
61#define DIGITAL_REF_AT_0_COMP_GAIN 4
62/* Speed of reference level decrease.
63 */
64#define DIFF_REF_TO_ANALOG 5
65
66#ifdef MIC_LEVEL_FEEDBACK
67#define NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET 7
68#endif
69/* Size of analog gain table */
70#define GAIN_TBL_LEN 32
71/* Matlab code:
72 * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12));
73 */
74/* Q12 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000075static const uint16_t kGainTableAnalog[GAIN_TBL_LEN] = {4096, 4251, 4412, 4579, 4752,
niklase@google.com470e71d2011-07-07 08:21:25 +000076 4932, 5118, 5312, 5513, 5722, 5938, 6163, 6396, 6638, 6889, 7150, 7420, 7701, 7992,
77 8295, 8609, 8934, 9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953};
78
79/* Gain/Suppression tables for virtual Mic (in Q10) */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000080static const uint16_t kGainTableVirtualMic[128] = {1052, 1081, 1110, 1141, 1172, 1204,
niklase@google.com470e71d2011-07-07 08:21:25 +000081 1237, 1271, 1305, 1341, 1378, 1416, 1454, 1494, 1535, 1577, 1620, 1664, 1710, 1757,
82 1805, 1854, 1905, 1957, 2010, 2065, 2122, 2180, 2239, 2301, 2364, 2428, 2495, 2563,
83 2633, 2705, 2779, 2855, 2933, 3013, 3096, 3180, 3267, 3357, 3449, 3543, 3640, 3739,
84 3842, 3947, 4055, 4166, 4280, 4397, 4517, 4640, 4767, 4898, 5032, 5169, 5311, 5456,
85 5605, 5758, 5916, 6078, 6244, 6415, 6590, 6770, 6956, 7146, 7341, 7542, 7748, 7960,
86 8178, 8402, 8631, 8867, 9110, 9359, 9615, 9878, 10148, 10426, 10711, 11004, 11305,
87 11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807, 15212, 15628,
88 16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923, 20468, 21028, 21603,
89 22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808, 27541, 28295, 29069, 29864,
90 30681, 31520, 32382};
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000091static const uint16_t kSuppressionTableVirtualMic[128] = {1024, 1006, 988, 970, 952,
niklase@google.com470e71d2011-07-07 08:21:25 +000092 935, 918, 902, 886, 870, 854, 839, 824, 809, 794, 780, 766, 752, 739, 726, 713, 700,
93 687, 675, 663, 651, 639, 628, 616, 605, 594, 584, 573, 563, 553, 543, 533, 524, 514,
94 505, 496, 487, 478, 470, 461, 453, 445, 437, 429, 421, 414, 406, 399, 392, 385, 378,
95 371, 364, 358, 351, 345, 339, 333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278,
96 273, 268, 263, 258, 254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204,
97 200, 197, 193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155, 153, 150,
98 147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118, 116, 114, 112, 110,
99 108, 106, 104, 102};
100
101/* Table for target energy levels. Values in Q(-7)
102 * Matlab code
103 * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n', round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */
104
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000105static const int32_t kTargetLevelTable[64] = {134209536, 106606424, 84680493, 67264106,
niklase@google.com470e71d2011-07-07 08:21:25 +0000106 53429779, 42440782, 33711911, 26778323, 21270778, 16895980, 13420954, 10660642,
107 8468049, 6726411, 5342978, 4244078, 3371191, 2677832, 2127078, 1689598, 1342095,
108 1066064, 846805, 672641, 534298, 424408, 337119, 267783, 212708, 168960, 134210,
109 106606, 84680, 67264, 53430, 42441, 33712, 26778, 21271, 16896, 13421, 10661, 8468,
110 6726, 5343, 4244, 3371, 2678, 2127, 1690, 1342, 1066, 847, 673, 534, 424, 337, 268,
111 213, 169, 134, 107, 85, 67};
112
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000113int WebRtcAgc_AddMic(void *state, int16_t *in_mic, int16_t *in_mic_H,
114 int16_t samples)
niklase@google.com470e71d2011-07-07 08:21:25 +0000115{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000116 int32_t nrg, max_nrg, sample, tmp32;
117 int32_t *ptr;
118 uint16_t targetGainIdx, gain;
119 int16_t i, n, L, M, subFrames, tmp16, tmp_speech[16];
niklase@google.com470e71d2011-07-07 08:21:25 +0000120 Agc_t *stt;
121 stt = (Agc_t *)state;
122
123 //default/initial values corresponding to 10ms for wb and swb
124 M = 10;
125 L = 16;
126 subFrames = 160;
127
128 if (stt->fs == 8000)
129 {
130 if (samples == 80)
131 {
132 subFrames = 80;
133 M = 10;
134 L = 8;
135 } else if (samples == 160)
136 {
137 subFrames = 80;
138 M = 20;
139 L = 8;
140 } else
141 {
142#ifdef AGC_DEBUG //test log
143 fprintf(stt->fpt,
144 "AGC->add_mic, frame %d: Invalid number of samples\n\n",
145 (stt->fcount + 1));
146#endif
147 return -1;
148 }
149 } else if (stt->fs == 16000)
150 {
151 if (samples == 160)
152 {
153 subFrames = 160;
154 M = 10;
155 L = 16;
156 } else if (samples == 320)
157 {
158 subFrames = 160;
159 M = 20;
160 L = 16;
161 } else
162 {
163#ifdef AGC_DEBUG //test log
164 fprintf(stt->fpt,
165 "AGC->add_mic, frame %d: Invalid number of samples\n\n",
166 (stt->fcount + 1));
167#endif
168 return -1;
169 }
170 } else if (stt->fs == 32000)
171 {
172 /* SWB is processed as 160 sample for L and H bands */
173 if (samples == 160)
174 {
175 subFrames = 160;
176 M = 10;
177 L = 16;
178 } else
179 {
180#ifdef AGC_DEBUG
181 fprintf(stt->fpt,
182 "AGC->add_mic, frame %d: Invalid sample rate\n\n",
183 (stt->fcount + 1));
184#endif
185 return -1;
186 }
187 }
188
189 /* Check for valid pointers based on sampling rate */
190 if ((stt->fs == 32000) && (in_mic_H == NULL))
191 {
192 return -1;
193 }
194 /* Check for valid pointer for low band */
195 if (in_mic == NULL)
196 {
197 return -1;
198 }
199
200 /* apply slowly varying digital gain */
201 if (stt->micVol > stt->maxAnalog)
202 {
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +0000203 /* |maxLevel| is strictly >= |micVol|, so this condition should be
204 * satisfied here, ensuring there is no divide-by-zero. */
205 assert(stt->maxLevel > stt->maxAnalog);
206
niklase@google.com470e71d2011-07-07 08:21:25 +0000207 /* Q1 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000208 tmp16 = (int16_t)(stt->micVol - stt->maxAnalog);
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 tmp32 = WEBRTC_SPL_MUL_16_16(GAIN_TBL_LEN - 1, tmp16);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000210 tmp16 = (int16_t)(stt->maxLevel - stt->maxAnalog);
211 targetGainIdx = (uint16_t)WEBRTC_SPL_DIV(tmp32, tmp16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000212 assert(targetGainIdx < GAIN_TBL_LEN);
213
214 /* Increment through the table towards the target gain.
215 * If micVol drops below maxAnalog, we allow the gain
216 * to be dropped immediately. */
217 if (stt->gainTableIdx < targetGainIdx)
218 {
219 stt->gainTableIdx++;
220 } else if (stt->gainTableIdx > targetGainIdx)
221 {
222 stt->gainTableIdx--;
223 }
224
225 /* Q12 */
226 gain = kGainTableAnalog[stt->gainTableIdx];
227
228 for (i = 0; i < samples; i++)
229 {
230 // For lower band
231 tmp32 = WEBRTC_SPL_MUL_16_U16(in_mic[i], gain);
232 sample = WEBRTC_SPL_RSHIFT_W32(tmp32, 12);
233 if (sample > 32767)
234 {
235 in_mic[i] = 32767;
236 } else if (sample < -32768)
237 {
238 in_mic[i] = -32768;
239 } else
240 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000241 in_mic[i] = (int16_t)sample;
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 }
243
244 // For higher band
245 if (stt->fs == 32000)
246 {
247 tmp32 = WEBRTC_SPL_MUL_16_U16(in_mic_H[i], gain);
248 sample = WEBRTC_SPL_RSHIFT_W32(tmp32, 12);
249 if (sample > 32767)
250 {
251 in_mic_H[i] = 32767;
252 } else if (sample < -32768)
253 {
254 in_mic_H[i] = -32768;
255 } else
256 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000257 in_mic_H[i] = (int16_t)sample;
niklase@google.com470e71d2011-07-07 08:21:25 +0000258 }
259 }
260 }
261 } else
262 {
263 stt->gainTableIdx = 0;
264 }
265
266 /* compute envelope */
267 if ((M == 10) && (stt->inQueue > 0))
268 {
269 ptr = stt->env[1];
270 } else
271 {
272 ptr = stt->env[0];
273 }
274
275 for (i = 0; i < M; i++)
276 {
277 /* iterate over samples */
278 max_nrg = 0;
279 for (n = 0; n < L; n++)
280 {
281 nrg = WEBRTC_SPL_MUL_16_16(in_mic[i * L + n], in_mic[i * L + n]);
282 if (nrg > max_nrg)
283 {
284 max_nrg = nrg;
285 }
286 }
287 ptr[i] = max_nrg;
288 }
289
290 /* compute energy */
291 if ((M == 10) && (stt->inQueue > 0))
292 {
293 ptr = stt->Rxx16w32_array[1];
294 } else
295 {
296 ptr = stt->Rxx16w32_array[0];
297 }
298
299 for (i = 0; i < WEBRTC_SPL_RSHIFT_W16(M, 1); i++)
300 {
301 if (stt->fs == 16000)
302 {
303 WebRtcSpl_DownsampleBy2(&in_mic[i * 32], 32, tmp_speech, stt->filterState);
304 } else
305 {
306 memcpy(tmp_speech, &in_mic[i * 16], 16 * sizeof(short));
307 }
308 /* Compute energy in blocks of 16 samples */
309 ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4);
310 }
311
312 /* update queue information */
313 if ((stt->inQueue == 0) && (M == 10))
314 {
315 stt->inQueue = 1;
316 } else
317 {
318 stt->inQueue = 2;
319 }
320
321 /* call VAD (use low band only) */
322 for (i = 0; i < samples; i += subFrames)
323 {
324 WebRtcAgc_ProcessVad(&stt->vadMic, &in_mic[i], subFrames);
325 }
326
327 return 0;
328}
329
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000330int WebRtcAgc_AddFarend(void *state, const int16_t *in_far, int16_t samples)
niklase@google.com470e71d2011-07-07 08:21:25 +0000331{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000332 int32_t errHandle = 0;
333 int16_t i, subFrames;
niklase@google.com470e71d2011-07-07 08:21:25 +0000334 Agc_t *stt;
335 stt = (Agc_t *)state;
336
337 if (stt == NULL)
338 {
339 return -1;
340 }
341
342 if (stt->fs == 8000)
343 {
344 if ((samples != 80) && (samples != 160))
345 {
346#ifdef AGC_DEBUG //test log
347 fprintf(stt->fpt,
348 "AGC->add_far_end, frame %d: Invalid number of samples\n\n",
349 stt->fcount);
350#endif
351 return -1;
352 }
353 subFrames = 80;
354 } else if (stt->fs == 16000)
355 {
356 if ((samples != 160) && (samples != 320))
357 {
358#ifdef AGC_DEBUG //test log
359 fprintf(stt->fpt,
360 "AGC->add_far_end, frame %d: Invalid number of samples\n\n",
361 stt->fcount);
362#endif
363 return -1;
364 }
365 subFrames = 160;
366 } else if (stt->fs == 32000)
367 {
368 if ((samples != 160) && (samples != 320))
369 {
370#ifdef AGC_DEBUG //test log
371 fprintf(stt->fpt,
372 "AGC->add_far_end, frame %d: Invalid number of samples\n\n",
373 stt->fcount);
374#endif
375 return -1;
376 }
377 subFrames = 160;
378 } else
379 {
380#ifdef AGC_DEBUG //test log
381 fprintf(stt->fpt,
382 "AGC->add_far_end, frame %d: Invalid sample rate\n\n",
383 stt->fcount + 1);
384#endif
385 return -1;
386 }
387
388 for (i = 0; i < samples; i += subFrames)
389 {
390 errHandle += WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, &in_far[i], subFrames);
391 }
392
393 return errHandle;
394}
395
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000396int WebRtcAgc_VirtualMic(void *agcInst, int16_t *in_near, int16_t *in_near_H,
397 int16_t samples, int32_t micLevelIn,
398 int32_t *micLevelOut)
niklase@google.com470e71d2011-07-07 08:21:25 +0000399{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000400 int32_t tmpFlt, micLevelTmp, gainIdx;
401 uint16_t gain;
402 int16_t ii;
niklase@google.com470e71d2011-07-07 08:21:25 +0000403 Agc_t *stt;
404
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000405 uint32_t nrg;
406 int16_t sampleCntr;
407 uint32_t frameNrg = 0;
408 uint32_t frameNrgLimit = 5500;
409 int16_t numZeroCrossing = 0;
410 const int16_t kZeroCrossingLowLim = 15;
411 const int16_t kZeroCrossingHighLim = 20;
niklase@google.com470e71d2011-07-07 08:21:25 +0000412
413 stt = (Agc_t *)agcInst;
414
415 /*
416 * Before applying gain decide if this is a low-level signal.
417 * The idea is that digital AGC will not adapt to low-level
418 * signals.
419 */
420 if (stt->fs != 8000)
421 {
422 frameNrgLimit = frameNrgLimit << 1;
423 }
424
425 frameNrg = WEBRTC_SPL_MUL_16_16(in_near[0], in_near[0]);
426 for (sampleCntr = 1; sampleCntr < samples; sampleCntr++)
427 {
428
429 // increment frame energy if it is less than the limit
430 // the correct value of the energy is not important
431 if (frameNrg < frameNrgLimit)
432 {
433 nrg = WEBRTC_SPL_MUL_16_16(in_near[sampleCntr], in_near[sampleCntr]);
434 frameNrg += nrg;
435 }
436
437 // Count the zero crossings
438 numZeroCrossing += ((in_near[sampleCntr] ^ in_near[sampleCntr - 1]) < 0);
439 }
440
441 if ((frameNrg < 500) || (numZeroCrossing <= 5))
442 {
443 stt->lowLevelSignal = 1;
444 } else if (numZeroCrossing <= kZeroCrossingLowLim)
445 {
446 stt->lowLevelSignal = 0;
447 } else if (frameNrg <= frameNrgLimit)
448 {
449 stt->lowLevelSignal = 1;
450 } else if (numZeroCrossing >= kZeroCrossingHighLim)
451 {
452 stt->lowLevelSignal = 1;
453 } else
454 {
455 stt->lowLevelSignal = 0;
456 }
457
458 micLevelTmp = WEBRTC_SPL_LSHIFT_W32(micLevelIn, stt->scale);
459 /* Set desired level */
460 gainIdx = stt->micVol;
461 if (stt->micVol > stt->maxAnalog)
462 {
463 gainIdx = stt->maxAnalog;
464 }
465 if (micLevelTmp != stt->micRef)
466 {
467 /* Something has happened with the physical level, restart. */
468 stt->micRef = micLevelTmp;
469 stt->micVol = 127;
470 *micLevelOut = 127;
471 stt->micGainIdx = 127;
472 gainIdx = 127;
473 }
474 /* Pre-process the signal to emulate the microphone level. */
475 /* Take one step at a time in the gain table. */
476 if (gainIdx > 127)
477 {
478 gain = kGainTableVirtualMic[gainIdx - 128];
479 } else
480 {
481 gain = kSuppressionTableVirtualMic[127 - gainIdx];
482 }
483 for (ii = 0; ii < samples; ii++)
484 {
485 tmpFlt = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_U16(in_near[ii], gain), 10);
486 if (tmpFlt > 32767)
487 {
488 tmpFlt = 32767;
489 gainIdx--;
490 if (gainIdx >= 127)
491 {
492 gain = kGainTableVirtualMic[gainIdx - 127];
493 } else
494 {
495 gain = kSuppressionTableVirtualMic[127 - gainIdx];
496 }
497 }
498 if (tmpFlt < -32768)
499 {
500 tmpFlt = -32768;
501 gainIdx--;
502 if (gainIdx >= 127)
503 {
504 gain = kGainTableVirtualMic[gainIdx - 127];
505 } else
506 {
507 gain = kSuppressionTableVirtualMic[127 - gainIdx];
508 }
509 }
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000510 in_near[ii] = (int16_t)tmpFlt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 if (stt->fs == 32000)
512 {
513 tmpFlt = WEBRTC_SPL_MUL_16_U16(in_near_H[ii], gain);
514 tmpFlt = WEBRTC_SPL_RSHIFT_W32(tmpFlt, 10);
515 if (tmpFlt > 32767)
516 {
517 tmpFlt = 32767;
518 }
519 if (tmpFlt < -32768)
520 {
521 tmpFlt = -32768;
522 }
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000523 in_near_H[ii] = (int16_t)tmpFlt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000524 }
525 }
526 /* Set the level we (finally) used */
527 stt->micGainIdx = gainIdx;
528// *micLevelOut = stt->micGainIdx;
529 *micLevelOut = WEBRTC_SPL_RSHIFT_W32(stt->micGainIdx, stt->scale);
530 /* Add to Mic as if it was the output from a true microphone */
531 if (WebRtcAgc_AddMic(agcInst, in_near, in_near_H, samples) != 0)
532 {
533 return -1;
534 }
535 return 0;
536}
537
538void WebRtcAgc_UpdateAgcThresholds(Agc_t *stt)
539{
540
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000541 int16_t tmp16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000542#ifdef MIC_LEVEL_FEEDBACK
543 int zeros;
544
545 if (stt->micLvlSat)
546 {
547 /* Lower the analog target level since we have reached its maximum */
548 zeros = WebRtcSpl_NormW32(stt->Rxx160_LPw32);
549 stt->targetIdxOffset = WEBRTC_SPL_RSHIFT_W16((3 * zeros) - stt->targetIdx - 2, 2);
550 }
551#endif
552
553 /* Set analog target level in envelope dBOv scale */
554 tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000555 tmp16 = WebRtcSpl_DivW32W16ResW16((int32_t)tmp16, ANALOG_TARGET_LEVEL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16;
557 if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN)
558 {
559 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN;
560 }
561 if (stt->agcMode == kAgcModeFixedDigital)
562 {
563 /* Adjust for different parameter interpretation in FixedDigital mode */
564 stt->analogTarget = stt->compressionGaindB;
565 }
566#ifdef MIC_LEVEL_FEEDBACK
567 stt->analogTarget += stt->targetIdxOffset;
568#endif
569 /* Since the offset between RMS and ENV is not constant, we should make this into a
570 * table, but for now, we'll stick with a constant, tuned for the chosen analog
571 * target level.
572 */
573 stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS;
574#ifdef MIC_LEVEL_FEEDBACK
575 stt->targetIdx += stt->targetIdxOffset;
576#endif
577 /* Analog adaptation limits */
578 /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */
579 stt->analogTargetLevel = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */
580 stt->startUpperLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 1];/* -19 dBov */
581 stt->startLowerLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 1];/* -21 dBov */
582 stt->upperPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 2];/* -18 dBov */
583 stt->lowerPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 2];/* -22 dBov */
584 stt->upperSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 5];/* -15 dBov */
585 stt->lowerSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 5];/* -25 dBov */
586 stt->upperLimit = stt->startUpperLimit;
587 stt->lowerLimit = stt->startLowerLimit;
588}
589
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000590void WebRtcAgc_SaturationCtrl(Agc_t *stt, uint8_t *saturated, int32_t *env)
niklase@google.com470e71d2011-07-07 08:21:25 +0000591{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000592 int16_t i, tmpW16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000593
594 /* Check if the signal is saturated */
595 for (i = 0; i < 10; i++)
596 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000597 tmpW16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(env[i], 20);
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 if (tmpW16 > 875)
599 {
600 stt->envSum += tmpW16;
601 }
602 }
603
604 if (stt->envSum > 25000)
605 {
606 *saturated = 1;
607 stt->envSum = 0;
608 }
609
610 /* stt->envSum *= 0.99; */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000611 stt->envSum = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(stt->envSum,
612 (int16_t)32440, 15);
niklase@google.com470e71d2011-07-07 08:21:25 +0000613}
614
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000615void WebRtcAgc_ZeroCtrl(Agc_t *stt, int32_t *inMicLevel, int32_t *env)
niklase@google.com470e71d2011-07-07 08:21:25 +0000616{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000617 int16_t i;
618 int32_t tmp32 = 0;
619 int32_t midVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000620
621 /* Is the input signal zero? */
622 for (i = 0; i < 10; i++)
623 {
624 tmp32 += env[i];
625 }
626
627 /* Each block is allowed to have a few non-zero
628 * samples.
629 */
630 if (tmp32 < 500)
631 {
632 stt->msZero += 10;
633 } else
634 {
635 stt->msZero = 0;
636 }
637
638 if (stt->muteGuardMs > 0)
639 {
640 stt->muteGuardMs -= 10;
641 }
642
643 if (stt->msZero > 500)
644 {
645 stt->msZero = 0;
646
647 /* Increase microphone level only if it's less than 50% */
648 midVal = WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog + stt->minLevel + 1, 1);
649 if (*inMicLevel < midVal)
650 {
651 /* *inMicLevel *= 1.1; */
652 tmp32 = WEBRTC_SPL_MUL(1126, *inMicLevel);
653 *inMicLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 10);
654 /* Reduces risk of a muted mic repeatedly triggering excessive levels due
655 * to zero signal detection. */
656 *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax);
657 stt->micVol = *inMicLevel;
658 }
659
660#ifdef AGC_DEBUG //test log
661 fprintf(stt->fpt,
662 "\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold, micVol:\n",
663 stt->fcount, stt->micVol);
664#endif
665
666 stt->activeSpeech = 0;
667 stt->Rxx16_LPw32Max = 0;
668
669 /* The AGC has a tendency (due to problems with the VAD parameters), to
670 * vastly increase the volume after a muting event. This timer prevents
671 * upwards adaptation for a short period. */
672 stt->muteGuardMs = kMuteGuardTimeMs;
673 }
674}
675
676void WebRtcAgc_SpeakerInactiveCtrl(Agc_t *stt)
677{
678 /* Check if the near end speaker is inactive.
679 * If that is the case the VAD threshold is
680 * increased since the VAD speech model gets
681 * more sensitive to any sound after a long
682 * silence.
683 */
684
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000685 int32_t tmp32;
686 int16_t vadThresh;
niklase@google.com470e71d2011-07-07 08:21:25 +0000687
688 if (stt->vadMic.stdLongTerm < 2500)
689 {
690 stt->vadThreshold = 1500;
691 } else
692 {
693 vadThresh = kNormalVadThreshold;
694 if (stt->vadMic.stdLongTerm < 4500)
695 {
696 /* Scale between min and max threshold */
697 vadThresh += WEBRTC_SPL_RSHIFT_W16(4500 - stt->vadMic.stdLongTerm, 1);
698 }
699
700 /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000701 tmp32 = (int32_t)vadThresh;
702 tmp32 += WEBRTC_SPL_MUL_16_16((int16_t)31, stt->vadThreshold);
703 stt->vadThreshold = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp32, 5);
niklase@google.com470e71d2011-07-07 08:21:25 +0000704 }
705}
706
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000707void WebRtcAgc_ExpCurve(int16_t volume, int16_t *index)
niklase@google.com470e71d2011-07-07 08:21:25 +0000708{
709 // volume in Q14
710 // index in [0-7]
711 /* 8 different curves */
712 if (volume > 5243)
713 {
714 if (volume > 7864)
715 {
716 if (volume > 12124)
717 {
718 *index = 7;
719 } else
720 {
721 *index = 6;
722 }
723 } else
724 {
725 if (volume > 6554)
726 {
727 *index = 5;
728 } else
729 {
730 *index = 4;
731 }
732 }
733 } else
734 {
735 if (volume > 2621)
736 {
737 if (volume > 3932)
738 {
739 *index = 3;
740 } else
741 {
742 *index = 2;
743 }
744 } else
745 {
746 if (volume > 1311)
747 {
748 *index = 1;
749 } else
750 {
751 *index = 0;
752 }
753 }
754 }
755}
756
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000757int32_t WebRtcAgc_ProcessAnalog(void *state, int32_t inMicLevel,
758 int32_t *outMicLevel,
759 int16_t vadLogRatio,
760 int16_t echo, uint8_t *saturationWarning)
niklase@google.com470e71d2011-07-07 08:21:25 +0000761{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000762 uint32_t tmpU32;
763 int32_t Rxx16w32, tmp32;
764 int32_t inMicLevelTmp, lastMicVol;
765 int16_t i;
766 uint8_t saturated = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 Agc_t *stt;
768
769 stt = (Agc_t *)state;
770 inMicLevelTmp = WEBRTC_SPL_LSHIFT_W32(inMicLevel, stt->scale);
771
772 if (inMicLevelTmp > stt->maxAnalog)
773 {
774#ifdef AGC_DEBUG //test log
775 fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n", stt->fcount);
776#endif
777 return -1;
778 } else if (inMicLevelTmp < stt->minLevel)
779 {
780#ifdef AGC_DEBUG //test log
781 fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n", stt->fcount);
782#endif
783 return -1;
784 }
785
786 if (stt->firstCall == 0)
787 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000788 int32_t tmpVol;
niklase@google.com470e71d2011-07-07 08:21:25 +0000789 stt->firstCall = 1;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000790 tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (int32_t)51, 9);
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 tmpVol = (stt->minLevel + tmp32);
792
793 /* If the mic level is very low at start, increase it! */
794 if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog))
795 {
796 inMicLevelTmp = tmpVol;
797 }
798 stt->micVol = inMicLevelTmp;
799 }
800
801 /* Set the mic level to the previous output value if there is digital input gain */
802 if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog))
803 {
804 inMicLevelTmp = stt->micVol;
805 }
806
807 /* If the mic level was manually changed to a very low value raise it! */
808 if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput))
809 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000810 tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (int32_t)51, 9);
niklase@google.com470e71d2011-07-07 08:21:25 +0000811 inMicLevelTmp = (stt->minLevel + tmp32);
812 stt->micVol = inMicLevelTmp;
813#ifdef MIC_LEVEL_FEEDBACK
814 //stt->numBlocksMicLvlSat = 0;
815#endif
816#ifdef AGC_DEBUG //test log
817 fprintf(stt->fpt,
818 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual decrease, raise vol\n",
819 stt->fcount);
820#endif
821 }
822
823 if (inMicLevelTmp != stt->micVol)
824 {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000825 if (inMicLevel == stt->lastInMicLevel) {
826 // We requested a volume adjustment, but it didn't occur. This is
827 // probably due to a coarse quantization of the volume slider.
828 // Restore the requested value to prevent getting stuck.
829 inMicLevelTmp = stt->micVol;
830 }
831 else {
832 // As long as the value changed, update to match.
833 stt->micVol = inMicLevelTmp;
834 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000835 }
836
837 if (inMicLevelTmp > stt->maxLevel)
838 {
839 // Always allow the user to raise the volume above the maxLevel.
840 stt->maxLevel = inMicLevelTmp;
841 }
842
843 // Store last value here, after we've taken care of manual updates etc.
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000844 stt->lastInMicLevel = inMicLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000845 lastMicVol = stt->micVol;
846
847 /* Checks if the signal is saturated. Also a check if individual samples
848 * are larger than 12000 is done. If they are the counter for increasing
849 * the volume level is set to -100ms
850 */
851 WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
852
853 /* The AGC is always allowed to lower the level if the signal is saturated */
854 if (saturated == 1)
855 {
856 /* Lower the recording level
857 * Rxx160_LP is adjusted down because it is so slow it could
858 * cause the AGC to make wrong decisions. */
859 /* stt->Rxx160_LPw32 *= 0.875; */
860 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 3), 7);
861
862 stt->zeroCtrlMax = stt->micVol;
863
864 /* stt->micVol *= 0.903; */
865 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000866 tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32));
867 stt->micVol = (int32_t)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000868 if (stt->micVol > lastMicVol - 2)
869 {
870 stt->micVol = lastMicVol - 2;
871 }
872 inMicLevelTmp = stt->micVol;
873
874#ifdef AGC_DEBUG //test log
875 fprintf(stt->fpt,
876 "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
877 stt->fcount, stt->micVol);
878#endif
879
880 if (stt->micVol < stt->minOutput)
881 {
882 *saturationWarning = 1;
883 }
884
885 /* Reset counter for decrease of volume level to avoid
886 * decreasing too much. The saturation control can still
887 * lower the level if needed. */
888 stt->msTooHigh = -100;
889
890 /* Enable the control mechanism to ensure that our measure,
891 * Rxx160_LP, is in the correct range. This must be done since
892 * the measure is very slow. */
893 stt->activeSpeech = 0;
894 stt->Rxx16_LPw32Max = 0;
895
896 /* Reset to initial values */
897 stt->msecSpeechInnerChange = kMsecSpeechInner;
898 stt->msecSpeechOuterChange = kMsecSpeechOuter;
899 stt->changeToSlowMode = 0;
900
901 stt->muteGuardMs = 0;
902
903 stt->upperLimit = stt->startUpperLimit;
904 stt->lowerLimit = stt->startLowerLimit;
905#ifdef MIC_LEVEL_FEEDBACK
906 //stt->numBlocksMicLvlSat = 0;
907#endif
908 }
909
910 /* Check if the input speech is zero. If so the mic volume
911 * is increased. On some computers the input is zero up as high
912 * level as 17% */
913 WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
914
915 /* Check if the near end speaker is inactive.
916 * If that is the case the VAD threshold is
917 * increased since the VAD speech model gets
918 * more sensitive to any sound after a long
919 * silence.
920 */
921 WebRtcAgc_SpeakerInactiveCtrl(stt);
922
923 for (i = 0; i < 5; i++)
924 {
925 /* Computed on blocks of 16 samples */
926
927 Rxx16w32 = stt->Rxx16w32_array[0][i];
928
929 /* Rxx160w32 in Q(-7) */
930 tmp32 = WEBRTC_SPL_RSHIFT_W32(Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos], 3);
931 stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
932 stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
933
934 /* Circular buffer */
ajm@google.com6bed0642011-07-12 14:57:10 +0000935 stt->Rxx16pos++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000936 if (stt->Rxx16pos == RXX_BUFFER_LEN)
937 {
938 stt->Rxx16pos = 0;
939 }
940
941 /* Rxx16_LPw32 in Q(-4) */
942 tmp32 = WEBRTC_SPL_RSHIFT_W32(Rxx16w32 - stt->Rxx16_LPw32, kAlphaShortTerm);
943 stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
944
945 if (vadLogRatio > stt->vadThreshold)
946 {
947 /* Speech detected! */
948
949 /* Check if Rxx160_LP is in the correct range. If
950 * it is too high/low then we set it to the maximum of
951 * Rxx16_LPw32 during the first 200ms of speech.
952 */
953 if (stt->activeSpeech < 250)
954 {
955 stt->activeSpeech += 2;
956
957 if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max)
958 {
959 stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
960 }
961 } else if (stt->activeSpeech == 250)
962 {
963 stt->activeSpeech += 2;
964 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx16_LPw32Max, 3);
965 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, RXX_BUFFER_LEN);
966 }
967
968 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160w32 - stt->Rxx160_LPw32, kAlphaLongTerm);
969 stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
970
971 if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit)
972 {
973 stt->msTooHigh += 2;
974 stt->msTooLow = 0;
975 stt->changeToSlowMode = 0;
976
977 if (stt->msTooHigh > stt->msecSpeechOuterChange)
978 {
979 stt->msTooHigh = 0;
980
981 /* Lower the recording level */
982 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
983 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
984 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 53);
985
986 /* Reduce the max gain to avoid excessive oscillation
987 * (but never drop below the maximum analog level).
988 * stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
989 */
990 tmp32 = (15 * stt->maxLevel) + stt->micVol;
991 stt->maxLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 4);
992 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
993
994 stt->zeroCtrlMax = stt->micVol;
995
996 /* 0.95 in Q15 */
997 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000998 tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32));
999 stt->micVol = (int32_t)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001000 if (stt->micVol > lastMicVol - 1)
1001 {
1002 stt->micVol = lastMicVol - 1;
1003 }
1004 inMicLevelTmp = stt->micVol;
1005
1006 /* Enable the control mechanism to ensure that our measure,
1007 * Rxx160_LP, is in the correct range.
1008 */
1009 stt->activeSpeech = 0;
1010 stt->Rxx16_LPw32Max = 0;
1011#ifdef MIC_LEVEL_FEEDBACK
1012 //stt->numBlocksMicLvlSat = 0;
1013#endif
1014#ifdef AGC_DEBUG //test log
1015 fprintf(stt->fpt,
1016 "\tAGC->ProcessAnalog, frame %d: measure > 2ndUpperLim, micVol = %d, maxLevel = %d\n",
1017 stt->fcount, stt->micVol, stt->maxLevel);
1018#endif
1019 }
1020 } else if (stt->Rxx160_LPw32 > stt->upperLimit)
1021 {
1022 stt->msTooHigh += 2;
1023 stt->msTooLow = 0;
1024 stt->changeToSlowMode = 0;
1025
1026 if (stt->msTooHigh > stt->msecSpeechInnerChange)
1027 {
1028 /* Lower the recording level */
1029 stt->msTooHigh = 0;
1030 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
1031 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
1032 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 53);
1033
1034 /* Reduce the max gain to avoid excessive oscillation
1035 * (but never drop below the maximum analog level).
1036 * stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
1037 */
1038 tmp32 = (15 * stt->maxLevel) + stt->micVol;
1039 stt->maxLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 4);
1040 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
1041
1042 stt->zeroCtrlMax = stt->micVol;
1043
1044 /* 0.965 in Q15 */
1045 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001046 tmpU32 = WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel));
1047 stt->micVol = (int32_t)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001048 if (stt->micVol > lastMicVol - 1)
1049 {
1050 stt->micVol = lastMicVol - 1;
1051 }
1052 inMicLevelTmp = stt->micVol;
1053
1054#ifdef MIC_LEVEL_FEEDBACK
1055 //stt->numBlocksMicLvlSat = 0;
1056#endif
1057#ifdef AGC_DEBUG //test log
1058 fprintf(stt->fpt,
1059 "\tAGC->ProcessAnalog, frame %d: measure > UpperLim, micVol = %d, maxLevel = %d\n",
1060 stt->fcount, stt->micVol, stt->maxLevel);
1061#endif
1062 }
1063 } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit)
1064 {
1065 stt->msTooHigh = 0;
1066 stt->changeToSlowMode = 0;
1067 stt->msTooLow += 2;
1068
1069 if (stt->msTooLow > stt->msecSpeechOuterChange)
1070 {
1071 /* Raise the recording level */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001072 int16_t index, weightFIX;
1073 int16_t volNormFIX = 16384; // =1 in Q14.
niklase@google.com470e71d2011-07-07 08:21:25 +00001074
1075 stt->msTooLow = 0;
1076
1077 /* Normalize the volume level */
1078 tmp32 = WEBRTC_SPL_LSHIFT_W32(inMicLevelTmp - stt->minLevel, 14);
1079 if (stt->maxInit != stt->minLevel)
1080 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001081 volNormFIX = (int16_t)WEBRTC_SPL_DIV(tmp32,
niklase@google.com470e71d2011-07-07 08:21:25 +00001082 (stt->maxInit - stt->minLevel));
1083 }
1084
1085 /* Find correct curve */
1086 WebRtcAgc_ExpCurve(volNormFIX, &index);
1087
1088 /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05 */
1089 weightFIX = kOffset1[index]
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001090 - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(kSlope1[index],
niklase@google.com470e71d2011-07-07 08:21:25 +00001091 volNormFIX, 13);
1092
1093 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
1094 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
1095 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 67);
1096
1097 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001098 tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
1099 stt->micVol = (int32_t)WEBRTC_SPL_RSHIFT_U32(tmpU32, 14) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 if (stt->micVol < lastMicVol + 2)
1101 {
1102 stt->micVol = lastMicVol + 2;
1103 }
1104
1105 inMicLevelTmp = stt->micVol;
1106
1107#ifdef MIC_LEVEL_FEEDBACK
1108 /* Count ms in level saturation */
1109 //if (stt->micVol > stt->maxAnalog) {
1110 if (stt->micVol > 150)
1111 {
1112 /* mic level is saturated */
1113 stt->numBlocksMicLvlSat++;
1114 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1115 }
1116#endif
1117#ifdef AGC_DEBUG //test log
1118 fprintf(stt->fpt,
1119 "\tAGC->ProcessAnalog, frame %d: measure < 2ndLowerLim, micVol = %d\n",
1120 stt->fcount, stt->micVol);
1121#endif
1122 }
1123 } else if (stt->Rxx160_LPw32 < stt->lowerLimit)
1124 {
1125 stt->msTooHigh = 0;
1126 stt->changeToSlowMode = 0;
1127 stt->msTooLow += 2;
1128
1129 if (stt->msTooLow > stt->msecSpeechInnerChange)
1130 {
1131 /* Raise the recording level */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001132 int16_t index, weightFIX;
1133 int16_t volNormFIX = 16384; // =1 in Q14.
niklase@google.com470e71d2011-07-07 08:21:25 +00001134
1135 stt->msTooLow = 0;
1136
1137 /* Normalize the volume level */
1138 tmp32 = WEBRTC_SPL_LSHIFT_W32(inMicLevelTmp - stt->minLevel, 14);
1139 if (stt->maxInit != stt->minLevel)
1140 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001141 volNormFIX = (int16_t)WEBRTC_SPL_DIV(tmp32,
niklase@google.com470e71d2011-07-07 08:21:25 +00001142 (stt->maxInit - stt->minLevel));
1143 }
1144
1145 /* Find correct curve */
1146 WebRtcAgc_ExpCurve(volNormFIX, &index);
1147
1148 /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1 */
1149 weightFIX = kOffset2[index]
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001150 - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(kSlope2[index],
niklase@google.com470e71d2011-07-07 08:21:25 +00001151 volNormFIX, 13);
1152
1153 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
1154 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
1155 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 67);
1156
1157 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001158 tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
1159 stt->micVol = (int32_t)WEBRTC_SPL_RSHIFT_U32(tmpU32, 14) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001160 if (stt->micVol < lastMicVol + 1)
1161 {
1162 stt->micVol = lastMicVol + 1;
1163 }
1164
1165 inMicLevelTmp = stt->micVol;
1166
1167#ifdef MIC_LEVEL_FEEDBACK
1168 /* Count ms in level saturation */
1169 //if (stt->micVol > stt->maxAnalog) {
1170 if (stt->micVol > 150)
1171 {
1172 /* mic level is saturated */
1173 stt->numBlocksMicLvlSat++;
1174 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1175 }
1176#endif
1177#ifdef AGC_DEBUG //test log
1178 fprintf(stt->fpt,
1179 "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol = %d\n",
1180 stt->fcount, stt->micVol);
1181#endif
1182
1183 }
1184 } else
1185 {
1186 /* The signal is inside the desired range which is:
1187 * lowerLimit < Rxx160_LP/640 < upperLimit
1188 */
1189 if (stt->changeToSlowMode > 4000)
1190 {
1191 stt->msecSpeechInnerChange = 1000;
1192 stt->msecSpeechOuterChange = 500;
1193 stt->upperLimit = stt->upperPrimaryLimit;
1194 stt->lowerLimit = stt->lowerPrimaryLimit;
1195 } else
1196 {
1197 stt->changeToSlowMode += 2; // in milliseconds
1198 }
1199 stt->msTooLow = 0;
1200 stt->msTooHigh = 0;
1201
1202 stt->micVol = inMicLevelTmp;
1203
1204 }
1205#ifdef MIC_LEVEL_FEEDBACK
1206 if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET)
1207 {
1208 stt->micLvlSat = 1;
1209 fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1210 WebRtcAgc_UpdateAgcThresholds(stt);
1211 WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]),
1212 stt->compressionGaindB, stt->targetLevelDbfs, stt->limiterEnable,
1213 stt->analogTarget);
1214 stt->numBlocksMicLvlSat = 0;
1215 stt->micLvlSat = 0;
1216 fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset);
1217 fprintf(stderr, "target after = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1218 }
1219#endif
1220 }
1221 }
1222
1223 /* Ensure gain is not increased in presence of echo or after a mute event
1224 * (but allow the zeroCtrl() increase on the frame of a mute detection).
1225 */
1226 if (echo == 1 || (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs))
1227 {
1228 if (stt->micVol > lastMicVol)
1229 {
1230 stt->micVol = lastMicVol;
1231 }
1232 }
1233
1234 /* limit the gain */
1235 if (stt->micVol > stt->maxLevel)
1236 {
1237 stt->micVol = stt->maxLevel;
1238 } else if (stt->micVol < stt->minOutput)
1239 {
1240 stt->micVol = stt->minOutput;
1241 }
1242
1243 *outMicLevel = WEBRTC_SPL_RSHIFT_W32(stt->micVol, stt->scale);
1244 if (*outMicLevel > WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog, stt->scale))
1245 {
1246 *outMicLevel = WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog, stt->scale);
1247 }
1248
1249 return 0;
1250}
1251
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001252int WebRtcAgc_Process(void *agcInst, const int16_t *in_near,
1253 const int16_t *in_near_H, int16_t samples,
1254 int16_t *out, int16_t *out_H, int32_t inMicLevel,
1255 int32_t *outMicLevel, int16_t echo,
1256 uint8_t *saturationWarning)
niklase@google.com470e71d2011-07-07 08:21:25 +00001257{
1258 Agc_t *stt;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001259 int32_t inMicLevelTmp;
1260 int16_t subFrames, i;
1261 uint8_t satWarningTmp = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001262
1263 stt = (Agc_t *)agcInst;
1264
1265 //
1266 if (stt == NULL)
1267 {
1268 return -1;
1269 }
1270 //
1271
1272
1273 if (stt->fs == 8000)
1274 {
1275 if ((samples != 80) && (samples != 160))
1276 {
1277#ifdef AGC_DEBUG //test log
1278 fprintf(stt->fpt,
1279 "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount);
1280#endif
1281 return -1;
1282 }
1283 subFrames = 80;
1284 } else if (stt->fs == 16000)
1285 {
1286 if ((samples != 160) && (samples != 320))
1287 {
1288#ifdef AGC_DEBUG //test log
1289 fprintf(stt->fpt,
1290 "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount);
1291#endif
1292 return -1;
1293 }
1294 subFrames = 160;
1295 } else if (stt->fs == 32000)
1296 {
1297 if ((samples != 160) && (samples != 320))
1298 {
1299#ifdef AGC_DEBUG //test log
1300 fprintf(stt->fpt,
1301 "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount);
1302#endif
1303 return -1;
1304 }
1305 subFrames = 160;
1306 } else
1307 {
1308#ifdef AGC_DEBUG// test log
1309 fprintf(stt->fpt,
1310 "AGC->Process, frame %d: Invalid sample rate\n\n", stt->fcount);
1311#endif
1312 return -1;
1313 }
1314
1315 /* Check for valid pointers based on sampling rate */
1316 if (stt->fs == 32000 && in_near_H == NULL)
1317 {
1318 return -1;
1319 }
1320 /* Check for valid pointers for low band */
1321 if (in_near == NULL)
1322 {
1323 return -1;
1324 }
1325
1326 *saturationWarning = 0;
1327 //TODO: PUT IN RANGE CHECKING FOR INPUT LEVELS
1328 *outMicLevel = inMicLevel;
1329 inMicLevelTmp = inMicLevel;
1330
andrew@webrtc.org64235092011-08-19 21:22:08 +00001331 // TODO(andrew): clearly we don't need input and output pointers...
1332 // Change the interface to take a shared input/output.
1333 if (in_near != out)
1334 {
1335 // Only needed if they don't already point to the same place.
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001336 memcpy(out, in_near, samples * sizeof(int16_t));
andrew@webrtc.org64235092011-08-19 21:22:08 +00001337 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001338 if (stt->fs == 32000)
1339 {
andrew@webrtc.org64235092011-08-19 21:22:08 +00001340 if (in_near_H != out_H)
1341 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001342 memcpy(out_H, in_near_H, samples * sizeof(int16_t));
andrew@webrtc.org64235092011-08-19 21:22:08 +00001343 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001344 }
1345
1346#ifdef AGC_DEBUG//test log
1347 stt->fcount++;
1348#endif
1349
1350 for (i = 0; i < samples; i += subFrames)
1351 {
1352 if (WebRtcAgc_ProcessDigital(&stt->digitalAgc, &in_near[i], &in_near_H[i], &out[i], &out_H[i],
1353 stt->fs, stt->lowLevelSignal) == -1)
1354 {
1355#ifdef AGC_DEBUG//test log
1356 fprintf(stt->fpt, "AGC->Process, frame %d: Error from DigAGC\n\n", stt->fcount);
1357#endif
1358 return -1;
1359 }
1360 if ((stt->agcMode < kAgcModeFixedDigital) && ((stt->lowLevelSignal == 0)
1361 || (stt->agcMode != kAgcModeAdaptiveDigital)))
1362 {
1363 if (WebRtcAgc_ProcessAnalog(agcInst, inMicLevelTmp, outMicLevel,
1364 stt->vadMic.logRatio, echo, saturationWarning) == -1)
1365 {
1366 return -1;
1367 }
1368 }
1369#ifdef AGC_DEBUG//test log
1370 fprintf(stt->agcLog, "%5d\t%d\t%d\t%d\n", stt->fcount, inMicLevelTmp, *outMicLevel, stt->maxLevel, stt->micVol);
1371#endif
1372
1373 /* update queue */
1374 if (stt->inQueue > 1)
1375 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001376 memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t));
1377 memcpy(stt->Rxx16w32_array[0], stt->Rxx16w32_array[1], 5 * sizeof(int32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00001378 }
1379
1380 if (stt->inQueue > 0)
1381 {
1382 stt->inQueue--;
1383 }
1384
1385 /* If 20ms frames are used the input mic level must be updated so that
1386 * the analog AGC does not think that there has been a manual volume
1387 * change. */
1388 inMicLevelTmp = *outMicLevel;
1389
1390 /* Store a positive saturation warning. */
1391 if (*saturationWarning == 1)
1392 {
1393 satWarningTmp = 1;
1394 }
1395 }
1396
1397 /* Trigger the saturation warning if displayed by any of the frames. */
1398 *saturationWarning = satWarningTmp;
1399
1400 return 0;
1401}
1402
1403int WebRtcAgc_set_config(void *agcInst, WebRtcAgc_config_t agcConfig)
1404{
1405 Agc_t *stt;
1406 stt = (Agc_t *)agcInst;
1407
1408 if (stt == NULL)
1409 {
1410 return -1;
1411 }
1412
1413 if (stt->initFlag != kInitCheck)
1414 {
1415 stt->lastError = AGC_UNINITIALIZED_ERROR;
1416 return -1;
1417 }
1418
1419 if (agcConfig.limiterEnable != kAgcFalse && agcConfig.limiterEnable != kAgcTrue)
1420 {
1421 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1422 return -1;
1423 }
1424 stt->limiterEnable = agcConfig.limiterEnable;
1425 stt->compressionGaindB = agcConfig.compressionGaindB;
1426 if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31))
1427 {
1428 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1429 return -1;
1430 }
1431 stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
1432
1433 if (stt->agcMode == kAgcModeFixedDigital)
1434 {
1435 /* Adjust for different parameter interpretation in FixedDigital mode */
1436 stt->compressionGaindB += agcConfig.targetLevelDbfs;
1437 }
1438
1439 /* Update threshold levels for analog adaptation */
1440 WebRtcAgc_UpdateAgcThresholds(stt);
1441
1442 /* Recalculate gain table */
1443 if (WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
1444 stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1)
1445 {
1446#ifdef AGC_DEBUG//test log
1447 fprintf(stt->fpt, "AGC->set_config, frame %d: Error from calcGainTable\n\n", stt->fcount);
1448#endif
1449 return -1;
1450 }
1451 /* Store the config in a WebRtcAgc_config_t */
1452 stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
1453 stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
1454 stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
1455
1456 return 0;
1457}
1458
1459int WebRtcAgc_get_config(void *agcInst, WebRtcAgc_config_t *config)
1460{
1461 Agc_t *stt;
1462 stt = (Agc_t *)agcInst;
1463
1464 if (stt == NULL)
1465 {
1466 return -1;
1467 }
1468
1469 if (config == NULL)
1470 {
1471 stt->lastError = AGC_NULL_POINTER_ERROR;
1472 return -1;
1473 }
1474
1475 if (stt->initFlag != kInitCheck)
1476 {
1477 stt->lastError = AGC_UNINITIALIZED_ERROR;
1478 return -1;
1479 }
1480
1481 config->limiterEnable = stt->usedConfig.limiterEnable;
1482 config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
1483 config->compressionGaindB = stt->usedConfig.compressionGaindB;
1484
1485 return 0;
1486}
1487
1488int WebRtcAgc_Create(void **agcInst)
1489{
1490 Agc_t *stt;
1491 if (agcInst == NULL)
1492 {
1493 return -1;
1494 }
1495 stt = (Agc_t *)malloc(sizeof(Agc_t));
1496
1497 *agcInst = stt;
1498 if (stt == NULL)
1499 {
1500 return -1;
1501 }
1502
1503#ifdef AGC_DEBUG
1504 stt->fpt = fopen("./agc_test_log.txt", "wt");
1505 stt->agcLog = fopen("./agc_debug_log.txt", "wt");
1506 stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
1507#endif
1508
1509 stt->initFlag = 0;
1510 stt->lastError = 0;
1511
1512 return 0;
1513}
1514
1515int WebRtcAgc_Free(void *state)
1516{
1517 Agc_t *stt;
1518
1519 stt = (Agc_t *)state;
1520#ifdef AGC_DEBUG
1521 fclose(stt->fpt);
1522 fclose(stt->agcLog);
1523 fclose(stt->digitalAgc.logFile);
1524#endif
1525 free(stt);
1526
1527 return 0;
1528}
1529
1530/* minLevel - Minimum volume level
1531 * maxLevel - Maximum volume level
1532 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001533int WebRtcAgc_Init(void *agcInst, int32_t minLevel, int32_t maxLevel,
1534 int16_t agcMode, uint32_t fs)
niklase@google.com470e71d2011-07-07 08:21:25 +00001535{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001536 int32_t max_add, tmp32;
1537 int16_t i;
niklase@google.com470e71d2011-07-07 08:21:25 +00001538 int tmpNorm;
1539 Agc_t *stt;
1540
1541 /* typecast state pointer */
1542 stt = (Agc_t *)agcInst;
1543
1544 if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0)
1545 {
1546 stt->lastError = AGC_UNINITIALIZED_ERROR;
1547 return -1;
1548 }
1549
1550 /* Analog AGC variables */
1551 stt->envSum = 0;
1552
1553 /* mode = 0 - Only saturation protection
1554 * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1555 * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1556 * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
1557 */
1558#ifdef AGC_DEBUG//test log
1559 stt->fcount = 0;
1560 fprintf(stt->fpt, "AGC->Init\n");
1561#endif
1562 if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital)
1563 {
1564#ifdef AGC_DEBUG//test log
1565 fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
1566#endif
1567 return -1;
1568 }
1569 stt->agcMode = agcMode;
1570 stt->fs = fs;
1571
1572 /* initialize input VAD */
1573 WebRtcAgc_InitVad(&stt->vadMic);
1574
1575 /* If the volume range is smaller than 0-256 then
1576 * the levels are shifted up to Q8-domain */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001577 tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001578 stt->scale = tmpNorm - 23;
1579 if (stt->scale < 0)
1580 {
1581 stt->scale = 0;
1582 }
1583 // TODO(bjornv): Investigate if we really need to scale up a small range now when we have
1584 // a guard against zero-increments. For now, we do not support scale up (scale = 0).
1585 stt->scale = 0;
1586 maxLevel = WEBRTC_SPL_LSHIFT_W32(maxLevel, stt->scale);
1587 minLevel = WEBRTC_SPL_LSHIFT_W32(minLevel, stt->scale);
1588
1589 /* Make minLevel and maxLevel static in AdaptiveDigital */
1590 if (stt->agcMode == kAgcModeAdaptiveDigital)
1591 {
1592 minLevel = 0;
1593 maxLevel = 255;
1594 stt->scale = 0;
1595 }
1596 /* The maximum supplemental volume range is based on a vague idea
1597 * of how much lower the gain will be than the real analog gain. */
1598 max_add = WEBRTC_SPL_RSHIFT_W32(maxLevel - minLevel, 2);
1599
1600 /* Minimum/maximum volume level that can be set */
1601 stt->minLevel = minLevel;
1602 stt->maxAnalog = maxLevel;
1603 stt->maxLevel = maxLevel + max_add;
1604 stt->maxInit = stt->maxLevel;
1605
1606 stt->zeroCtrlMax = stt->maxAnalog;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001607 stt->lastInMicLevel = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001608
1609 /* Initialize micVol parameter */
1610 stt->micVol = stt->maxAnalog;
1611 if (stt->agcMode == kAgcModeAdaptiveDigital)
1612 {
1613 stt->micVol = 127; /* Mid-point of mic level */
1614 }
1615 stt->micRef = stt->micVol;
1616 stt->micGainIdx = 127;
1617#ifdef MIC_LEVEL_FEEDBACK
1618 stt->numBlocksMicLvlSat = 0;
1619 stt->micLvlSat = 0;
1620#endif
1621#ifdef AGC_DEBUG//test log
1622 fprintf(stt->fpt,
1623 "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
1624 stt->minLevel, stt->maxAnalog, stt->maxLevel);
1625#endif
1626
1627 /* Minimum output volume is 4% higher than the available lowest volume level */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001628 tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (int32_t)10, 8);
niklase@google.com470e71d2011-07-07 08:21:25 +00001629 stt->minOutput = (stt->minLevel + tmp32);
1630
1631 stt->msTooLow = 0;
1632 stt->msTooHigh = 0;
1633 stt->changeToSlowMode = 0;
1634 stt->firstCall = 0;
1635 stt->msZero = 0;
1636 stt->muteGuardMs = 0;
1637 stt->gainTableIdx = 0;
1638
1639 stt->msecSpeechInnerChange = kMsecSpeechInner;
1640 stt->msecSpeechOuterChange = kMsecSpeechOuter;
1641
1642 stt->activeSpeech = 0;
1643 stt->Rxx16_LPw32Max = 0;
1644
1645 stt->vadThreshold = kNormalVadThreshold;
1646 stt->inActive = 0;
1647
1648 for (i = 0; i < RXX_BUFFER_LEN; i++)
1649 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001650 stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
niklase@google.com470e71d2011-07-07 08:21:25 +00001651 }
1652 stt->Rxx160w32 = 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
1653
1654 stt->Rxx16pos = 0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001655 stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */
niklase@google.com470e71d2011-07-07 08:21:25 +00001656
1657 for (i = 0; i < 5; i++)
1658 {
1659 stt->Rxx16w32_array[0][i] = 0;
1660 }
bjornv@webrtc.org281b7982012-05-30 07:41:57 +00001661 for (i = 0; i < 10; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001662 {
1663 stt->env[0][i] = 0;
bjornv@webrtc.org281b7982012-05-30 07:41:57 +00001664 stt->env[1][i] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001665 }
1666 stt->inQueue = 0;
1667
1668#ifdef MIC_LEVEL_FEEDBACK
1669 stt->targetIdxOffset = 0;
1670#endif
1671
1672 WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
1673
1674 stt->initFlag = kInitCheck;
1675 // Default config settings.
1676 stt->defaultConfig.limiterEnable = kAgcTrue;
1677 stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
1678 stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
1679
1680 if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1)
1681 {
1682 stt->lastError = AGC_UNSPECIFIED_ERROR;
1683 return -1;
1684 }
1685 stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value
1686
1687 stt->lowLevelSignal = 0;
1688
1689 /* Only positive values are allowed that are not too large */
1690 if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000))
1691 {
1692#ifdef AGC_DEBUG//test log
1693 fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
1694#endif
1695 return -1;
1696 } else
1697 {
1698#ifdef AGC_DEBUG//test log
1699 fprintf(stt->fpt, "\n");
1700#endif
1701 return 0;
1702 }
1703}