1 /*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 /* 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*/
28 static const WebRtc_Word16 kSlope1[8] = {21793, 12517, 7189, 4129, 2372, 1362, 472, 78};
29
30 /* The offset in Q14 */
31 static const WebRtc_Word16 kOffset1[8] = {25395, 23911, 22206, 20737, 19612, 18805, 17951,
32 17367};
33
34 /* The slope of in Q13*/
35 static const WebRtc_Word16 kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337};
36
37 /* The offset in Q14 */
38 static const WebRtc_Word16 kOffset2[8] = {18432, 18379, 18290, 18177, 18052, 17920, 17670,
39 17286};
40
41 static const WebRtc_Word16 kMuteGuardTimeMs = 8000;
42 static const WebRtc_Word16 kInitCheck = 42;
43
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 */
75 static const WebRtc_UWord16 kGainTableAnalog[GAIN_TBL_LEN] = {4096, 4251, 4412, 4579, 4752,
76 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) */
80 static const WebRtc_UWord16 kGainTableVirtualMic[128] = {1052, 1081, 1110, 1141, 1172, 1204,
81 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};
91 static const WebRtc_UWord16 kSuppressionTableVirtualMic[128] = {1024, 1006, 988, 970, 952,
92 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
105 static const WebRtc_Word32 kTargetLevelTable[64] = {134209536, 106606424, 84680493, 67264106,
106 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
WebRtcAgc_AddMic(void * state,WebRtc_Word16 * in_mic,WebRtc_Word16 * in_mic_H,WebRtc_Word16 samples)113 int WebRtcAgc_AddMic(void *state, WebRtc_Word16 *in_mic, WebRtc_Word16 *in_mic_H,
114 WebRtc_Word16 samples)
115 {
116 WebRtc_Word32 nrg, max_nrg, sample, tmp32;
117 WebRtc_Word32 *ptr;
118 WebRtc_UWord16 targetGainIdx, gain;
119 WebRtc_Word16 i, n, L, M, subFrames, tmp16, tmp_speech[16];
120 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 {
203 /* Q1 */
204 tmp16 = (WebRtc_Word16)(stt->micVol - stt->maxAnalog);
205 tmp32 = WEBRTC_SPL_MUL_16_16(GAIN_TBL_LEN - 1, tmp16);
206 tmp16 = (WebRtc_Word16)(stt->maxLevel - stt->maxAnalog);
207 targetGainIdx = (WebRtc_UWord16)WEBRTC_SPL_DIV(tmp32, tmp16);
208 assert(targetGainIdx < GAIN_TBL_LEN);
209
210 /* Increment through the table towards the target gain.
211 * If micVol drops below maxAnalog, we allow the gain
212 * to be dropped immediately. */
213 if (stt->gainTableIdx < targetGainIdx)
214 {
215 stt->gainTableIdx++;
216 } else if (stt->gainTableIdx > targetGainIdx)
217 {
218 stt->gainTableIdx--;
219 }
220
221 /* Q12 */
222 gain = kGainTableAnalog[stt->gainTableIdx];
223
224 for (i = 0; i < samples; i++)
225 {
226 // For lower band
227 tmp32 = WEBRTC_SPL_MUL_16_U16(in_mic[i], gain);
228 sample = WEBRTC_SPL_RSHIFT_W32(tmp32, 12);
229 if (sample > 32767)
230 {
231 in_mic[i] = 32767;
232 } else if (sample < -32768)
233 {
234 in_mic[i] = -32768;
235 } else
236 {
237 in_mic[i] = (WebRtc_Word16)sample;
238 }
239
240 // For higher band
241 if (stt->fs == 32000)
242 {
243 tmp32 = WEBRTC_SPL_MUL_16_U16(in_mic_H[i], gain);
244 sample = WEBRTC_SPL_RSHIFT_W32(tmp32, 12);
245 if (sample > 32767)
246 {
247 in_mic_H[i] = 32767;
248 } else if (sample < -32768)
249 {
250 in_mic_H[i] = -32768;
251 } else
252 {
253 in_mic_H[i] = (WebRtc_Word16)sample;
254 }
255 }
256 }
257 } else
258 {
259 stt->gainTableIdx = 0;
260 }
261
262 /* compute envelope */
263 if ((M == 10) && (stt->inQueue > 0))
264 {
265 ptr = stt->env[1];
266 } else
267 {
268 ptr = stt->env[0];
269 }
270
271 for (i = 0; i < M; i++)
272 {
273 /* iterate over samples */
274 max_nrg = 0;
275 for (n = 0; n < L; n++)
276 {
277 nrg = WEBRTC_SPL_MUL_16_16(in_mic[i * L + n], in_mic[i * L + n]);
278 if (nrg > max_nrg)
279 {
280 max_nrg = nrg;
281 }
282 }
283 ptr[i] = max_nrg;
284 }
285
286 /* compute energy */
287 if ((M == 10) && (stt->inQueue > 0))
288 {
289 ptr = stt->Rxx16w32_array[1];
290 } else
291 {
292 ptr = stt->Rxx16w32_array[0];
293 }
294
295 for (i = 0; i < WEBRTC_SPL_RSHIFT_W16(M, 1); i++)
296 {
297 if (stt->fs == 16000)
298 {
299 WebRtcSpl_DownsampleBy2(&in_mic[i * 32], 32, tmp_speech, stt->filterState);
300 } else
301 {
302 memcpy(tmp_speech, &in_mic[i * 16], 16 * sizeof(short));
303 }
304 /* Compute energy in blocks of 16 samples */
305 ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4);
306 }
307
308 /* update queue information */
309 if ((stt->inQueue == 0) && (M == 10))
310 {
311 stt->inQueue = 1;
312 } else
313 {
314 stt->inQueue = 2;
315 }
316
317 /* call VAD (use low band only) */
318 for (i = 0; i < samples; i += subFrames)
319 {
320 WebRtcAgc_ProcessVad(&stt->vadMic, &in_mic[i], subFrames);
321 }
322
323 return 0;
324 }
325
WebRtcAgc_AddFarend(void * state,const WebRtc_Word16 * in_far,WebRtc_Word16 samples)326 int WebRtcAgc_AddFarend(void *state, const WebRtc_Word16 *in_far, WebRtc_Word16 samples)
327 {
328 WebRtc_Word32 errHandle = 0;
329 WebRtc_Word16 i, subFrames;
330 Agc_t *stt;
331 stt = (Agc_t *)state;
332
333 if (stt == NULL)
334 {
335 return -1;
336 }
337
338 if (stt->fs == 8000)
339 {
340 if ((samples != 80) && (samples != 160))
341 {
342 #ifdef AGC_DEBUG //test log
343 fprintf(stt->fpt,
344 "AGC->add_far_end, frame %d: Invalid number of samples\n\n",
345 stt->fcount);
346 #endif
347 return -1;
348 }
349 subFrames = 80;
350 } else if (stt->fs == 16000)
351 {
352 if ((samples != 160) && (samples != 320))
353 {
354 #ifdef AGC_DEBUG //test log
355 fprintf(stt->fpt,
356 "AGC->add_far_end, frame %d: Invalid number of samples\n\n",
357 stt->fcount);
358 #endif
359 return -1;
360 }
361 subFrames = 160;
362 } else if (stt->fs == 32000)
363 {
364 if ((samples != 160) && (samples != 320))
365 {
366 #ifdef AGC_DEBUG //test log
367 fprintf(stt->fpt,
368 "AGC->add_far_end, frame %d: Invalid number of samples\n\n",
369 stt->fcount);
370 #endif
371 return -1;
372 }
373 subFrames = 160;
374 } else
375 {
376 #ifdef AGC_DEBUG //test log
377 fprintf(stt->fpt,
378 "AGC->add_far_end, frame %d: Invalid sample rate\n\n",
379 stt->fcount + 1);
380 #endif
381 return -1;
382 }
383
384 for (i = 0; i < samples; i += subFrames)
385 {
386 errHandle += WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, &in_far[i], subFrames);
387 }
388
389 return errHandle;
390 }
391
WebRtcAgc_VirtualMic(void * agcInst,WebRtc_Word16 * in_near,WebRtc_Word16 * in_near_H,WebRtc_Word16 samples,WebRtc_Word32 micLevelIn,WebRtc_Word32 * micLevelOut)392 int WebRtcAgc_VirtualMic(void *agcInst, WebRtc_Word16 *in_near, WebRtc_Word16 *in_near_H,
393 WebRtc_Word16 samples, WebRtc_Word32 micLevelIn,
394 WebRtc_Word32 *micLevelOut)
395 {
396 WebRtc_Word32 tmpFlt, micLevelTmp, gainIdx;
397 WebRtc_UWord16 gain;
398 WebRtc_Word16 ii;
399 Agc_t *stt;
400
401 WebRtc_UWord32 nrg;
402 WebRtc_Word16 sampleCntr;
403 WebRtc_UWord32 frameNrg = 0;
404 WebRtc_UWord32 frameNrgLimit = 5500;
405 WebRtc_Word16 numZeroCrossing = 0;
406 const WebRtc_Word16 kZeroCrossingLowLim = 15;
407 const WebRtc_Word16 kZeroCrossingHighLim = 20;
408
409 stt = (Agc_t *)agcInst;
410
411 /*
412 * Before applying gain decide if this is a low-level signal.
413 * The idea is that digital AGC will not adapt to low-level
414 * signals.
415 */
416 if (stt->fs != 8000)
417 {
418 frameNrgLimit = frameNrgLimit << 1;
419 }
420
421 frameNrg = WEBRTC_SPL_MUL_16_16(in_near[0], in_near[0]);
422 for (sampleCntr = 1; sampleCntr < samples; sampleCntr++)
423 {
424
425 // increment frame energy if it is less than the limit
426 // the correct value of the energy is not important
427 if (frameNrg < frameNrgLimit)
428 {
429 nrg = WEBRTC_SPL_MUL_16_16(in_near[sampleCntr], in_near[sampleCntr]);
430 frameNrg += nrg;
431 }
432
433 // Count the zero crossings
434 numZeroCrossing += ((in_near[sampleCntr] ^ in_near[sampleCntr - 1]) < 0);
435 }
436
437 if ((frameNrg < 500) || (numZeroCrossing <= 5))
438 {
439 stt->lowLevelSignal = 1;
440 } else if (numZeroCrossing <= kZeroCrossingLowLim)
441 {
442 stt->lowLevelSignal = 0;
443 } else if (frameNrg <= frameNrgLimit)
444 {
445 stt->lowLevelSignal = 1;
446 } else if (numZeroCrossing >= kZeroCrossingHighLim)
447 {
448 stt->lowLevelSignal = 1;
449 } else
450 {
451 stt->lowLevelSignal = 0;
452 }
453
454 micLevelTmp = WEBRTC_SPL_LSHIFT_W32(micLevelIn, stt->scale);
455 /* Set desired level */
456 gainIdx = stt->micVol;
457 if (stt->micVol > stt->maxAnalog)
458 {
459 gainIdx = stt->maxAnalog;
460 }
461 if (micLevelTmp != stt->micRef)
462 {
463 /* Something has happened with the physical level, restart. */
464 stt->micRef = micLevelTmp;
465 stt->micVol = 127;
466 *micLevelOut = 127;
467 stt->micGainIdx = 127;
468 gainIdx = 127;
469 }
470 /* Pre-process the signal to emulate the microphone level. */
471 /* Take one step at a time in the gain table. */
472 if (gainIdx > 127)
473 {
474 gain = kGainTableVirtualMic[gainIdx - 128];
475 } else
476 {
477 gain = kSuppressionTableVirtualMic[127 - gainIdx];
478 }
479 for (ii = 0; ii < samples; ii++)
480 {
481 tmpFlt = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_U16(in_near[ii], gain), 10);
482 if (tmpFlt > 32767)
483 {
484 tmpFlt = 32767;
485 gainIdx--;
486 if (gainIdx >= 127)
487 {
488 gain = kGainTableVirtualMic[gainIdx - 127];
489 } else
490 {
491 gain = kSuppressionTableVirtualMic[127 - gainIdx];
492 }
493 }
494 if (tmpFlt < -32768)
495 {
496 tmpFlt = -32768;
497 gainIdx--;
498 if (gainIdx >= 127)
499 {
500 gain = kGainTableVirtualMic[gainIdx - 127];
501 } else
502 {
503 gain = kSuppressionTableVirtualMic[127 - gainIdx];
504 }
505 }
506 in_near[ii] = (WebRtc_Word16)tmpFlt;
507 if (stt->fs == 32000)
508 {
509 tmpFlt = WEBRTC_SPL_MUL_16_U16(in_near_H[ii], gain);
510 tmpFlt = WEBRTC_SPL_RSHIFT_W32(tmpFlt, 10);
511 if (tmpFlt > 32767)
512 {
513 tmpFlt = 32767;
514 }
515 if (tmpFlt < -32768)
516 {
517 tmpFlt = -32768;
518 }
519 in_near_H[ii] = (WebRtc_Word16)tmpFlt;
520 }
521 }
522 /* Set the level we (finally) used */
523 stt->micGainIdx = gainIdx;
524 // *micLevelOut = stt->micGainIdx;
525 *micLevelOut = WEBRTC_SPL_RSHIFT_W32(stt->micGainIdx, stt->scale);
526 /* Add to Mic as if it was the output from a true microphone */
527 if (WebRtcAgc_AddMic(agcInst, in_near, in_near_H, samples) != 0)
528 {
529 return -1;
530 }
531 return 0;
532 }
533
WebRtcAgc_UpdateAgcThresholds(Agc_t * stt)534 void WebRtcAgc_UpdateAgcThresholds(Agc_t *stt)
535 {
536
537 WebRtc_Word16 tmp16;
538 #ifdef MIC_LEVEL_FEEDBACK
539 int zeros;
540
541 if (stt->micLvlSat)
542 {
543 /* Lower the analog target level since we have reached its maximum */
544 zeros = WebRtcSpl_NormW32(stt->Rxx160_LPw32);
545 stt->targetIdxOffset = WEBRTC_SPL_RSHIFT_W16((3 * zeros) - stt->targetIdx - 2, 2);
546 }
547 #endif
548
549 /* Set analog target level in envelope dBOv scale */
550 tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2;
551 tmp16 = WebRtcSpl_DivW32W16ResW16((WebRtc_Word32)tmp16, ANALOG_TARGET_LEVEL);
552 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16;
553 if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN)
554 {
555 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN;
556 }
557 if (stt->agcMode == kAgcModeFixedDigital)
558 {
559 /* Adjust for different parameter interpretation in FixedDigital mode */
560 stt->analogTarget = stt->compressionGaindB;
561 }
562 #ifdef MIC_LEVEL_FEEDBACK
563 stt->analogTarget += stt->targetIdxOffset;
564 #endif
565 /* Since the offset between RMS and ENV is not constant, we should make this into a
566 * table, but for now, we'll stick with a constant, tuned for the chosen analog
567 * target level.
568 */
569 stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS;
570 #ifdef MIC_LEVEL_FEEDBACK
571 stt->targetIdx += stt->targetIdxOffset;
572 #endif
573 /* Analog adaptation limits */
574 /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */
575 stt->analogTargetLevel = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */
576 stt->startUpperLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 1];/* -19 dBov */
577 stt->startLowerLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 1];/* -21 dBov */
578 stt->upperPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 2];/* -18 dBov */
579 stt->lowerPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 2];/* -22 dBov */
580 stt->upperSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 5];/* -15 dBov */
581 stt->lowerSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 5];/* -25 dBov */
582 stt->upperLimit = stt->startUpperLimit;
583 stt->lowerLimit = stt->startLowerLimit;
584 }
585
WebRtcAgc_SaturationCtrl(Agc_t * stt,WebRtc_UWord8 * saturated,WebRtc_Word32 * env)586 void WebRtcAgc_SaturationCtrl(Agc_t *stt, WebRtc_UWord8 *saturated, WebRtc_Word32 *env)
587 {
588 WebRtc_Word16 i, tmpW16;
589
590 /* Check if the signal is saturated */
591 for (i = 0; i < 10; i++)
592 {
593 tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(env[i], 20);
594 if (tmpW16 > 875)
595 {
596 stt->envSum += tmpW16;
597 }
598 }
599
600 if (stt->envSum > 25000)
601 {
602 *saturated = 1;
603 stt->envSum = 0;
604 }
605
606 /* stt->envSum *= 0.99; */
607 stt->envSum = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(stt->envSum,
608 (WebRtc_Word16)32440, 15);
609 }
610
WebRtcAgc_ZeroCtrl(Agc_t * stt,WebRtc_Word32 * inMicLevel,WebRtc_Word32 * env)611 void WebRtcAgc_ZeroCtrl(Agc_t *stt, WebRtc_Word32 *inMicLevel, WebRtc_Word32 *env)
612 {
613 WebRtc_Word16 i;
614 WebRtc_Word32 tmp32 = 0;
615 WebRtc_Word32 midVal;
616
617 /* Is the input signal zero? */
618 for (i = 0; i < 10; i++)
619 {
620 tmp32 += env[i];
621 }
622
623 /* Each block is allowed to have a few non-zero
624 * samples.
625 */
626 if (tmp32 < 500)
627 {
628 stt->msZero += 10;
629 } else
630 {
631 stt->msZero = 0;
632 }
633
634 if (stt->muteGuardMs > 0)
635 {
636 stt->muteGuardMs -= 10;
637 }
638
639 if (stt->msZero > 500)
640 {
641 stt->msZero = 0;
642
643 /* Increase microphone level only if it's less than 50% */
644 midVal = WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog + stt->minLevel + 1, 1);
645 if (*inMicLevel < midVal)
646 {
647 /* *inMicLevel *= 1.1; */
648 tmp32 = WEBRTC_SPL_MUL(1126, *inMicLevel);
649 *inMicLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 10);
650 /* Reduces risk of a muted mic repeatedly triggering excessive levels due
651 * to zero signal detection. */
652 *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax);
653 stt->micVol = *inMicLevel;
654 }
655
656 #ifdef AGC_DEBUG //test log
657 fprintf(stt->fpt,
658 "\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold, micVol:\n",
659 stt->fcount, stt->micVol);
660 #endif
661
662 stt->activeSpeech = 0;
663 stt->Rxx16_LPw32Max = 0;
664
665 /* The AGC has a tendency (due to problems with the VAD parameters), to
666 * vastly increase the volume after a muting event. This timer prevents
667 * upwards adaptation for a short period. */
668 stt->muteGuardMs = kMuteGuardTimeMs;
669 }
670 }
671
WebRtcAgc_SpeakerInactiveCtrl(Agc_t * stt)672 void WebRtcAgc_SpeakerInactiveCtrl(Agc_t *stt)
673 {
674 /* Check if the near end speaker is inactive.
675 * If that is the case the VAD threshold is
676 * increased since the VAD speech model gets
677 * more sensitive to any sound after a long
678 * silence.
679 */
680
681 WebRtc_Word32 tmp32;
682 WebRtc_Word16 vadThresh;
683
684 if (stt->vadMic.stdLongTerm < 2500)
685 {
686 stt->vadThreshold = 1500;
687 } else
688 {
689 vadThresh = kNormalVadThreshold;
690 if (stt->vadMic.stdLongTerm < 4500)
691 {
692 /* Scale between min and max threshold */
693 vadThresh += WEBRTC_SPL_RSHIFT_W16(4500 - stt->vadMic.stdLongTerm, 1);
694 }
695
696 /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */
697 tmp32 = (WebRtc_Word32)vadThresh;
698 tmp32 += WEBRTC_SPL_MUL_16_16((WebRtc_Word16)31, stt->vadThreshold);
699 stt->vadThreshold = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 5);
700 }
701 }
702
WebRtcAgc_ExpCurve(WebRtc_Word16 volume,WebRtc_Word16 * index)703 void WebRtcAgc_ExpCurve(WebRtc_Word16 volume, WebRtc_Word16 *index)
704 {
705 // volume in Q14
706 // index in [0-7]
707 /* 8 different curves */
708 if (volume > 5243)
709 {
710 if (volume > 7864)
711 {
712 if (volume > 12124)
713 {
714 *index = 7;
715 } else
716 {
717 *index = 6;
718 }
719 } else
720 {
721 if (volume > 6554)
722 {
723 *index = 5;
724 } else
725 {
726 *index = 4;
727 }
728 }
729 } else
730 {
731 if (volume > 2621)
732 {
733 if (volume > 3932)
734 {
735 *index = 3;
736 } else
737 {
738 *index = 2;
739 }
740 } else
741 {
742 if (volume > 1311)
743 {
744 *index = 1;
745 } else
746 {
747 *index = 0;
748 }
749 }
750 }
751 }
752
WebRtcAgc_ProcessAnalog(void * state,WebRtc_Word32 inMicLevel,WebRtc_Word32 * outMicLevel,WebRtc_Word16 vadLogRatio,WebRtc_Word16 echo,WebRtc_UWord8 * saturationWarning)753 WebRtc_Word32 WebRtcAgc_ProcessAnalog(void *state, WebRtc_Word32 inMicLevel,
754 WebRtc_Word32 *outMicLevel,
755 WebRtc_Word16 vadLogRatio,
756 WebRtc_Word16 echo, WebRtc_UWord8 *saturationWarning)
757 {
758 WebRtc_UWord32 tmpU32;
759 WebRtc_Word32 Rxx16w32, tmp32;
760 WebRtc_Word32 inMicLevelTmp, lastMicVol;
761 WebRtc_Word16 i;
762 WebRtc_UWord8 saturated = 0;
763 Agc_t *stt;
764
765 stt = (Agc_t *)state;
766 inMicLevelTmp = WEBRTC_SPL_LSHIFT_W32(inMicLevel, stt->scale);
767
768 if (inMicLevelTmp > stt->maxAnalog)
769 {
770 #ifdef AGC_DEBUG //test log
771 fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n", stt->fcount);
772 #endif
773 return -1;
774 } else if (inMicLevelTmp < stt->minLevel)
775 {
776 #ifdef AGC_DEBUG //test log
777 fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n", stt->fcount);
778 #endif
779 return -1;
780 }
781
782 if (stt->firstCall == 0)
783 {
784 WebRtc_Word32 tmpVol;
785 stt->firstCall = 1;
786 tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (WebRtc_Word32)51, 9);
787 tmpVol = (stt->minLevel + tmp32);
788
789 /* If the mic level is very low at start, increase it! */
790 if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog))
791 {
792 inMicLevelTmp = tmpVol;
793 }
794 stt->micVol = inMicLevelTmp;
795 }
796
797 /* Set the mic level to the previous output value if there is digital input gain */
798 if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog))
799 {
800 inMicLevelTmp = stt->micVol;
801 }
802
803 /* If the mic level was manually changed to a very low value raise it! */
804 if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput))
805 {
806 tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (WebRtc_Word32)51, 9);
807 inMicLevelTmp = (stt->minLevel + tmp32);
808 stt->micVol = inMicLevelTmp;
809 #ifdef MIC_LEVEL_FEEDBACK
810 //stt->numBlocksMicLvlSat = 0;
811 #endif
812 #ifdef AGC_DEBUG //test log
813 fprintf(stt->fpt,
814 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual decrease, raise vol\n",
815 stt->fcount);
816 #endif
817 }
818
819 if (inMicLevelTmp != stt->micVol)
820 {
821 // Incoming level mismatch; update our level.
822 // This could be the case if the volume is changed manually, or if the
823 // sound device has a low volume resolution.
824 stt->micVol = inMicLevelTmp;
825 }
826
827 if (inMicLevelTmp > stt->maxLevel)
828 {
829 // Always allow the user to raise the volume above the maxLevel.
830 stt->maxLevel = inMicLevelTmp;
831 }
832
833 // Store last value here, after we've taken care of manual updates etc.
834 lastMicVol = stt->micVol;
835
836 /* Checks if the signal is saturated. Also a check if individual samples
837 * are larger than 12000 is done. If they are the counter for increasing
838 * the volume level is set to -100ms
839 */
840 WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
841
842 /* The AGC is always allowed to lower the level if the signal is saturated */
843 if (saturated == 1)
844 {
845 /* Lower the recording level
846 * Rxx160_LP is adjusted down because it is so slow it could
847 * cause the AGC to make wrong decisions. */
848 /* stt->Rxx160_LPw32 *= 0.875; */
849 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 3), 7);
850
851 stt->zeroCtrlMax = stt->micVol;
852
853 /* stt->micVol *= 0.903; */
854 tmp32 = inMicLevelTmp - stt->minLevel;
855 tmpU32 = WEBRTC_SPL_UMUL(29591, (WebRtc_UWord32)(tmp32));
856 stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel;
857 if (stt->micVol > lastMicVol - 2)
858 {
859 stt->micVol = lastMicVol - 2;
860 }
861 inMicLevelTmp = stt->micVol;
862
863 #ifdef AGC_DEBUG //test log
864 fprintf(stt->fpt,
865 "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
866 stt->fcount, stt->micVol);
867 #endif
868
869 if (stt->micVol < stt->minOutput)
870 {
871 *saturationWarning = 1;
872 }
873
874 /* Reset counter for decrease of volume level to avoid
875 * decreasing too much. The saturation control can still
876 * lower the level if needed. */
877 stt->msTooHigh = -100;
878
879 /* Enable the control mechanism to ensure that our measure,
880 * Rxx160_LP, is in the correct range. This must be done since
881 * the measure is very slow. */
882 stt->activeSpeech = 0;
883 stt->Rxx16_LPw32Max = 0;
884
885 /* Reset to initial values */
886 stt->msecSpeechInnerChange = kMsecSpeechInner;
887 stt->msecSpeechOuterChange = kMsecSpeechOuter;
888 stt->changeToSlowMode = 0;
889
890 stt->muteGuardMs = 0;
891
892 stt->upperLimit = stt->startUpperLimit;
893 stt->lowerLimit = stt->startLowerLimit;
894 #ifdef MIC_LEVEL_FEEDBACK
895 //stt->numBlocksMicLvlSat = 0;
896 #endif
897 }
898
899 /* Check if the input speech is zero. If so the mic volume
900 * is increased. On some computers the input is zero up as high
901 * level as 17% */
902 WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
903
904 /* Check if the near end speaker is inactive.
905 * If that is the case the VAD threshold is
906 * increased since the VAD speech model gets
907 * more sensitive to any sound after a long
908 * silence.
909 */
910 WebRtcAgc_SpeakerInactiveCtrl(stt);
911
912 for (i = 0; i < 5; i++)
913 {
914 /* Computed on blocks of 16 samples */
915
916 Rxx16w32 = stt->Rxx16w32_array[0][i];
917
918 /* Rxx160w32 in Q(-7) */
919 tmp32 = WEBRTC_SPL_RSHIFT_W32(Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos], 3);
920 stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
921 stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
922
923 /* Circular buffer */
924 if (++(stt->Rxx16pos) == RXX_BUFFER_LEN)
925 {
926 stt->Rxx16pos = 0;
927 }
928
929 /* Rxx16_LPw32 in Q(-4) */
930 tmp32 = WEBRTC_SPL_RSHIFT_W32(Rxx16w32 - stt->Rxx16_LPw32, kAlphaShortTerm);
931 stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
932
933 if (vadLogRatio > stt->vadThreshold)
934 {
935 /* Speech detected! */
936
937 /* Check if Rxx160_LP is in the correct range. If
938 * it is too high/low then we set it to the maximum of
939 * Rxx16_LPw32 during the first 200ms of speech.
940 */
941 if (stt->activeSpeech < 250)
942 {
943 stt->activeSpeech += 2;
944
945 if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max)
946 {
947 stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
948 }
949 } else if (stt->activeSpeech == 250)
950 {
951 stt->activeSpeech += 2;
952 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx16_LPw32Max, 3);
953 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, RXX_BUFFER_LEN);
954 }
955
956 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160w32 - stt->Rxx160_LPw32, kAlphaLongTerm);
957 stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
958
959 if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit)
960 {
961 stt->msTooHigh += 2;
962 stt->msTooLow = 0;
963 stt->changeToSlowMode = 0;
964
965 if (stt->msTooHigh > stt->msecSpeechOuterChange)
966 {
967 stt->msTooHigh = 0;
968
969 /* Lower the recording level */
970 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
971 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
972 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 53);
973
974 /* Reduce the max gain to avoid excessive oscillation
975 * (but never drop below the maximum analog level).
976 * stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
977 */
978 tmp32 = (15 * stt->maxLevel) + stt->micVol;
979 stt->maxLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 4);
980 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
981
982 stt->zeroCtrlMax = stt->micVol;
983
984 /* 0.95 in Q15 */
985 tmp32 = inMicLevelTmp - stt->minLevel;
986 tmpU32 = WEBRTC_SPL_UMUL(31130, (WebRtc_UWord32)(tmp32));
987 stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel;
988 if (stt->micVol > lastMicVol - 1)
989 {
990 stt->micVol = lastMicVol - 1;
991 }
992 inMicLevelTmp = stt->micVol;
993
994 /* Enable the control mechanism to ensure that our measure,
995 * Rxx160_LP, is in the correct range.
996 */
997 stt->activeSpeech = 0;
998 stt->Rxx16_LPw32Max = 0;
999 #ifdef MIC_LEVEL_FEEDBACK
1000 //stt->numBlocksMicLvlSat = 0;
1001 #endif
1002 #ifdef AGC_DEBUG //test log
1003 fprintf(stt->fpt,
1004 "\tAGC->ProcessAnalog, frame %d: measure > 2ndUpperLim, micVol = %d, maxLevel = %d\n",
1005 stt->fcount, stt->micVol, stt->maxLevel);
1006 #endif
1007 }
1008 } else if (stt->Rxx160_LPw32 > stt->upperLimit)
1009 {
1010 stt->msTooHigh += 2;
1011 stt->msTooLow = 0;
1012 stt->changeToSlowMode = 0;
1013
1014 if (stt->msTooHigh > stt->msecSpeechInnerChange)
1015 {
1016 /* Lower the recording level */
1017 stt->msTooHigh = 0;
1018 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
1019 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
1020 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 53);
1021
1022 /* Reduce the max gain to avoid excessive oscillation
1023 * (but never drop below the maximum analog level).
1024 * stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
1025 */
1026 tmp32 = (15 * stt->maxLevel) + stt->micVol;
1027 stt->maxLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 4);
1028 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
1029
1030 stt->zeroCtrlMax = stt->micVol;
1031
1032 /* 0.965 in Q15 */
1033 tmp32 = inMicLevelTmp - stt->minLevel;
1034 tmpU32 = WEBRTC_SPL_UMUL(31621, (WebRtc_UWord32)(inMicLevelTmp - stt->minLevel));
1035 stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel;
1036 if (stt->micVol > lastMicVol - 1)
1037 {
1038 stt->micVol = lastMicVol - 1;
1039 }
1040 inMicLevelTmp = stt->micVol;
1041
1042 #ifdef MIC_LEVEL_FEEDBACK
1043 //stt->numBlocksMicLvlSat = 0;
1044 #endif
1045 #ifdef AGC_DEBUG //test log
1046 fprintf(stt->fpt,
1047 "\tAGC->ProcessAnalog, frame %d: measure > UpperLim, micVol = %d, maxLevel = %d\n",
1048 stt->fcount, stt->micVol, stt->maxLevel);
1049 #endif
1050 }
1051 } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit)
1052 {
1053 stt->msTooHigh = 0;
1054 stt->changeToSlowMode = 0;
1055 stt->msTooLow += 2;
1056
1057 if (stt->msTooLow > stt->msecSpeechOuterChange)
1058 {
1059 /* Raise the recording level */
1060 WebRtc_Word16 index, weightFIX;
1061 WebRtc_Word16 volNormFIX = 16384; // =1 in Q14.
1062
1063 stt->msTooLow = 0;
1064
1065 /* Normalize the volume level */
1066 tmp32 = WEBRTC_SPL_LSHIFT_W32(inMicLevelTmp - stt->minLevel, 14);
1067 if (stt->maxInit != stt->minLevel)
1068 {
1069 volNormFIX = (WebRtc_Word16)WEBRTC_SPL_DIV(tmp32,
1070 (stt->maxInit - stt->minLevel));
1071 }
1072
1073 /* Find correct curve */
1074 WebRtcAgc_ExpCurve(volNormFIX, &index);
1075
1076 /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05 */
1077 weightFIX = kOffset1[index]
1078 - (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(kSlope1[index],
1079 volNormFIX, 13);
1080
1081 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
1082 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
1083 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 67);
1084
1085 tmp32 = inMicLevelTmp - stt->minLevel;
1086 tmpU32 = ((WebRtc_UWord32)weightFIX * (WebRtc_UWord32)(inMicLevelTmp - stt->minLevel));
1087 stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 14) + stt->minLevel;
1088 if (stt->micVol < lastMicVol + 2)
1089 {
1090 stt->micVol = lastMicVol + 2;
1091 }
1092
1093 inMicLevelTmp = stt->micVol;
1094
1095 #ifdef MIC_LEVEL_FEEDBACK
1096 /* Count ms in level saturation */
1097 //if (stt->micVol > stt->maxAnalog) {
1098 if (stt->micVol > 150)
1099 {
1100 /* mic level is saturated */
1101 stt->numBlocksMicLvlSat++;
1102 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1103 }
1104 #endif
1105 #ifdef AGC_DEBUG //test log
1106 fprintf(stt->fpt,
1107 "\tAGC->ProcessAnalog, frame %d: measure < 2ndLowerLim, micVol = %d\n",
1108 stt->fcount, stt->micVol);
1109 #endif
1110 }
1111 } else if (stt->Rxx160_LPw32 < stt->lowerLimit)
1112 {
1113 stt->msTooHigh = 0;
1114 stt->changeToSlowMode = 0;
1115 stt->msTooLow += 2;
1116
1117 if (stt->msTooLow > stt->msecSpeechInnerChange)
1118 {
1119 /* Raise the recording level */
1120 WebRtc_Word16 index, weightFIX;
1121 WebRtc_Word16 volNormFIX = 16384; // =1 in Q14.
1122
1123 stt->msTooLow = 0;
1124
1125 /* Normalize the volume level */
1126 tmp32 = WEBRTC_SPL_LSHIFT_W32(inMicLevelTmp - stt->minLevel, 14);
1127 if (stt->maxInit != stt->minLevel)
1128 {
1129 volNormFIX = (WebRtc_Word16)WEBRTC_SPL_DIV(tmp32,
1130 (stt->maxInit - stt->minLevel));
1131 }
1132
1133 /* Find correct curve */
1134 WebRtcAgc_ExpCurve(volNormFIX, &index);
1135
1136 /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1 */
1137 weightFIX = kOffset2[index]
1138 - (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(kSlope2[index],
1139 volNormFIX, 13);
1140
1141 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
1142 tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6);
1143 stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 67);
1144
1145 tmp32 = inMicLevelTmp - stt->minLevel;
1146 tmpU32 = ((WebRtc_UWord32)weightFIX * (WebRtc_UWord32)(inMicLevelTmp - stt->minLevel));
1147 stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 14) + stt->minLevel;
1148 if (stt->micVol < lastMicVol + 1)
1149 {
1150 stt->micVol = lastMicVol + 1;
1151 }
1152
1153 inMicLevelTmp = stt->micVol;
1154
1155 #ifdef MIC_LEVEL_FEEDBACK
1156 /* Count ms in level saturation */
1157 //if (stt->micVol > stt->maxAnalog) {
1158 if (stt->micVol > 150)
1159 {
1160 /* mic level is saturated */
1161 stt->numBlocksMicLvlSat++;
1162 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1163 }
1164 #endif
1165 #ifdef AGC_DEBUG //test log
1166 fprintf(stt->fpt,
1167 "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol = %d\n",
1168 stt->fcount, stt->micVol);
1169 #endif
1170
1171 }
1172 } else
1173 {
1174 /* The signal is inside the desired range which is:
1175 * lowerLimit < Rxx160_LP/640 < upperLimit
1176 */
1177 if (stt->changeToSlowMode > 4000)
1178 {
1179 stt->msecSpeechInnerChange = 1000;
1180 stt->msecSpeechOuterChange = 500;
1181 stt->upperLimit = stt->upperPrimaryLimit;
1182 stt->lowerLimit = stt->lowerPrimaryLimit;
1183 } else
1184 {
1185 stt->changeToSlowMode += 2; // in milliseconds
1186 }
1187 stt->msTooLow = 0;
1188 stt->msTooHigh = 0;
1189
1190 stt->micVol = inMicLevelTmp;
1191
1192 }
1193 #ifdef MIC_LEVEL_FEEDBACK
1194 if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET)
1195 {
1196 stt->micLvlSat = 1;
1197 fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1198 WebRtcAgc_UpdateAgcThresholds(stt);
1199 WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]),
1200 stt->compressionGaindB, stt->targetLevelDbfs, stt->limiterEnable,
1201 stt->analogTarget);
1202 stt->numBlocksMicLvlSat = 0;
1203 stt->micLvlSat = 0;
1204 fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset);
1205 fprintf(stderr, "target after = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1206 }
1207 #endif
1208 }
1209 }
1210
1211 /* Ensure gain is not increased in presence of echo or after a mute event
1212 * (but allow the zeroCtrl() increase on the frame of a mute detection).
1213 */
1214 if (echo == 1 || (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs))
1215 {
1216 if (stt->micVol > lastMicVol)
1217 {
1218 stt->micVol = lastMicVol;
1219 }
1220 }
1221
1222 /* limit the gain */
1223 if (stt->micVol > stt->maxLevel)
1224 {
1225 stt->micVol = stt->maxLevel;
1226 } else if (stt->micVol < stt->minOutput)
1227 {
1228 stt->micVol = stt->minOutput;
1229 }
1230
1231 *outMicLevel = WEBRTC_SPL_RSHIFT_W32(stt->micVol, stt->scale);
1232 if (*outMicLevel > WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog, stt->scale))
1233 {
1234 *outMicLevel = WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog, stt->scale);
1235 }
1236
1237 return 0;
1238 }
1239
WebRtcAgc_Process(void * agcInst,const WebRtc_Word16 * in_near,const WebRtc_Word16 * in_near_H,WebRtc_Word16 samples,WebRtc_Word16 * out,WebRtc_Word16 * out_H,WebRtc_Word32 inMicLevel,WebRtc_Word32 * outMicLevel,WebRtc_Word16 echo,WebRtc_UWord8 * saturationWarning)1240 int WebRtcAgc_Process(void *agcInst, const WebRtc_Word16 *in_near,
1241 const WebRtc_Word16 *in_near_H, WebRtc_Word16 samples,
1242 WebRtc_Word16 *out, WebRtc_Word16 *out_H, WebRtc_Word32 inMicLevel,
1243 WebRtc_Word32 *outMicLevel, WebRtc_Word16 echo,
1244 WebRtc_UWord8 *saturationWarning)
1245 {
1246 Agc_t *stt;
1247 WebRtc_Word32 inMicLevelTmp;
1248 WebRtc_Word16 subFrames, i;
1249 WebRtc_UWord8 satWarningTmp = 0;
1250
1251 stt = (Agc_t *)agcInst;
1252
1253 //
1254 if (stt == NULL)
1255 {
1256 return -1;
1257 }
1258 //
1259
1260
1261 if (stt->fs == 8000)
1262 {
1263 if ((samples != 80) && (samples != 160))
1264 {
1265 #ifdef AGC_DEBUG //test log
1266 fprintf(stt->fpt,
1267 "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount);
1268 #endif
1269 return -1;
1270 }
1271 subFrames = 80;
1272 } else if (stt->fs == 16000)
1273 {
1274 if ((samples != 160) && (samples != 320))
1275 {
1276 #ifdef AGC_DEBUG //test log
1277 fprintf(stt->fpt,
1278 "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount);
1279 #endif
1280 return -1;
1281 }
1282 subFrames = 160;
1283 } else if (stt->fs == 32000)
1284 {
1285 if ((samples != 160) && (samples != 320))
1286 {
1287 #ifdef AGC_DEBUG //test log
1288 fprintf(stt->fpt,
1289 "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount);
1290 #endif
1291 return -1;
1292 }
1293 subFrames = 160;
1294 } else
1295 {
1296 #ifdef AGC_DEBUG// test log
1297 fprintf(stt->fpt,
1298 "AGC->Process, frame %d: Invalid sample rate\n\n", stt->fcount);
1299 #endif
1300 return -1;
1301 }
1302
1303 /* Check for valid pointers based on sampling rate */
1304 if (stt->fs == 32000 && in_near_H == NULL)
1305 {
1306 return -1;
1307 }
1308 /* Check for valid pointers for low band */
1309 if (in_near == NULL)
1310 {
1311 return -1;
1312 }
1313
1314 *saturationWarning = 0;
1315 //TODO: PUT IN RANGE CHECKING FOR INPUT LEVELS
1316 *outMicLevel = inMicLevel;
1317 inMicLevelTmp = inMicLevel;
1318
1319 memcpy(out, in_near, samples * sizeof(WebRtc_Word16));
1320 if (stt->fs == 32000)
1321 {
1322 memcpy(out_H, in_near_H, samples * sizeof(WebRtc_Word16));
1323 }
1324
1325 #ifdef AGC_DEBUG//test log
1326 stt->fcount++;
1327 #endif
1328
1329 for (i = 0; i < samples; i += subFrames)
1330 {
1331 if (WebRtcAgc_ProcessDigital(&stt->digitalAgc, &in_near[i], &in_near_H[i], &out[i], &out_H[i],
1332 stt->fs, stt->lowLevelSignal) == -1)
1333 {
1334 #ifdef AGC_DEBUG//test log
1335 fprintf(stt->fpt, "AGC->Process, frame %d: Error from DigAGC\n\n", stt->fcount);
1336 #endif
1337 return -1;
1338 }
1339 if ((stt->agcMode < kAgcModeFixedDigital) && ((stt->lowLevelSignal == 0)
1340 || (stt->agcMode != kAgcModeAdaptiveDigital)))
1341 {
1342 if (WebRtcAgc_ProcessAnalog(agcInst, inMicLevelTmp, outMicLevel,
1343 stt->vadMic.logRatio, echo, saturationWarning) == -1)
1344 {
1345 return -1;
1346 }
1347 }
1348 #ifdef AGC_DEBUG//test log
1349 fprintf(stt->agcLog, "%5d\t%d\t%d\t%d\n", stt->fcount, inMicLevelTmp, *outMicLevel, stt->maxLevel, stt->micVol);
1350 #endif
1351
1352 /* update queue */
1353 if (stt->inQueue > 1)
1354 {
1355 memcpy(stt->env[0], stt->env[1], 10 * sizeof(WebRtc_Word32));
1356 memcpy(stt->Rxx16w32_array[0], stt->Rxx16w32_array[1], 5 * sizeof(WebRtc_Word32));
1357 }
1358
1359 if (stt->inQueue > 0)
1360 {
1361 stt->inQueue--;
1362 }
1363
1364 /* If 20ms frames are used the input mic level must be updated so that
1365 * the analog AGC does not think that there has been a manual volume
1366 * change. */
1367 inMicLevelTmp = *outMicLevel;
1368
1369 /* Store a positive saturation warning. */
1370 if (*saturationWarning == 1)
1371 {
1372 satWarningTmp = 1;
1373 }
1374 }
1375
1376 /* Trigger the saturation warning if displayed by any of the frames. */
1377 *saturationWarning = satWarningTmp;
1378
1379 return 0;
1380 }
1381
WebRtcAgc_set_config(void * agcInst,WebRtcAgc_config_t agcConfig)1382 int WebRtcAgc_set_config(void *agcInst, WebRtcAgc_config_t agcConfig)
1383 {
1384 Agc_t *stt;
1385 stt = (Agc_t *)agcInst;
1386
1387 if (stt == NULL)
1388 {
1389 return -1;
1390 }
1391
1392 if (stt->initFlag != kInitCheck)
1393 {
1394 stt->lastError = AGC_UNINITIALIZED_ERROR;
1395 return -1;
1396 }
1397
1398 if (agcConfig.limiterEnable != kAgcFalse && agcConfig.limiterEnable != kAgcTrue)
1399 {
1400 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1401 return -1;
1402 }
1403 stt->limiterEnable = agcConfig.limiterEnable;
1404 stt->compressionGaindB = agcConfig.compressionGaindB;
1405 if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31))
1406 {
1407 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1408 return -1;
1409 }
1410 stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
1411
1412 if (stt->agcMode == kAgcModeFixedDigital)
1413 {
1414 /* Adjust for different parameter interpretation in FixedDigital mode */
1415 stt->compressionGaindB += agcConfig.targetLevelDbfs;
1416 }
1417
1418 /* Update threshold levels for analog adaptation */
1419 WebRtcAgc_UpdateAgcThresholds(stt);
1420
1421 /* Recalculate gain table */
1422 if (WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
1423 stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1)
1424 {
1425 #ifdef AGC_DEBUG//test log
1426 fprintf(stt->fpt, "AGC->set_config, frame %d: Error from calcGainTable\n\n", stt->fcount);
1427 #endif
1428 return -1;
1429 }
1430 /* Store the config in a WebRtcAgc_config_t */
1431 stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
1432 stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
1433 stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
1434
1435 return 0;
1436 }
1437
WebRtcAgc_get_config(void * agcInst,WebRtcAgc_config_t * config)1438 int WebRtcAgc_get_config(void *agcInst, WebRtcAgc_config_t *config)
1439 {
1440 Agc_t *stt;
1441 stt = (Agc_t *)agcInst;
1442
1443 if (stt == NULL)
1444 {
1445 return -1;
1446 }
1447
1448 if (config == NULL)
1449 {
1450 stt->lastError = AGC_NULL_POINTER_ERROR;
1451 return -1;
1452 }
1453
1454 if (stt->initFlag != kInitCheck)
1455 {
1456 stt->lastError = AGC_UNINITIALIZED_ERROR;
1457 return -1;
1458 }
1459
1460 config->limiterEnable = stt->usedConfig.limiterEnable;
1461 config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
1462 config->compressionGaindB = stt->usedConfig.compressionGaindB;
1463
1464 return 0;
1465 }
1466
WebRtcAgc_Create(void ** agcInst)1467 int WebRtcAgc_Create(void **agcInst)
1468 {
1469 Agc_t *stt;
1470 if (agcInst == NULL)
1471 {
1472 return -1;
1473 }
1474 stt = (Agc_t *)malloc(sizeof(Agc_t));
1475
1476 *agcInst = stt;
1477 if (stt == NULL)
1478 {
1479 return -1;
1480 }
1481
1482 #ifdef AGC_DEBUG
1483 stt->fpt = fopen("./agc_test_log.txt", "wt");
1484 stt->agcLog = fopen("./agc_debug_log.txt", "wt");
1485 stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
1486 #endif
1487
1488 stt->initFlag = 0;
1489 stt->lastError = 0;
1490
1491 return 0;
1492 }
1493
WebRtcAgc_Free(void * state)1494 int WebRtcAgc_Free(void *state)
1495 {
1496 Agc_t *stt;
1497
1498 stt = (Agc_t *)state;
1499 #ifdef AGC_DEBUG
1500 fclose(stt->fpt);
1501 fclose(stt->agcLog);
1502 fclose(stt->digitalAgc.logFile);
1503 #endif
1504 free(stt);
1505
1506 return 0;
1507 }
1508
1509 /* minLevel - Minimum volume level
1510 * maxLevel - Maximum volume level
1511 */
WebRtcAgc_Init(void * agcInst,WebRtc_Word32 minLevel,WebRtc_Word32 maxLevel,WebRtc_Word16 agcMode,WebRtc_UWord32 fs)1512 int WebRtcAgc_Init(void *agcInst, WebRtc_Word32 minLevel, WebRtc_Word32 maxLevel,
1513 WebRtc_Word16 agcMode, WebRtc_UWord32 fs)
1514 {
1515 WebRtc_Word32 max_add, tmp32;
1516 WebRtc_Word16 i;
1517 int tmpNorm;
1518 Agc_t *stt;
1519
1520 /* typecast state pointer */
1521 stt = (Agc_t *)agcInst;
1522
1523 if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0)
1524 {
1525 stt->lastError = AGC_UNINITIALIZED_ERROR;
1526 return -1;
1527 }
1528
1529 /* Analog AGC variables */
1530 stt->envSum = 0;
1531
1532 /* mode = 0 - Only saturation protection
1533 * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1534 * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1535 * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
1536 */
1537 #ifdef AGC_DEBUG//test log
1538 stt->fcount = 0;
1539 fprintf(stt->fpt, "AGC->Init\n");
1540 #endif
1541 if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital)
1542 {
1543 #ifdef AGC_DEBUG//test log
1544 fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
1545 #endif
1546 return -1;
1547 }
1548 stt->agcMode = agcMode;
1549 stt->fs = fs;
1550
1551 /* initialize input VAD */
1552 WebRtcAgc_InitVad(&stt->vadMic);
1553
1554 /* If the volume range is smaller than 0-256 then
1555 * the levels are shifted up to Q8-domain */
1556 tmpNorm = WebRtcSpl_NormU32((WebRtc_UWord32)maxLevel);
1557 stt->scale = tmpNorm - 23;
1558 if (stt->scale < 0)
1559 {
1560 stt->scale = 0;
1561 }
1562 // TODO(bjornv): Investigate if we really need to scale up a small range now when we have
1563 // a guard against zero-increments. For now, we do not support scale up (scale = 0).
1564 stt->scale = 0;
1565 maxLevel = WEBRTC_SPL_LSHIFT_W32(maxLevel, stt->scale);
1566 minLevel = WEBRTC_SPL_LSHIFT_W32(minLevel, stt->scale);
1567
1568 /* Make minLevel and maxLevel static in AdaptiveDigital */
1569 if (stt->agcMode == kAgcModeAdaptiveDigital)
1570 {
1571 minLevel = 0;
1572 maxLevel = 255;
1573 stt->scale = 0;
1574 }
1575 /* The maximum supplemental volume range is based on a vague idea
1576 * of how much lower the gain will be than the real analog gain. */
1577 max_add = WEBRTC_SPL_RSHIFT_W32(maxLevel - minLevel, 2);
1578
1579 /* Minimum/maximum volume level that can be set */
1580 stt->minLevel = minLevel;
1581 stt->maxAnalog = maxLevel;
1582 stt->maxLevel = maxLevel + max_add;
1583 stt->maxInit = stt->maxLevel;
1584
1585 stt->zeroCtrlMax = stt->maxAnalog;
1586
1587 /* Initialize micVol parameter */
1588 stt->micVol = stt->maxAnalog;
1589 if (stt->agcMode == kAgcModeAdaptiveDigital)
1590 {
1591 stt->micVol = 127; /* Mid-point of mic level */
1592 }
1593 stt->micRef = stt->micVol;
1594 stt->micGainIdx = 127;
1595 #ifdef MIC_LEVEL_FEEDBACK
1596 stt->numBlocksMicLvlSat = 0;
1597 stt->micLvlSat = 0;
1598 #endif
1599 #ifdef AGC_DEBUG//test log
1600 fprintf(stt->fpt,
1601 "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
1602 stt->minLevel, stt->maxAnalog, stt->maxLevel);
1603 #endif
1604
1605 /* Minimum output volume is 4% higher than the available lowest volume level */
1606 tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (WebRtc_Word32)10, 8);
1607 stt->minOutput = (stt->minLevel + tmp32);
1608
1609 stt->msTooLow = 0;
1610 stt->msTooHigh = 0;
1611 stt->changeToSlowMode = 0;
1612 stt->firstCall = 0;
1613 stt->msZero = 0;
1614 stt->muteGuardMs = 0;
1615 stt->gainTableIdx = 0;
1616
1617 stt->msecSpeechInnerChange = kMsecSpeechInner;
1618 stt->msecSpeechOuterChange = kMsecSpeechOuter;
1619
1620 stt->activeSpeech = 0;
1621 stt->Rxx16_LPw32Max = 0;
1622
1623 stt->vadThreshold = kNormalVadThreshold;
1624 stt->inActive = 0;
1625
1626 for (i = 0; i < RXX_BUFFER_LEN; i++)
1627 {
1628 stt->Rxx16_vectorw32[i] = (WebRtc_Word32)1000; /* -54dBm0 */
1629 }
1630 stt->Rxx160w32 = 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
1631
1632 stt->Rxx16pos = 0;
1633 stt->Rxx16_LPw32 = (WebRtc_Word32)16284; /* Q(-4) */
1634
1635 for (i = 0; i < 5; i++)
1636 {
1637 stt->Rxx16w32_array[0][i] = 0;
1638 }
1639 for (i = 0; i < 20; i++)
1640 {
1641 stt->env[0][i] = 0;
1642 }
1643 stt->inQueue = 0;
1644
1645 #ifdef MIC_LEVEL_FEEDBACK
1646 stt->targetIdxOffset = 0;
1647 #endif
1648
1649 WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
1650
1651 stt->initFlag = kInitCheck;
1652 // Default config settings.
1653 stt->defaultConfig.limiterEnable = kAgcTrue;
1654 stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
1655 stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
1656
1657 if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1)
1658 {
1659 stt->lastError = AGC_UNSPECIFIED_ERROR;
1660 return -1;
1661 }
1662 stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value
1663
1664 stt->lowLevelSignal = 0;
1665
1666 /* Only positive values are allowed that are not too large */
1667 if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000))
1668 {
1669 #ifdef AGC_DEBUG//test log
1670 fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
1671 #endif
1672 return -1;
1673 } else
1674 {
1675 #ifdef AGC_DEBUG//test log
1676 fprintf(stt->fpt, "\n");
1677 #endif
1678 return 0;
1679 }
1680 }
1681
WebRtcAgc_Version(WebRtc_Word8 * versionStr,WebRtc_Word16 length)1682 int WebRtcAgc_Version(WebRtc_Word8 *versionStr, WebRtc_Word16 length)
1683 {
1684 const WebRtc_Word8 version[] = "AGC 1.7.0";
1685 const WebRtc_Word16 versionLen = (WebRtc_Word16)strlen(version) + 1;
1686
1687 if (versionStr == NULL)
1688 {
1689 return -1;
1690 }
1691
1692 if (versionLen > length)
1693 {
1694 return -1;
1695 }
1696
1697 strncpy(versionStr, version, versionLen);
1698 return 0;
1699 }
1700