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*/ 28static const WebRtc_Word16 kSlope1[8] = {21793, 12517, 7189, 4129, 2372, 1362, 472, 78}; 29 30/* The offset in Q14 */ 31static const WebRtc_Word16 kOffset1[8] = {25395, 23911, 22206, 20737, 19612, 18805, 17951, 32 17367}; 33 34/* The slope of in Q13*/ 35static const WebRtc_Word16 kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337}; 36 37/* The offset in Q14 */ 38static const WebRtc_Word16 kOffset2[8] = {18432, 18379, 18290, 18177, 18052, 17920, 17670, 39 17286}; 40 41static const WebRtc_Word16 kMuteGuardTimeMs = 8000; 42static 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 */ 75static 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) */ 80static 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}; 91static 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 105static 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 113int 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 /* |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 207 /* Q1 */ 208 tmp16 = (WebRtc_Word16)(stt->micVol - stt->maxAnalog); 209 tmp32 = WEBRTC_SPL_MUL_16_16(GAIN_TBL_LEN - 1, tmp16); 210 tmp16 = (WebRtc_Word16)(stt->maxLevel - stt->maxAnalog); 211 targetGainIdx = (WebRtc_UWord16)WEBRTC_SPL_DIV(tmp32, tmp16); 212 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 { 241 in_mic[i] = (WebRtc_Word16)sample; 242 } 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 { 257 in_mic_H[i] = (WebRtc_Word16)sample; 258 } 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 330int WebRtcAgc_AddFarend(void *state, const WebRtc_Word16 *in_far, WebRtc_Word16 samples) 331{ 332 WebRtc_Word32 errHandle = 0; 333 WebRtc_Word16 i, subFrames; 334 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 396int WebRtcAgc_VirtualMic(void *agcInst, WebRtc_Word16 *in_near, WebRtc_Word16 *in_near_H, 397 WebRtc_Word16 samples, WebRtc_Word32 micLevelIn, 398 WebRtc_Word32 *micLevelOut) 399{ 400 WebRtc_Word32 tmpFlt, micLevelTmp, gainIdx; 401 WebRtc_UWord16 gain; 402 WebRtc_Word16 ii; 403 Agc_t *stt; 404 405 WebRtc_UWord32 nrg; 406 WebRtc_Word16 sampleCntr; 407 WebRtc_UWord32 frameNrg = 0; 408 WebRtc_UWord32 frameNrgLimit = 5500; 409 WebRtc_Word16 numZeroCrossing = 0; 410 const WebRtc_Word16 kZeroCrossingLowLim = 15; 411 const WebRtc_Word16 kZeroCrossingHighLim = 20; 412 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 } 510 in_near[ii] = (WebRtc_Word16)tmpFlt; 511 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 } 523 in_near_H[ii] = (WebRtc_Word16)tmpFlt; 524 } 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 541 WebRtc_Word16 tmp16; 542#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; 555 tmp16 = WebRtcSpl_DivW32W16ResW16((WebRtc_Word32)tmp16, ANALOG_TARGET_LEVEL); 556 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 590void WebRtcAgc_SaturationCtrl(Agc_t *stt, WebRtc_UWord8 *saturated, WebRtc_Word32 *env) 591{ 592 WebRtc_Word16 i, tmpW16; 593 594 /* Check if the signal is saturated */ 595 for (i = 0; i < 10; i++) 596 { 597 tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(env[i], 20); 598 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; */ 611 stt->envSum = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(stt->envSum, 612 (WebRtc_Word16)32440, 15); 613} 614 615void WebRtcAgc_ZeroCtrl(Agc_t *stt, WebRtc_Word32 *inMicLevel, WebRtc_Word32 *env) 616{ 617 WebRtc_Word16 i; 618 WebRtc_Word32 tmp32 = 0; 619 WebRtc_Word32 midVal; 620 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 685 WebRtc_Word32 tmp32; 686 WebRtc_Word16 vadThresh; 687 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; */ 701 tmp32 = (WebRtc_Word32)vadThresh; 702 tmp32 += WEBRTC_SPL_MUL_16_16((WebRtc_Word16)31, stt->vadThreshold); 703 stt->vadThreshold = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 5); 704 } 705} 706 707void WebRtcAgc_ExpCurve(WebRtc_Word16 volume, WebRtc_Word16 *index) 708{ 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 757WebRtc_Word32 WebRtcAgc_ProcessAnalog(void *state, WebRtc_Word32 inMicLevel, 758 WebRtc_Word32 *outMicLevel, 759 WebRtc_Word16 vadLogRatio, 760 WebRtc_Word16 echo, WebRtc_UWord8 *saturationWarning) 761{ 762 WebRtc_UWord32 tmpU32; 763 WebRtc_Word32 Rxx16w32, tmp32; 764 WebRtc_Word32 inMicLevelTmp, lastMicVol; 765 WebRtc_Word16 i; 766 WebRtc_UWord8 saturated = 0; 767 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 { 788 WebRtc_Word32 tmpVol; 789 stt->firstCall = 1; 790 tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (WebRtc_Word32)51, 9); 791 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 { 810 tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (WebRtc_Word32)51, 9); 811 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; 859 tmpU32 = WEBRTC_SPL_UMUL(29591, (WebRtc_UWord32)(tmp32)); 860 stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel; 861 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 */ 928 stt->Rxx16pos++; 929 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; 991 tmpU32 = WEBRTC_SPL_UMUL(31130, (WebRtc_UWord32)(tmp32)); 992 stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel; 993 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; 1039 tmpU32 = WEBRTC_SPL_UMUL(31621, (WebRtc_UWord32)(inMicLevelTmp - stt->minLevel)); 1040 stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel; 1041 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 */ 1065 WebRtc_Word16 index, weightFIX; 1066 WebRtc_Word16 volNormFIX = 16384; // =1 in Q14. 1067 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 { 1074 volNormFIX = (WebRtc_Word16)WEBRTC_SPL_DIV(tmp32, 1075 (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] 1083 - (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(kSlope1[index], 1084 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; 1091 tmpU32 = ((WebRtc_UWord32)weightFIX * (WebRtc_UWord32)(inMicLevelTmp - stt->minLevel)); 1092 stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 14) + stt->minLevel; 1093 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 */ 1125 WebRtc_Word16 index, weightFIX; 1126 WebRtc_Word16 volNormFIX = 16384; // =1 in Q14. 1127 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 { 1134 volNormFIX = (WebRtc_Word16)WEBRTC_SPL_DIV(tmp32, 1135 (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] 1143 - (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(kSlope2[index], 1144 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; 1151 tmpU32 = ((WebRtc_UWord32)weightFIX * (WebRtc_UWord32)(inMicLevelTmp - stt->minLevel)); 1152 stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 14) + stt->minLevel; 1153 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 1245int WebRtcAgc_Process(void *agcInst, const WebRtc_Word16 *in_near, 1246 const WebRtc_Word16 *in_near_H, WebRtc_Word16 samples, 1247 WebRtc_Word16 *out, WebRtc_Word16 *out_H, WebRtc_Word32 inMicLevel, 1248 WebRtc_Word32 *outMicLevel, WebRtc_Word16 echo, 1249 WebRtc_UWord8 *saturationWarning) 1250{ 1251 Agc_t *stt; 1252 WebRtc_Word32 inMicLevelTmp; 1253 WebRtc_Word16 subFrames, i; 1254 WebRtc_UWord8 satWarningTmp = 0; 1255 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 1324 // 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. 1329 memcpy(out, in_near, samples * sizeof(WebRtc_Word16)); 1330 } 1331 if (stt->fs == 32000) 1332 { 1333 if (in_near_H != out_H) 1334 { 1335 memcpy(out_H, in_near_H, samples * sizeof(WebRtc_Word16)); 1336 } 1337 } 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 { 1369 memcpy(stt->env[0], stt->env[1], 10 * sizeof(WebRtc_Word32)); 1370 memcpy(stt->Rxx16w32_array[0], stt->Rxx16w32_array[1], 5 * sizeof(WebRtc_Word32)); 1371 } 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 */ 1526int WebRtcAgc_Init(void *agcInst, WebRtc_Word32 minLevel, WebRtc_Word32 maxLevel, 1527 WebRtc_Word16 agcMode, WebRtc_UWord32 fs) 1528{ 1529 WebRtc_Word32 max_add, tmp32; 1530 WebRtc_Word16 i; 1531 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 */ 1570 tmpNorm = WebRtcSpl_NormU32((WebRtc_UWord32)maxLevel); 1571 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 */ 1620 tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (WebRtc_Word32)10, 8); 1621 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 { 1642 stt->Rxx16_vectorw32[i] = (WebRtc_Word32)1000; /* -54dBm0 */ 1643 } 1644 stt->Rxx160w32 = 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */ 1645 1646 stt->Rxx16pos = 0; 1647 stt->Rxx16_LPw32 = (WebRtc_Word32)16284; /* Q(-4) */ 1648 1649 for (i = 0; i < 5; i++) 1650 { 1651 stt->Rxx16w32_array[0][i] = 0; 1652 } 1653 for (i = 0; i < 20; i++) 1654 { 1655 stt->env[0][i] = 0; 1656 } 1657 stt->inQueue = 0; 1658 1659#ifdef MIC_LEVEL_FEEDBACK 1660 stt->targetIdxOffset = 0; 1661#endif 1662 1663 WebRtcSpl_MemSetW32(stt->filterState, 0, 8); 1664 1665 stt->initFlag = kInitCheck; 1666 // Default config settings. 1667 stt->defaultConfig.limiterEnable = kAgcTrue; 1668 stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL; 1669 stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN; 1670 1671 if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1) 1672 { 1673 stt->lastError = AGC_UNSPECIFIED_ERROR; 1674 return -1; 1675 } 1676 stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value 1677 1678 stt->lowLevelSignal = 0; 1679 1680 /* Only positive values are allowed that are not too large */ 1681 if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000)) 1682 { 1683#ifdef AGC_DEBUG//test log 1684 fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n"); 1685#endif 1686 return -1; 1687 } else 1688 { 1689#ifdef AGC_DEBUG//test log 1690 fprintf(stt->fpt, "\n"); 1691#endif 1692 return 0; 1693 } 1694} 1695 1696int WebRtcAgc_Version(WebRtc_Word8 *versionStr, WebRtc_Word16 length) 1697{ 1698 const WebRtc_Word8 version[] = "AGC 1.7.0"; 1699 const WebRtc_Word16 versionLen = (WebRtc_Word16)strlen(version) + 1; 1700 1701 if (versionStr == NULL) 1702 { 1703 return -1; 1704 } 1705 1706 if (versionLen > length) 1707 { 1708 return -1; 1709 } 1710 1711 strncpy(versionStr, version, versionLen); 1712 return 0; 1713} 1714