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 #include "aecm_core.h"
12
13 #include <assert.h>
14 #include <stdlib.h>
15
16 #include "cpu_features_wrapper.h"
17 #include "delay_estimator_wrapper.h"
18 #include "echo_control_mobile.h"
19 #include "ring_buffer.h"
20 #include "typedefs.h"
21
22 #ifdef ARM_WINM_LOG
23 #include <stdio.h>
24 #include <windows.h>
25 #endif
26
27 #ifdef AEC_DEBUG
28 FILE *dfile;
29 FILE *testfile;
30 #endif
31
32 #ifdef _MSC_VER // visual c++
33 #define ALIGN8_BEG __declspec(align(8))
34 #define ALIGN8_END
35 #else // gcc or icc
36 #define ALIGN8_BEG
37 #define ALIGN8_END __attribute__((aligned(8)))
38 #endif
39
40 #ifdef AECM_SHORT
41
42 // Square root of Hanning window in Q14
43 const WebRtc_Word16 WebRtcAecm_kSqrtHanning[] =
44 {
45 0, 804, 1606, 2404, 3196, 3981, 4756, 5520,
46 6270, 7005, 7723, 8423, 9102, 9760, 10394, 11003,
47 11585, 12140, 12665, 13160, 13623, 14053, 14449, 14811,
48 15137, 15426, 15679, 15893, 16069, 16207, 16305, 16364,
49 16384
50 };
51
52 #else
53
54 // Square root of Hanning window in Q14
55 const ALIGN8_BEG WebRtc_Word16 WebRtcAecm_kSqrtHanning[] ALIGN8_END =
56 {
57 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
58 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019, 8364,
59 8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514, 11795, 12068, 12335,
60 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189, 14384, 14571, 14749, 14918,
61 15079, 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034, 16111, 16179, 16237,
62 16286, 16325, 16354, 16373, 16384
63 };
64
65 #endif
66
67 //Q15 alpha = 0.99439986968132 const Factor for magnitude approximation
68 static const WebRtc_UWord16 kAlpha1 = 32584;
69 //Q15 beta = 0.12967166976970 const Factor for magnitude approximation
70 static const WebRtc_UWord16 kBeta1 = 4249;
71 //Q15 alpha = 0.94234827210087 const Factor for magnitude approximation
72 static const WebRtc_UWord16 kAlpha2 = 30879;
73 //Q15 beta = 0.33787806009150 const Factor for magnitude approximation
74 static const WebRtc_UWord16 kBeta2 = 11072;
75 //Q15 alpha = 0.82247698684306 const Factor for magnitude approximation
76 static const WebRtc_UWord16 kAlpha3 = 26951;
77 //Q15 beta = 0.57762063060713 const Factor for magnitude approximation
78 static const WebRtc_UWord16 kBeta3 = 18927;
79
80 // Initialization table for echo channel in 8 kHz
81 static const WebRtc_Word16 kChannelStored8kHz[PART_LEN1] = {
82 2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418,
83 1451, 1506, 1562, 1644, 1726, 1804, 1882, 1918,
84 1953, 1982, 2010, 2025, 2040, 2034, 2027, 2021,
85 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683,
86 1635, 1604, 1572, 1545, 1517, 1481, 1444, 1405,
87 1367, 1331, 1294, 1270, 1245, 1239, 1233, 1247,
88 1260, 1282, 1303, 1338, 1373, 1407, 1441, 1470,
89 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649,
90 1676
91 };
92
93 // Initialization table for echo channel in 16 kHz
94 static const WebRtc_Word16 kChannelStored16kHz[PART_LEN1] = {
95 2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882,
96 1953, 2010, 2040, 2027, 2014, 1980, 1869, 1732,
97 1635, 1572, 1517, 1444, 1367, 1294, 1245, 1233,
98 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621,
99 1676, 1741, 1802, 1861, 1921, 1983, 2040, 2102,
100 2170, 2265, 2375, 2515, 2651, 2781, 2922, 3075,
101 3253, 3471, 3738, 3976, 4151, 4258, 4308, 4288,
102 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484,
103 3153
104 };
105
106 static const WebRtc_Word16 kCosTable[] = {
107 8192, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112,
108 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834,
109 7791, 7745, 7697, 7647, 7595, 7540, 7483, 7424, 7362,
110 7299, 7233, 7164, 7094, 7021, 6947, 6870, 6791, 6710,
111 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991, 5892,
112 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930,
113 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845,
114 3719, 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667,
115 2531, 2395, 2258, 2120, 1981, 1842, 1703, 1563, 1422,
116 1281, 1140, 998, 856, 713, 571, 428, 285, 142,
117 0, -142, -285, -428, -571, -713, -856, -998, -1140,
118 -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395,
119 -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591,
120 -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698,
121 -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690,
122 -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542,
123 -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233,
124 -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745,
125 -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067,
126 -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190,
127 -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112,
128 -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
129 -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362,
130 -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710,
131 -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892,
132 -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930,
133 -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845,
134 -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667,
135 -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422,
136 -1281, -1140, -998, -856, -713, -571, -428, -285, -142,
137 0, 142, 285, 428, 571, 713, 856, 998, 1140,
138 1281, 1422, 1563, 1703, 1842, 1981, 2120, 2258, 2395,
139 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591,
140 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698,
141 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586, 5690,
142 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542,
143 6627, 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233,
144 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745,
145 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067,
146 8091, 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190
147 };
148
149 static const WebRtc_Word16 kSinTable[] = {
150 0, 142, 285, 428, 571, 713, 856, 998,
151 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120,
152 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200,
153 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219,
154 4341, 4461, 4580, 4698, 4815, 4930, 5043, 5155,
155 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991,
156 6087, 6182, 6275, 6366, 6455, 6542, 6627, 6710,
157 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299,
158 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745,
159 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041,
160 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180,
161 8187, 8190, 8191, 8190, 8187, 8180, 8172, 8160,
162 8147, 8130, 8112, 8091, 8067, 8041, 8012, 7982,
163 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647,
164 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164,
165 7094, 7021, 6947, 6870, 6791, 6710, 6627, 6542,
166 6455, 6366, 6275, 6182, 6087, 5991, 5892, 5792,
167 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930,
168 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971,
169 3845, 3719, 3591, 3462, 3331, 3200, 3068, 2935,
170 2801, 2667, 2531, 2395, 2258, 2120, 1981, 1842,
171 1703, 1563, 1422, 1281, 1140, 998, 856, 713,
172 571, 428, 285, 142, 0, -142, -285, -428,
173 -571, -713, -856, -998, -1140, -1281, -1422, -1563,
174 -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667,
175 -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719,
176 -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698,
177 -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586,
178 -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366,
179 -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021,
180 -7094, -7164, -7233, -7299, -7362, -7424, -7483, -7540,
181 -7595, -7647, -7697, -7745, -7791, -7834, -7874, -7912,
182 -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130,
183 -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190,
184 -8187, -8180, -8172, -8160, -8147, -8130, -8112, -8091,
185 -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
186 -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424,
187 -7362, -7299, -7233, -7164, -7094, -7021, -6947, -6870,
188 -6791, -6710, -6627, -6542, -6455, -6366, -6275, -6182,
189 -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374,
190 -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461,
191 -4341, -4219, -4096, -3971, -3845, -3719, -3591, -3462,
192 -3331, -3200, -3068, -2935, -2801, -2667, -2531, -2395,
193 -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281,
194 -1140, -998, -856, -713, -571, -428, -285, -142
195 };
196
197 static const WebRtc_Word16 kNoiseEstQDomain = 15;
198 static const WebRtc_Word16 kNoiseEstIncCount = 5;
199
200 static void ComfortNoise(AecmCore_t* aecm,
201 const WebRtc_UWord16* dfa,
202 complex16_t* out,
203 const WebRtc_Word16* lambda);
204
205 static WebRtc_Word16 CalcSuppressionGain(AecmCore_t * const aecm);
206
207 // Moves the pointer to the next entry and inserts |far_spectrum| and
208 // corresponding Q-domain in its buffer.
209 //
210 // Inputs:
211 // - self : Pointer to the delay estimation instance
212 // - far_spectrum : Pointer to the far end spectrum
213 // - far_q : Q-domain of far end spectrum
214 //
UpdateFarHistory(AecmCore_t * self,uint16_t * far_spectrum,int far_q)215 static void UpdateFarHistory(AecmCore_t* self,
216 uint16_t* far_spectrum,
217 int far_q) {
218 // Get new buffer position
219 self->far_history_pos++;
220 if (self->far_history_pos >= MAX_DELAY) {
221 self->far_history_pos = 0;
222 }
223 // Update Q-domain buffer
224 self->far_q_domains[self->far_history_pos] = far_q;
225 // Update far end spectrum buffer
226 memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]),
227 far_spectrum,
228 sizeof(uint16_t) * PART_LEN1);
229 }
230
231 // Returns a pointer to the far end spectrum aligned to current near end
232 // spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been
233 // called before AlignedFarend(...). Otherwise, you get the pointer to the
234 // previous frame. The memory is only valid until the next call of
235 // WebRtc_DelayEstimatorProcessFix(...).
236 //
237 // Inputs:
238 // - self : Pointer to the AECM instance.
239 // - delay : Current delay estimate.
240 //
241 // Output:
242 // - far_q : The Q-domain of the aligned far end spectrum
243 //
244 // Return value:
245 // - far_spectrum : Pointer to the aligned far end spectrum
246 // NULL - Error
247 //
AlignedFarend(AecmCore_t * self,int * far_q,int delay)248 static const uint16_t* AlignedFarend(AecmCore_t* self, int* far_q, int delay) {
249 int buffer_position = 0;
250 assert(self != NULL);
251 buffer_position = self->far_history_pos - delay;
252
253 // Check buffer position
254 if (buffer_position < 0) {
255 buffer_position += MAX_DELAY;
256 }
257 // Get Q-domain
258 *far_q = self->far_q_domains[buffer_position];
259 // Return far end spectrum
260 return &(self->far_history[buffer_position * PART_LEN1]);
261 }
262
263 #ifdef ARM_WINM_LOG
264 HANDLE logFile = NULL;
265 #endif
266
267 // Declare function pointers.
268 CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
269 StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
270 ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
271 WindowAndFFT WebRtcAecm_WindowAndFFT;
272 InverseFFTAndWindow WebRtcAecm_InverseFFTAndWindow;
273
WebRtcAecm_CreateCore(AecmCore_t ** aecmInst)274 int WebRtcAecm_CreateCore(AecmCore_t **aecmInst)
275 {
276 AecmCore_t *aecm = malloc(sizeof(AecmCore_t));
277 *aecmInst = aecm;
278 if (aecm == NULL)
279 {
280 return -1;
281 }
282
283 if (WebRtc_CreateBuffer(&aecm->farFrameBuf, FRAME_LEN + PART_LEN,
284 sizeof(int16_t)) == -1)
285 {
286 WebRtcAecm_FreeCore(aecm);
287 aecm = NULL;
288 return -1;
289 }
290
291 if (WebRtc_CreateBuffer(&aecm->nearNoisyFrameBuf, FRAME_LEN + PART_LEN,
292 sizeof(int16_t)) == -1)
293 {
294 WebRtcAecm_FreeCore(aecm);
295 aecm = NULL;
296 return -1;
297 }
298
299 if (WebRtc_CreateBuffer(&aecm->nearCleanFrameBuf, FRAME_LEN + PART_LEN,
300 sizeof(int16_t)) == -1)
301 {
302 WebRtcAecm_FreeCore(aecm);
303 aecm = NULL;
304 return -1;
305 }
306
307 if (WebRtc_CreateBuffer(&aecm->outFrameBuf, FRAME_LEN + PART_LEN,
308 sizeof(int16_t)) == -1)
309 {
310 WebRtcAecm_FreeCore(aecm);
311 aecm = NULL;
312 return -1;
313 }
314
315 if (WebRtc_CreateDelayEstimator(&aecm->delay_estimator,
316 PART_LEN1,
317 MAX_DELAY,
318 0) == -1) {
319 WebRtcAecm_FreeCore(aecm);
320 aecm = NULL;
321 return -1;
322 }
323
324 // Init some aecm pointers. 16 and 32 byte alignment is only necessary
325 // for Neon code currently.
326 aecm->xBuf = (WebRtc_Word16*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31);
327 aecm->dBufClean = (WebRtc_Word16*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31);
328 aecm->dBufNoisy = (WebRtc_Word16*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31);
329 aecm->outBuf = (WebRtc_Word16*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15);
330 aecm->channelStored = (WebRtc_Word16*) (((uintptr_t)
331 aecm->channelStored_buf + 15) & ~ 15);
332 aecm->channelAdapt16 = (WebRtc_Word16*) (((uintptr_t)
333 aecm->channelAdapt16_buf + 15) & ~ 15);
334 aecm->channelAdapt32 = (WebRtc_Word32*) (((uintptr_t)
335 aecm->channelAdapt32_buf + 31) & ~ 31);
336
337 return 0;
338 }
339
WebRtcAecm_InitEchoPathCore(AecmCore_t * aecm,const WebRtc_Word16 * echo_path)340 void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const WebRtc_Word16* echo_path)
341 {
342 int i = 0;
343
344 // Reset the stored channel
345 memcpy(aecm->channelStored, echo_path, sizeof(WebRtc_Word16) * PART_LEN1);
346 // Reset the adapted channels
347 memcpy(aecm->channelAdapt16, echo_path, sizeof(WebRtc_Word16) * PART_LEN1);
348 for (i = 0; i < PART_LEN1; i++)
349 {
350 aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
351 (WebRtc_Word32)(aecm->channelAdapt16[i]), 16);
352 }
353
354 // Reset channel storing variables
355 aecm->mseAdaptOld = 1000;
356 aecm->mseStoredOld = 1000;
357 aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
358 aecm->mseChannelCount = 0;
359 }
360
WindowAndFFTC(WebRtc_Word16 * fft,const WebRtc_Word16 * time_signal,complex16_t * freq_signal,int time_signal_scaling)361 static void WindowAndFFTC(WebRtc_Word16* fft,
362 const WebRtc_Word16* time_signal,
363 complex16_t* freq_signal,
364 int time_signal_scaling)
365 {
366 int i, j;
367
368 memset(fft, 0, sizeof(WebRtc_Word16) * PART_LEN4);
369 // FFT of signal
370 for (i = 0, j = 0; i < PART_LEN; i++, j += 2)
371 {
372 // Window time domain signal and insert into real part of
373 // transformation array |fft|
374 fft[j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(
375 (time_signal[i] << time_signal_scaling),
376 WebRtcAecm_kSqrtHanning[i],
377 14);
378 fft[PART_LEN2 + j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(
379 (time_signal[i + PART_LEN] << time_signal_scaling),
380 WebRtcAecm_kSqrtHanning[PART_LEN - i],
381 14);
382 // Inserting zeros in imaginary parts not necessary since we
383 // initialized the array with all zeros
384 }
385
386 WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
387 WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1);
388
389 // Take only the first PART_LEN2 samples
390 for (i = 0, j = 0; j < PART_LEN2; i += 1, j += 2)
391 {
392 freq_signal[i].real = fft[j];
393
394 // The imaginary part has to switch sign
395 freq_signal[i].imag = - fft[j+1];
396 }
397 }
398
InverseFFTAndWindowC(AecmCore_t * aecm,WebRtc_Word16 * fft,complex16_t * efw,WebRtc_Word16 * output,const WebRtc_Word16 * nearendClean)399 static void InverseFFTAndWindowC(AecmCore_t* aecm,
400 WebRtc_Word16* fft,
401 complex16_t* efw,
402 WebRtc_Word16* output,
403 const WebRtc_Word16* nearendClean)
404 {
405 int i, j, outCFFT;
406 WebRtc_Word32 tmp32no1;
407
408 // Synthesis
409 for (i = 1; i < PART_LEN; i++)
410 {
411 j = WEBRTC_SPL_LSHIFT_W32(i, 1);
412 fft[j] = efw[i].real;
413
414 // mirrored data, even
415 fft[PART_LEN4 - j] = efw[i].real;
416 fft[j + 1] = -efw[i].imag;
417
418 //mirrored data, odd
419 fft[PART_LEN4 - (j - 1)] = efw[i].imag;
420 }
421 fft[0] = efw[0].real;
422 fft[1] = -efw[0].imag;
423
424 fft[PART_LEN2] = efw[PART_LEN].real;
425 fft[PART_LEN2 + 1] = -efw[PART_LEN].imag;
426
427 // inverse FFT, result should be scaled with outCFFT
428 WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
429 outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1);
430
431 //take only the real values and scale with outCFFT
432 for (i = 0; i < PART_LEN2; i++)
433 {
434 j = WEBRTC_SPL_LSHIFT_W32(i, 1);
435 fft[i] = fft[j];
436 }
437
438 for (i = 0; i < PART_LEN; i++)
439 {
440 fft[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
441 fft[i],
442 WebRtcAecm_kSqrtHanning[i],
443 14);
444 tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)fft[i],
445 outCFFT - aecm->dfaCleanQDomain);
446 fft[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
447 tmp32no1 + aecm->outBuf[i],
448 WEBRTC_SPL_WORD16_MIN);
449 output[i] = fft[i];
450
451 tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT(
452 fft[PART_LEN + i],
453 WebRtcAecm_kSqrtHanning[PART_LEN - i],
454 14);
455 tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1,
456 outCFFT - aecm->dfaCleanQDomain);
457 aecm->outBuf[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(
458 WEBRTC_SPL_WORD16_MAX,
459 tmp32no1,
460 WEBRTC_SPL_WORD16_MIN);
461 }
462
463 #ifdef ARM_WINM_LOG_
464 // measure tick end
465 QueryPerformanceCounter((LARGE_INTEGER*)&end);
466 diff__ = ((end - start) * 1000) / (freq/1000);
467 milliseconds = (unsigned int)(diff__ & 0xffffffff);
468 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
469 #endif
470
471 // Copy the current block to the old position (aecm->outBuf is shifted elsewhere)
472 memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN);
473 memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN);
474 if (nearendClean != NULL)
475 {
476 memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN);
477 }
478 }
479
CalcLinearEnergiesC(AecmCore_t * aecm,const WebRtc_UWord16 * far_spectrum,WebRtc_Word32 * echo_est,WebRtc_UWord32 * far_energy,WebRtc_UWord32 * echo_energy_adapt,WebRtc_UWord32 * echo_energy_stored)480 static void CalcLinearEnergiesC(AecmCore_t* aecm,
481 const WebRtc_UWord16* far_spectrum,
482 WebRtc_Word32* echo_est,
483 WebRtc_UWord32* far_energy,
484 WebRtc_UWord32* echo_energy_adapt,
485 WebRtc_UWord32* echo_energy_stored)
486 {
487 int i;
488
489 // Get energy for the delayed far end signal and estimated
490 // echo using both stored and adapted channels.
491 for (i = 0; i < PART_LEN1; i++)
492 {
493 echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
494 far_spectrum[i]);
495 (*far_energy) += (WebRtc_UWord32)(far_spectrum[i]);
496 (*echo_energy_adapt) += WEBRTC_SPL_UMUL_16_16(aecm->channelAdapt16[i],
497 far_spectrum[i]);
498 (*echo_energy_stored) += (WebRtc_UWord32)echo_est[i];
499 }
500 }
501
StoreAdaptiveChannelC(AecmCore_t * aecm,const WebRtc_UWord16 * far_spectrum,WebRtc_Word32 * echo_est)502 static void StoreAdaptiveChannelC(AecmCore_t* aecm,
503 const WebRtc_UWord16* far_spectrum,
504 WebRtc_Word32* echo_est)
505 {
506 int i;
507
508 // During startup we store the channel every block.
509 memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(WebRtc_Word16) * PART_LEN1);
510 // Recalculate echo estimate
511 for (i = 0; i < PART_LEN; i += 4)
512 {
513 echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
514 far_spectrum[i]);
515 echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1],
516 far_spectrum[i + 1]);
517 echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2],
518 far_spectrum[i + 2]);
519 echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3],
520 far_spectrum[i + 3]);
521 }
522 echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
523 far_spectrum[i]);
524 }
525
ResetAdaptiveChannelC(AecmCore_t * aecm)526 static void ResetAdaptiveChannelC(AecmCore_t* aecm)
527 {
528 int i;
529
530 // The stored channel has a significantly lower MSE than the adaptive one for
531 // two consecutive calculations. Reset the adaptive channel.
532 memcpy(aecm->channelAdapt16, aecm->channelStored,
533 sizeof(WebRtc_Word16) * PART_LEN1);
534 // Restore the W32 channel
535 for (i = 0; i < PART_LEN; i += 4)
536 {
537 aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
538 (WebRtc_Word32)aecm->channelStored[i], 16);
539 aecm->channelAdapt32[i + 1] = WEBRTC_SPL_LSHIFT_W32(
540 (WebRtc_Word32)aecm->channelStored[i + 1], 16);
541 aecm->channelAdapt32[i + 2] = WEBRTC_SPL_LSHIFT_W32(
542 (WebRtc_Word32)aecm->channelStored[i + 2], 16);
543 aecm->channelAdapt32[i + 3] = WEBRTC_SPL_LSHIFT_W32(
544 (WebRtc_Word32)aecm->channelStored[i + 3], 16);
545 }
546 aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)aecm->channelStored[i], 16);
547 }
548
549 // WebRtcAecm_InitCore(...)
550 //
551 // This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
552 // Input:
553 // - aecm : Pointer to the Echo Suppression instance
554 // - samplingFreq : Sampling Frequency
555 //
556 // Output:
557 // - aecm : Initialized instance
558 //
559 // Return value : 0 - Ok
560 // -1 - Error
561 //
WebRtcAecm_InitCore(AecmCore_t * const aecm,int samplingFreq)562 int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq)
563 {
564 int i = 0;
565 WebRtc_Word32 tmp32 = PART_LEN1 * PART_LEN1;
566 WebRtc_Word16 tmp16 = PART_LEN1;
567
568 if (samplingFreq != 8000 && samplingFreq != 16000)
569 {
570 samplingFreq = 8000;
571 return -1;
572 }
573 // sanity check of sampling frequency
574 aecm->mult = (WebRtc_Word16)samplingFreq / 8000;
575
576 aecm->farBufWritePos = 0;
577 aecm->farBufReadPos = 0;
578 aecm->knownDelay = 0;
579 aecm->lastKnownDelay = 0;
580
581 WebRtc_InitBuffer(aecm->farFrameBuf);
582 WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
583 WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
584 WebRtc_InitBuffer(aecm->outFrameBuf);
585
586 memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
587 memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
588 memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
589 memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
590
591 aecm->seed = 666;
592 aecm->totCount = 0;
593
594 if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
595 return -1;
596 }
597 // Set far end histories to zero
598 memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
599 memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
600 aecm->far_history_pos = MAX_DELAY;
601
602 aecm->nlpFlag = 1;
603 aecm->fixedDelay = -1;
604
605 aecm->dfaCleanQDomain = 0;
606 aecm->dfaCleanQDomainOld = 0;
607 aecm->dfaNoisyQDomain = 0;
608 aecm->dfaNoisyQDomainOld = 0;
609
610 memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
611 aecm->farLogEnergy = 0;
612 memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
613 memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
614
615 // Initialize the echo channels with a stored shape.
616 if (samplingFreq == 8000)
617 {
618 WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
619 }
620 else
621 {
622 WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
623 }
624
625 memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
626 memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
627 aecm->noiseEstCtr = 0;
628
629 aecm->cngMode = AecmTrue;
630
631 memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
632 memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
633 // Shape the initial noise level to an approximate pink noise.
634 for (i = 0; i < (PART_LEN1 >> 1) - 1; i++)
635 {
636 aecm->noiseEst[i] = (tmp32 << 8);
637 tmp16--;
638 tmp32 -= (WebRtc_Word32)((tmp16 << 1) + 1);
639 }
640 for (; i < PART_LEN1; i++)
641 {
642 aecm->noiseEst[i] = (tmp32 << 8);
643 }
644
645 aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
646 aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
647 aecm->farEnergyMaxMin = 0;
648 aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the
649 // beginning.
650 aecm->farEnergyMSE = 0;
651 aecm->currentVADValue = 0;
652 aecm->vadUpdateCount = 0;
653 aecm->firstVAD = 1;
654
655 aecm->startupState = 0;
656 aecm->supGain = SUPGAIN_DEFAULT;
657 aecm->supGainOld = SUPGAIN_DEFAULT;
658
659 aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
660 aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
661 aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
662 aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
663
664 assert(PART_LEN % 16 == 0);
665
666 // Initialize function pointers.
667 WebRtcAecm_WindowAndFFT = WindowAndFFTC;
668 WebRtcAecm_InverseFFTAndWindow = InverseFFTAndWindowC;
669 WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
670 WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
671 WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
672
673 #ifdef WEBRTC_DETECT_ARM_NEON
674 uint64_t features = WebRtc_GetCPUFeaturesARM();
675 if ((features & kCPUFeatureNEON) != 0)
676 {
677 WebRtcAecm_InitNeon();
678 }
679 #elif defined(WEBRTC_ARCH_ARM_NEON)
680 WebRtcAecm_InitNeon();
681 #endif
682
683 return 0;
684 }
685
686 // TODO(bjornv): This function is currently not used. Add support for these
687 // parameters from a higher level
WebRtcAecm_Control(AecmCore_t * aecm,int delay,int nlpFlag)688 int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag)
689 {
690 aecm->nlpFlag = nlpFlag;
691 aecm->fixedDelay = delay;
692
693 return 0;
694 }
695
WebRtcAecm_FreeCore(AecmCore_t * aecm)696 int WebRtcAecm_FreeCore(AecmCore_t *aecm)
697 {
698 if (aecm == NULL)
699 {
700 return -1;
701 }
702
703 WebRtc_FreeBuffer(aecm->farFrameBuf);
704 WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
705 WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
706 WebRtc_FreeBuffer(aecm->outFrameBuf);
707
708 WebRtc_FreeDelayEstimator(aecm->delay_estimator);
709 free(aecm);
710
711 return 0;
712 }
713
WebRtcAecm_ProcessFrame(AecmCore_t * aecm,const WebRtc_Word16 * farend,const WebRtc_Word16 * nearendNoisy,const WebRtc_Word16 * nearendClean,WebRtc_Word16 * out)714 int WebRtcAecm_ProcessFrame(AecmCore_t * aecm,
715 const WebRtc_Word16 * farend,
716 const WebRtc_Word16 * nearendNoisy,
717 const WebRtc_Word16 * nearendClean,
718 WebRtc_Word16 * out)
719 {
720 WebRtc_Word16 outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary.
721 WebRtc_Word16* outBlock = (WebRtc_Word16*) (((uintptr_t) outBlock_buf + 15) & ~ 15);
722
723 WebRtc_Word16 farFrame[FRAME_LEN];
724 const int16_t* out_ptr = NULL;
725 int size = 0;
726
727 // Buffer the current frame.
728 // Fetch an older one corresponding to the delay.
729 WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
730 WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
731
732 // Buffer the synchronized far and near frames,
733 // to pass the smaller blocks individually.
734 WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
735 WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
736 if (nearendClean != NULL)
737 {
738 WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
739 }
740
741 // Process as many blocks as possible.
742 while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN)
743 {
744 int16_t far_block[PART_LEN];
745 const int16_t* far_block_ptr = NULL;
746 int16_t near_noisy_block[PART_LEN];
747 const int16_t* near_noisy_block_ptr = NULL;
748
749 WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block,
750 PART_LEN);
751 WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf,
752 (void**) &near_noisy_block_ptr,
753 near_noisy_block,
754 PART_LEN);
755 if (nearendClean != NULL)
756 {
757 int16_t near_clean_block[PART_LEN];
758 const int16_t* near_clean_block_ptr = NULL;
759
760 WebRtc_ReadBuffer(aecm->nearCleanFrameBuf,
761 (void**) &near_clean_block_ptr,
762 near_clean_block,
763 PART_LEN);
764 if (WebRtcAecm_ProcessBlock(aecm,
765 far_block_ptr,
766 near_noisy_block_ptr,
767 near_clean_block_ptr,
768 outBlock) == -1)
769 {
770 return -1;
771 }
772 } else
773 {
774 if (WebRtcAecm_ProcessBlock(aecm,
775 far_block_ptr,
776 near_noisy_block_ptr,
777 NULL,
778 outBlock) == -1)
779 {
780 return -1;
781 }
782 }
783
784 WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
785 }
786
787 // Stuff the out buffer if we have less than a frame to output.
788 // This should only happen for the first frame.
789 size = (int) WebRtc_available_read(aecm->outFrameBuf);
790 if (size < FRAME_LEN)
791 {
792 WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
793 }
794
795 // Obtain an output frame.
796 WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN);
797 if (out_ptr != out) {
798 // ReadBuffer() hasn't copied to |out| in this case.
799 memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
800 }
801
802 return 0;
803 }
804
805 // WebRtcAecm_AsymFilt(...)
806 //
807 // Performs asymmetric filtering.
808 //
809 // Inputs:
810 // - filtOld : Previous filtered value.
811 // - inVal : New input value.
812 // - stepSizePos : Step size when we have a positive contribution.
813 // - stepSizeNeg : Step size when we have a negative contribution.
814 //
815 // Output:
816 //
817 // Return: - Filtered value.
818 //
WebRtcAecm_AsymFilt(const WebRtc_Word16 filtOld,const WebRtc_Word16 inVal,const WebRtc_Word16 stepSizePos,const WebRtc_Word16 stepSizeNeg)819 WebRtc_Word16 WebRtcAecm_AsymFilt(const WebRtc_Word16 filtOld, const WebRtc_Word16 inVal,
820 const WebRtc_Word16 stepSizePos,
821 const WebRtc_Word16 stepSizeNeg)
822 {
823 WebRtc_Word16 retVal;
824
825 if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN))
826 {
827 return inVal;
828 }
829 retVal = filtOld;
830 if (filtOld > inVal)
831 {
832 retVal -= WEBRTC_SPL_RSHIFT_W16(filtOld - inVal, stepSizeNeg);
833 } else
834 {
835 retVal += WEBRTC_SPL_RSHIFT_W16(inVal - filtOld, stepSizePos);
836 }
837
838 return retVal;
839 }
840
841 // WebRtcAecm_CalcEnergies(...)
842 //
843 // This function calculates the log of energies for nearend, farend and estimated
844 // echoes. There is also an update of energy decision levels, i.e. internal VAD.
845 //
846 //
847 // @param aecm [i/o] Handle of the AECM instance.
848 // @param far_spectrum [in] Pointer to farend spectrum.
849 // @param far_q [in] Q-domain of farend spectrum.
850 // @param nearEner [in] Near end energy for current block in
851 // Q(aecm->dfaQDomain).
852 // @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
853 //
WebRtcAecm_CalcEnergies(AecmCore_t * aecm,const WebRtc_UWord16 * far_spectrum,const WebRtc_Word16 far_q,const WebRtc_UWord32 nearEner,WebRtc_Word32 * echoEst)854 void WebRtcAecm_CalcEnergies(AecmCore_t * aecm,
855 const WebRtc_UWord16* far_spectrum,
856 const WebRtc_Word16 far_q,
857 const WebRtc_UWord32 nearEner,
858 WebRtc_Word32 * echoEst)
859 {
860 // Local variables
861 WebRtc_UWord32 tmpAdapt = 0;
862 WebRtc_UWord32 tmpStored = 0;
863 WebRtc_UWord32 tmpFar = 0;
864
865 int i;
866
867 WebRtc_Word16 zeros, frac;
868 WebRtc_Word16 tmp16;
869 WebRtc_Word16 increase_max_shifts = 4;
870 WebRtc_Word16 decrease_max_shifts = 11;
871 WebRtc_Word16 increase_min_shifts = 11;
872 WebRtc_Word16 decrease_min_shifts = 3;
873 WebRtc_Word16 kLogLowValue = WEBRTC_SPL_LSHIFT_W16(PART_LEN_SHIFT, 7);
874
875 // Get log of near end energy and store in buffer
876
877 // Shift buffer
878 memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
879 sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1));
880
881 // Logarithm of integrated magnitude spectrum (nearEner)
882 tmp16 = kLogLowValue;
883 if (nearEner)
884 {
885 zeros = WebRtcSpl_NormU32(nearEner);
886 frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(
887 (WEBRTC_SPL_LSHIFT_U32(nearEner, zeros) & 0x7FFFFFFF),
888 23);
889 // log2 in Q8
890 tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
891 tmp16 -= WEBRTC_SPL_LSHIFT_W16(aecm->dfaNoisyQDomain, 8);
892 }
893 aecm->nearLogEnergy[0] = tmp16;
894 // END: Get log of near end energy
895
896 WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored);
897
898 // Shift buffers
899 memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
900 sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1));
901 memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
902 sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1));
903
904 // Logarithm of delayed far end energy
905 tmp16 = kLogLowValue;
906 if (tmpFar)
907 {
908 zeros = WebRtcSpl_NormU32(tmpFar);
909 frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpFar, zeros)
910 & 0x7FFFFFFF), 23);
911 // log2 in Q8
912 tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
913 tmp16 -= WEBRTC_SPL_LSHIFT_W16(far_q, 8);
914 }
915 aecm->farLogEnergy = tmp16;
916
917 // Logarithm of estimated echo energy through adapted channel
918 tmp16 = kLogLowValue;
919 if (tmpAdapt)
920 {
921 zeros = WebRtcSpl_NormU32(tmpAdapt);
922 frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpAdapt, zeros)
923 & 0x7FFFFFFF), 23);
924 //log2 in Q8
925 tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
926 tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8);
927 }
928 aecm->echoAdaptLogEnergy[0] = tmp16;
929
930 // Logarithm of estimated echo energy through stored channel
931 tmp16 = kLogLowValue;
932 if (tmpStored)
933 {
934 zeros = WebRtcSpl_NormU32(tmpStored);
935 frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpStored, zeros)
936 & 0x7FFFFFFF), 23);
937 //log2 in Q8
938 tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
939 tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8);
940 }
941 aecm->echoStoredLogEnergy[0] = tmp16;
942
943 // Update farend energy levels (min, max, vad, mse)
944 if (aecm->farLogEnergy > FAR_ENERGY_MIN)
945 {
946 if (aecm->startupState == 0)
947 {
948 increase_max_shifts = 2;
949 decrease_min_shifts = 2;
950 increase_min_shifts = 8;
951 }
952
953 aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
954 increase_min_shifts, decrease_min_shifts);
955 aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
956 increase_max_shifts, decrease_max_shifts);
957 aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
958
959 // Dynamic VAD region size
960 tmp16 = 2560 - aecm->farEnergyMin;
961 if (tmp16 > 0)
962 {
963 tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, FAR_ENERGY_VAD_REGION, 9);
964 } else
965 {
966 tmp16 = 0;
967 }
968 tmp16 += FAR_ENERGY_VAD_REGION;
969
970 if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024))
971 {
972 // In startup phase or VAD update halted
973 aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
974 } else
975 {
976 if (aecm->farEnergyVAD > aecm->farLogEnergy)
977 {
978 aecm->farEnergyVAD += WEBRTC_SPL_RSHIFT_W16(aecm->farLogEnergy +
979 tmp16 -
980 aecm->farEnergyVAD,
981 6);
982 aecm->vadUpdateCount = 0;
983 } else
984 {
985 aecm->vadUpdateCount++;
986 }
987 }
988 // Put MSE threshold higher than VAD
989 aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
990 }
991
992 // Update VAD variables
993 if (aecm->farLogEnergy > aecm->farEnergyVAD)
994 {
995 if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF))
996 {
997 // We are in startup or have significant dynamics in input speech level
998 aecm->currentVADValue = 1;
999 }
1000 } else
1001 {
1002 aecm->currentVADValue = 0;
1003 }
1004 if ((aecm->currentVADValue) && (aecm->firstVAD))
1005 {
1006 aecm->firstVAD = 0;
1007 if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0])
1008 {
1009 // The estimated echo has higher energy than the near end signal.
1010 // This means that the initialization was too aggressive. Scale
1011 // down by a factor 8
1012 for (i = 0; i < PART_LEN1; i++)
1013 {
1014 aecm->channelAdapt16[i] >>= 3;
1015 }
1016 // Compensate the adapted echo energy level accordingly.
1017 aecm->echoAdaptLogEnergy[0] -= (3 << 8);
1018 aecm->firstVAD = 1;
1019 }
1020 }
1021 }
1022
1023 // WebRtcAecm_CalcStepSize(...)
1024 //
1025 // This function calculates the step size used in channel estimation
1026 //
1027 //
1028 // @param aecm [in] Handle of the AECM instance.
1029 // @param mu [out] (Return value) Stepsize in log2(), i.e. number of shifts.
1030 //
1031 //
WebRtcAecm_CalcStepSize(AecmCore_t * const aecm)1032 WebRtc_Word16 WebRtcAecm_CalcStepSize(AecmCore_t * const aecm)
1033 {
1034
1035 WebRtc_Word32 tmp32;
1036 WebRtc_Word16 tmp16;
1037 WebRtc_Word16 mu = MU_MAX;
1038
1039 // Here we calculate the step size mu used in the
1040 // following NLMS based Channel estimation algorithm
1041 if (!aecm->currentVADValue)
1042 {
1043 // Far end energy level too low, no channel update
1044 mu = 0;
1045 } else if (aecm->startupState > 0)
1046 {
1047 if (aecm->farEnergyMin >= aecm->farEnergyMax)
1048 {
1049 mu = MU_MIN;
1050 } else
1051 {
1052 tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
1053 tmp32 = WEBRTC_SPL_MUL_16_16(tmp16, MU_DIFF);
1054 tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
1055 mu = MU_MIN - 1 - (WebRtc_Word16)(tmp32);
1056 // The -1 is an alternative to rounding. This way we get a larger
1057 // stepsize, so we in some sense compensate for truncation in NLMS
1058 }
1059 if (mu < MU_MAX)
1060 {
1061 mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
1062 }
1063 }
1064
1065 return mu;
1066 }
1067
1068 // WebRtcAecm_UpdateChannel(...)
1069 //
1070 // This function performs channel estimation. NLMS and decision on channel storage.
1071 //
1072 //
1073 // @param aecm [i/o] Handle of the AECM instance.
1074 // @param far_spectrum [in] Absolute value of the farend signal in Q(far_q)
1075 // @param far_q [in] Q-domain of the farend signal
1076 // @param dfa [in] Absolute value of the nearend signal (Q[aecm->dfaQDomain])
1077 // @param mu [in] NLMS step size.
1078 // @param echoEst [i/o] Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
1079 //
WebRtcAecm_UpdateChannel(AecmCore_t * aecm,const WebRtc_UWord16 * far_spectrum,const WebRtc_Word16 far_q,const WebRtc_UWord16 * const dfa,const WebRtc_Word16 mu,WebRtc_Word32 * echoEst)1080 void WebRtcAecm_UpdateChannel(AecmCore_t * aecm,
1081 const WebRtc_UWord16* far_spectrum,
1082 const WebRtc_Word16 far_q,
1083 const WebRtc_UWord16 * const dfa,
1084 const WebRtc_Word16 mu,
1085 WebRtc_Word32 * echoEst)
1086 {
1087
1088 WebRtc_UWord32 tmpU32no1, tmpU32no2;
1089 WebRtc_Word32 tmp32no1, tmp32no2;
1090 WebRtc_Word32 mseStored;
1091 WebRtc_Word32 mseAdapt;
1092
1093 int i;
1094
1095 WebRtc_Word16 zerosFar, zerosNum, zerosCh, zerosDfa;
1096 WebRtc_Word16 shiftChFar, shiftNum, shift2ResChan;
1097 WebRtc_Word16 tmp16no1;
1098 WebRtc_Word16 xfaQ, dfaQ;
1099
1100 // This is the channel estimation algorithm. It is base on NLMS but has a variable step
1101 // length, which was calculated above.
1102 if (mu)
1103 {
1104 for (i = 0; i < PART_LEN1; i++)
1105 {
1106 // Determine norm of channel and farend to make sure we don't get overflow in
1107 // multiplication
1108 zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
1109 zerosFar = WebRtcSpl_NormU32((WebRtc_UWord32)far_spectrum[i]);
1110 if (zerosCh + zerosFar > 31)
1111 {
1112 // Multiplication is safe
1113 tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i],
1114 far_spectrum[i]);
1115 shiftChFar = 0;
1116 } else
1117 {
1118 // We need to shift down before multiplication
1119 shiftChFar = 32 - zerosCh - zerosFar;
1120 tmpU32no1 = WEBRTC_SPL_UMUL_32_16(
1121 WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], shiftChFar),
1122 far_spectrum[i]);
1123 }
1124 // Determine Q-domain of numerator
1125 zerosNum = WebRtcSpl_NormU32(tmpU32no1);
1126 if (dfa[i])
1127 {
1128 zerosDfa = WebRtcSpl_NormU32((WebRtc_UWord32)dfa[i]);
1129 } else
1130 {
1131 zerosDfa = 32;
1132 }
1133 tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain -
1134 RESOLUTION_CHANNEL32 - far_q + shiftChFar;
1135 if (zerosNum > tmp16no1 + 1)
1136 {
1137 xfaQ = tmp16no1;
1138 dfaQ = zerosDfa - 2;
1139 } else
1140 {
1141 xfaQ = zerosNum - 2;
1142 dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
1143 shiftChFar + xfaQ;
1144 }
1145 // Add in the same Q-domain
1146 tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
1147 tmpU32no2 = WEBRTC_SPL_SHIFT_W32((WebRtc_UWord32)dfa[i], dfaQ);
1148 tmp32no1 = (WebRtc_Word32)tmpU32no2 - (WebRtc_Word32)tmpU32no1;
1149 zerosNum = WebRtcSpl_NormW32(tmp32no1);
1150 if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q)))
1151 {
1152 //
1153 // Update is needed
1154 //
1155 // This is what we would like to compute
1156 //
1157 // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
1158 // tmp32norm = (i + 1)
1159 // aecm->channelAdapt[i] += (2^mu) * tmp32no1
1160 // / (tmp32norm * far_spectrum[i])
1161 //
1162
1163 // Make sure we don't get overflow in multiplication.
1164 if (zerosNum + zerosFar > 31)
1165 {
1166 if (tmp32no1 > 0)
1167 {
1168 tmp32no2 = (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(tmp32no1,
1169 far_spectrum[i]);
1170 } else
1171 {
1172 tmp32no2 = -(WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(-tmp32no1,
1173 far_spectrum[i]);
1174 }
1175 shiftNum = 0;
1176 } else
1177 {
1178 shiftNum = 32 - (zerosNum + zerosFar);
1179 if (tmp32no1 > 0)
1180 {
1181 tmp32no2 = (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(
1182 WEBRTC_SPL_RSHIFT_W32(tmp32no1, shiftNum),
1183 far_spectrum[i]);
1184 } else
1185 {
1186 tmp32no2 = -(WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(
1187 WEBRTC_SPL_RSHIFT_W32(-tmp32no1, shiftNum),
1188 far_spectrum[i]);
1189 }
1190 }
1191 // Normalize with respect to frequency bin
1192 tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
1193 // Make sure we are in the right Q-domain
1194 shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
1195 if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan)
1196 {
1197 tmp32no2 = WEBRTC_SPL_WORD32_MAX;
1198 } else
1199 {
1200 tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
1201 }
1202 aecm->channelAdapt32[i] = WEBRTC_SPL_ADD_SAT_W32(aecm->channelAdapt32[i],
1203 tmp32no2);
1204 if (aecm->channelAdapt32[i] < 0)
1205 {
1206 // We can never have negative channel gain
1207 aecm->channelAdapt32[i] = 0;
1208 }
1209 aecm->channelAdapt16[i]
1210 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], 16);
1211 }
1212 }
1213 }
1214 // END: Adaptive channel update
1215
1216 // Determine if we should store or restore the channel
1217 if ((aecm->startupState == 0) & (aecm->currentVADValue))
1218 {
1219 // During startup we store the channel every block,
1220 // and we recalculate echo estimate
1221 WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
1222 } else
1223 {
1224 if (aecm->farLogEnergy < aecm->farEnergyMSE)
1225 {
1226 aecm->mseChannelCount = 0;
1227 } else
1228 {
1229 aecm->mseChannelCount++;
1230 }
1231 // Enough data for validation. Store channel if we can.
1232 if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10))
1233 {
1234 // We have enough data.
1235 // Calculate MSE of "Adapt" and "Stored" versions.
1236 // It is actually not MSE, but average absolute error.
1237 mseStored = 0;
1238 mseAdapt = 0;
1239 for (i = 0; i < MIN_MSE_COUNT; i++)
1240 {
1241 tmp32no1 = ((WebRtc_Word32)aecm->echoStoredLogEnergy[i]
1242 - (WebRtc_Word32)aecm->nearLogEnergy[i]);
1243 tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
1244 mseStored += tmp32no2;
1245
1246 tmp32no1 = ((WebRtc_Word32)aecm->echoAdaptLogEnergy[i]
1247 - (WebRtc_Word32)aecm->nearLogEnergy[i]);
1248 tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
1249 mseAdapt += tmp32no2;
1250 }
1251 if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt))
1252 & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF
1253 * aecm->mseAdaptOld)))
1254 {
1255 // The stored channel has a significantly lower MSE than the adaptive one for
1256 // two consecutive calculations. Reset the adaptive channel.
1257 WebRtcAecm_ResetAdaptiveChannel(aecm);
1258 } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt
1259 < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold))
1260 {
1261 // The adaptive channel has a significantly lower MSE than the stored one.
1262 // The MSE for the adaptive channel has also been low for two consecutive
1263 // calculations. Store the adaptive channel.
1264 WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
1265
1266 // Update threshold
1267 if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX)
1268 {
1269 aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
1270 } else
1271 {
1272 aecm->mseThreshold += WEBRTC_SPL_MUL_16_16_RSFT(mseAdapt
1273 - WEBRTC_SPL_MUL_16_16_RSFT(aecm->mseThreshold, 5, 3), 205, 8);
1274 }
1275
1276 }
1277
1278 // Reset counter
1279 aecm->mseChannelCount = 0;
1280
1281 // Store the MSE values.
1282 aecm->mseStoredOld = mseStored;
1283 aecm->mseAdaptOld = mseAdapt;
1284 }
1285 }
1286 // END: Determine if we should store or reset channel estimate.
1287 }
1288
1289 // CalcSuppressionGain(...)
1290 //
1291 // This function calculates the suppression gain that is used in the Wiener filter.
1292 //
1293 //
1294 // @param aecm [i/n] Handle of the AECM instance.
1295 // @param supGain [out] (Return value) Suppression gain with which to scale the noise
1296 // level (Q14).
1297 //
1298 //
CalcSuppressionGain(AecmCore_t * const aecm)1299 static WebRtc_Word16 CalcSuppressionGain(AecmCore_t * const aecm)
1300 {
1301 WebRtc_Word32 tmp32no1;
1302
1303 WebRtc_Word16 supGain = SUPGAIN_DEFAULT;
1304 WebRtc_Word16 tmp16no1;
1305 WebRtc_Word16 dE = 0;
1306
1307 // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far
1308 // end energy and echo estimation error.
1309 // Adjust for the far end signal level. A low signal level indicates no far end signal,
1310 // hence we set the suppression gain to 0
1311 if (!aecm->currentVADValue)
1312 {
1313 supGain = 0;
1314 } else
1315 {
1316 // Adjust for possible double talk. If we have large variations in estimation error we
1317 // likely have double talk (or poor channel).
1318 tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET);
1319 dE = WEBRTC_SPL_ABS_W16(tmp16no1);
1320
1321 if (dE < ENERGY_DEV_TOL)
1322 {
1323 // Likely no double talk. The better estimation, the more we can suppress signal.
1324 // Update counters
1325 if (dE < SUPGAIN_EPC_DT)
1326 {
1327 tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffAB, dE);
1328 tmp32no1 += (SUPGAIN_EPC_DT >> 1);
1329 tmp16no1 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
1330 supGain = aecm->supGainErrParamA - tmp16no1;
1331 } else
1332 {
1333 tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffBD,
1334 (ENERGY_DEV_TOL - dE));
1335 tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
1336 tmp16no1 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL
1337 - SUPGAIN_EPC_DT));
1338 supGain = aecm->supGainErrParamD + tmp16no1;
1339 }
1340 } else
1341 {
1342 // Likely in double talk. Use default value
1343 supGain = aecm->supGainErrParamD;
1344 }
1345 }
1346
1347 if (supGain > aecm->supGainOld)
1348 {
1349 tmp16no1 = supGain;
1350 } else
1351 {
1352 tmp16no1 = aecm->supGainOld;
1353 }
1354 aecm->supGainOld = supGain;
1355 if (tmp16no1 < aecm->supGain)
1356 {
1357 aecm->supGain += (WebRtc_Word16)((tmp16no1 - aecm->supGain) >> 4);
1358 } else
1359 {
1360 aecm->supGain += (WebRtc_Word16)((tmp16no1 - aecm->supGain) >> 4);
1361 }
1362
1363 // END: Update suppression gain
1364
1365 return aecm->supGain;
1366 }
1367
1368 // Transforms a time domain signal into the frequency domain, outputting the
1369 // complex valued signal, absolute value and sum of absolute values.
1370 //
1371 // time_signal [in] Pointer to time domain signal
1372 // freq_signal_real [out] Pointer to real part of frequency domain array
1373 // freq_signal_imag [out] Pointer to imaginary part of frequency domain
1374 // array
1375 // freq_signal_abs [out] Pointer to absolute value of frequency domain
1376 // array
1377 // freq_signal_sum_abs [out] Pointer to the sum of all absolute values in
1378 // the frequency domain array
1379 // return value The Q-domain of current frequency values
1380 //
TimeToFrequencyDomain(const WebRtc_Word16 * time_signal,complex16_t * freq_signal,WebRtc_UWord16 * freq_signal_abs,WebRtc_UWord32 * freq_signal_sum_abs)1381 static int TimeToFrequencyDomain(const WebRtc_Word16* time_signal,
1382 complex16_t* freq_signal,
1383 WebRtc_UWord16* freq_signal_abs,
1384 WebRtc_UWord32* freq_signal_sum_abs)
1385 {
1386 int i = 0;
1387 int time_signal_scaling = 0;
1388
1389 WebRtc_Word32 tmp32no1;
1390 WebRtc_Word32 tmp32no2;
1391
1392 // In fft_buf, +16 for 32-byte alignment.
1393 WebRtc_Word16 fft_buf[PART_LEN4 + 16];
1394 WebRtc_Word16 *fft = (WebRtc_Word16 *) (((uintptr_t) fft_buf + 31) & ~31);
1395
1396 WebRtc_Word16 tmp16no1;
1397 WebRtc_Word16 tmp16no2;
1398 #ifdef AECM_WITH_ABS_APPROX
1399 WebRtc_Word16 max_value = 0;
1400 WebRtc_Word16 min_value = 0;
1401 WebRtc_UWord16 alpha = 0;
1402 WebRtc_UWord16 beta = 0;
1403 #endif
1404
1405 #ifdef AECM_DYNAMIC_Q
1406 tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2);
1407 time_signal_scaling = WebRtcSpl_NormW16(tmp16no1);
1408 #endif
1409
1410 WebRtcAecm_WindowAndFFT(fft, time_signal, freq_signal, time_signal_scaling);
1411
1412 // Extract imaginary and real part, calculate the magnitude for all frequency bins
1413 freq_signal[0].imag = 0;
1414 freq_signal[PART_LEN].imag = 0;
1415 freq_signal[PART_LEN].real = fft[PART_LEN2];
1416 freq_signal_abs[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(
1417 freq_signal[0].real);
1418 freq_signal_abs[PART_LEN] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(
1419 freq_signal[PART_LEN].real);
1420 (*freq_signal_sum_abs) = (WebRtc_UWord32)(freq_signal_abs[0]) +
1421 (WebRtc_UWord32)(freq_signal_abs[PART_LEN]);
1422
1423 for (i = 1; i < PART_LEN; i++)
1424 {
1425 if (freq_signal[i].real == 0)
1426 {
1427 freq_signal_abs[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(
1428 freq_signal[i].imag);
1429 }
1430 else if (freq_signal[i].imag == 0)
1431 {
1432 freq_signal_abs[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(
1433 freq_signal[i].real);
1434 }
1435 else
1436 {
1437 // Approximation for magnitude of complex fft output
1438 // magn = sqrt(real^2 + imag^2)
1439 // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
1440 //
1441 // The parameters alpha and beta are stored in Q15
1442
1443 #ifdef AECM_WITH_ABS_APPROX
1444 tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
1445 tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
1446
1447 if(tmp16no1 > tmp16no2)
1448 {
1449 max_value = tmp16no1;
1450 min_value = tmp16no2;
1451 } else
1452 {
1453 max_value = tmp16no2;
1454 min_value = tmp16no1;
1455 }
1456
1457 // Magnitude in Q(-6)
1458 if ((max_value >> 2) > min_value)
1459 {
1460 alpha = kAlpha1;
1461 beta = kBeta1;
1462 } else if ((max_value >> 1) > min_value)
1463 {
1464 alpha = kAlpha2;
1465 beta = kBeta2;
1466 } else
1467 {
1468 alpha = kAlpha3;
1469 beta = kBeta3;
1470 }
1471 tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(max_value,
1472 alpha,
1473 15);
1474 tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(min_value,
1475 beta,
1476 15);
1477 freq_signal_abs[i] = (WebRtc_UWord16)tmp16no1 +
1478 (WebRtc_UWord16)tmp16no2;
1479 #else
1480 #ifdef WEBRTC_ARCH_ARM_V7A
1481 __asm__("smulbb %0, %1, %2" : "=r"(tmp32no1) : "r"(freq_signal[i].real),
1482 "r"(freq_signal[i].real));
1483 __asm__("smlabb %0, %1, %2, %3" :: "r"(tmp32no2), "r"(freq_signal[i].imag),
1484 "r"(freq_signal[i].imag), "r"(tmp32no1));
1485 #else
1486 tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
1487 tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
1488 tmp32no1 = WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1);
1489 tmp32no2 = WEBRTC_SPL_MUL_16_16(tmp16no2, tmp16no2);
1490 tmp32no2 = WEBRTC_SPL_ADD_SAT_W32(tmp32no1, tmp32no2);
1491 #endif // WEBRTC_ARCH_ARM_V7A
1492 tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2);
1493
1494 freq_signal_abs[i] = (WebRtc_UWord16)tmp32no1;
1495 #endif // AECM_WITH_ABS_APPROX
1496 }
1497 (*freq_signal_sum_abs) += (WebRtc_UWord32)freq_signal_abs[i];
1498 }
1499
1500 return time_signal_scaling;
1501 }
1502
WebRtcAecm_ProcessBlock(AecmCore_t * aecm,const WebRtc_Word16 * farend,const WebRtc_Word16 * nearendNoisy,const WebRtc_Word16 * nearendClean,WebRtc_Word16 * output)1503 int WebRtcAecm_ProcessBlock(AecmCore_t * aecm,
1504 const WebRtc_Word16 * farend,
1505 const WebRtc_Word16 * nearendNoisy,
1506 const WebRtc_Word16 * nearendClean,
1507 WebRtc_Word16 * output)
1508 {
1509 int i;
1510
1511 WebRtc_UWord32 xfaSum;
1512 WebRtc_UWord32 dfaNoisySum;
1513 WebRtc_UWord32 dfaCleanSum;
1514 WebRtc_UWord32 echoEst32Gained;
1515 WebRtc_UWord32 tmpU32;
1516
1517 WebRtc_Word32 tmp32no1;
1518
1519 WebRtc_UWord16 xfa[PART_LEN1];
1520 WebRtc_UWord16 dfaNoisy[PART_LEN1];
1521 WebRtc_UWord16 dfaClean[PART_LEN1];
1522 WebRtc_UWord16* ptrDfaClean = dfaClean;
1523 const WebRtc_UWord16* far_spectrum_ptr = NULL;
1524
1525 // 32 byte aligned buffers (with +8 or +16).
1526 // TODO (kma): define fft with complex16_t.
1527 WebRtc_Word16 fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe.
1528 WebRtc_Word32 echoEst32_buf[PART_LEN1 + 8];
1529 WebRtc_Word32 dfw_buf[PART_LEN1 + 8];
1530 WebRtc_Word32 efw_buf[PART_LEN1 + 8];
1531
1532 WebRtc_Word16* fft = (WebRtc_Word16*) (((uintptr_t) fft_buf + 31) & ~ 31);
1533 WebRtc_Word32* echoEst32 = (WebRtc_Word32*) (((uintptr_t) echoEst32_buf + 31) & ~ 31);
1534 complex16_t* dfw = (complex16_t*) (((uintptr_t) dfw_buf + 31) & ~ 31);
1535 complex16_t* efw = (complex16_t*) (((uintptr_t) efw_buf + 31) & ~ 31);
1536
1537 WebRtc_Word16 hnl[PART_LEN1];
1538 WebRtc_Word16 numPosCoef = 0;
1539 WebRtc_Word16 nlpGain = ONE_Q14;
1540 int delay;
1541 WebRtc_Word16 tmp16no1;
1542 WebRtc_Word16 tmp16no2;
1543 WebRtc_Word16 mu;
1544 WebRtc_Word16 supGain;
1545 WebRtc_Word16 zeros32, zeros16;
1546 WebRtc_Word16 zerosDBufNoisy, zerosDBufClean, zerosXBuf;
1547 int far_q;
1548 WebRtc_Word16 resolutionDiff, qDomainDiff;
1549
1550 const int kMinPrefBand = 4;
1551 const int kMaxPrefBand = 24;
1552 WebRtc_Word32 avgHnl32 = 0;
1553
1554 #ifdef ARM_WINM_LOG_
1555 DWORD temp;
1556 static int flag0 = 0;
1557 __int64 freq, start, end, diff__;
1558 unsigned int milliseconds;
1559 #endif
1560
1561 // Determine startup state. There are three states:
1562 // (0) the first CONV_LEN blocks
1563 // (1) another CONV_LEN blocks
1564 // (2) the rest
1565
1566 if (aecm->startupState < 2)
1567 {
1568 aecm->startupState = (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2);
1569 }
1570 // END: Determine startup state
1571
1572 // Buffer near and far end signals
1573 memcpy(aecm->xBuf + PART_LEN, farend, sizeof(WebRtc_Word16) * PART_LEN);
1574 memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(WebRtc_Word16) * PART_LEN);
1575 if (nearendClean != NULL)
1576 {
1577 memcpy(aecm->dBufClean + PART_LEN, nearendClean, sizeof(WebRtc_Word16) * PART_LEN);
1578 }
1579
1580 #ifdef ARM_WINM_LOG_
1581 // measure tick start
1582 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
1583 QueryPerformanceCounter((LARGE_INTEGER*)&start);
1584 #endif
1585
1586 // Transform far end signal from time domain to frequency domain.
1587 far_q = TimeToFrequencyDomain(aecm->xBuf,
1588 dfw,
1589 xfa,
1590 &xfaSum);
1591
1592 // Transform noisy near end signal from time domain to frequency domain.
1593 zerosDBufNoisy = TimeToFrequencyDomain(aecm->dBufNoisy,
1594 dfw,
1595 dfaNoisy,
1596 &dfaNoisySum);
1597 aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain;
1598 aecm->dfaNoisyQDomain = (WebRtc_Word16)zerosDBufNoisy;
1599
1600
1601 if (nearendClean == NULL)
1602 {
1603 ptrDfaClean = dfaNoisy;
1604 aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld;
1605 aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain;
1606 dfaCleanSum = dfaNoisySum;
1607 } else
1608 {
1609 // Transform clean near end signal from time domain to frequency domain.
1610 zerosDBufClean = TimeToFrequencyDomain(aecm->dBufClean,
1611 dfw,
1612 dfaClean,
1613 &dfaCleanSum);
1614 aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain;
1615 aecm->dfaCleanQDomain = (WebRtc_Word16)zerosDBufClean;
1616 }
1617
1618 #ifdef ARM_WINM_LOG_
1619 // measure tick end
1620 QueryPerformanceCounter((LARGE_INTEGER*)&end);
1621 diff__ = ((end - start) * 1000) / (freq/1000);
1622 milliseconds = (unsigned int)(diff__ & 0xffffffff);
1623 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
1624 // measure tick start
1625 QueryPerformanceCounter((LARGE_INTEGER*)&start);
1626 #endif
1627
1628 // Get the delay
1629 // Save far-end history and estimate delay
1630 UpdateFarHistory(aecm, xfa, far_q);
1631 delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator,
1632 xfa,
1633 dfaNoisy,
1634 PART_LEN1,
1635 far_q,
1636 zerosDBufNoisy);
1637 if (delay == -1)
1638 {
1639 return -1;
1640 }
1641 else if (delay == -2)
1642 {
1643 // If the delay is unknown, we assume zero.
1644 // NOTE: this will have to be adjusted if we ever add lookahead.
1645 delay = 0;
1646 }
1647
1648 if (aecm->fixedDelay >= 0)
1649 {
1650 // Use fixed delay
1651 delay = aecm->fixedDelay;
1652 }
1653
1654 #ifdef ARM_WINM_LOG_
1655 // measure tick end
1656 QueryPerformanceCounter((LARGE_INTEGER*)&end);
1657 diff__ = ((end - start) * 1000) / (freq/1000);
1658 milliseconds = (unsigned int)(diff__ & 0xffffffff);
1659 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
1660 // measure tick start
1661 QueryPerformanceCounter((LARGE_INTEGER*)&start);
1662 #endif
1663 // Get aligned far end spectrum
1664 far_spectrum_ptr = AlignedFarend(aecm, &far_q, delay);
1665 zerosXBuf = (WebRtc_Word16) far_q;
1666 if (far_spectrum_ptr == NULL)
1667 {
1668 return -1;
1669 }
1670
1671 // Calculate log(energy) and update energy threshold levels
1672 WebRtcAecm_CalcEnergies(aecm,
1673 far_spectrum_ptr,
1674 zerosXBuf,
1675 dfaNoisySum,
1676 echoEst32);
1677
1678 // Calculate stepsize
1679 mu = WebRtcAecm_CalcStepSize(aecm);
1680
1681 // Update counters
1682 aecm->totCount++;
1683
1684 // This is the channel estimation algorithm.
1685 // It is base on NLMS but has a variable step length, which was calculated above.
1686 WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu, echoEst32);
1687 supGain = CalcSuppressionGain(aecm);
1688
1689 #ifdef ARM_WINM_LOG_
1690 // measure tick end
1691 QueryPerformanceCounter((LARGE_INTEGER*)&end);
1692 diff__ = ((end - start) * 1000) / (freq/1000);
1693 milliseconds = (unsigned int)(diff__ & 0xffffffff);
1694 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
1695 // measure tick start
1696 QueryPerformanceCounter((LARGE_INTEGER*)&start);
1697 #endif
1698
1699 // Calculate Wiener filter hnl[]
1700 for (i = 0; i < PART_LEN1; i++)
1701 {
1702 // Far end signal through channel estimate in Q8
1703 // How much can we shift right to preserve resolution
1704 tmp32no1 = echoEst32[i] - aecm->echoFilt[i];
1705 aecm->echoFilt[i] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32no1, 50), 8);
1706
1707 zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1;
1708 zeros16 = WebRtcSpl_NormW16(supGain) + 1;
1709 if (zeros32 + zeros16 > 16)
1710 {
1711 // Multiplication is safe
1712 // Result in Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+aecm->xfaQDomainBuf[diff])
1713 echoEst32Gained = WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32)aecm->echoFilt[i],
1714 (WebRtc_UWord16)supGain);
1715 resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
1716 resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
1717 } else
1718 {
1719 tmp16no1 = 17 - zeros32 - zeros16;
1720 resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
1721 resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
1722 if (zeros32 > tmp16no1)
1723 {
1724 echoEst32Gained = WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32)aecm->echoFilt[i],
1725 (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_W16(supGain,
1726 tmp16no1)); // Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
1727 } else
1728 {
1729 // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
1730 echoEst32Gained = WEBRTC_SPL_UMUL_32_16(
1731 (WebRtc_UWord32)WEBRTC_SPL_RSHIFT_W32(aecm->echoFilt[i], tmp16no1),
1732 (WebRtc_UWord16)supGain);
1733 }
1734 }
1735
1736 zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]);
1737 if ((zeros16 < (aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld))
1738 & (aecm->nearFilt[i]))
1739 {
1740 tmp16no1 = WEBRTC_SPL_SHIFT_W16(aecm->nearFilt[i], zeros16);
1741 qDomainDiff = zeros16 - aecm->dfaCleanQDomain + aecm->dfaCleanQDomainOld;
1742 } else
1743 {
1744 tmp16no1 = WEBRTC_SPL_SHIFT_W16(aecm->nearFilt[i],
1745 aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld);
1746 qDomainDiff = 0;
1747 }
1748 tmp16no2 = WEBRTC_SPL_SHIFT_W16(ptrDfaClean[i], qDomainDiff);
1749 tmp32no1 = (WebRtc_Word32)(tmp16no2 - tmp16no1);
1750 tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 4);
1751 tmp16no2 += tmp16no1;
1752 zeros16 = WebRtcSpl_NormW16(tmp16no2);
1753 if ((tmp16no2) & (-qDomainDiff > zeros16))
1754 {
1755 aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX;
1756 } else
1757 {
1758 aecm->nearFilt[i] = WEBRTC_SPL_SHIFT_W16(tmp16no2, -qDomainDiff);
1759 }
1760
1761 // Wiener filter coefficients, resulting hnl in Q14
1762 if (echoEst32Gained == 0)
1763 {
1764 hnl[i] = ONE_Q14;
1765 } else if (aecm->nearFilt[i] == 0)
1766 {
1767 hnl[i] = 0;
1768 } else
1769 {
1770 // Multiply the suppression gain
1771 // Rounding
1772 echoEst32Gained += (WebRtc_UWord32)(aecm->nearFilt[i] >> 1);
1773 tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained, (WebRtc_UWord16)aecm->nearFilt[i]);
1774
1775 // Current resolution is
1776 // Q-(RESOLUTION_CHANNEL + RESOLUTION_SUPGAIN - max(0, 17 - zeros16 - zeros32))
1777 // Make sure we are in Q14
1778 tmp32no1 = (WebRtc_Word32)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff);
1779 if (tmp32no1 > ONE_Q14)
1780 {
1781 hnl[i] = 0;
1782 } else if (tmp32no1 < 0)
1783 {
1784 hnl[i] = ONE_Q14;
1785 } else
1786 {
1787 // 1-echoEst/dfa
1788 hnl[i] = ONE_Q14 - (WebRtc_Word16)tmp32no1;
1789 if (hnl[i] < 0)
1790 {
1791 hnl[i] = 0;
1792 }
1793 }
1794 }
1795 if (hnl[i])
1796 {
1797 numPosCoef++;
1798 }
1799 }
1800 // Only in wideband. Prevent the gain in upper band from being larger than
1801 // in lower band.
1802 if (aecm->mult == 2)
1803 {
1804 // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause
1805 // speech distortion in double-talk.
1806 for (i = 0; i < PART_LEN1; i++)
1807 {
1808 hnl[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(hnl[i], hnl[i], 14);
1809 }
1810
1811 for (i = kMinPrefBand; i <= kMaxPrefBand; i++)
1812 {
1813 avgHnl32 += (WebRtc_Word32)hnl[i];
1814 }
1815 assert(kMaxPrefBand - kMinPrefBand + 1 > 0);
1816 avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1);
1817
1818 for (i = kMaxPrefBand; i < PART_LEN1; i++)
1819 {
1820 if (hnl[i] > (WebRtc_Word16)avgHnl32)
1821 {
1822 hnl[i] = (WebRtc_Word16)avgHnl32;
1823 }
1824 }
1825 }
1826
1827 #ifdef ARM_WINM_LOG_
1828 // measure tick end
1829 QueryPerformanceCounter((LARGE_INTEGER*)&end);
1830 diff__ = ((end - start) * 1000) / (freq/1000);
1831 milliseconds = (unsigned int)(diff__ & 0xffffffff);
1832 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
1833 // measure tick start
1834 QueryPerformanceCounter((LARGE_INTEGER*)&start);
1835 #endif
1836
1837 // Calculate NLP gain, result is in Q14
1838 if (aecm->nlpFlag)
1839 {
1840 for (i = 0; i < PART_LEN1; i++)
1841 {
1842 // Truncate values close to zero and one.
1843 if (hnl[i] > NLP_COMP_HIGH)
1844 {
1845 hnl[i] = ONE_Q14;
1846 } else if (hnl[i] < NLP_COMP_LOW)
1847 {
1848 hnl[i] = 0;
1849 }
1850
1851 // Remove outliers
1852 if (numPosCoef < 3)
1853 {
1854 nlpGain = 0;
1855 } else
1856 {
1857 nlpGain = ONE_Q14;
1858 }
1859
1860 // NLP
1861 if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14))
1862 {
1863 hnl[i] = ONE_Q14;
1864 } else
1865 {
1866 hnl[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(hnl[i], nlpGain, 14);
1867 }
1868
1869 // multiply with Wiener coefficients
1870 efw[i].real = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
1871 hnl[i], 14));
1872 efw[i].imag = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
1873 hnl[i], 14));
1874 }
1875 }
1876 else
1877 {
1878 // multiply with Wiener coefficients
1879 for (i = 0; i < PART_LEN1; i++)
1880 {
1881 efw[i].real = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
1882 hnl[i], 14));
1883 efw[i].imag = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
1884 hnl[i], 14));
1885 }
1886 }
1887
1888 if (aecm->cngMode == AecmTrue)
1889 {
1890 ComfortNoise(aecm, ptrDfaClean, efw, hnl);
1891 }
1892
1893 #ifdef ARM_WINM_LOG_
1894 // measure tick end
1895 QueryPerformanceCounter((LARGE_INTEGER*)&end);
1896 diff__ = ((end - start) * 1000) / (freq/1000);
1897 milliseconds = (unsigned int)(diff__ & 0xffffffff);
1898 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
1899 // measure tick start
1900 QueryPerformanceCounter((LARGE_INTEGER*)&start);
1901 #endif
1902
1903 WebRtcAecm_InverseFFTAndWindow(aecm, fft, efw, output, nearendClean);
1904
1905 return 0;
1906 }
1907
1908
1909 // Generate comfort noise and add to output signal.
1910 //
1911 // \param[in] aecm Handle of the AECM instance.
1912 // \param[in] dfa Absolute value of the nearend signal (Q[aecm->dfaQDomain]).
1913 // \param[in,out] outReal Real part of the output signal (Q[aecm->dfaQDomain]).
1914 // \param[in,out] outImag Imaginary part of the output signal (Q[aecm->dfaQDomain]).
1915 // \param[in] lambda Suppression gain with which to scale the noise level (Q14).
1916 //
ComfortNoise(AecmCore_t * aecm,const WebRtc_UWord16 * dfa,complex16_t * out,const WebRtc_Word16 * lambda)1917 static void ComfortNoise(AecmCore_t* aecm,
1918 const WebRtc_UWord16* dfa,
1919 complex16_t* out,
1920 const WebRtc_Word16* lambda)
1921 {
1922 WebRtc_Word16 i;
1923 WebRtc_Word16 tmp16;
1924 WebRtc_Word32 tmp32;
1925
1926 WebRtc_Word16 randW16[PART_LEN];
1927 WebRtc_Word16 uReal[PART_LEN1];
1928 WebRtc_Word16 uImag[PART_LEN1];
1929 WebRtc_Word32 outLShift32;
1930 WebRtc_Word16 noiseRShift16[PART_LEN1];
1931
1932 WebRtc_Word16 shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain;
1933 WebRtc_Word16 minTrackShift;
1934
1935 assert(shiftFromNearToNoise >= 0);
1936 assert(shiftFromNearToNoise < 16);
1937
1938 if (aecm->noiseEstCtr < 100)
1939 {
1940 // Track the minimum more quickly initially.
1941 aecm->noiseEstCtr++;
1942 minTrackShift = 6;
1943 } else
1944 {
1945 minTrackShift = 9;
1946 }
1947
1948 // Estimate noise power.
1949 for (i = 0; i < PART_LEN1; i++)
1950 {
1951
1952 // Shift to the noise domain.
1953 tmp32 = (WebRtc_Word32)dfa[i];
1954 outLShift32 = WEBRTC_SPL_LSHIFT_W32(tmp32, shiftFromNearToNoise);
1955
1956 if (outLShift32 < aecm->noiseEst[i])
1957 {
1958 // Reset "too low" counter
1959 aecm->noiseEstTooLowCtr[i] = 0;
1960 // Track the minimum.
1961 if (aecm->noiseEst[i] < (1 << minTrackShift))
1962 {
1963 // For small values, decrease noiseEst[i] every
1964 // |kNoiseEstIncCount| block. The regular approach below can not
1965 // go further down due to truncation.
1966 aecm->noiseEstTooHighCtr[i]++;
1967 if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount)
1968 {
1969 aecm->noiseEst[i]--;
1970 aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter
1971 }
1972 }
1973 else
1974 {
1975 aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32) >> minTrackShift);
1976 }
1977 } else
1978 {
1979 // Reset "too high" counter
1980 aecm->noiseEstTooHighCtr[i] = 0;
1981 // Ramp slowly upwards until we hit the minimum again.
1982 if ((aecm->noiseEst[i] >> 19) > 0)
1983 {
1984 // Avoid overflow.
1985 // Multiplication with 2049 will cause wrap around. Scale
1986 // down first and then multiply
1987 aecm->noiseEst[i] >>= 11;
1988 aecm->noiseEst[i] *= 2049;
1989 }
1990 else if ((aecm->noiseEst[i] >> 11) > 0)
1991 {
1992 // Large enough for relative increase
1993 aecm->noiseEst[i] *= 2049;
1994 aecm->noiseEst[i] >>= 11;
1995 }
1996 else
1997 {
1998 // Make incremental increases based on size every
1999 // |kNoiseEstIncCount| block
2000 aecm->noiseEstTooLowCtr[i]++;
2001 if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount)
2002 {
2003 aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1;
2004 aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
2005 }
2006 }
2007 }
2008 }
2009
2010 for (i = 0; i < PART_LEN1; i++)
2011 {
2012 tmp32 = WEBRTC_SPL_RSHIFT_W32(aecm->noiseEst[i], shiftFromNearToNoise);
2013 if (tmp32 > 32767)
2014 {
2015 tmp32 = 32767;
2016 aecm->noiseEst[i] = WEBRTC_SPL_LSHIFT_W32(tmp32, shiftFromNearToNoise);
2017 }
2018 noiseRShift16[i] = (WebRtc_Word16)tmp32;
2019
2020 tmp16 = ONE_Q14 - lambda[i];
2021 noiseRShift16[i]
2022 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, noiseRShift16[i], 14);
2023 }
2024
2025 // Generate a uniform random array on [0 2^15-1].
2026 WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
2027
2028 // Generate noise according to estimated energy.
2029 uReal[0] = 0; // Reject LF noise.
2030 uImag[0] = 0;
2031 for (i = 1; i < PART_LEN1; i++)
2032 {
2033 // Get a random index for the cos and sin tables over [0 359].
2034 tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(359, randW16[i - 1], 15);
2035
2036 // Tables are in Q13.
2037 uReal[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(noiseRShift16[i],
2038 kCosTable[tmp16], 13);
2039 uImag[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(-noiseRShift16[i],
2040 kSinTable[tmp16], 13);
2041 }
2042 uImag[PART_LEN] = 0;
2043
2044 #if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
2045 for (i = 0; i < PART_LEN1; i++)
2046 {
2047 out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]);
2048 out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]);
2049 }
2050 #else
2051 for (i = 0; i < PART_LEN1 -1; )
2052 {
2053 out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]);
2054 out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]);
2055 i++;
2056
2057 out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]);
2058 out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]);
2059 i++;
2060 }
2061 out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]);
2062 out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]);
2063 #endif
2064 }
2065
WebRtcAecm_BufferFarFrame(AecmCore_t * const aecm,const WebRtc_Word16 * const farend,const int farLen)2066 void WebRtcAecm_BufferFarFrame(AecmCore_t* const aecm,
2067 const WebRtc_Word16* const farend,
2068 const int farLen)
2069 {
2070 int writeLen = farLen, writePos = 0;
2071
2072 // Check if the write position must be wrapped
2073 while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN)
2074 {
2075 // Write to remaining buffer space before wrapping
2076 writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
2077 memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
2078 sizeof(WebRtc_Word16) * writeLen);
2079 aecm->farBufWritePos = 0;
2080 writePos = writeLen;
2081 writeLen = farLen - writeLen;
2082 }
2083
2084 memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
2085 sizeof(WebRtc_Word16) * writeLen);
2086 aecm->farBufWritePos += writeLen;
2087 }
2088
WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm,WebRtc_Word16 * const farend,const int farLen,const int knownDelay)2089 void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, WebRtc_Word16 * const farend,
2090 const int farLen, const int knownDelay)
2091 {
2092 int readLen = farLen;
2093 int readPos = 0;
2094 int delayChange = knownDelay - aecm->lastKnownDelay;
2095
2096 aecm->farBufReadPos -= delayChange;
2097
2098 // Check if delay forces a read position wrap
2099 while (aecm->farBufReadPos < 0)
2100 {
2101 aecm->farBufReadPos += FAR_BUF_LEN;
2102 }
2103 while (aecm->farBufReadPos > FAR_BUF_LEN - 1)
2104 {
2105 aecm->farBufReadPos -= FAR_BUF_LEN;
2106 }
2107
2108 aecm->lastKnownDelay = knownDelay;
2109
2110 // Check if read position must be wrapped
2111 while (aecm->farBufReadPos + readLen > FAR_BUF_LEN)
2112 {
2113
2114 // Read from remaining buffer space before wrapping
2115 readLen = FAR_BUF_LEN - aecm->farBufReadPos;
2116 memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
2117 sizeof(WebRtc_Word16) * readLen);
2118 aecm->farBufReadPos = 0;
2119 readPos = readLen;
2120 readLen = farLen - readLen;
2121 }
2122 memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
2123 sizeof(WebRtc_Word16) * readLen);
2124 aecm->farBufReadPos += readLen;
2125 }
2126
2127