blob: 0965defec19cd99ebe981735a77e359198f9b35f [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
25#include "analog_agc.h"
26
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 {
825 // Incoming level mismatch; update our level.
826 // This could be the case if the volume is changed manually, or if the
827 // sound device has a low volume resolution.
828 stt->micVol = inMicLevelTmp;
829 }
830
831 if (inMicLevelTmp > stt->maxLevel)
832 {
833 // Always allow the user to raise the volume above the maxLevel.
834 stt->maxLevel = inMicLevelTmp;
835 }
836
837 // Store last value here, after we've taken care of manual updates etc.
838 lastMicVol = stt->micVol;
839
840 /* Checks if the signal is saturated. Also a check if individual samples
841 * are larger than 12000 is done. If they are the counter for increasing
842 * the volume level is set to -100ms
843 */
844 WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
845
846 /* The AGC is always allowed to lower the level if the signal is saturated */
847 if (saturated == 1)
848 {
849 /* Lower the recording level
850 * Rxx160_LP is adjusted down because it is so slow it could
851 * cause the AGC to make wrong decisions. */
852 /* stt->Rxx160_LPw32 *= 0.875; */
853 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 3), 7);
854
855 stt->zeroCtrlMax = stt->micVol;
856
857 /* stt->micVol *= 0.903; */
858 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000859 tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32));
860 stt->micVol = (int32_t)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000861 if (stt->micVol > lastMicVol - 2)
862 {
863 stt->micVol = lastMicVol - 2;
864 }
865 inMicLevelTmp = stt->micVol;
866
867#ifdef AGC_DEBUG //test log
868 fprintf(stt->fpt,
869 "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
870 stt->fcount, stt->micVol);
871#endif
872
873 if (stt->micVol < stt->minOutput)
874 {
875 *saturationWarning = 1;
876 }
877
878 /* Reset counter for decrease of volume level to avoid
879 * decreasing too much. The saturation control can still
880 * lower the level if needed. */
881 stt->msTooHigh = -100;
882
883 /* Enable the control mechanism to ensure that our measure,
884 * Rxx160_LP, is in the correct range. This must be done since
885 * the measure is very slow. */
886 stt->activeSpeech = 0;
887 stt->Rxx16_LPw32Max = 0;
888
889 /* Reset to initial values */
890 stt->msecSpeechInnerChange = kMsecSpeechInner;
891 stt->msecSpeechOuterChange = kMsecSpeechOuter;
892 stt->changeToSlowMode = 0;
893
894 stt->muteGuardMs = 0;
895
896 stt->upperLimit = stt->startUpperLimit;
897 stt->lowerLimit = stt->startLowerLimit;
898#ifdef MIC_LEVEL_FEEDBACK
899 //stt->numBlocksMicLvlSat = 0;
900#endif
901 }
902
903 /* Check if the input speech is zero. If so the mic volume
904 * is increased. On some computers the input is zero up as high
905 * level as 17% */
906 WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
907
908 /* Check if the near end speaker is inactive.
909 * If that is the case the VAD threshold is
910 * increased since the VAD speech model gets
911 * more sensitive to any sound after a long
912 * silence.
913 */
914 WebRtcAgc_SpeakerInactiveCtrl(stt);
915
916 for (i = 0; i < 5; i++)
917 {
918 /* Computed on blocks of 16 samples */
919
920 Rxx16w32 = stt->Rxx16w32_array[0][i];
921
922 /* Rxx160w32 in Q(-7) */
923 tmp32 = WEBRTC_SPL_RSHIFT_W32(Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos], 3);
924 stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
925 stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
926
927 /* Circular buffer */
ajm@google.com6bed0642011-07-12 14:57:10 +0000928 stt->Rxx16pos++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000929 if (stt->Rxx16pos == RXX_BUFFER_LEN)
930 {
931 stt->Rxx16pos = 0;
932 }
933
934 /* Rxx16_LPw32 in Q(-4) */
935 tmp32 = WEBRTC_SPL_RSHIFT_W32(Rxx16w32 - stt->Rxx16_LPw32, kAlphaShortTerm);
936 stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
937
938 if (vadLogRatio > stt->vadThreshold)
939 {
940 /* Speech detected! */
941
942 /* Check if Rxx160_LP is in the correct range. If
943 * it is too high/low then we set it to the maximum of
944 * Rxx16_LPw32 during the first 200ms of speech.
945 */
946 if (stt->activeSpeech < 250)
947 {
948 stt->activeSpeech += 2;
949
950 if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max)
951 {
952 stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
953 }
954 } else if (stt->activeSpeech == 250)
955 {
956 stt->activeSpeech += 2;
957 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx16_LPw32Max, 3);
958 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, RXX_BUFFER_LEN);
959 }
960
961 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160w32 - stt->Rxx160_LPw32, kAlphaLongTerm);
962 stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
963
964 if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit)
965 {
966 stt->msTooHigh += 2;
967 stt->msTooLow = 0;
968 stt->changeToSlowMode = 0;
969
970 if (stt->msTooHigh > stt->msecSpeechOuterChange)
971 {
972 stt->msTooHigh = 0;
973
974 /* Lower the recording level */
975 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
976 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
977 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 53);
978
979 /* Reduce the max gain to avoid excessive oscillation
980 * (but never drop below the maximum analog level).
981 * stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
982 */
983 tmp32 = (15 * stt->maxLevel) + stt->micVol;
984 stt->maxLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 4);
985 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
986
987 stt->zeroCtrlMax = stt->micVol;
988
989 /* 0.95 in Q15 */
990 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000991 tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32));
992 stt->micVol = (int32_t)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 if (stt->micVol > lastMicVol - 1)
994 {
995 stt->micVol = lastMicVol - 1;
996 }
997 inMicLevelTmp = stt->micVol;
998
999 /* Enable the control mechanism to ensure that our measure,
1000 * Rxx160_LP, is in the correct range.
1001 */
1002 stt->activeSpeech = 0;
1003 stt->Rxx16_LPw32Max = 0;
1004#ifdef MIC_LEVEL_FEEDBACK
1005 //stt->numBlocksMicLvlSat = 0;
1006#endif
1007#ifdef AGC_DEBUG //test log
1008 fprintf(stt->fpt,
1009 "\tAGC->ProcessAnalog, frame %d: measure > 2ndUpperLim, micVol = %d, maxLevel = %d\n",
1010 stt->fcount, stt->micVol, stt->maxLevel);
1011#endif
1012 }
1013 } else if (stt->Rxx160_LPw32 > stt->upperLimit)
1014 {
1015 stt->msTooHigh += 2;
1016 stt->msTooLow = 0;
1017 stt->changeToSlowMode = 0;
1018
1019 if (stt->msTooHigh > stt->msecSpeechInnerChange)
1020 {
1021 /* Lower the recording level */
1022 stt->msTooHigh = 0;
1023 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
1024 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
1025 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 53);
1026
1027 /* Reduce the max gain to avoid excessive oscillation
1028 * (but never drop below the maximum analog level).
1029 * stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
1030 */
1031 tmp32 = (15 * stt->maxLevel) + stt->micVol;
1032 stt->maxLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 4);
1033 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
1034
1035 stt->zeroCtrlMax = stt->micVol;
1036
1037 /* 0.965 in Q15 */
1038 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001039 tmpU32 = WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel));
1040 stt->micVol = (int32_t)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001041 if (stt->micVol > lastMicVol - 1)
1042 {
1043 stt->micVol = lastMicVol - 1;
1044 }
1045 inMicLevelTmp = stt->micVol;
1046
1047#ifdef MIC_LEVEL_FEEDBACK
1048 //stt->numBlocksMicLvlSat = 0;
1049#endif
1050#ifdef AGC_DEBUG //test log
1051 fprintf(stt->fpt,
1052 "\tAGC->ProcessAnalog, frame %d: measure > UpperLim, micVol = %d, maxLevel = %d\n",
1053 stt->fcount, stt->micVol, stt->maxLevel);
1054#endif
1055 }
1056 } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit)
1057 {
1058 stt->msTooHigh = 0;
1059 stt->changeToSlowMode = 0;
1060 stt->msTooLow += 2;
1061
1062 if (stt->msTooLow > stt->msecSpeechOuterChange)
1063 {
1064 /* Raise the recording level */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001065 int16_t index, weightFIX;
1066 int16_t volNormFIX = 16384; // =1 in Q14.
niklase@google.com470e71d2011-07-07 08:21:25 +00001067
1068 stt->msTooLow = 0;
1069
1070 /* Normalize the volume level */
1071 tmp32 = WEBRTC_SPL_LSHIFT_W32(inMicLevelTmp - stt->minLevel, 14);
1072 if (stt->maxInit != stt->minLevel)
1073 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001074 volNormFIX = (int16_t)WEBRTC_SPL_DIV(tmp32,
niklase@google.com470e71d2011-07-07 08:21:25 +00001075 (stt->maxInit - stt->minLevel));
1076 }
1077
1078 /* Find correct curve */
1079 WebRtcAgc_ExpCurve(volNormFIX, &index);
1080
1081 /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05 */
1082 weightFIX = kOffset1[index]
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001083 - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(kSlope1[index],
niklase@google.com470e71d2011-07-07 08:21:25 +00001084 volNormFIX, 13);
1085
1086 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
1087 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
1088 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 67);
1089
1090 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001091 tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
1092 stt->micVol = (int32_t)WEBRTC_SPL_RSHIFT_U32(tmpU32, 14) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001093 if (stt->micVol < lastMicVol + 2)
1094 {
1095 stt->micVol = lastMicVol + 2;
1096 }
1097
1098 inMicLevelTmp = stt->micVol;
1099
1100#ifdef MIC_LEVEL_FEEDBACK
1101 /* Count ms in level saturation */
1102 //if (stt->micVol > stt->maxAnalog) {
1103 if (stt->micVol > 150)
1104 {
1105 /* mic level is saturated */
1106 stt->numBlocksMicLvlSat++;
1107 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1108 }
1109#endif
1110#ifdef AGC_DEBUG //test log
1111 fprintf(stt->fpt,
1112 "\tAGC->ProcessAnalog, frame %d: measure < 2ndLowerLim, micVol = %d\n",
1113 stt->fcount, stt->micVol);
1114#endif
1115 }
1116 } else if (stt->Rxx160_LPw32 < stt->lowerLimit)
1117 {
1118 stt->msTooHigh = 0;
1119 stt->changeToSlowMode = 0;
1120 stt->msTooLow += 2;
1121
1122 if (stt->msTooLow > stt->msecSpeechInnerChange)
1123 {
1124 /* Raise the recording level */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001125 int16_t index, weightFIX;
1126 int16_t volNormFIX = 16384; // =1 in Q14.
niklase@google.com470e71d2011-07-07 08:21:25 +00001127
1128 stt->msTooLow = 0;
1129
1130 /* Normalize the volume level */
1131 tmp32 = WEBRTC_SPL_LSHIFT_W32(inMicLevelTmp - stt->minLevel, 14);
1132 if (stt->maxInit != stt->minLevel)
1133 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001134 volNormFIX = (int16_t)WEBRTC_SPL_DIV(tmp32,
niklase@google.com470e71d2011-07-07 08:21:25 +00001135 (stt->maxInit - stt->minLevel));
1136 }
1137
1138 /* Find correct curve */
1139 WebRtcAgc_ExpCurve(volNormFIX, &index);
1140
1141 /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1 */
1142 weightFIX = kOffset2[index]
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001143 - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(kSlope2[index],
niklase@google.com470e71d2011-07-07 08:21:25 +00001144 volNormFIX, 13);
1145
1146 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
1147 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
1148 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 67);
1149
1150 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001151 tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
1152 stt->micVol = (int32_t)WEBRTC_SPL_RSHIFT_U32(tmpU32, 14) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001153 if (stt->micVol < lastMicVol + 1)
1154 {
1155 stt->micVol = lastMicVol + 1;
1156 }
1157
1158 inMicLevelTmp = stt->micVol;
1159
1160#ifdef MIC_LEVEL_FEEDBACK
1161 /* Count ms in level saturation */
1162 //if (stt->micVol > stt->maxAnalog) {
1163 if (stt->micVol > 150)
1164 {
1165 /* mic level is saturated */
1166 stt->numBlocksMicLvlSat++;
1167 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1168 }
1169#endif
1170#ifdef AGC_DEBUG //test log
1171 fprintf(stt->fpt,
1172 "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol = %d\n",
1173 stt->fcount, stt->micVol);
1174#endif
1175
1176 }
1177 } else
1178 {
1179 /* The signal is inside the desired range which is:
1180 * lowerLimit < Rxx160_LP/640 < upperLimit
1181 */
1182 if (stt->changeToSlowMode > 4000)
1183 {
1184 stt->msecSpeechInnerChange = 1000;
1185 stt->msecSpeechOuterChange = 500;
1186 stt->upperLimit = stt->upperPrimaryLimit;
1187 stt->lowerLimit = stt->lowerPrimaryLimit;
1188 } else
1189 {
1190 stt->changeToSlowMode += 2; // in milliseconds
1191 }
1192 stt->msTooLow = 0;
1193 stt->msTooHigh = 0;
1194
1195 stt->micVol = inMicLevelTmp;
1196
1197 }
1198#ifdef MIC_LEVEL_FEEDBACK
1199 if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET)
1200 {
1201 stt->micLvlSat = 1;
1202 fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1203 WebRtcAgc_UpdateAgcThresholds(stt);
1204 WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]),
1205 stt->compressionGaindB, stt->targetLevelDbfs, stt->limiterEnable,
1206 stt->analogTarget);
1207 stt->numBlocksMicLvlSat = 0;
1208 stt->micLvlSat = 0;
1209 fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset);
1210 fprintf(stderr, "target after = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1211 }
1212#endif
1213 }
1214 }
1215
1216 /* Ensure gain is not increased in presence of echo or after a mute event
1217 * (but allow the zeroCtrl() increase on the frame of a mute detection).
1218 */
1219 if (echo == 1 || (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs))
1220 {
1221 if (stt->micVol > lastMicVol)
1222 {
1223 stt->micVol = lastMicVol;
1224 }
1225 }
1226
1227 /* limit the gain */
1228 if (stt->micVol > stt->maxLevel)
1229 {
1230 stt->micVol = stt->maxLevel;
1231 } else if (stt->micVol < stt->minOutput)
1232 {
1233 stt->micVol = stt->minOutput;
1234 }
1235
1236 *outMicLevel = WEBRTC_SPL_RSHIFT_W32(stt->micVol, stt->scale);
1237 if (*outMicLevel > WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog, stt->scale))
1238 {
1239 *outMicLevel = WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog, stt->scale);
1240 }
1241
1242 return 0;
1243}
1244
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001245int WebRtcAgc_Process(void *agcInst, const int16_t *in_near,
1246 const int16_t *in_near_H, int16_t samples,
1247 int16_t *out, int16_t *out_H, int32_t inMicLevel,
1248 int32_t *outMicLevel, int16_t echo,
1249 uint8_t *saturationWarning)
niklase@google.com470e71d2011-07-07 08:21:25 +00001250{
1251 Agc_t *stt;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001252 int32_t inMicLevelTmp;
1253 int16_t subFrames, i;
1254 uint8_t satWarningTmp = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001255
1256 stt = (Agc_t *)agcInst;
1257
1258 //
1259 if (stt == NULL)
1260 {
1261 return -1;
1262 }
1263 //
1264
1265
1266 if (stt->fs == 8000)
1267 {
1268 if ((samples != 80) && (samples != 160))
1269 {
1270#ifdef AGC_DEBUG //test log
1271 fprintf(stt->fpt,
1272 "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount);
1273#endif
1274 return -1;
1275 }
1276 subFrames = 80;
1277 } else if (stt->fs == 16000)
1278 {
1279 if ((samples != 160) && (samples != 320))
1280 {
1281#ifdef AGC_DEBUG //test log
1282 fprintf(stt->fpt,
1283 "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount);
1284#endif
1285 return -1;
1286 }
1287 subFrames = 160;
1288 } else if (stt->fs == 32000)
1289 {
1290 if ((samples != 160) && (samples != 320))
1291 {
1292#ifdef AGC_DEBUG //test log
1293 fprintf(stt->fpt,
1294 "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount);
1295#endif
1296 return -1;
1297 }
1298 subFrames = 160;
1299 } else
1300 {
1301#ifdef AGC_DEBUG// test log
1302 fprintf(stt->fpt,
1303 "AGC->Process, frame %d: Invalid sample rate\n\n", stt->fcount);
1304#endif
1305 return -1;
1306 }
1307
1308 /* Check for valid pointers based on sampling rate */
1309 if (stt->fs == 32000 && in_near_H == NULL)
1310 {
1311 return -1;
1312 }
1313 /* Check for valid pointers for low band */
1314 if (in_near == NULL)
1315 {
1316 return -1;
1317 }
1318
1319 *saturationWarning = 0;
1320 //TODO: PUT IN RANGE CHECKING FOR INPUT LEVELS
1321 *outMicLevel = inMicLevel;
1322 inMicLevelTmp = inMicLevel;
1323
andrew@webrtc.org64235092011-08-19 21:22:08 +00001324 // TODO(andrew): clearly we don't need input and output pointers...
1325 // Change the interface to take a shared input/output.
1326 if (in_near != out)
1327 {
1328 // Only needed if they don't already point to the same place.
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001329 memcpy(out, in_near, samples * sizeof(int16_t));
andrew@webrtc.org64235092011-08-19 21:22:08 +00001330 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001331 if (stt->fs == 32000)
1332 {
andrew@webrtc.org64235092011-08-19 21:22:08 +00001333 if (in_near_H != out_H)
1334 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001335 memcpy(out_H, in_near_H, samples * sizeof(int16_t));
andrew@webrtc.org64235092011-08-19 21:22:08 +00001336 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001337 }
1338
1339#ifdef AGC_DEBUG//test log
1340 stt->fcount++;
1341#endif
1342
1343 for (i = 0; i < samples; i += subFrames)
1344 {
1345 if (WebRtcAgc_ProcessDigital(&stt->digitalAgc, &in_near[i], &in_near_H[i], &out[i], &out_H[i],
1346 stt->fs, stt->lowLevelSignal) == -1)
1347 {
1348#ifdef AGC_DEBUG//test log
1349 fprintf(stt->fpt, "AGC->Process, frame %d: Error from DigAGC\n\n", stt->fcount);
1350#endif
1351 return -1;
1352 }
1353 if ((stt->agcMode < kAgcModeFixedDigital) && ((stt->lowLevelSignal == 0)
1354 || (stt->agcMode != kAgcModeAdaptiveDigital)))
1355 {
1356 if (WebRtcAgc_ProcessAnalog(agcInst, inMicLevelTmp, outMicLevel,
1357 stt->vadMic.logRatio, echo, saturationWarning) == -1)
1358 {
1359 return -1;
1360 }
1361 }
1362#ifdef AGC_DEBUG//test log
1363 fprintf(stt->agcLog, "%5d\t%d\t%d\t%d\n", stt->fcount, inMicLevelTmp, *outMicLevel, stt->maxLevel, stt->micVol);
1364#endif
1365
1366 /* update queue */
1367 if (stt->inQueue > 1)
1368 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001369 memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t));
1370 memcpy(stt->Rxx16w32_array[0], stt->Rxx16w32_array[1], 5 * sizeof(int32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00001371 }
1372
1373 if (stt->inQueue > 0)
1374 {
1375 stt->inQueue--;
1376 }
1377
1378 /* If 20ms frames are used the input mic level must be updated so that
1379 * the analog AGC does not think that there has been a manual volume
1380 * change. */
1381 inMicLevelTmp = *outMicLevel;
1382
1383 /* Store a positive saturation warning. */
1384 if (*saturationWarning == 1)
1385 {
1386 satWarningTmp = 1;
1387 }
1388 }
1389
1390 /* Trigger the saturation warning if displayed by any of the frames. */
1391 *saturationWarning = satWarningTmp;
1392
1393 return 0;
1394}
1395
1396int WebRtcAgc_set_config(void *agcInst, WebRtcAgc_config_t agcConfig)
1397{
1398 Agc_t *stt;
1399 stt = (Agc_t *)agcInst;
1400
1401 if (stt == NULL)
1402 {
1403 return -1;
1404 }
1405
1406 if (stt->initFlag != kInitCheck)
1407 {
1408 stt->lastError = AGC_UNINITIALIZED_ERROR;
1409 return -1;
1410 }
1411
1412 if (agcConfig.limiterEnable != kAgcFalse && agcConfig.limiterEnable != kAgcTrue)
1413 {
1414 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1415 return -1;
1416 }
1417 stt->limiterEnable = agcConfig.limiterEnable;
1418 stt->compressionGaindB = agcConfig.compressionGaindB;
1419 if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31))
1420 {
1421 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1422 return -1;
1423 }
1424 stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
1425
1426 if (stt->agcMode == kAgcModeFixedDigital)
1427 {
1428 /* Adjust for different parameter interpretation in FixedDigital mode */
1429 stt->compressionGaindB += agcConfig.targetLevelDbfs;
1430 }
1431
1432 /* Update threshold levels for analog adaptation */
1433 WebRtcAgc_UpdateAgcThresholds(stt);
1434
1435 /* Recalculate gain table */
1436 if (WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
1437 stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1)
1438 {
1439#ifdef AGC_DEBUG//test log
1440 fprintf(stt->fpt, "AGC->set_config, frame %d: Error from calcGainTable\n\n", stt->fcount);
1441#endif
1442 return -1;
1443 }
1444 /* Store the config in a WebRtcAgc_config_t */
1445 stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
1446 stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
1447 stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
1448
1449 return 0;
1450}
1451
1452int WebRtcAgc_get_config(void *agcInst, WebRtcAgc_config_t *config)
1453{
1454 Agc_t *stt;
1455 stt = (Agc_t *)agcInst;
1456
1457 if (stt == NULL)
1458 {
1459 return -1;
1460 }
1461
1462 if (config == NULL)
1463 {
1464 stt->lastError = AGC_NULL_POINTER_ERROR;
1465 return -1;
1466 }
1467
1468 if (stt->initFlag != kInitCheck)
1469 {
1470 stt->lastError = AGC_UNINITIALIZED_ERROR;
1471 return -1;
1472 }
1473
1474 config->limiterEnable = stt->usedConfig.limiterEnable;
1475 config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
1476 config->compressionGaindB = stt->usedConfig.compressionGaindB;
1477
1478 return 0;
1479}
1480
1481int WebRtcAgc_Create(void **agcInst)
1482{
1483 Agc_t *stt;
1484 if (agcInst == NULL)
1485 {
1486 return -1;
1487 }
1488 stt = (Agc_t *)malloc(sizeof(Agc_t));
1489
1490 *agcInst = stt;
1491 if (stt == NULL)
1492 {
1493 return -1;
1494 }
1495
1496#ifdef AGC_DEBUG
1497 stt->fpt = fopen("./agc_test_log.txt", "wt");
1498 stt->agcLog = fopen("./agc_debug_log.txt", "wt");
1499 stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
1500#endif
1501
1502 stt->initFlag = 0;
1503 stt->lastError = 0;
1504
1505 return 0;
1506}
1507
1508int WebRtcAgc_Free(void *state)
1509{
1510 Agc_t *stt;
1511
1512 stt = (Agc_t *)state;
1513#ifdef AGC_DEBUG
1514 fclose(stt->fpt);
1515 fclose(stt->agcLog);
1516 fclose(stt->digitalAgc.logFile);
1517#endif
1518 free(stt);
1519
1520 return 0;
1521}
1522
1523/* minLevel - Minimum volume level
1524 * maxLevel - Maximum volume level
1525 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001526int WebRtcAgc_Init(void *agcInst, int32_t minLevel, int32_t maxLevel,
1527 int16_t agcMode, uint32_t fs)
niklase@google.com470e71d2011-07-07 08:21:25 +00001528{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001529 int32_t max_add, tmp32;
1530 int16_t i;
niklase@google.com470e71d2011-07-07 08:21:25 +00001531 int tmpNorm;
1532 Agc_t *stt;
1533
1534 /* typecast state pointer */
1535 stt = (Agc_t *)agcInst;
1536
1537 if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0)
1538 {
1539 stt->lastError = AGC_UNINITIALIZED_ERROR;
1540 return -1;
1541 }
1542
1543 /* Analog AGC variables */
1544 stt->envSum = 0;
1545
1546 /* mode = 0 - Only saturation protection
1547 * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1548 * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1549 * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
1550 */
1551#ifdef AGC_DEBUG//test log
1552 stt->fcount = 0;
1553 fprintf(stt->fpt, "AGC->Init\n");
1554#endif
1555 if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital)
1556 {
1557#ifdef AGC_DEBUG//test log
1558 fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
1559#endif
1560 return -1;
1561 }
1562 stt->agcMode = agcMode;
1563 stt->fs = fs;
1564
1565 /* initialize input VAD */
1566 WebRtcAgc_InitVad(&stt->vadMic);
1567
1568 /* If the volume range is smaller than 0-256 then
1569 * the levels are shifted up to Q8-domain */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001570 tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001571 stt->scale = tmpNorm - 23;
1572 if (stt->scale < 0)
1573 {
1574 stt->scale = 0;
1575 }
1576 // TODO(bjornv): Investigate if we really need to scale up a small range now when we have
1577 // a guard against zero-increments. For now, we do not support scale up (scale = 0).
1578 stt->scale = 0;
1579 maxLevel = WEBRTC_SPL_LSHIFT_W32(maxLevel, stt->scale);
1580 minLevel = WEBRTC_SPL_LSHIFT_W32(minLevel, stt->scale);
1581
1582 /* Make minLevel and maxLevel static in AdaptiveDigital */
1583 if (stt->agcMode == kAgcModeAdaptiveDigital)
1584 {
1585 minLevel = 0;
1586 maxLevel = 255;
1587 stt->scale = 0;
1588 }
1589 /* The maximum supplemental volume range is based on a vague idea
1590 * of how much lower the gain will be than the real analog gain. */
1591 max_add = WEBRTC_SPL_RSHIFT_W32(maxLevel - minLevel, 2);
1592
1593 /* Minimum/maximum volume level that can be set */
1594 stt->minLevel = minLevel;
1595 stt->maxAnalog = maxLevel;
1596 stt->maxLevel = maxLevel + max_add;
1597 stt->maxInit = stt->maxLevel;
1598
1599 stt->zeroCtrlMax = stt->maxAnalog;
1600
1601 /* Initialize micVol parameter */
1602 stt->micVol = stt->maxAnalog;
1603 if (stt->agcMode == kAgcModeAdaptiveDigital)
1604 {
1605 stt->micVol = 127; /* Mid-point of mic level */
1606 }
1607 stt->micRef = stt->micVol;
1608 stt->micGainIdx = 127;
1609#ifdef MIC_LEVEL_FEEDBACK
1610 stt->numBlocksMicLvlSat = 0;
1611 stt->micLvlSat = 0;
1612#endif
1613#ifdef AGC_DEBUG//test log
1614 fprintf(stt->fpt,
1615 "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
1616 stt->minLevel, stt->maxAnalog, stt->maxLevel);
1617#endif
1618
1619 /* Minimum output volume is 4% higher than the available lowest volume level */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001620 tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (int32_t)10, 8);
niklase@google.com470e71d2011-07-07 08:21:25 +00001621 stt->minOutput = (stt->minLevel + tmp32);
1622
1623 stt->msTooLow = 0;
1624 stt->msTooHigh = 0;
1625 stt->changeToSlowMode = 0;
1626 stt->firstCall = 0;
1627 stt->msZero = 0;
1628 stt->muteGuardMs = 0;
1629 stt->gainTableIdx = 0;
1630
1631 stt->msecSpeechInnerChange = kMsecSpeechInner;
1632 stt->msecSpeechOuterChange = kMsecSpeechOuter;
1633
1634 stt->activeSpeech = 0;
1635 stt->Rxx16_LPw32Max = 0;
1636
1637 stt->vadThreshold = kNormalVadThreshold;
1638 stt->inActive = 0;
1639
1640 for (i = 0; i < RXX_BUFFER_LEN; i++)
1641 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001642 stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
niklase@google.com470e71d2011-07-07 08:21:25 +00001643 }
1644 stt->Rxx160w32 = 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
1645
1646 stt->Rxx16pos = 0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001647 stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */
niklase@google.com470e71d2011-07-07 08:21:25 +00001648
1649 for (i = 0; i < 5; i++)
1650 {
1651 stt->Rxx16w32_array[0][i] = 0;
1652 }
bjornv@webrtc.org281b7982012-05-30 07:41:57 +00001653 for (i = 0; i < 10; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001654 {
1655 stt->env[0][i] = 0;
bjornv@webrtc.org281b7982012-05-30 07:41:57 +00001656 stt->env[1][i] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001657 }
1658 stt->inQueue = 0;
1659
1660#ifdef MIC_LEVEL_FEEDBACK
1661 stt->targetIdxOffset = 0;
1662#endif
1663
1664 WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
1665
1666 stt->initFlag = kInitCheck;
1667 // Default config settings.
1668 stt->defaultConfig.limiterEnable = kAgcTrue;
1669 stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
1670 stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
1671
1672 if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1)
1673 {
1674 stt->lastError = AGC_UNSPECIFIED_ERROR;
1675 return -1;
1676 }
1677 stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value
1678
1679 stt->lowLevelSignal = 0;
1680
1681 /* Only positive values are allowed that are not too large */
1682 if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000))
1683 {
1684#ifdef AGC_DEBUG//test log
1685 fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
1686#endif
1687 return -1;
1688 } else
1689 {
1690#ifdef AGC_DEBUG//test log
1691 fprintf(stt->fpt, "\n");
1692#endif
1693 return 0;
1694 }
1695}