blob: 0b50bcb908dd8c5ffef26037a869d12a12b334a4 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
bjornv@webrtc.org0c6f9312012-01-30 09:39:08 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11/* analog_agc.c
12 *
13 * Using a feedback system, determines an appropriate analog volume level
14 * given an input signal and current volume level. Targets a conservative
15 * signal level and is intended for use with a digital AGC to apply
16 * additional gain.
17 *
18 */
19
20#include <assert.h>
21#include <stdlib.h>
bjornv@webrtc.orgea297872014-09-23 11:21:39 +000022#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +000023#include <stdio.h>
24#endif
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000025#include "webrtc/modules/audio_processing/agc/analog_agc.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000026
27/* The slope of in Q13*/
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000028static const int16_t kSlope1[8] = {21793, 12517, 7189, 4129, 2372, 1362, 472, 78};
niklase@google.com470e71d2011-07-07 08:21:25 +000029
30/* The offset in Q14 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000031static const int16_t kOffset1[8] = {25395, 23911, 22206, 20737, 19612, 18805, 17951,
niklase@google.com470e71d2011-07-07 08:21:25 +000032 17367};
33
34/* The slope of in Q13*/
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000035static const int16_t kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337};
niklase@google.com470e71d2011-07-07 08:21:25 +000036
37/* The offset in Q14 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000038static const int16_t kOffset2[8] = {18432, 18379, 18290, 18177, 18052, 17920, 17670,
niklase@google.com470e71d2011-07-07 08:21:25 +000039 17286};
40
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000041static const int16_t kMuteGuardTimeMs = 8000;
42static const int16_t kInitCheck = 42;
aluebs@webrtc.org96a62622014-12-15 21:54:50 +000043static const int16_t kNumSubframes = 10;
niklase@google.com470e71d2011-07-07 08:21:25 +000044
45/* Default settings if config is not used */
46#define AGC_DEFAULT_TARGET_LEVEL 3
47#define AGC_DEFAULT_COMP_GAIN 9
48/* This is the target level for the analog part in ENV scale. To convert to RMS scale you
49 * have to add OFFSET_ENV_TO_RMS.
50 */
51#define ANALOG_TARGET_LEVEL 11
52#define ANALOG_TARGET_LEVEL_2 5 // ANALOG_TARGET_LEVEL / 2
53/* Offset between RMS scale (analog part) and ENV scale (digital part). This value actually
54 * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future replace it with
55 * a table.
56 */
57#define OFFSET_ENV_TO_RMS 9
58/* The reference input level at which the digital part gives an output of targetLevelDbfs
59 * (desired level) if we have no compression gain. This level should be set high enough not
60 * to compress the peaks due to the dynamics.
61 */
62#define DIGITAL_REF_AT_0_COMP_GAIN 4
63/* Speed of reference level decrease.
64 */
65#define DIFF_REF_TO_ANALOG 5
66
67#ifdef MIC_LEVEL_FEEDBACK
68#define NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET 7
69#endif
70/* Size of analog gain table */
71#define GAIN_TBL_LEN 32
72/* Matlab code:
73 * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12));
74 */
75/* Q12 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000076static const uint16_t kGainTableAnalog[GAIN_TBL_LEN] = {4096, 4251, 4412, 4579, 4752,
niklase@google.com470e71d2011-07-07 08:21:25 +000077 4932, 5118, 5312, 5513, 5722, 5938, 6163, 6396, 6638, 6889, 7150, 7420, 7701, 7992,
78 8295, 8609, 8934, 9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953};
79
80/* Gain/Suppression tables for virtual Mic (in Q10) */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000081static const uint16_t kGainTableVirtualMic[128] = {1052, 1081, 1110, 1141, 1172, 1204,
niklase@google.com470e71d2011-07-07 08:21:25 +000082 1237, 1271, 1305, 1341, 1378, 1416, 1454, 1494, 1535, 1577, 1620, 1664, 1710, 1757,
83 1805, 1854, 1905, 1957, 2010, 2065, 2122, 2180, 2239, 2301, 2364, 2428, 2495, 2563,
84 2633, 2705, 2779, 2855, 2933, 3013, 3096, 3180, 3267, 3357, 3449, 3543, 3640, 3739,
85 3842, 3947, 4055, 4166, 4280, 4397, 4517, 4640, 4767, 4898, 5032, 5169, 5311, 5456,
86 5605, 5758, 5916, 6078, 6244, 6415, 6590, 6770, 6956, 7146, 7341, 7542, 7748, 7960,
87 8178, 8402, 8631, 8867, 9110, 9359, 9615, 9878, 10148, 10426, 10711, 11004, 11305,
88 11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807, 15212, 15628,
89 16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923, 20468, 21028, 21603,
90 22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808, 27541, 28295, 29069, 29864,
91 30681, 31520, 32382};
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000092static const uint16_t kSuppressionTableVirtualMic[128] = {1024, 1006, 988, 970, 952,
niklase@google.com470e71d2011-07-07 08:21:25 +000093 935, 918, 902, 886, 870, 854, 839, 824, 809, 794, 780, 766, 752, 739, 726, 713, 700,
94 687, 675, 663, 651, 639, 628, 616, 605, 594, 584, 573, 563, 553, 543, 533, 524, 514,
95 505, 496, 487, 478, 470, 461, 453, 445, 437, 429, 421, 414, 406, 399, 392, 385, 378,
96 371, 364, 358, 351, 345, 339, 333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278,
97 273, 268, 263, 258, 254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204,
98 200, 197, 193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155, 153, 150,
99 147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118, 116, 114, 112, 110,
100 108, 106, 104, 102};
101
102/* Table for target energy levels. Values in Q(-7)
103 * Matlab code
104 * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n', round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */
105
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000106static const int32_t kTargetLevelTable[64] = {134209536, 106606424, 84680493, 67264106,
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 53429779, 42440782, 33711911, 26778323, 21270778, 16895980, 13420954, 10660642,
108 8468049, 6726411, 5342978, 4244078, 3371191, 2677832, 2127078, 1689598, 1342095,
109 1066064, 846805, 672641, 534298, 424408, 337119, 267783, 212708, 168960, 134210,
110 106606, 84680, 67264, 53430, 42441, 33712, 26778, 21271, 16896, 13421, 10661, 8468,
111 6726, 5343, 4244, 3371, 2678, 2127, 1690, 1342, 1066, 847, 673, 534, 424, 337, 268,
112 213, 169, 134, 107, 85, 67};
113
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000114int WebRtcAgc_AddMic(void *state, int16_t *in_mic, int16_t *in_mic_H,
115 int16_t samples)
niklase@google.com470e71d2011-07-07 08:21:25 +0000116{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000117 int32_t nrg, max_nrg, sample, tmp32;
118 int32_t *ptr;
119 uint16_t targetGainIdx, gain;
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000120 int16_t i, n, L, tmp16, tmp_speech[16];
niklase@google.com470e71d2011-07-07 08:21:25 +0000121 Agc_t *stt;
122 stt = (Agc_t *)state;
123
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000124 if (stt->fs == 8000) {
125 L = 8;
126 if (samples != 80) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000127 return -1;
128 }
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000129 } else {
130 L = 16;
131 if (samples != 160) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000132 return -1;
133 }
134 }
135
136 /* Check for valid pointers based on sampling rate */
137 if ((stt->fs == 32000) && (in_mic_H == NULL))
138 {
139 return -1;
140 }
141 /* Check for valid pointer for low band */
142 if (in_mic == NULL)
143 {
144 return -1;
145 }
146
147 /* apply slowly varying digital gain */
148 if (stt->micVol > stt->maxAnalog)
149 {
andrew@webrtc.org3905b0c2012-01-04 15:47:20 +0000150 /* |maxLevel| is strictly >= |micVol|, so this condition should be
151 * satisfied here, ensuring there is no divide-by-zero. */
152 assert(stt->maxLevel > stt->maxAnalog);
153
niklase@google.com470e71d2011-07-07 08:21:25 +0000154 /* Q1 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000155 tmp16 = (int16_t)(stt->micVol - stt->maxAnalog);
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 tmp32 = WEBRTC_SPL_MUL_16_16(GAIN_TBL_LEN - 1, tmp16);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000157 tmp16 = (int16_t)(stt->maxLevel - stt->maxAnalog);
bjornv@webrtc.orgdf9fef62014-08-28 12:57:32 +0000158 targetGainIdx = tmp32 / tmp16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000159 assert(targetGainIdx < GAIN_TBL_LEN);
160
161 /* Increment through the table towards the target gain.
162 * If micVol drops below maxAnalog, we allow the gain
163 * to be dropped immediately. */
164 if (stt->gainTableIdx < targetGainIdx)
165 {
166 stt->gainTableIdx++;
167 } else if (stt->gainTableIdx > targetGainIdx)
168 {
169 stt->gainTableIdx--;
170 }
171
172 /* Q12 */
173 gain = kGainTableAnalog[stt->gainTableIdx];
174
175 for (i = 0; i < samples; i++)
176 {
177 // For lower band
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000178 sample = (in_mic[i] * gain) >> 12;
niklase@google.com470e71d2011-07-07 08:21:25 +0000179 if (sample > 32767)
180 {
181 in_mic[i] = 32767;
182 } else if (sample < -32768)
183 {
184 in_mic[i] = -32768;
185 } else
186 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000187 in_mic[i] = (int16_t)sample;
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 }
189
190 // For higher band
191 if (stt->fs == 32000)
192 {
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000193 sample = (in_mic_H[i] * gain) >> 12;
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 if (sample > 32767)
195 {
196 in_mic_H[i] = 32767;
197 } else if (sample < -32768)
198 {
199 in_mic_H[i] = -32768;
200 } else
201 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000202 in_mic_H[i] = (int16_t)sample;
niklase@google.com470e71d2011-07-07 08:21:25 +0000203 }
204 }
205 }
206 } else
207 {
208 stt->gainTableIdx = 0;
209 }
210
211 /* compute envelope */
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000212 if (stt->inQueue > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000213 {
214 ptr = stt->env[1];
215 } else
216 {
217 ptr = stt->env[0];
218 }
219
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000220 for (i = 0; i < kNumSubframes; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000221 {
222 /* iterate over samples */
223 max_nrg = 0;
224 for (n = 0; n < L; n++)
225 {
226 nrg = WEBRTC_SPL_MUL_16_16(in_mic[i * L + n], in_mic[i * L + n]);
227 if (nrg > max_nrg)
228 {
229 max_nrg = nrg;
230 }
231 }
232 ptr[i] = max_nrg;
233 }
234
235 /* compute energy */
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000236 if (stt->inQueue > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000237 {
238 ptr = stt->Rxx16w32_array[1];
239 } else
240 {
241 ptr = stt->Rxx16w32_array[0];
242 }
243
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000244 for (i = 0; i < kNumSubframes / 2; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 {
246 if (stt->fs == 16000)
247 {
248 WebRtcSpl_DownsampleBy2(&in_mic[i * 32], 32, tmp_speech, stt->filterState);
249 } else
250 {
251 memcpy(tmp_speech, &in_mic[i * 16], 16 * sizeof(short));
252 }
253 /* Compute energy in blocks of 16 samples */
254 ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4);
255 }
256
257 /* update queue information */
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000258 if (stt->inQueue == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000259 {
260 stt->inQueue = 1;
261 } else
262 {
263 stt->inQueue = 2;
264 }
265
266 /* call VAD (use low band only) */
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000267 WebRtcAgc_ProcessVad(&stt->vadMic, in_mic, samples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000268
269 return 0;
270}
271
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000272int WebRtcAgc_AddFarend(void *state, const int16_t *in_far, int16_t samples)
niklase@google.com470e71d2011-07-07 08:21:25 +0000273{
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 Agc_t *stt;
275 stt = (Agc_t *)state;
276
277 if (stt == NULL)
278 {
279 return -1;
280 }
281
282 if (stt->fs == 8000)
283 {
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000284 if (samples != 80)
niklase@google.com470e71d2011-07-07 08:21:25 +0000285 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000286 return -1;
287 }
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000288 } else if (stt->fs == 16000 || stt->fs == 32000)
niklase@google.com470e71d2011-07-07 08:21:25 +0000289 {
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000290 if (samples != 160)
niklase@google.com470e71d2011-07-07 08:21:25 +0000291 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000292 return -1;
293 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000294 } else
295 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000296 return -1;
297 }
298
aluebs@webrtc.org96a62622014-12-15 21:54:50 +0000299 return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000300}
301
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000302int WebRtcAgc_VirtualMic(void *agcInst, int16_t *in_near, int16_t *in_near_H,
303 int16_t samples, int32_t micLevelIn,
304 int32_t *micLevelOut)
niklase@google.com470e71d2011-07-07 08:21:25 +0000305{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000306 int32_t tmpFlt, micLevelTmp, gainIdx;
307 uint16_t gain;
308 int16_t ii;
niklase@google.com470e71d2011-07-07 08:21:25 +0000309 Agc_t *stt;
310
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000311 uint32_t nrg;
312 int16_t sampleCntr;
313 uint32_t frameNrg = 0;
314 uint32_t frameNrgLimit = 5500;
315 int16_t numZeroCrossing = 0;
316 const int16_t kZeroCrossingLowLim = 15;
317 const int16_t kZeroCrossingHighLim = 20;
niklase@google.com470e71d2011-07-07 08:21:25 +0000318
319 stt = (Agc_t *)agcInst;
320
321 /*
322 * Before applying gain decide if this is a low-level signal.
323 * The idea is that digital AGC will not adapt to low-level
324 * signals.
325 */
326 if (stt->fs != 8000)
327 {
328 frameNrgLimit = frameNrgLimit << 1;
329 }
330
331 frameNrg = WEBRTC_SPL_MUL_16_16(in_near[0], in_near[0]);
332 for (sampleCntr = 1; sampleCntr < samples; sampleCntr++)
333 {
334
335 // increment frame energy if it is less than the limit
336 // the correct value of the energy is not important
337 if (frameNrg < frameNrgLimit)
338 {
339 nrg = WEBRTC_SPL_MUL_16_16(in_near[sampleCntr], in_near[sampleCntr]);
340 frameNrg += nrg;
341 }
342
343 // Count the zero crossings
344 numZeroCrossing += ((in_near[sampleCntr] ^ in_near[sampleCntr - 1]) < 0);
345 }
346
347 if ((frameNrg < 500) || (numZeroCrossing <= 5))
348 {
349 stt->lowLevelSignal = 1;
350 } else if (numZeroCrossing <= kZeroCrossingLowLim)
351 {
352 stt->lowLevelSignal = 0;
353 } else if (frameNrg <= frameNrgLimit)
354 {
355 stt->lowLevelSignal = 1;
356 } else if (numZeroCrossing >= kZeroCrossingHighLim)
357 {
358 stt->lowLevelSignal = 1;
359 } else
360 {
361 stt->lowLevelSignal = 0;
362 }
363
bjornv@webrtc.org750423c2014-09-30 09:26:36 +0000364 micLevelTmp = micLevelIn << stt->scale;
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 /* Set desired level */
366 gainIdx = stt->micVol;
367 if (stt->micVol > stt->maxAnalog)
368 {
369 gainIdx = stt->maxAnalog;
370 }
371 if (micLevelTmp != stt->micRef)
372 {
373 /* Something has happened with the physical level, restart. */
374 stt->micRef = micLevelTmp;
375 stt->micVol = 127;
376 *micLevelOut = 127;
377 stt->micGainIdx = 127;
378 gainIdx = 127;
379 }
380 /* Pre-process the signal to emulate the microphone level. */
381 /* Take one step at a time in the gain table. */
382 if (gainIdx > 127)
383 {
384 gain = kGainTableVirtualMic[gainIdx - 128];
385 } else
386 {
387 gain = kSuppressionTableVirtualMic[127 - gainIdx];
388 }
389 for (ii = 0; ii < samples; ii++)
390 {
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000391 tmpFlt = (in_near[ii] * gain) >> 10;
niklase@google.com470e71d2011-07-07 08:21:25 +0000392 if (tmpFlt > 32767)
393 {
394 tmpFlt = 32767;
395 gainIdx--;
396 if (gainIdx >= 127)
397 {
398 gain = kGainTableVirtualMic[gainIdx - 127];
399 } else
400 {
401 gain = kSuppressionTableVirtualMic[127 - gainIdx];
402 }
403 }
404 if (tmpFlt < -32768)
405 {
406 tmpFlt = -32768;
407 gainIdx--;
408 if (gainIdx >= 127)
409 {
410 gain = kGainTableVirtualMic[gainIdx - 127];
411 } else
412 {
413 gain = kSuppressionTableVirtualMic[127 - gainIdx];
414 }
415 }
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000416 in_near[ii] = (int16_t)tmpFlt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000417 if (stt->fs == 32000)
418 {
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000419 tmpFlt = (in_near_H[ii] * gain) >> 10;
niklase@google.com470e71d2011-07-07 08:21:25 +0000420 if (tmpFlt > 32767)
421 {
422 tmpFlt = 32767;
423 }
424 if (tmpFlt < -32768)
425 {
426 tmpFlt = -32768;
427 }
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000428 in_near_H[ii] = (int16_t)tmpFlt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000429 }
430 }
431 /* Set the level we (finally) used */
432 stt->micGainIdx = gainIdx;
433// *micLevelOut = stt->micGainIdx;
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000434 *micLevelOut = stt->micGainIdx >> stt->scale;
niklase@google.com470e71d2011-07-07 08:21:25 +0000435 /* Add to Mic as if it was the output from a true microphone */
436 if (WebRtcAgc_AddMic(agcInst, in_near, in_near_H, samples) != 0)
437 {
438 return -1;
439 }
440 return 0;
441}
442
443void WebRtcAgc_UpdateAgcThresholds(Agc_t *stt)
444{
445
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000446 int16_t tmp16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000447#ifdef MIC_LEVEL_FEEDBACK
448 int zeros;
449
450 if (stt->micLvlSat)
451 {
452 /* Lower the analog target level since we have reached its maximum */
453 zeros = WebRtcSpl_NormW32(stt->Rxx160_LPw32);
bjornv@webrtc.orgd4fe8242014-10-13 13:01:13 +0000454 stt->targetIdxOffset = (3 * zeros - stt->targetIdx - 2) / 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000455 }
456#endif
457
458 /* Set analog target level in envelope dBOv scale */
459 tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000460 tmp16 = WebRtcSpl_DivW32W16ResW16((int32_t)tmp16, ANALOG_TARGET_LEVEL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000461 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16;
462 if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN)
463 {
464 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN;
465 }
466 if (stt->agcMode == kAgcModeFixedDigital)
467 {
468 /* Adjust for different parameter interpretation in FixedDigital mode */
469 stt->analogTarget = stt->compressionGaindB;
470 }
471#ifdef MIC_LEVEL_FEEDBACK
472 stt->analogTarget += stt->targetIdxOffset;
473#endif
474 /* Since the offset between RMS and ENV is not constant, we should make this into a
475 * table, but for now, we'll stick with a constant, tuned for the chosen analog
476 * target level.
477 */
478 stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS;
479#ifdef MIC_LEVEL_FEEDBACK
480 stt->targetIdx += stt->targetIdxOffset;
481#endif
482 /* Analog adaptation limits */
483 /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */
484 stt->analogTargetLevel = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */
485 stt->startUpperLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 1];/* -19 dBov */
486 stt->startLowerLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 1];/* -21 dBov */
487 stt->upperPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 2];/* -18 dBov */
488 stt->lowerPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 2];/* -22 dBov */
489 stt->upperSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 5];/* -15 dBov */
490 stt->lowerSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 5];/* -25 dBov */
491 stt->upperLimit = stt->startUpperLimit;
492 stt->lowerLimit = stt->startLowerLimit;
493}
494
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000495void WebRtcAgc_SaturationCtrl(Agc_t *stt, uint8_t *saturated, int32_t *env)
niklase@google.com470e71d2011-07-07 08:21:25 +0000496{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000497 int16_t i, tmpW16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000498
499 /* Check if the signal is saturated */
500 for (i = 0; i < 10; i++)
501 {
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000502 tmpW16 = (int16_t)(env[i] >> 20);
niklase@google.com470e71d2011-07-07 08:21:25 +0000503 if (tmpW16 > 875)
504 {
505 stt->envSum += tmpW16;
506 }
507 }
508
509 if (stt->envSum > 25000)
510 {
511 *saturated = 1;
512 stt->envSum = 0;
513 }
514
515 /* stt->envSum *= 0.99; */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000516 stt->envSum = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(stt->envSum,
517 (int16_t)32440, 15);
niklase@google.com470e71d2011-07-07 08:21:25 +0000518}
519
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000520void WebRtcAgc_ZeroCtrl(Agc_t *stt, int32_t *inMicLevel, int32_t *env)
niklase@google.com470e71d2011-07-07 08:21:25 +0000521{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000522 int16_t i;
523 int32_t tmp32 = 0;
524 int32_t midVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000525
526 /* Is the input signal zero? */
527 for (i = 0; i < 10; i++)
528 {
529 tmp32 += env[i];
530 }
531
532 /* Each block is allowed to have a few non-zero
533 * samples.
534 */
535 if (tmp32 < 500)
536 {
537 stt->msZero += 10;
538 } else
539 {
540 stt->msZero = 0;
541 }
542
543 if (stt->muteGuardMs > 0)
544 {
545 stt->muteGuardMs -= 10;
546 }
547
548 if (stt->msZero > 500)
549 {
550 stt->msZero = 0;
551
552 /* Increase microphone level only if it's less than 50% */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000553 midVal = (stt->maxAnalog + stt->minLevel + 1) / 2;
niklase@google.com470e71d2011-07-07 08:21:25 +0000554 if (*inMicLevel < midVal)
555 {
556 /* *inMicLevel *= 1.1; */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000557 *inMicLevel = (1126 * *inMicLevel) >> 10;
niklase@google.com470e71d2011-07-07 08:21:25 +0000558 /* Reduces risk of a muted mic repeatedly triggering excessive levels due
559 * to zero signal detection. */
560 *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax);
561 stt->micVol = *inMicLevel;
562 }
563
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000564#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000565 fprintf(stt->fpt,
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000566 "\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold,"
567 " micVol: %d\n",
568 stt->fcount,
569 stt->micVol);
niklase@google.com470e71d2011-07-07 08:21:25 +0000570#endif
571
572 stt->activeSpeech = 0;
573 stt->Rxx16_LPw32Max = 0;
574
575 /* The AGC has a tendency (due to problems with the VAD parameters), to
576 * vastly increase the volume after a muting event. This timer prevents
577 * upwards adaptation for a short period. */
578 stt->muteGuardMs = kMuteGuardTimeMs;
579 }
580}
581
582void WebRtcAgc_SpeakerInactiveCtrl(Agc_t *stt)
583{
584 /* Check if the near end speaker is inactive.
585 * If that is the case the VAD threshold is
586 * increased since the VAD speech model gets
587 * more sensitive to any sound after a long
588 * silence.
589 */
590
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000591 int32_t tmp32;
592 int16_t vadThresh;
niklase@google.com470e71d2011-07-07 08:21:25 +0000593
594 if (stt->vadMic.stdLongTerm < 2500)
595 {
596 stt->vadThreshold = 1500;
597 } else
598 {
599 vadThresh = kNormalVadThreshold;
600 if (stt->vadMic.stdLongTerm < 4500)
601 {
602 /* Scale between min and max threshold */
bjornv@webrtc.orgd4fe8242014-10-13 13:01:13 +0000603 vadThresh += (4500 - stt->vadMic.stdLongTerm) / 2;
niklase@google.com470e71d2011-07-07 08:21:25 +0000604 }
605
606 /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000607 tmp32 = (int32_t)vadThresh;
608 tmp32 += WEBRTC_SPL_MUL_16_16((int16_t)31, stt->vadThreshold);
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000609 stt->vadThreshold = (int16_t)(tmp32 >> 5);
niklase@google.com470e71d2011-07-07 08:21:25 +0000610 }
611}
612
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000613void WebRtcAgc_ExpCurve(int16_t volume, int16_t *index)
niklase@google.com470e71d2011-07-07 08:21:25 +0000614{
615 // volume in Q14
616 // index in [0-7]
617 /* 8 different curves */
618 if (volume > 5243)
619 {
620 if (volume > 7864)
621 {
622 if (volume > 12124)
623 {
624 *index = 7;
625 } else
626 {
627 *index = 6;
628 }
629 } else
630 {
631 if (volume > 6554)
632 {
633 *index = 5;
634 } else
635 {
636 *index = 4;
637 }
638 }
639 } else
640 {
641 if (volume > 2621)
642 {
643 if (volume > 3932)
644 {
645 *index = 3;
646 } else
647 {
648 *index = 2;
649 }
650 } else
651 {
652 if (volume > 1311)
653 {
654 *index = 1;
655 } else
656 {
657 *index = 0;
658 }
659 }
660 }
661}
662
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000663int32_t WebRtcAgc_ProcessAnalog(void *state, int32_t inMicLevel,
664 int32_t *outMicLevel,
665 int16_t vadLogRatio,
666 int16_t echo, uint8_t *saturationWarning)
niklase@google.com470e71d2011-07-07 08:21:25 +0000667{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000668 uint32_t tmpU32;
669 int32_t Rxx16w32, tmp32;
670 int32_t inMicLevelTmp, lastMicVol;
671 int16_t i;
672 uint8_t saturated = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000673 Agc_t *stt;
674
675 stt = (Agc_t *)state;
bjornv@webrtc.org750423c2014-09-30 09:26:36 +0000676 inMicLevelTmp = inMicLevel << stt->scale;
niklase@google.com470e71d2011-07-07 08:21:25 +0000677
678 if (inMicLevelTmp > stt->maxAnalog)
679 {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000680#ifdef WEBRTC_AGC_DEBUG_DUMP
681 fprintf(stt->fpt,
682 "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n",
683 stt->fcount);
niklase@google.com470e71d2011-07-07 08:21:25 +0000684#endif
685 return -1;
686 } else if (inMicLevelTmp < stt->minLevel)
687 {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000688#ifdef WEBRTC_AGC_DEBUG_DUMP
689 fprintf(stt->fpt,
690 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n",
691 stt->fcount);
niklase@google.com470e71d2011-07-07 08:21:25 +0000692#endif
693 return -1;
694 }
695
696 if (stt->firstCall == 0)
697 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000698 int32_t tmpVol;
niklase@google.com470e71d2011-07-07 08:21:25 +0000699 stt->firstCall = 1;
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000700 tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
niklase@google.com470e71d2011-07-07 08:21:25 +0000701 tmpVol = (stt->minLevel + tmp32);
702
703 /* If the mic level is very low at start, increase it! */
704 if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog))
705 {
706 inMicLevelTmp = tmpVol;
707 }
708 stt->micVol = inMicLevelTmp;
709 }
710
711 /* Set the mic level to the previous output value if there is digital input gain */
712 if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog))
713 {
714 inMicLevelTmp = stt->micVol;
715 }
716
717 /* If the mic level was manually changed to a very low value raise it! */
718 if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput))
719 {
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000720 tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
niklase@google.com470e71d2011-07-07 08:21:25 +0000721 inMicLevelTmp = (stt->minLevel + tmp32);
722 stt->micVol = inMicLevelTmp;
723#ifdef MIC_LEVEL_FEEDBACK
724 //stt->numBlocksMicLvlSat = 0;
725#endif
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000726#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000727 fprintf(stt->fpt,
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000728 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual"
729 " decrease, raise vol\n",
niklase@google.com470e71d2011-07-07 08:21:25 +0000730 stt->fcount);
731#endif
732 }
733
734 if (inMicLevelTmp != stt->micVol)
735 {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000736 if (inMicLevel == stt->lastInMicLevel) {
737 // We requested a volume adjustment, but it didn't occur. This is
738 // probably due to a coarse quantization of the volume slider.
739 // Restore the requested value to prevent getting stuck.
740 inMicLevelTmp = stt->micVol;
741 }
742 else {
743 // As long as the value changed, update to match.
744 stt->micVol = inMicLevelTmp;
745 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000746 }
747
748 if (inMicLevelTmp > stt->maxLevel)
749 {
750 // Always allow the user to raise the volume above the maxLevel.
751 stt->maxLevel = inMicLevelTmp;
752 }
753
754 // Store last value here, after we've taken care of manual updates etc.
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000755 stt->lastInMicLevel = inMicLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000756 lastMicVol = stt->micVol;
757
758 /* Checks if the signal is saturated. Also a check if individual samples
759 * are larger than 12000 is done. If they are the counter for increasing
760 * the volume level is set to -100ms
761 */
762 WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
763
764 /* The AGC is always allowed to lower the level if the signal is saturated */
765 if (saturated == 1)
766 {
767 /* Lower the recording level
768 * Rxx160_LP is adjusted down because it is so slow it could
769 * cause the AGC to make wrong decisions. */
770 /* stt->Rxx160_LPw32 *= 0.875; */
bjornv@webrtc.org23ec8372014-09-30 09:29:28 +0000771 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 8) * 7;
niklase@google.com470e71d2011-07-07 08:21:25 +0000772
773 stt->zeroCtrlMax = stt->micVol;
774
775 /* stt->micVol *= 0.903; */
776 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000777 tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32));
bjornv@webrtc.org348eac62014-10-02 08:07:05 +0000778 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000779 if (stt->micVol > lastMicVol - 2)
780 {
781 stt->micVol = lastMicVol - 2;
782 }
783 inMicLevelTmp = stt->micVol;
784
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000785#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000786 fprintf(stt->fpt,
787 "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000788 stt->fcount,
789 stt->micVol);
niklase@google.com470e71d2011-07-07 08:21:25 +0000790#endif
791
792 if (stt->micVol < stt->minOutput)
793 {
794 *saturationWarning = 1;
795 }
796
797 /* Reset counter for decrease of volume level to avoid
798 * decreasing too much. The saturation control can still
799 * lower the level if needed. */
800 stt->msTooHigh = -100;
801
802 /* Enable the control mechanism to ensure that our measure,
803 * Rxx160_LP, is in the correct range. This must be done since
804 * the measure is very slow. */
805 stt->activeSpeech = 0;
806 stt->Rxx16_LPw32Max = 0;
807
808 /* Reset to initial values */
809 stt->msecSpeechInnerChange = kMsecSpeechInner;
810 stt->msecSpeechOuterChange = kMsecSpeechOuter;
811 stt->changeToSlowMode = 0;
812
813 stt->muteGuardMs = 0;
814
815 stt->upperLimit = stt->startUpperLimit;
816 stt->lowerLimit = stt->startLowerLimit;
817#ifdef MIC_LEVEL_FEEDBACK
818 //stt->numBlocksMicLvlSat = 0;
819#endif
820 }
821
822 /* Check if the input speech is zero. If so the mic volume
823 * is increased. On some computers the input is zero up as high
824 * level as 17% */
825 WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
826
827 /* Check if the near end speaker is inactive.
828 * If that is the case the VAD threshold is
829 * increased since the VAD speech model gets
830 * more sensitive to any sound after a long
831 * silence.
832 */
833 WebRtcAgc_SpeakerInactiveCtrl(stt);
834
835 for (i = 0; i < 5; i++)
836 {
837 /* Computed on blocks of 16 samples */
838
839 Rxx16w32 = stt->Rxx16w32_array[0][i];
840
841 /* Rxx160w32 in Q(-7) */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000842 tmp32 = (Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos]) >> 3;
niklase@google.com470e71d2011-07-07 08:21:25 +0000843 stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
844 stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
845
846 /* Circular buffer */
ajm@google.com6bed0642011-07-12 14:57:10 +0000847 stt->Rxx16pos++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000848 if (stt->Rxx16pos == RXX_BUFFER_LEN)
849 {
850 stt->Rxx16pos = 0;
851 }
852
853 /* Rxx16_LPw32 in Q(-4) */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000854 tmp32 = (Rxx16w32 - stt->Rxx16_LPw32) >> kAlphaShortTerm;
niklase@google.com470e71d2011-07-07 08:21:25 +0000855 stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
856
857 if (vadLogRatio > stt->vadThreshold)
858 {
859 /* Speech detected! */
860
861 /* Check if Rxx160_LP is in the correct range. If
862 * it is too high/low then we set it to the maximum of
863 * Rxx16_LPw32 during the first 200ms of speech.
864 */
865 if (stt->activeSpeech < 250)
866 {
867 stt->activeSpeech += 2;
868
869 if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max)
870 {
871 stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
872 }
873 } else if (stt->activeSpeech == 250)
874 {
875 stt->activeSpeech += 2;
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000876 tmp32 = stt->Rxx16_LPw32Max >> 3;
bjornv@webrtc.org23ec8372014-09-30 09:29:28 +0000877 stt->Rxx160_LPw32 = tmp32 * RXX_BUFFER_LEN;
niklase@google.com470e71d2011-07-07 08:21:25 +0000878 }
879
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000880 tmp32 = (stt->Rxx160w32 - stt->Rxx160_LPw32) >> kAlphaLongTerm;
niklase@google.com470e71d2011-07-07 08:21:25 +0000881 stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
882
883 if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit)
884 {
885 stt->msTooHigh += 2;
886 stt->msTooLow = 0;
887 stt->changeToSlowMode = 0;
888
889 if (stt->msTooHigh > stt->msecSpeechOuterChange)
890 {
891 stt->msTooHigh = 0;
892
893 /* Lower the recording level */
894 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000895 tmp32 = stt->Rxx160_LPw32 >> 6;
bjornv@webrtc.org23ec8372014-09-30 09:29:28 +0000896 stt->Rxx160_LPw32 = tmp32 * 53;
niklase@google.com470e71d2011-07-07 08:21:25 +0000897
898 /* Reduce the max gain to avoid excessive oscillation
899 * (but never drop below the maximum analog level).
niklase@google.com470e71d2011-07-07 08:21:25 +0000900 */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000901 stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000902 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
903
904 stt->zeroCtrlMax = stt->micVol;
905
906 /* 0.95 in Q15 */
907 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000908 tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32));
bjornv@webrtc.org348eac62014-10-02 08:07:05 +0000909 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000910 if (stt->micVol > lastMicVol - 1)
911 {
912 stt->micVol = lastMicVol - 1;
913 }
914 inMicLevelTmp = stt->micVol;
915
916 /* Enable the control mechanism to ensure that our measure,
917 * Rxx160_LP, is in the correct range.
918 */
919 stt->activeSpeech = 0;
920 stt->Rxx16_LPw32Max = 0;
921#ifdef MIC_LEVEL_FEEDBACK
922 //stt->numBlocksMicLvlSat = 0;
923#endif
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000924#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000925 fprintf(stt->fpt,
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000926 "\tAGC->ProcessAnalog, frame %d: measure >"
927 " 2ndUpperLim, micVol = %d, maxLevel = %d\n",
928 stt->fcount,
929 stt->micVol,
930 stt->maxLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000931#endif
932 }
933 } else if (stt->Rxx160_LPw32 > stt->upperLimit)
934 {
935 stt->msTooHigh += 2;
936 stt->msTooLow = 0;
937 stt->changeToSlowMode = 0;
938
939 if (stt->msTooHigh > stt->msecSpeechInnerChange)
940 {
941 /* Lower the recording level */
942 stt->msTooHigh = 0;
943 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000944 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 53;
niklase@google.com470e71d2011-07-07 08:21:25 +0000945
946 /* Reduce the max gain to avoid excessive oscillation
947 * (but never drop below the maximum analog level).
niklase@google.com470e71d2011-07-07 08:21:25 +0000948 */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +0000949 stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
niklase@google.com470e71d2011-07-07 08:21:25 +0000950 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
951
952 stt->zeroCtrlMax = stt->micVol;
953
954 /* 0.965 in Q15 */
955 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000956 tmpU32 = WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel));
bjornv@webrtc.org348eac62014-10-02 08:07:05 +0000957 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 if (stt->micVol > lastMicVol - 1)
959 {
960 stt->micVol = lastMicVol - 1;
961 }
962 inMicLevelTmp = stt->micVol;
963
964#ifdef MIC_LEVEL_FEEDBACK
965 //stt->numBlocksMicLvlSat = 0;
966#endif
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000967#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +0000968 fprintf(stt->fpt,
bjornv@webrtc.orgea297872014-09-23 11:21:39 +0000969 "\tAGC->ProcessAnalog, frame %d: measure >"
970 " UpperLim, micVol = %d, maxLevel = %d\n",
971 stt->fcount,
972 stt->micVol,
973 stt->maxLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000974#endif
975 }
976 } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit)
977 {
978 stt->msTooHigh = 0;
979 stt->changeToSlowMode = 0;
980 stt->msTooLow += 2;
981
982 if (stt->msTooLow > stt->msecSpeechOuterChange)
983 {
984 /* Raise the recording level */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000985 int16_t index, weightFIX;
986 int16_t volNormFIX = 16384; // =1 in Q14.
niklase@google.com470e71d2011-07-07 08:21:25 +0000987
988 stt->msTooLow = 0;
989
990 /* Normalize the volume level */
bjornv@webrtc.org750423c2014-09-30 09:26:36 +0000991 tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 if (stt->maxInit != stt->minLevel)
993 {
bjornv@webrtc.orgdf9fef62014-08-28 12:57:32 +0000994 volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000995 }
996
997 /* Find correct curve */
998 WebRtcAgc_ExpCurve(volNormFIX, &index);
999
1000 /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05 */
1001 weightFIX = kOffset1[index]
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001002 - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(kSlope1[index],
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 volNormFIX, 13);
1004
1005 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +00001006 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
niklase@google.com470e71d2011-07-07 08:21:25 +00001007
1008 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001009 tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
bjornv@webrtc.org348eac62014-10-02 08:07:05 +00001010 stt->micVol = (tmpU32 >> 14) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001011 if (stt->micVol < lastMicVol + 2)
1012 {
1013 stt->micVol = lastMicVol + 2;
1014 }
1015
1016 inMicLevelTmp = stt->micVol;
1017
1018#ifdef MIC_LEVEL_FEEDBACK
1019 /* Count ms in level saturation */
1020 //if (stt->micVol > stt->maxAnalog) {
1021 if (stt->micVol > 150)
1022 {
1023 /* mic level is saturated */
1024 stt->numBlocksMicLvlSat++;
1025 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1026 }
1027#endif
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001028#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 fprintf(stt->fpt,
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001030 "\tAGC->ProcessAnalog, frame %d: measure <"
1031 " 2ndLowerLim, micVol = %d\n",
1032 stt->fcount,
1033 stt->micVol);
niklase@google.com470e71d2011-07-07 08:21:25 +00001034#endif
1035 }
1036 } else if (stt->Rxx160_LPw32 < stt->lowerLimit)
1037 {
1038 stt->msTooHigh = 0;
1039 stt->changeToSlowMode = 0;
1040 stt->msTooLow += 2;
1041
1042 if (stt->msTooLow > stt->msecSpeechInnerChange)
1043 {
1044 /* Raise the recording level */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001045 int16_t index, weightFIX;
1046 int16_t volNormFIX = 16384; // =1 in Q14.
niklase@google.com470e71d2011-07-07 08:21:25 +00001047
1048 stt->msTooLow = 0;
1049
1050 /* Normalize the volume level */
bjornv@webrtc.org750423c2014-09-30 09:26:36 +00001051 tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
niklase@google.com470e71d2011-07-07 08:21:25 +00001052 if (stt->maxInit != stt->minLevel)
1053 {
bjornv@webrtc.orgdf9fef62014-08-28 12:57:32 +00001054 volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 }
1056
1057 /* Find correct curve */
1058 WebRtcAgc_ExpCurve(volNormFIX, &index);
1059
1060 /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1 */
1061 weightFIX = kOffset2[index]
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001062 - (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(kSlope2[index],
niklase@google.com470e71d2011-07-07 08:21:25 +00001063 volNormFIX, 13);
1064
1065 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +00001066 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
niklase@google.com470e71d2011-07-07 08:21:25 +00001067
1068 tmp32 = inMicLevelTmp - stt->minLevel;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001069 tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
bjornv@webrtc.org348eac62014-10-02 08:07:05 +00001070 stt->micVol = (tmpU32 >> 14) + stt->minLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001071 if (stt->micVol < lastMicVol + 1)
1072 {
1073 stt->micVol = lastMicVol + 1;
1074 }
1075
1076 inMicLevelTmp = stt->micVol;
1077
1078#ifdef MIC_LEVEL_FEEDBACK
1079 /* Count ms in level saturation */
1080 //if (stt->micVol > stt->maxAnalog) {
1081 if (stt->micVol > 150)
1082 {
1083 /* mic level is saturated */
1084 stt->numBlocksMicLvlSat++;
1085 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1086 }
1087#endif
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001088#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001089 fprintf(stt->fpt,
1090 "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol = %d\n",
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001091 stt->fcount,
1092 stt->micVol);
niklase@google.com470e71d2011-07-07 08:21:25 +00001093#endif
1094
1095 }
1096 } else
1097 {
1098 /* The signal is inside the desired range which is:
1099 * lowerLimit < Rxx160_LP/640 < upperLimit
1100 */
1101 if (stt->changeToSlowMode > 4000)
1102 {
1103 stt->msecSpeechInnerChange = 1000;
1104 stt->msecSpeechOuterChange = 500;
1105 stt->upperLimit = stt->upperPrimaryLimit;
1106 stt->lowerLimit = stt->lowerPrimaryLimit;
1107 } else
1108 {
1109 stt->changeToSlowMode += 2; // in milliseconds
1110 }
1111 stt->msTooLow = 0;
1112 stt->msTooHigh = 0;
1113
1114 stt->micVol = inMicLevelTmp;
1115
1116 }
1117#ifdef MIC_LEVEL_FEEDBACK
1118 if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET)
1119 {
1120 stt->micLvlSat = 1;
1121 fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1122 WebRtcAgc_UpdateAgcThresholds(stt);
1123 WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]),
1124 stt->compressionGaindB, stt->targetLevelDbfs, stt->limiterEnable,
1125 stt->analogTarget);
1126 stt->numBlocksMicLvlSat = 0;
1127 stt->micLvlSat = 0;
1128 fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset);
1129 fprintf(stderr, "target after = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1130 }
1131#endif
1132 }
1133 }
1134
1135 /* Ensure gain is not increased in presence of echo or after a mute event
1136 * (but allow the zeroCtrl() increase on the frame of a mute detection).
1137 */
1138 if (echo == 1 || (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs))
1139 {
1140 if (stt->micVol > lastMicVol)
1141 {
1142 stt->micVol = lastMicVol;
1143 }
1144 }
1145
1146 /* limit the gain */
1147 if (stt->micVol > stt->maxLevel)
1148 {
1149 stt->micVol = stt->maxLevel;
1150 } else if (stt->micVol < stt->minOutput)
1151 {
1152 stt->micVol = stt->minOutput;
1153 }
1154
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +00001155 *outMicLevel = WEBRTC_SPL_MIN(stt->micVol, stt->maxAnalog) >> stt->scale;
niklase@google.com470e71d2011-07-07 08:21:25 +00001156
1157 return 0;
1158}
1159
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001160int WebRtcAgc_Process(void *agcInst, const int16_t *in_near,
1161 const int16_t *in_near_H, int16_t samples,
1162 int16_t *out, int16_t *out_H, int32_t inMicLevel,
1163 int32_t *outMicLevel, int16_t echo,
1164 uint8_t *saturationWarning)
niklase@google.com470e71d2011-07-07 08:21:25 +00001165{
1166 Agc_t *stt;
niklase@google.com470e71d2011-07-07 08:21:25 +00001167
1168 stt = (Agc_t *)agcInst;
1169
1170 //
1171 if (stt == NULL)
1172 {
1173 return -1;
1174 }
1175 //
1176
1177
1178 if (stt->fs == 8000)
1179 {
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001180 if (samples != 80)
niklase@google.com470e71d2011-07-07 08:21:25 +00001181 {
niklase@google.com470e71d2011-07-07 08:21:25 +00001182 return -1;
1183 }
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001184 } else if (stt->fs == 16000 || stt->fs == 32000)
niklase@google.com470e71d2011-07-07 08:21:25 +00001185 {
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001186 if (samples != 160)
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 {
niklase@google.com470e71d2011-07-07 08:21:25 +00001188 return -1;
1189 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001190 } else
1191 {
niklase@google.com470e71d2011-07-07 08:21:25 +00001192 return -1;
1193 }
1194
1195 /* Check for valid pointers based on sampling rate */
1196 if (stt->fs == 32000 && in_near_H == NULL)
1197 {
1198 return -1;
1199 }
1200 /* Check for valid pointers for low band */
1201 if (in_near == NULL)
1202 {
1203 return -1;
1204 }
1205
1206 *saturationWarning = 0;
1207 //TODO: PUT IN RANGE CHECKING FOR INPUT LEVELS
1208 *outMicLevel = inMicLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +00001209
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001210#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001211 stt->fcount++;
1212#endif
1213
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001214 if (WebRtcAgc_ProcessDigital(&stt->digitalAgc,
1215 in_near,
1216 in_near_H,
1217 out,
1218 out_H,
1219 stt->fs,
1220 stt->lowLevelSignal) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001221 {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001222#ifdef WEBRTC_AGC_DEBUG_DUMP
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001223 fprintf(stt->fpt,
1224 "AGC->Process, frame %d: Error from DigAGC\n\n",
1225 stt->fcount);
niklase@google.com470e71d2011-07-07 08:21:25 +00001226#endif
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001227 return -1;
1228 }
1229 if (stt->agcMode < kAgcModeFixedDigital &&
1230 (stt->lowLevelSignal == 0 || stt->agcMode != kAgcModeAdaptiveDigital))
1231 {
1232 if (WebRtcAgc_ProcessAnalog(agcInst,
1233 inMicLevel,
1234 outMicLevel,
1235 stt->vadMic.logRatio,
1236 echo,
1237 saturationWarning) == -1)
1238 {
niklase@google.com470e71d2011-07-07 08:21:25 +00001239 return -1;
1240 }
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001241 }
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001242#ifdef WEBRTC_AGC_DEBUG_DUMP
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001243 fprintf(stt->agcLog,
1244 "%5d\t%d\t%d\t%d\t%d\n",
1245 stt->fcount,
1246 inMicLevel,
1247 *outMicLevel,
1248 stt->maxLevel,
1249 stt->micVol);
niklase@google.com470e71d2011-07-07 08:21:25 +00001250#endif
1251
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001252 /* update queue */
1253 if (stt->inQueue > 1)
1254 {
1255 memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t));
1256 memcpy(stt->Rxx16w32_array[0],
1257 stt->Rxx16w32_array[1],
1258 5 * sizeof(int32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00001259 }
1260
aluebs@webrtc.org96a62622014-12-15 21:54:50 +00001261 if (stt->inQueue > 0)
1262 {
1263 stt->inQueue--;
1264 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001265
1266 return 0;
1267}
1268
1269int WebRtcAgc_set_config(void *agcInst, WebRtcAgc_config_t agcConfig)
1270{
1271 Agc_t *stt;
1272 stt = (Agc_t *)agcInst;
1273
1274 if (stt == NULL)
1275 {
1276 return -1;
1277 }
1278
1279 if (stt->initFlag != kInitCheck)
1280 {
1281 stt->lastError = AGC_UNINITIALIZED_ERROR;
1282 return -1;
1283 }
1284
1285 if (agcConfig.limiterEnable != kAgcFalse && agcConfig.limiterEnable != kAgcTrue)
1286 {
1287 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1288 return -1;
1289 }
1290 stt->limiterEnable = agcConfig.limiterEnable;
1291 stt->compressionGaindB = agcConfig.compressionGaindB;
1292 if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31))
1293 {
1294 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1295 return -1;
1296 }
1297 stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
1298
1299 if (stt->agcMode == kAgcModeFixedDigital)
1300 {
1301 /* Adjust for different parameter interpretation in FixedDigital mode */
1302 stt->compressionGaindB += agcConfig.targetLevelDbfs;
1303 }
1304
1305 /* Update threshold levels for analog adaptation */
1306 WebRtcAgc_UpdateAgcThresholds(stt);
1307
1308 /* Recalculate gain table */
1309 if (WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
1310 stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1)
1311 {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001312#ifdef WEBRTC_AGC_DEBUG_DUMP
1313 fprintf(stt->fpt,
1314 "AGC->set_config, frame %d: Error from calcGainTable\n\n",
1315 stt->fcount);
niklase@google.com470e71d2011-07-07 08:21:25 +00001316#endif
1317 return -1;
1318 }
1319 /* Store the config in a WebRtcAgc_config_t */
1320 stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
1321 stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
1322 stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
1323
1324 return 0;
1325}
1326
1327int WebRtcAgc_get_config(void *agcInst, WebRtcAgc_config_t *config)
1328{
1329 Agc_t *stt;
1330 stt = (Agc_t *)agcInst;
1331
1332 if (stt == NULL)
1333 {
1334 return -1;
1335 }
1336
1337 if (config == NULL)
1338 {
1339 stt->lastError = AGC_NULL_POINTER_ERROR;
1340 return -1;
1341 }
1342
1343 if (stt->initFlag != kInitCheck)
1344 {
1345 stt->lastError = AGC_UNINITIALIZED_ERROR;
1346 return -1;
1347 }
1348
1349 config->limiterEnable = stt->usedConfig.limiterEnable;
1350 config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
1351 config->compressionGaindB = stt->usedConfig.compressionGaindB;
1352
1353 return 0;
1354}
1355
1356int WebRtcAgc_Create(void **agcInst)
1357{
1358 Agc_t *stt;
1359 if (agcInst == NULL)
1360 {
1361 return -1;
1362 }
1363 stt = (Agc_t *)malloc(sizeof(Agc_t));
1364
1365 *agcInst = stt;
1366 if (stt == NULL)
1367 {
1368 return -1;
1369 }
1370
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001371#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001372 stt->fpt = fopen("./agc_test_log.txt", "wt");
1373 stt->agcLog = fopen("./agc_debug_log.txt", "wt");
1374 stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
1375#endif
1376
1377 stt->initFlag = 0;
1378 stt->lastError = 0;
1379
1380 return 0;
1381}
1382
1383int WebRtcAgc_Free(void *state)
1384{
1385 Agc_t *stt;
1386
1387 stt = (Agc_t *)state;
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001388#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001389 fclose(stt->fpt);
1390 fclose(stt->agcLog);
1391 fclose(stt->digitalAgc.logFile);
1392#endif
1393 free(stt);
1394
1395 return 0;
1396}
1397
1398/* minLevel - Minimum volume level
1399 * maxLevel - Maximum volume level
1400 */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001401int WebRtcAgc_Init(void *agcInst, int32_t minLevel, int32_t maxLevel,
1402 int16_t agcMode, uint32_t fs)
niklase@google.com470e71d2011-07-07 08:21:25 +00001403{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001404 int32_t max_add, tmp32;
1405 int16_t i;
niklase@google.com470e71d2011-07-07 08:21:25 +00001406 int tmpNorm;
1407 Agc_t *stt;
1408
1409 /* typecast state pointer */
1410 stt = (Agc_t *)agcInst;
1411
1412 if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0)
1413 {
1414 stt->lastError = AGC_UNINITIALIZED_ERROR;
1415 return -1;
1416 }
1417
1418 /* Analog AGC variables */
1419 stt->envSum = 0;
1420
1421 /* mode = 0 - Only saturation protection
1422 * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1423 * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1424 * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
1425 */
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001426#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001427 stt->fcount = 0;
1428 fprintf(stt->fpt, "AGC->Init\n");
1429#endif
1430 if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital)
1431 {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001432#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001433 fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
1434#endif
1435 return -1;
1436 }
1437 stt->agcMode = agcMode;
1438 stt->fs = fs;
1439
1440 /* initialize input VAD */
1441 WebRtcAgc_InitVad(&stt->vadMic);
1442
1443 /* If the volume range is smaller than 0-256 then
1444 * the levels are shifted up to Q8-domain */
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001445 tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001446 stt->scale = tmpNorm - 23;
1447 if (stt->scale < 0)
1448 {
1449 stt->scale = 0;
1450 }
1451 // TODO(bjornv): Investigate if we really need to scale up a small range now when we have
1452 // a guard against zero-increments. For now, we do not support scale up (scale = 0).
1453 stt->scale = 0;
bjornv@webrtc.org750423c2014-09-30 09:26:36 +00001454 maxLevel <<= stt->scale;
1455 minLevel <<= stt->scale;
niklase@google.com470e71d2011-07-07 08:21:25 +00001456
1457 /* Make minLevel and maxLevel static in AdaptiveDigital */
1458 if (stt->agcMode == kAgcModeAdaptiveDigital)
1459 {
1460 minLevel = 0;
1461 maxLevel = 255;
1462 stt->scale = 0;
1463 }
1464 /* The maximum supplemental volume range is based on a vague idea
1465 * of how much lower the gain will be than the real analog gain. */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +00001466 max_add = (maxLevel - minLevel) / 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001467
1468 /* Minimum/maximum volume level that can be set */
1469 stt->minLevel = minLevel;
1470 stt->maxAnalog = maxLevel;
1471 stt->maxLevel = maxLevel + max_add;
1472 stt->maxInit = stt->maxLevel;
1473
1474 stt->zeroCtrlMax = stt->maxAnalog;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001475 stt->lastInMicLevel = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001476
1477 /* Initialize micVol parameter */
1478 stt->micVol = stt->maxAnalog;
1479 if (stt->agcMode == kAgcModeAdaptiveDigital)
1480 {
1481 stt->micVol = 127; /* Mid-point of mic level */
1482 }
1483 stt->micRef = stt->micVol;
1484 stt->micGainIdx = 127;
1485#ifdef MIC_LEVEL_FEEDBACK
1486 stt->numBlocksMicLvlSat = 0;
1487 stt->micLvlSat = 0;
1488#endif
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001489#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001490 fprintf(stt->fpt,
1491 "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001492 stt->minLevel,
1493 stt->maxAnalog,
1494 stt->maxLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001495#endif
1496
1497 /* Minimum output volume is 4% higher than the available lowest volume level */
bjornv@webrtc.orgf02ba9b2014-10-15 11:16:48 +00001498 tmp32 = ((stt->maxLevel - stt->minLevel) * 10) >> 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00001499 stt->minOutput = (stt->minLevel + tmp32);
1500
1501 stt->msTooLow = 0;
1502 stt->msTooHigh = 0;
1503 stt->changeToSlowMode = 0;
1504 stt->firstCall = 0;
1505 stt->msZero = 0;
1506 stt->muteGuardMs = 0;
1507 stt->gainTableIdx = 0;
1508
1509 stt->msecSpeechInnerChange = kMsecSpeechInner;
1510 stt->msecSpeechOuterChange = kMsecSpeechOuter;
1511
1512 stt->activeSpeech = 0;
1513 stt->Rxx16_LPw32Max = 0;
1514
1515 stt->vadThreshold = kNormalVadThreshold;
1516 stt->inActive = 0;
1517
1518 for (i = 0; i < RXX_BUFFER_LEN; i++)
1519 {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001520 stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
niklase@google.com470e71d2011-07-07 08:21:25 +00001521 }
1522 stt->Rxx160w32 = 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
1523
1524 stt->Rxx16pos = 0;
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +00001525 stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */
niklase@google.com470e71d2011-07-07 08:21:25 +00001526
1527 for (i = 0; i < 5; i++)
1528 {
1529 stt->Rxx16w32_array[0][i] = 0;
1530 }
bjornv@webrtc.org281b7982012-05-30 07:41:57 +00001531 for (i = 0; i < 10; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001532 {
1533 stt->env[0][i] = 0;
bjornv@webrtc.org281b7982012-05-30 07:41:57 +00001534 stt->env[1][i] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001535 }
1536 stt->inQueue = 0;
1537
1538#ifdef MIC_LEVEL_FEEDBACK
1539 stt->targetIdxOffset = 0;
1540#endif
1541
1542 WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
1543
1544 stt->initFlag = kInitCheck;
1545 // Default config settings.
1546 stt->defaultConfig.limiterEnable = kAgcTrue;
1547 stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
1548 stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
1549
1550 if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1)
1551 {
1552 stt->lastError = AGC_UNSPECIFIED_ERROR;
1553 return -1;
1554 }
1555 stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value
1556
1557 stt->lowLevelSignal = 0;
1558
1559 /* Only positive values are allowed that are not too large */
1560 if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000))
1561 {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001562#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001563 fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
1564#endif
1565 return -1;
1566 } else
1567 {
bjornv@webrtc.orgea297872014-09-23 11:21:39 +00001568#ifdef WEBRTC_AGC_DEBUG_DUMP
niklase@google.com470e71d2011-07-07 08:21:25 +00001569 fprintf(stt->fpt, "\n");
1570#endif
1571 return 0;
1572 }
1573}