Line data Source code
1 : /*
2 : * Copyright (c) 2012 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 "webrtc/modules/audio_processing/aecm/aecm_core.h"
12 :
13 : #include <stddef.h>
14 : #include <stdlib.h>
15 :
16 : extern "C" {
17 : #include "webrtc/common_audio/ring_buffer.h"
18 : #include "webrtc/common_audio/signal_processing/include/real_fft.h"
19 : }
20 : #include "webrtc/modules/audio_processing/aecm/echo_control_mobile.h"
21 : #include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
22 : extern "C" {
23 : #include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
24 : }
25 :
26 : #include "webrtc/base/checks.h"
27 : #include "webrtc/typedefs.h"
28 :
29 : #ifdef AEC_DEBUG
30 : FILE *dfile;
31 : FILE *testfile;
32 : #endif
33 :
34 : const int16_t WebRtcAecm_kCosTable[] = {
35 : 8192, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112,
36 : 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834,
37 : 7791, 7745, 7697, 7647, 7595, 7540, 7483, 7424, 7362,
38 : 7299, 7233, 7164, 7094, 7021, 6947, 6870, 6791, 6710,
39 : 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991, 5892,
40 : 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930,
41 : 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845,
42 : 3719, 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667,
43 : 2531, 2395, 2258, 2120, 1981, 1842, 1703, 1563, 1422,
44 : 1281, 1140, 998, 856, 713, 571, 428, 285, 142,
45 : 0, -142, -285, -428, -571, -713, -856, -998, -1140,
46 : -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395,
47 : -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591,
48 : -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698,
49 : -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690,
50 : -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542,
51 : -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233,
52 : -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745,
53 : -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067,
54 : -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190,
55 : -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112,
56 : -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
57 : -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362,
58 : -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710,
59 : -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892,
60 : -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930,
61 : -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845,
62 : -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667,
63 : -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422,
64 : -1281, -1140, -998, -856, -713, -571, -428, -285, -142,
65 : 0, 142, 285, 428, 571, 713, 856, 998, 1140,
66 : 1281, 1422, 1563, 1703, 1842, 1981, 2120, 2258, 2395,
67 : 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591,
68 : 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698,
69 : 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586, 5690,
70 : 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542,
71 : 6627, 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233,
72 : 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745,
73 : 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067,
74 : 8091, 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190
75 : };
76 :
77 : const int16_t WebRtcAecm_kSinTable[] = {
78 : 0, 142, 285, 428, 571, 713, 856, 998,
79 : 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120,
80 : 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200,
81 : 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219,
82 : 4341, 4461, 4580, 4698, 4815, 4930, 5043, 5155,
83 : 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991,
84 : 6087, 6182, 6275, 6366, 6455, 6542, 6627, 6710,
85 : 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299,
86 : 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745,
87 : 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041,
88 : 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180,
89 : 8187, 8190, 8191, 8190, 8187, 8180, 8172, 8160,
90 : 8147, 8130, 8112, 8091, 8067, 8041, 8012, 7982,
91 : 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647,
92 : 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164,
93 : 7094, 7021, 6947, 6870, 6791, 6710, 6627, 6542,
94 : 6455, 6366, 6275, 6182, 6087, 5991, 5892, 5792,
95 : 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930,
96 : 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971,
97 : 3845, 3719, 3591, 3462, 3331, 3200, 3068, 2935,
98 : 2801, 2667, 2531, 2395, 2258, 2120, 1981, 1842,
99 : 1703, 1563, 1422, 1281, 1140, 998, 856, 713,
100 : 571, 428, 285, 142, 0, -142, -285, -428,
101 : -571, -713, -856, -998, -1140, -1281, -1422, -1563,
102 : -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667,
103 : -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719,
104 : -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698,
105 : -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586,
106 : -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366,
107 : -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021,
108 : -7094, -7164, -7233, -7299, -7362, -7424, -7483, -7540,
109 : -7595, -7647, -7697, -7745, -7791, -7834, -7874, -7912,
110 : -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130,
111 : -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190,
112 : -8187, -8180, -8172, -8160, -8147, -8130, -8112, -8091,
113 : -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
114 : -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424,
115 : -7362, -7299, -7233, -7164, -7094, -7021, -6947, -6870,
116 : -6791, -6710, -6627, -6542, -6455, -6366, -6275, -6182,
117 : -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374,
118 : -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461,
119 : -4341, -4219, -4096, -3971, -3845, -3719, -3591, -3462,
120 : -3331, -3200, -3068, -2935, -2801, -2667, -2531, -2395,
121 : -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281,
122 : -1140, -998, -856, -713, -571, -428, -285, -142
123 : };
124 :
125 : // Initialization table for echo channel in 8 kHz
126 : static const int16_t kChannelStored8kHz[PART_LEN1] = {
127 : 2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418,
128 : 1451, 1506, 1562, 1644, 1726, 1804, 1882, 1918,
129 : 1953, 1982, 2010, 2025, 2040, 2034, 2027, 2021,
130 : 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683,
131 : 1635, 1604, 1572, 1545, 1517, 1481, 1444, 1405,
132 : 1367, 1331, 1294, 1270, 1245, 1239, 1233, 1247,
133 : 1260, 1282, 1303, 1338, 1373, 1407, 1441, 1470,
134 : 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649,
135 : 1676
136 : };
137 :
138 : // Initialization table for echo channel in 16 kHz
139 : static const int16_t kChannelStored16kHz[PART_LEN1] = {
140 : 2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882,
141 : 1953, 2010, 2040, 2027, 2014, 1980, 1869, 1732,
142 : 1635, 1572, 1517, 1444, 1367, 1294, 1245, 1233,
143 : 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621,
144 : 1676, 1741, 1802, 1861, 1921, 1983, 2040, 2102,
145 : 2170, 2265, 2375, 2515, 2651, 2781, 2922, 3075,
146 : 3253, 3471, 3738, 3976, 4151, 4258, 4308, 4288,
147 : 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484,
148 : 3153
149 : };
150 :
151 : // Moves the pointer to the next entry and inserts |far_spectrum| and
152 : // corresponding Q-domain in its buffer.
153 : //
154 : // Inputs:
155 : // - self : Pointer to the delay estimation instance
156 : // - far_spectrum : Pointer to the far end spectrum
157 : // - far_q : Q-domain of far end spectrum
158 : //
159 0 : void WebRtcAecm_UpdateFarHistory(AecmCore* self,
160 : uint16_t* far_spectrum,
161 : int far_q) {
162 : // Get new buffer position
163 0 : self->far_history_pos++;
164 0 : if (self->far_history_pos >= MAX_DELAY) {
165 0 : self->far_history_pos = 0;
166 : }
167 : // Update Q-domain buffer
168 0 : self->far_q_domains[self->far_history_pos] = far_q;
169 : // Update far end spectrum buffer
170 0 : memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]),
171 : far_spectrum,
172 0 : sizeof(uint16_t) * PART_LEN1);
173 0 : }
174 :
175 : // Returns a pointer to the far end spectrum aligned to current near end
176 : // spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been
177 : // called before AlignedFarend(...). Otherwise, you get the pointer to the
178 : // previous frame. The memory is only valid until the next call of
179 : // WebRtc_DelayEstimatorProcessFix(...).
180 : //
181 : // Inputs:
182 : // - self : Pointer to the AECM instance.
183 : // - delay : Current delay estimate.
184 : //
185 : // Output:
186 : // - far_q : The Q-domain of the aligned far end spectrum
187 : //
188 : // Return value:
189 : // - far_spectrum : Pointer to the aligned far end spectrum
190 : // NULL - Error
191 : //
192 0 : const uint16_t* WebRtcAecm_AlignedFarend(AecmCore* self,
193 : int* far_q,
194 : int delay) {
195 0 : int buffer_position = 0;
196 0 : RTC_DCHECK(self);
197 0 : buffer_position = self->far_history_pos - delay;
198 :
199 : // Check buffer position
200 0 : if (buffer_position < 0) {
201 0 : buffer_position += MAX_DELAY;
202 : }
203 : // Get Q-domain
204 0 : *far_q = self->far_q_domains[buffer_position];
205 : // Return far end spectrum
206 0 : return &(self->far_history[buffer_position * PART_LEN1]);
207 : }
208 :
209 : // Declare function pointers.
210 : CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
211 : StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
212 : ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
213 :
214 0 : AecmCore* WebRtcAecm_CreateCore() {
215 0 : AecmCore* aecm = static_cast<AecmCore*>(malloc(sizeof(AecmCore)));
216 :
217 0 : aecm->farFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
218 : sizeof(int16_t));
219 0 : if (!aecm->farFrameBuf)
220 : {
221 0 : WebRtcAecm_FreeCore(aecm);
222 0 : return NULL;
223 : }
224 :
225 0 : aecm->nearNoisyFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
226 : sizeof(int16_t));
227 0 : if (!aecm->nearNoisyFrameBuf)
228 : {
229 0 : WebRtcAecm_FreeCore(aecm);
230 0 : return NULL;
231 : }
232 :
233 0 : aecm->nearCleanFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
234 : sizeof(int16_t));
235 0 : if (!aecm->nearCleanFrameBuf)
236 : {
237 0 : WebRtcAecm_FreeCore(aecm);
238 0 : return NULL;
239 : }
240 :
241 0 : aecm->outFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
242 : sizeof(int16_t));
243 0 : if (!aecm->outFrameBuf)
244 : {
245 0 : WebRtcAecm_FreeCore(aecm);
246 0 : return NULL;
247 : }
248 :
249 0 : aecm->delay_estimator_farend = WebRtc_CreateDelayEstimatorFarend(PART_LEN1,
250 : MAX_DELAY);
251 0 : if (aecm->delay_estimator_farend == NULL) {
252 0 : WebRtcAecm_FreeCore(aecm);
253 0 : return NULL;
254 : }
255 0 : aecm->delay_estimator =
256 0 : WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0);
257 0 : if (aecm->delay_estimator == NULL) {
258 0 : WebRtcAecm_FreeCore(aecm);
259 0 : return NULL;
260 : }
261 : // TODO(bjornv): Explicitly disable robust delay validation until no
262 : // performance regression has been established. Then remove the line.
263 0 : WebRtc_enable_robust_validation(aecm->delay_estimator, 0);
264 :
265 0 : aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT);
266 0 : if (aecm->real_fft == NULL) {
267 0 : WebRtcAecm_FreeCore(aecm);
268 0 : return NULL;
269 : }
270 :
271 : // Init some aecm pointers. 16 and 32 byte alignment is only necessary
272 : // for Neon code currently.
273 0 : aecm->xBuf = (int16_t*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31);
274 0 : aecm->dBufClean = (int16_t*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31);
275 0 : aecm->dBufNoisy = (int16_t*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31);
276 0 : aecm->outBuf = (int16_t*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15);
277 0 : aecm->channelStored = (int16_t*) (((uintptr_t)
278 0 : aecm->channelStored_buf + 15) & ~ 15);
279 0 : aecm->channelAdapt16 = (int16_t*) (((uintptr_t)
280 0 : aecm->channelAdapt16_buf + 15) & ~ 15);
281 0 : aecm->channelAdapt32 = (int32_t*) (((uintptr_t)
282 0 : aecm->channelAdapt32_buf + 31) & ~ 31);
283 :
284 0 : return aecm;
285 : }
286 :
287 0 : void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path) {
288 0 : int i = 0;
289 :
290 : // Reset the stored channel
291 0 : memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1);
292 : // Reset the adapted channels
293 0 : memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1);
294 0 : for (i = 0; i < PART_LEN1; i++)
295 : {
296 0 : aecm->channelAdapt32[i] = (int32_t)aecm->channelAdapt16[i] << 16;
297 : }
298 :
299 : // Reset channel storing variables
300 0 : aecm->mseAdaptOld = 1000;
301 0 : aecm->mseStoredOld = 1000;
302 0 : aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
303 0 : aecm->mseChannelCount = 0;
304 0 : }
305 :
306 0 : static void CalcLinearEnergiesC(AecmCore* aecm,
307 : const uint16_t* far_spectrum,
308 : int32_t* echo_est,
309 : uint32_t* far_energy,
310 : uint32_t* echo_energy_adapt,
311 : uint32_t* echo_energy_stored) {
312 : int i;
313 :
314 : // Get energy for the delayed far end signal and estimated
315 : // echo using both stored and adapted channels.
316 0 : for (i = 0; i < PART_LEN1; i++)
317 : {
318 0 : echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
319 : far_spectrum[i]);
320 0 : (*far_energy) += (uint32_t)(far_spectrum[i]);
321 0 : *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i];
322 0 : (*echo_energy_stored) += (uint32_t)echo_est[i];
323 : }
324 0 : }
325 :
326 0 : static void StoreAdaptiveChannelC(AecmCore* aecm,
327 : const uint16_t* far_spectrum,
328 : int32_t* echo_est) {
329 : int i;
330 :
331 : // During startup we store the channel every block.
332 0 : memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(int16_t) * PART_LEN1);
333 : // Recalculate echo estimate
334 0 : for (i = 0; i < PART_LEN; i += 4)
335 : {
336 0 : echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
337 : far_spectrum[i]);
338 0 : echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1],
339 : far_spectrum[i + 1]);
340 0 : echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2],
341 : far_spectrum[i + 2]);
342 0 : echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3],
343 : far_spectrum[i + 3]);
344 : }
345 0 : echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
346 : far_spectrum[i]);
347 0 : }
348 :
349 0 : static void ResetAdaptiveChannelC(AecmCore* aecm) {
350 : int i;
351 :
352 : // The stored channel has a significantly lower MSE than the adaptive one for
353 : // two consecutive calculations. Reset the adaptive channel.
354 0 : memcpy(aecm->channelAdapt16, aecm->channelStored,
355 0 : sizeof(int16_t) * PART_LEN1);
356 : // Restore the W32 channel
357 0 : for (i = 0; i < PART_LEN; i += 4)
358 : {
359 0 : aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
360 0 : aecm->channelAdapt32[i + 1] = (int32_t)aecm->channelStored[i + 1] << 16;
361 0 : aecm->channelAdapt32[i + 2] = (int32_t)aecm->channelStored[i + 2] << 16;
362 0 : aecm->channelAdapt32[i + 3] = (int32_t)aecm->channelStored[i + 3] << 16;
363 : }
364 0 : aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
365 0 : }
366 :
367 : // Initialize function pointers for ARM Neon platform.
368 : #if defined(WEBRTC_HAS_NEON)
369 : static void WebRtcAecm_InitNeon(void)
370 : {
371 : WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannelNeon;
372 : WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannelNeon;
373 : WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergiesNeon;
374 : }
375 : #endif
376 :
377 : // Initialize function pointers for MIPS platform.
378 : #if defined(MIPS32_LE)
379 : static void WebRtcAecm_InitMips(void)
380 : {
381 : #if defined(MIPS_DSP_R1_LE)
382 : WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannel_mips;
383 : WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannel_mips;
384 : #endif
385 : WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergies_mips;
386 : }
387 : #endif
388 :
389 : // WebRtcAecm_InitCore(...)
390 : //
391 : // This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
392 : // Input:
393 : // - aecm : Pointer to the Echo Suppression instance
394 : // - samplingFreq : Sampling Frequency
395 : //
396 : // Output:
397 : // - aecm : Initialized instance
398 : //
399 : // Return value : 0 - Ok
400 : // -1 - Error
401 : //
402 0 : int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq) {
403 0 : int i = 0;
404 0 : int32_t tmp32 = PART_LEN1 * PART_LEN1;
405 0 : int16_t tmp16 = PART_LEN1;
406 :
407 0 : if (samplingFreq != 8000 && samplingFreq != 16000)
408 : {
409 0 : samplingFreq = 8000;
410 0 : return -1;
411 : }
412 : // sanity check of sampling frequency
413 0 : aecm->mult = (int16_t)samplingFreq / 8000;
414 :
415 0 : aecm->farBufWritePos = 0;
416 0 : aecm->farBufReadPos = 0;
417 0 : aecm->knownDelay = 0;
418 0 : aecm->lastKnownDelay = 0;
419 :
420 0 : WebRtc_InitBuffer(aecm->farFrameBuf);
421 0 : WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
422 0 : WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
423 0 : WebRtc_InitBuffer(aecm->outFrameBuf);
424 :
425 0 : memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
426 0 : memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
427 0 : memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
428 0 : memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
429 :
430 0 : aecm->seed = 666;
431 0 : aecm->totCount = 0;
432 :
433 0 : if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) {
434 0 : return -1;
435 : }
436 0 : if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
437 0 : return -1;
438 : }
439 : // Set far end histories to zero
440 0 : memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
441 0 : memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
442 0 : aecm->far_history_pos = MAX_DELAY;
443 :
444 0 : aecm->nlpFlag = 1;
445 0 : aecm->fixedDelay = -1;
446 :
447 0 : aecm->dfaCleanQDomain = 0;
448 0 : aecm->dfaCleanQDomainOld = 0;
449 0 : aecm->dfaNoisyQDomain = 0;
450 0 : aecm->dfaNoisyQDomainOld = 0;
451 :
452 0 : memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
453 0 : aecm->farLogEnergy = 0;
454 0 : memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
455 0 : memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
456 :
457 : // Initialize the echo channels with a stored shape.
458 0 : if (samplingFreq == 8000)
459 : {
460 0 : WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
461 : }
462 : else
463 : {
464 0 : WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
465 : }
466 :
467 0 : memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
468 0 : memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
469 0 : aecm->noiseEstCtr = 0;
470 :
471 0 : aecm->cngMode = AecmTrue;
472 :
473 0 : memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
474 0 : memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
475 : // Shape the initial noise level to an approximate pink noise.
476 0 : for (i = 0; i < (PART_LEN1 >> 1) - 1; i++)
477 : {
478 0 : aecm->noiseEst[i] = (tmp32 << 8);
479 0 : tmp16--;
480 0 : tmp32 -= (int32_t)((tmp16 << 1) + 1);
481 : }
482 0 : for (; i < PART_LEN1; i++)
483 : {
484 0 : aecm->noiseEst[i] = (tmp32 << 8);
485 : }
486 :
487 0 : aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
488 0 : aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
489 0 : aecm->farEnergyMaxMin = 0;
490 0 : aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the
491 : // beginning.
492 0 : aecm->farEnergyMSE = 0;
493 0 : aecm->currentVADValue = 0;
494 0 : aecm->vadUpdateCount = 0;
495 0 : aecm->firstVAD = 1;
496 :
497 0 : aecm->startupState = 0;
498 0 : aecm->supGain = SUPGAIN_DEFAULT;
499 0 : aecm->supGainOld = SUPGAIN_DEFAULT;
500 :
501 0 : aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
502 0 : aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
503 0 : aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
504 0 : aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
505 :
506 : // Assert a preprocessor definition at compile-time. It's an assumption
507 : // used in assembly code, so check the assembly files before any change.
508 : static_assert(PART_LEN % 16 == 0, "PART_LEN is not a multiple of 16");
509 :
510 : // Initialize function pointers.
511 0 : WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
512 0 : WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
513 0 : WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
514 :
515 : #if defined(WEBRTC_HAS_NEON)
516 : WebRtcAecm_InitNeon();
517 : #endif
518 :
519 : #if defined(MIPS32_LE)
520 : WebRtcAecm_InitMips();
521 : #endif
522 0 : return 0;
523 : }
524 :
525 : // TODO(bjornv): This function is currently not used. Add support for these
526 : // parameters from a higher level
527 0 : int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag) {
528 0 : aecm->nlpFlag = nlpFlag;
529 0 : aecm->fixedDelay = delay;
530 :
531 0 : return 0;
532 : }
533 :
534 0 : void WebRtcAecm_FreeCore(AecmCore* aecm) {
535 0 : if (aecm == NULL) {
536 0 : return;
537 : }
538 :
539 0 : WebRtc_FreeBuffer(aecm->farFrameBuf);
540 0 : WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
541 0 : WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
542 0 : WebRtc_FreeBuffer(aecm->outFrameBuf);
543 :
544 0 : WebRtc_FreeDelayEstimator(aecm->delay_estimator);
545 0 : WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend);
546 0 : WebRtcSpl_FreeRealFFT(aecm->real_fft);
547 :
548 0 : free(aecm);
549 : }
550 :
551 0 : int WebRtcAecm_ProcessFrame(AecmCore* aecm,
552 : const int16_t* farend,
553 : const int16_t* nearendNoisy,
554 : const int16_t* nearendClean,
555 : int16_t* out) {
556 : int16_t outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary.
557 0 : int16_t* outBlock = (int16_t*) (((uintptr_t) outBlock_buf + 15) & ~ 15);
558 :
559 : int16_t farFrame[FRAME_LEN];
560 0 : const int16_t* out_ptr = NULL;
561 0 : int size = 0;
562 :
563 : // Buffer the current frame.
564 : // Fetch an older one corresponding to the delay.
565 0 : WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
566 0 : WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
567 :
568 : // Buffer the synchronized far and near frames,
569 : // to pass the smaller blocks individually.
570 0 : WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
571 0 : WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
572 0 : if (nearendClean != NULL)
573 : {
574 0 : WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
575 : }
576 :
577 : // Process as many blocks as possible.
578 0 : while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN)
579 : {
580 : int16_t far_block[PART_LEN];
581 0 : const int16_t* far_block_ptr = NULL;
582 : int16_t near_noisy_block[PART_LEN];
583 0 : const int16_t* near_noisy_block_ptr = NULL;
584 :
585 0 : WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block,
586 0 : PART_LEN);
587 0 : WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf,
588 : (void**) &near_noisy_block_ptr,
589 : near_noisy_block,
590 0 : PART_LEN);
591 0 : if (nearendClean != NULL)
592 : {
593 : int16_t near_clean_block[PART_LEN];
594 0 : const int16_t* near_clean_block_ptr = NULL;
595 :
596 0 : WebRtc_ReadBuffer(aecm->nearCleanFrameBuf,
597 : (void**) &near_clean_block_ptr,
598 : near_clean_block,
599 0 : PART_LEN);
600 0 : if (WebRtcAecm_ProcessBlock(aecm,
601 : far_block_ptr,
602 : near_noisy_block_ptr,
603 : near_clean_block_ptr,
604 : outBlock) == -1)
605 : {
606 0 : return -1;
607 : }
608 : } else
609 : {
610 0 : if (WebRtcAecm_ProcessBlock(aecm,
611 : far_block_ptr,
612 : near_noisy_block_ptr,
613 : NULL,
614 : outBlock) == -1)
615 : {
616 0 : return -1;
617 : }
618 : }
619 :
620 0 : WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
621 : }
622 :
623 : // Stuff the out buffer if we have less than a frame to output.
624 : // This should only happen for the first frame.
625 0 : size = (int) WebRtc_available_read(aecm->outFrameBuf);
626 0 : if (size < FRAME_LEN)
627 : {
628 0 : WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
629 : }
630 :
631 : // Obtain an output frame.
632 0 : WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN);
633 0 : if (out_ptr != out) {
634 : // ReadBuffer() hasn't copied to |out| in this case.
635 0 : memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
636 : }
637 :
638 0 : return 0;
639 : }
640 :
641 : // WebRtcAecm_AsymFilt(...)
642 : //
643 : // Performs asymmetric filtering.
644 : //
645 : // Inputs:
646 : // - filtOld : Previous filtered value.
647 : // - inVal : New input value.
648 : // - stepSizePos : Step size when we have a positive contribution.
649 : // - stepSizeNeg : Step size when we have a negative contribution.
650 : //
651 : // Output:
652 : //
653 : // Return: - Filtered value.
654 : //
655 0 : int16_t WebRtcAecm_AsymFilt(const int16_t filtOld, const int16_t inVal,
656 : const int16_t stepSizePos,
657 : const int16_t stepSizeNeg)
658 : {
659 : int16_t retVal;
660 :
661 0 : if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN))
662 : {
663 0 : return inVal;
664 : }
665 0 : retVal = filtOld;
666 0 : if (filtOld > inVal)
667 : {
668 0 : retVal -= (filtOld - inVal) >> stepSizeNeg;
669 : } else
670 : {
671 0 : retVal += (inVal - filtOld) >> stepSizePos;
672 : }
673 :
674 0 : return retVal;
675 : }
676 :
677 : // ExtractFractionPart(a, zeros)
678 : //
679 : // returns the fraction part of |a|, with |zeros| number of leading zeros, as an
680 : // int16_t scaled to Q8. There is no sanity check of |a| in the sense that the
681 : // number of zeros match.
682 0 : static int16_t ExtractFractionPart(uint32_t a, int zeros) {
683 0 : return (int16_t)(((a << zeros) & 0x7FFFFFFF) >> 23);
684 : }
685 :
686 : // Calculates and returns the log of |energy| in Q8. The input |energy| is
687 : // supposed to be in Q(|q_domain|).
688 0 : static int16_t LogOfEnergyInQ8(uint32_t energy, int q_domain) {
689 : static const int16_t kLogLowValue = PART_LEN_SHIFT << 7;
690 0 : int16_t log_energy_q8 = kLogLowValue;
691 0 : if (energy > 0) {
692 0 : int zeros = WebRtcSpl_NormU32(energy);
693 0 : int16_t frac = ExtractFractionPart(energy, zeros);
694 : // log2 of |energy| in Q8.
695 0 : log_energy_q8 += ((31 - zeros) << 8) + frac - (q_domain << 8);
696 : }
697 0 : return log_energy_q8;
698 : }
699 :
700 : // WebRtcAecm_CalcEnergies(...)
701 : //
702 : // This function calculates the log of energies for nearend, farend and estimated
703 : // echoes. There is also an update of energy decision levels, i.e. internal VAD.
704 : //
705 : //
706 : // @param aecm [i/o] Handle of the AECM instance.
707 : // @param far_spectrum [in] Pointer to farend spectrum.
708 : // @param far_q [in] Q-domain of farend spectrum.
709 : // @param nearEner [in] Near end energy for current block in
710 : // Q(aecm->dfaQDomain).
711 : // @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
712 : //
713 0 : void WebRtcAecm_CalcEnergies(AecmCore* aecm,
714 : const uint16_t* far_spectrum,
715 : const int16_t far_q,
716 : const uint32_t nearEner,
717 : int32_t* echoEst) {
718 : // Local variables
719 0 : uint32_t tmpAdapt = 0;
720 0 : uint32_t tmpStored = 0;
721 0 : uint32_t tmpFar = 0;
722 :
723 : int i;
724 :
725 : int16_t tmp16;
726 0 : int16_t increase_max_shifts = 4;
727 0 : int16_t decrease_max_shifts = 11;
728 0 : int16_t increase_min_shifts = 11;
729 0 : int16_t decrease_min_shifts = 3;
730 :
731 : // Get log of near end energy and store in buffer
732 :
733 : // Shift buffer
734 0 : memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
735 0 : sizeof(int16_t) * (MAX_BUF_LEN - 1));
736 :
737 : // Logarithm of integrated magnitude spectrum (nearEner)
738 0 : aecm->nearLogEnergy[0] = LogOfEnergyInQ8(nearEner, aecm->dfaNoisyQDomain);
739 :
740 0 : WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored);
741 :
742 : // Shift buffers
743 0 : memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
744 0 : sizeof(int16_t) * (MAX_BUF_LEN - 1));
745 0 : memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
746 0 : sizeof(int16_t) * (MAX_BUF_LEN - 1));
747 :
748 : // Logarithm of delayed far end energy
749 0 : aecm->farLogEnergy = LogOfEnergyInQ8(tmpFar, far_q);
750 :
751 : // Logarithm of estimated echo energy through adapted channel
752 0 : aecm->echoAdaptLogEnergy[0] = LogOfEnergyInQ8(tmpAdapt,
753 : RESOLUTION_CHANNEL16 + far_q);
754 :
755 : // Logarithm of estimated echo energy through stored channel
756 0 : aecm->echoStoredLogEnergy[0] =
757 0 : LogOfEnergyInQ8(tmpStored, RESOLUTION_CHANNEL16 + far_q);
758 :
759 : // Update farend energy levels (min, max, vad, mse)
760 0 : if (aecm->farLogEnergy > FAR_ENERGY_MIN)
761 : {
762 0 : if (aecm->startupState == 0)
763 : {
764 0 : increase_max_shifts = 2;
765 0 : decrease_min_shifts = 2;
766 0 : increase_min_shifts = 8;
767 : }
768 :
769 0 : aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
770 : increase_min_shifts, decrease_min_shifts);
771 0 : aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
772 : increase_max_shifts, decrease_max_shifts);
773 0 : aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
774 :
775 : // Dynamic VAD region size
776 0 : tmp16 = 2560 - aecm->farEnergyMin;
777 0 : if (tmp16 > 0)
778 : {
779 0 : tmp16 = (int16_t)((tmp16 * FAR_ENERGY_VAD_REGION) >> 9);
780 : } else
781 : {
782 0 : tmp16 = 0;
783 : }
784 0 : tmp16 += FAR_ENERGY_VAD_REGION;
785 :
786 0 : if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024))
787 : {
788 : // In startup phase or VAD update halted
789 0 : aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
790 : } else
791 : {
792 0 : if (aecm->farEnergyVAD > aecm->farLogEnergy)
793 : {
794 0 : aecm->farEnergyVAD +=
795 0 : (aecm->farLogEnergy + tmp16 - aecm->farEnergyVAD) >> 6;
796 0 : aecm->vadUpdateCount = 0;
797 : } else
798 : {
799 0 : aecm->vadUpdateCount++;
800 : }
801 : }
802 : // Put MSE threshold higher than VAD
803 0 : aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
804 : }
805 :
806 : // Update VAD variables
807 0 : if (aecm->farLogEnergy > aecm->farEnergyVAD)
808 : {
809 0 : if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF))
810 : {
811 : // We are in startup or have significant dynamics in input speech level
812 0 : aecm->currentVADValue = 1;
813 : }
814 : } else
815 : {
816 0 : aecm->currentVADValue = 0;
817 : }
818 0 : if ((aecm->currentVADValue) && (aecm->firstVAD))
819 : {
820 0 : aecm->firstVAD = 0;
821 0 : if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0])
822 : {
823 : // The estimated echo has higher energy than the near end signal.
824 : // This means that the initialization was too aggressive. Scale
825 : // down by a factor 8
826 0 : for (i = 0; i < PART_LEN1; i++)
827 : {
828 0 : aecm->channelAdapt16[i] >>= 3;
829 : }
830 : // Compensate the adapted echo energy level accordingly.
831 0 : aecm->echoAdaptLogEnergy[0] -= (3 << 8);
832 0 : aecm->firstVAD = 1;
833 : }
834 : }
835 0 : }
836 :
837 : // WebRtcAecm_CalcStepSize(...)
838 : //
839 : // This function calculates the step size used in channel estimation
840 : //
841 : //
842 : // @param aecm [in] Handle of the AECM instance.
843 : // @param mu [out] (Return value) Stepsize in log2(), i.e. number of shifts.
844 : //
845 : //
846 0 : int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm) {
847 : int32_t tmp32;
848 : int16_t tmp16;
849 0 : int16_t mu = MU_MAX;
850 :
851 : // Here we calculate the step size mu used in the
852 : // following NLMS based Channel estimation algorithm
853 0 : if (!aecm->currentVADValue)
854 : {
855 : // Far end energy level too low, no channel update
856 0 : mu = 0;
857 0 : } else if (aecm->startupState > 0)
858 : {
859 0 : if (aecm->farEnergyMin >= aecm->farEnergyMax)
860 : {
861 0 : mu = MU_MIN;
862 : } else
863 : {
864 0 : tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
865 0 : tmp32 = tmp16 * MU_DIFF;
866 0 : tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
867 0 : mu = MU_MIN - 1 - (int16_t)(tmp32);
868 : // The -1 is an alternative to rounding. This way we get a larger
869 : // stepsize, so we in some sense compensate for truncation in NLMS
870 : }
871 0 : if (mu < MU_MAX)
872 : {
873 0 : mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
874 : }
875 : }
876 :
877 0 : return mu;
878 : }
879 :
880 : // WebRtcAecm_UpdateChannel(...)
881 : //
882 : // This function performs channel estimation. NLMS and decision on channel storage.
883 : //
884 : //
885 : // @param aecm [i/o] Handle of the AECM instance.
886 : // @param far_spectrum [in] Absolute value of the farend signal in Q(far_q)
887 : // @param far_q [in] Q-domain of the farend signal
888 : // @param dfa [in] Absolute value of the nearend signal (Q[aecm->dfaQDomain])
889 : // @param mu [in] NLMS step size.
890 : // @param echoEst [i/o] Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
891 : //
892 0 : void WebRtcAecm_UpdateChannel(AecmCore* aecm,
893 : const uint16_t* far_spectrum,
894 : const int16_t far_q,
895 : const uint16_t* const dfa,
896 : const int16_t mu,
897 : int32_t* echoEst) {
898 : uint32_t tmpU32no1, tmpU32no2;
899 : int32_t tmp32no1, tmp32no2;
900 : int32_t mseStored;
901 : int32_t mseAdapt;
902 :
903 : int i;
904 :
905 : int16_t zerosFar, zerosNum, zerosCh, zerosDfa;
906 : int16_t shiftChFar, shiftNum, shift2ResChan;
907 : int16_t tmp16no1;
908 : int16_t xfaQ, dfaQ;
909 :
910 : // This is the channel estimation algorithm. It is base on NLMS but has a variable step
911 : // length, which was calculated above.
912 0 : if (mu)
913 : {
914 0 : for (i = 0; i < PART_LEN1; i++)
915 : {
916 : // Determine norm of channel and farend to make sure we don't get overflow in
917 : // multiplication
918 0 : zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
919 0 : zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]);
920 0 : if (zerosCh + zerosFar > 31)
921 : {
922 : // Multiplication is safe
923 0 : tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i],
924 : far_spectrum[i]);
925 0 : shiftChFar = 0;
926 : } else
927 : {
928 : // We need to shift down before multiplication
929 0 : shiftChFar = 32 - zerosCh - zerosFar;
930 0 : tmpU32no1 = (aecm->channelAdapt32[i] >> shiftChFar) *
931 0 : far_spectrum[i];
932 : }
933 : // Determine Q-domain of numerator
934 0 : zerosNum = WebRtcSpl_NormU32(tmpU32no1);
935 0 : if (dfa[i])
936 : {
937 0 : zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]);
938 : } else
939 : {
940 0 : zerosDfa = 32;
941 : }
942 0 : tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain -
943 0 : RESOLUTION_CHANNEL32 - far_q + shiftChFar;
944 0 : if (zerosNum > tmp16no1 + 1)
945 : {
946 0 : xfaQ = tmp16no1;
947 0 : dfaQ = zerosDfa - 2;
948 : } else
949 : {
950 0 : xfaQ = zerosNum - 2;
951 0 : dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
952 0 : shiftChFar + xfaQ;
953 : }
954 : // Add in the same Q-domain
955 0 : tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
956 0 : tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ);
957 0 : tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1;
958 0 : zerosNum = WebRtcSpl_NormW32(tmp32no1);
959 0 : if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q)))
960 : {
961 : //
962 : // Update is needed
963 : //
964 : // This is what we would like to compute
965 : //
966 : // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
967 : // tmp32norm = (i + 1)
968 : // aecm->channelAdapt[i] += (2^mu) * tmp32no1
969 : // / (tmp32norm * far_spectrum[i])
970 : //
971 :
972 : // Make sure we don't get overflow in multiplication.
973 0 : if (zerosNum + zerosFar > 31)
974 : {
975 0 : if (tmp32no1 > 0)
976 : {
977 0 : tmp32no2 = (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1,
978 : far_spectrum[i]);
979 : } else
980 : {
981 0 : tmp32no2 = -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1,
982 : far_spectrum[i]);
983 : }
984 0 : shiftNum = 0;
985 : } else
986 : {
987 0 : shiftNum = 32 - (zerosNum + zerosFar);
988 0 : if (tmp32no1 > 0)
989 : {
990 0 : tmp32no2 = (tmp32no1 >> shiftNum) * far_spectrum[i];
991 : } else
992 : {
993 0 : tmp32no2 = -((-tmp32no1 >> shiftNum) * far_spectrum[i]);
994 : }
995 : }
996 : // Normalize with respect to frequency bin
997 0 : tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
998 : // Make sure we are in the right Q-domain
999 0 : shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
1000 0 : if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan)
1001 : {
1002 0 : tmp32no2 = WEBRTC_SPL_WORD32_MAX;
1003 : } else
1004 : {
1005 0 : tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
1006 : }
1007 0 : aecm->channelAdapt32[i] =
1008 0 : WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2);
1009 0 : if (aecm->channelAdapt32[i] < 0)
1010 : {
1011 : // We can never have negative channel gain
1012 0 : aecm->channelAdapt32[i] = 0;
1013 : }
1014 0 : aecm->channelAdapt16[i] =
1015 0 : (int16_t)(aecm->channelAdapt32[i] >> 16);
1016 : }
1017 : }
1018 : }
1019 : // END: Adaptive channel update
1020 :
1021 : // Determine if we should store or restore the channel
1022 0 : if ((aecm->startupState == 0) & (aecm->currentVADValue))
1023 : {
1024 : // During startup we store the channel every block,
1025 : // and we recalculate echo estimate
1026 0 : WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
1027 : } else
1028 : {
1029 0 : if (aecm->farLogEnergy < aecm->farEnergyMSE)
1030 : {
1031 0 : aecm->mseChannelCount = 0;
1032 : } else
1033 : {
1034 0 : aecm->mseChannelCount++;
1035 : }
1036 : // Enough data for validation. Store channel if we can.
1037 0 : if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10))
1038 : {
1039 : // We have enough data.
1040 : // Calculate MSE of "Adapt" and "Stored" versions.
1041 : // It is actually not MSE, but average absolute error.
1042 0 : mseStored = 0;
1043 0 : mseAdapt = 0;
1044 0 : for (i = 0; i < MIN_MSE_COUNT; i++)
1045 : {
1046 0 : tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i]
1047 0 : - (int32_t)aecm->nearLogEnergy[i]);
1048 0 : tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
1049 0 : mseStored += tmp32no2;
1050 :
1051 0 : tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i]
1052 0 : - (int32_t)aecm->nearLogEnergy[i]);
1053 0 : tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
1054 0 : mseAdapt += tmp32no2;
1055 : }
1056 0 : if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt))
1057 0 : & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF
1058 0 : * aecm->mseAdaptOld)))
1059 : {
1060 : // The stored channel has a significantly lower MSE than the adaptive one for
1061 : // two consecutive calculations. Reset the adaptive channel.
1062 0 : WebRtcAecm_ResetAdaptiveChannel(aecm);
1063 0 : } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt
1064 0 : < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold))
1065 : {
1066 : // The adaptive channel has a significantly lower MSE than the stored one.
1067 : // The MSE for the adaptive channel has also been low for two consecutive
1068 : // calculations. Store the adaptive channel.
1069 0 : WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
1070 :
1071 : // Update threshold
1072 0 : if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX)
1073 : {
1074 0 : aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
1075 : } else
1076 : {
1077 0 : int scaled_threshold = aecm->mseThreshold * 5 / 8;
1078 0 : aecm->mseThreshold +=
1079 0 : ((mseAdapt - scaled_threshold) * 205) >> 8;
1080 : }
1081 :
1082 : }
1083 :
1084 : // Reset counter
1085 0 : aecm->mseChannelCount = 0;
1086 :
1087 : // Store the MSE values.
1088 0 : aecm->mseStoredOld = mseStored;
1089 0 : aecm->mseAdaptOld = mseAdapt;
1090 : }
1091 : }
1092 : // END: Determine if we should store or reset channel estimate.
1093 0 : }
1094 :
1095 : // CalcSuppressionGain(...)
1096 : //
1097 : // This function calculates the suppression gain that is used in the Wiener filter.
1098 : //
1099 : //
1100 : // @param aecm [i/n] Handle of the AECM instance.
1101 : // @param supGain [out] (Return value) Suppression gain with which to scale the noise
1102 : // level (Q14).
1103 : //
1104 : //
1105 0 : int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm) {
1106 : int32_t tmp32no1;
1107 :
1108 0 : int16_t supGain = SUPGAIN_DEFAULT;
1109 : int16_t tmp16no1;
1110 0 : int16_t dE = 0;
1111 :
1112 : // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far
1113 : // end energy and echo estimation error.
1114 : // Adjust for the far end signal level. A low signal level indicates no far end signal,
1115 : // hence we set the suppression gain to 0
1116 0 : if (!aecm->currentVADValue)
1117 : {
1118 0 : supGain = 0;
1119 : } else
1120 : {
1121 : // Adjust for possible double talk. If we have large variations in estimation error we
1122 : // likely have double talk (or poor channel).
1123 0 : tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET);
1124 0 : dE = WEBRTC_SPL_ABS_W16(tmp16no1);
1125 :
1126 0 : if (dE < ENERGY_DEV_TOL)
1127 : {
1128 : // Likely no double talk. The better estimation, the more we can suppress signal.
1129 : // Update counters
1130 0 : if (dE < SUPGAIN_EPC_DT)
1131 : {
1132 0 : tmp32no1 = aecm->supGainErrParamDiffAB * dE;
1133 0 : tmp32no1 += (SUPGAIN_EPC_DT >> 1);
1134 0 : tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
1135 0 : supGain = aecm->supGainErrParamA - tmp16no1;
1136 : } else
1137 : {
1138 0 : tmp32no1 = aecm->supGainErrParamDiffBD * (ENERGY_DEV_TOL - dE);
1139 0 : tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
1140 0 : tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL
1141 : - SUPGAIN_EPC_DT));
1142 0 : supGain = aecm->supGainErrParamD + tmp16no1;
1143 : }
1144 : } else
1145 : {
1146 : // Likely in double talk. Use default value
1147 0 : supGain = aecm->supGainErrParamD;
1148 : }
1149 : }
1150 :
1151 0 : if (supGain > aecm->supGainOld)
1152 : {
1153 0 : tmp16no1 = supGain;
1154 : } else
1155 : {
1156 0 : tmp16no1 = aecm->supGainOld;
1157 : }
1158 0 : aecm->supGainOld = supGain;
1159 0 : if (tmp16no1 < aecm->supGain)
1160 : {
1161 0 : aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
1162 : } else
1163 : {
1164 0 : aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
1165 : }
1166 :
1167 : // END: Update suppression gain
1168 :
1169 0 : return aecm->supGain;
1170 : }
1171 :
1172 0 : void WebRtcAecm_BufferFarFrame(AecmCore* const aecm,
1173 : const int16_t* const farend,
1174 : const int farLen) {
1175 0 : int writeLen = farLen, writePos = 0;
1176 :
1177 : // Check if the write position must be wrapped
1178 0 : while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN)
1179 : {
1180 : // Write to remaining buffer space before wrapping
1181 0 : writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
1182 0 : memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
1183 0 : sizeof(int16_t) * writeLen);
1184 0 : aecm->farBufWritePos = 0;
1185 0 : writePos = writeLen;
1186 0 : writeLen = farLen - writeLen;
1187 : }
1188 :
1189 0 : memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
1190 0 : sizeof(int16_t) * writeLen);
1191 0 : aecm->farBufWritePos += writeLen;
1192 0 : }
1193 :
1194 0 : void WebRtcAecm_FetchFarFrame(AecmCore* const aecm,
1195 : int16_t* const farend,
1196 : const int farLen,
1197 : const int knownDelay) {
1198 0 : int readLen = farLen;
1199 0 : int readPos = 0;
1200 0 : int delayChange = knownDelay - aecm->lastKnownDelay;
1201 :
1202 0 : aecm->farBufReadPos -= delayChange;
1203 :
1204 : // Check if delay forces a read position wrap
1205 0 : while (aecm->farBufReadPos < 0)
1206 : {
1207 0 : aecm->farBufReadPos += FAR_BUF_LEN;
1208 : }
1209 0 : while (aecm->farBufReadPos > FAR_BUF_LEN - 1)
1210 : {
1211 0 : aecm->farBufReadPos -= FAR_BUF_LEN;
1212 : }
1213 :
1214 0 : aecm->lastKnownDelay = knownDelay;
1215 :
1216 : // Check if read position must be wrapped
1217 0 : while (aecm->farBufReadPos + readLen > FAR_BUF_LEN)
1218 : {
1219 :
1220 : // Read from remaining buffer space before wrapping
1221 0 : readLen = FAR_BUF_LEN - aecm->farBufReadPos;
1222 0 : memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
1223 0 : sizeof(int16_t) * readLen);
1224 0 : aecm->farBufReadPos = 0;
1225 0 : readPos = readLen;
1226 0 : readLen = farLen - readLen;
1227 : }
1228 0 : memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
1229 0 : sizeof(int16_t) * readLen);
1230 0 : aecm->farBufReadPos += readLen;
1231 0 : }
|