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