Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/webrtc/modules/audio_processing/aecm/aecm_core.c @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

File size: 47.4 KB
Line 
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/signal_processing/include/real_fft.h"
18#include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
19#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
20#include "webrtc/modules/audio_processing/utility/ring_buffer.h"
21#include "webrtc/system_wrappers/interface/compile_assert_c.h"
22#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
23#include "webrtc/typedefs.h"
24
25#ifdef AEC_DEBUG
26FILE *dfile;
27FILE *testfile;
28#endif
29
30const 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
73const 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
122static 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
135static 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//
155void WebRtcAecm_UpdateFarHistory(AecmCore_t* 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//
188const uint16_t* WebRtcAecm_AlignedFarend(AecmCore_t* 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.
206CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
207StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
208ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
209
210int WebRtcAecm_CreateCore(AecmCore_t **aecmInst)
211{
212    AecmCore_t *aecm = malloc(sizeof(AecmCore_t));
213    *aecmInst = aecm;
214    if (aecm == NULL)
215    {
216        return -1;
217    }
218
219    aecm->farFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
220                                            sizeof(int16_t));
221    if (!aecm->farFrameBuf)
222    {
223        WebRtcAecm_FreeCore(aecm);
224        aecm = NULL;
225        return -1;
226    }
227
228    aecm->nearNoisyFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
229                                                  sizeof(int16_t));
230    if (!aecm->nearNoisyFrameBuf)
231    {
232        WebRtcAecm_FreeCore(aecm);
233        aecm = NULL;
234        return -1;
235    }
236
237    aecm->nearCleanFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
238                                                  sizeof(int16_t));
239    if (!aecm->nearCleanFrameBuf)
240    {
241        WebRtcAecm_FreeCore(aecm);
242        aecm = NULL;
243        return -1;
244    }
245
246    aecm->outFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
247                                            sizeof(int16_t));
248    if (!aecm->outFrameBuf)
249    {
250        WebRtcAecm_FreeCore(aecm);
251        aecm = NULL;
252        return -1;
253    }
254
255    aecm->delay_estimator_farend = WebRtc_CreateDelayEstimatorFarend(PART_LEN1,
256                                                                     MAX_DELAY);
257    if (aecm->delay_estimator_farend == NULL) {
258      WebRtcAecm_FreeCore(aecm);
259      aecm = NULL;
260      return -1;
261    }
262    aecm->delay_estimator =
263        WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0);
264    if (aecm->delay_estimator == NULL) {
265      WebRtcAecm_FreeCore(aecm);
266      aecm = NULL;
267      return -1;
268    }
269
270    aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT);
271    if (aecm->real_fft == NULL) {
272      WebRtcAecm_FreeCore(aecm);
273      aecm = NULL;
274      return -1;
275    }
276
277    // Init some aecm pointers. 16 and 32 byte alignment is only necessary
278    // for Neon code currently.
279    aecm->xBuf = (int16_t*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31);
280    aecm->dBufClean = (int16_t*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31);
281    aecm->dBufNoisy = (int16_t*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31);
282    aecm->outBuf = (int16_t*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15);
283    aecm->channelStored = (int16_t*) (((uintptr_t)
284                                             aecm->channelStored_buf + 15) & ~ 15);
285    aecm->channelAdapt16 = (int16_t*) (((uintptr_t)
286                                              aecm->channelAdapt16_buf + 15) & ~ 15);
287    aecm->channelAdapt32 = (int32_t*) (((uintptr_t)
288                                              aecm->channelAdapt32_buf + 31) & ~ 31);
289
290    return 0;
291}
292
293void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const int16_t* echo_path)
294{
295    int i = 0;
296
297    // Reset the stored channel
298    memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1);
299    // Reset the adapted channels
300    memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1);
301    for (i = 0; i < PART_LEN1; i++)
302    {
303        aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
304            (int32_t)(aecm->channelAdapt16[i]), 16);
305    }
306
307    // Reset channel storing variables
308    aecm->mseAdaptOld = 1000;
309    aecm->mseStoredOld = 1000;
310    aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
311    aecm->mseChannelCount = 0;
312}
313
314static void CalcLinearEnergiesC(AecmCore_t* aecm,
315                                const uint16_t* far_spectrum,
316                                int32_t* echo_est,
317                                uint32_t* far_energy,
318                                uint32_t* echo_energy_adapt,
319                                uint32_t* echo_energy_stored)
320{
321    int i;
322
323    // Get energy for the delayed far end signal and estimated
324    // echo using both stored and adapted channels.
325    for (i = 0; i < PART_LEN1; i++)
326    {
327        echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
328                                           far_spectrum[i]);
329        (*far_energy) += (uint32_t)(far_spectrum[i]);
330        (*echo_energy_adapt) += WEBRTC_SPL_UMUL_16_16(aecm->channelAdapt16[i],
331                                          far_spectrum[i]);
332        (*echo_energy_stored) += (uint32_t)echo_est[i];
333    }
334}
335
336static void StoreAdaptiveChannelC(AecmCore_t* aecm,
337                                  const uint16_t* far_spectrum,
338                                  int32_t* echo_est)
339{
340    int i;
341
342    // During startup we store the channel every block.
343    memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(int16_t) * PART_LEN1);
344    // Recalculate echo estimate
345    for (i = 0; i < PART_LEN; i += 4)
346    {
347        echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
348                                           far_spectrum[i]);
349        echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1],
350                                           far_spectrum[i + 1]);
351        echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2],
352                                           far_spectrum[i + 2]);
353        echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3],
354                                           far_spectrum[i + 3]);
355    }
356    echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
357                                       far_spectrum[i]);
358}
359
360static void ResetAdaptiveChannelC(AecmCore_t* aecm)
361{
362    int i;
363
364    // The stored channel has a significantly lower MSE than the adaptive one for
365    // two consecutive calculations. Reset the adaptive channel.
366    memcpy(aecm->channelAdapt16, aecm->channelStored,
367           sizeof(int16_t) * PART_LEN1);
368    // Restore the W32 channel
369    for (i = 0; i < PART_LEN; i += 4)
370    {
371        aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
372                (int32_t)aecm->channelStored[i], 16);
373        aecm->channelAdapt32[i + 1] = WEBRTC_SPL_LSHIFT_W32(
374                (int32_t)aecm->channelStored[i + 1], 16);
375        aecm->channelAdapt32[i + 2] = WEBRTC_SPL_LSHIFT_W32(
376                (int32_t)aecm->channelStored[i + 2], 16);
377        aecm->channelAdapt32[i + 3] = WEBRTC_SPL_LSHIFT_W32(
378                (int32_t)aecm->channelStored[i + 3], 16);
379    }
380    aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((int32_t)aecm->channelStored[i], 16);
381}
382
383// Initialize function pointers for ARM Neon platform.
384#if (defined WEBRTC_DETECT_ARM_NEON || defined WEBRTC_ARCH_ARM_NEON)
385static void WebRtcAecm_InitNeon(void)
386{
387  WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannelNeon;
388  WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannelNeon;
389  WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergiesNeon;
390}
391#endif
392
393// Initialize function pointers for MIPS platform.
394#if defined(MIPS32_LE)
395static void WebRtcAecm_InitMips(void)
396{
397#if defined(MIPS_DSP_R1_LE)
398  WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannel_mips;
399  WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannel_mips;
400#endif
401  WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergies_mips;
402}
403#endif
404
405// WebRtcAecm_InitCore(...)
406//
407// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
408// Input:
409//      - aecm            : Pointer to the Echo Suppression instance
410//      - samplingFreq   : Sampling Frequency
411//
412// Output:
413//      - aecm            : Initialized instance
414//
415// Return value         :  0 - Ok
416//                        -1 - Error
417//
418int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq)
419{
420    int i = 0;
421    int32_t tmp32 = PART_LEN1 * PART_LEN1;
422    int16_t tmp16 = PART_LEN1;
423
424    if (samplingFreq != 8000 && samplingFreq != 16000)
425    {
426        samplingFreq = 8000;
427        return -1;
428    }
429    // sanity check of sampling frequency
430    aecm->mult = (int16_t)samplingFreq / 8000;
431
432    aecm->farBufWritePos = 0;
433    aecm->farBufReadPos = 0;
434    aecm->knownDelay = 0;
435    aecm->lastKnownDelay = 0;
436
437    WebRtc_InitBuffer(aecm->farFrameBuf);
438    WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
439    WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
440    WebRtc_InitBuffer(aecm->outFrameBuf);
441
442    memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
443    memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
444    memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
445    memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
446
447    aecm->seed = 666;
448    aecm->totCount = 0;
449
450    if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) {
451      return -1;
452    }
453    if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
454      return -1;
455    }
456    // Set far end histories to zero
457    memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
458    memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
459    aecm->far_history_pos = MAX_DELAY;
460
461    aecm->nlpFlag = 1;
462    aecm->fixedDelay = -1;
463
464    aecm->dfaCleanQDomain = 0;
465    aecm->dfaCleanQDomainOld = 0;
466    aecm->dfaNoisyQDomain = 0;
467    aecm->dfaNoisyQDomainOld = 0;
468
469    memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
470    aecm->farLogEnergy = 0;
471    memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
472    memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
473
474    // Initialize the echo channels with a stored shape.
475    if (samplingFreq == 8000)
476    {
477        WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
478    }
479    else
480    {
481        WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
482    }
483
484    memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
485    memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
486    aecm->noiseEstCtr = 0;
487
488    aecm->cngMode = AecmTrue;
489
490    memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
491    memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
492    // Shape the initial noise level to an approximate pink noise.
493    for (i = 0; i < (PART_LEN1 >> 1) - 1; i++)
494    {
495        aecm->noiseEst[i] = (tmp32 << 8);
496        tmp16--;
497        tmp32 -= (int32_t)((tmp16 << 1) + 1);
498    }
499    for (; i < PART_LEN1; i++)
500    {
501        aecm->noiseEst[i] = (tmp32 << 8);
502    }
503
504    aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
505    aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
506    aecm->farEnergyMaxMin = 0;
507    aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the
508                                         // beginning.
509    aecm->farEnergyMSE = 0;
510    aecm->currentVADValue = 0;
511    aecm->vadUpdateCount = 0;
512    aecm->firstVAD = 1;
513
514    aecm->startupState = 0;
515    aecm->supGain = SUPGAIN_DEFAULT;
516    aecm->supGainOld = SUPGAIN_DEFAULT;
517
518    aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
519    aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
520    aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
521    aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
522
523    // Assert a preprocessor definition at compile-time. It's an assumption
524    // used in assembly code, so check the assembly files before any change.
525    COMPILE_ASSERT(PART_LEN % 16 == 0);
526
527    // Initialize function pointers.
528    WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
529    WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
530    WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
531
532#ifdef WEBRTC_DETECT_ARM_NEON
533    uint64_t features = WebRtc_GetCPUFeaturesARM();
534    if ((features & kCPUFeatureNEON) != 0)
535    {
536      WebRtcAecm_InitNeon();
537    }
538#elif defined(WEBRTC_ARCH_ARM_NEON)
539    WebRtcAecm_InitNeon();
540#endif
541
542#if defined(MIPS32_LE)
543    WebRtcAecm_InitMips();
544#endif
545    return 0;
546}
547
548// TODO(bjornv): This function is currently not used. Add support for these
549// parameters from a higher level
550int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag)
551{
552    aecm->nlpFlag = nlpFlag;
553    aecm->fixedDelay = delay;
554
555    return 0;
556}
557
558int WebRtcAecm_FreeCore(AecmCore_t *aecm)
559{
560    if (aecm == NULL)
561    {
562        return -1;
563    }
564
565    WebRtc_FreeBuffer(aecm->farFrameBuf);
566    WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
567    WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
568    WebRtc_FreeBuffer(aecm->outFrameBuf);
569
570    WebRtc_FreeDelayEstimator(aecm->delay_estimator);
571    WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend);
572    WebRtcSpl_FreeRealFFT(aecm->real_fft);
573
574    free(aecm);
575
576    return 0;
577}
578
579int WebRtcAecm_ProcessFrame(AecmCore_t * aecm,
580                            const int16_t * farend,
581                            const int16_t * nearendNoisy,
582                            const int16_t * nearendClean,
583                            int16_t * out)
584{
585    int16_t outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary.
586    int16_t* outBlock = (int16_t*) (((uintptr_t) outBlock_buf + 15) & ~ 15);
587
588    int16_t farFrame[FRAME_LEN];
589    const int16_t* out_ptr = NULL;
590    int size = 0;
591
592    // Buffer the current frame.
593    // Fetch an older one corresponding to the delay.
594    WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
595    WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
596
597    // Buffer the synchronized far and near frames,
598    // to pass the smaller blocks individually.
599    WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
600    WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
601    if (nearendClean != NULL)
602    {
603        WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
604    }
605
606    // Process as many blocks as possible.
607    while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN)
608    {
609        int16_t far_block[PART_LEN];
610        const int16_t* far_block_ptr = NULL;
611        int16_t near_noisy_block[PART_LEN];
612        const int16_t* near_noisy_block_ptr = NULL;
613
614        WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block,
615                          PART_LEN);
616        WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf,
617                          (void**) &near_noisy_block_ptr,
618                          near_noisy_block,
619                          PART_LEN);
620        if (nearendClean != NULL)
621        {
622            int16_t near_clean_block[PART_LEN];
623            const int16_t* near_clean_block_ptr = NULL;
624
625            WebRtc_ReadBuffer(aecm->nearCleanFrameBuf,
626                              (void**) &near_clean_block_ptr,
627                              near_clean_block,
628                              PART_LEN);
629            if (WebRtcAecm_ProcessBlock(aecm,
630                                        far_block_ptr,
631                                        near_noisy_block_ptr,
632                                        near_clean_block_ptr,
633                                        outBlock) == -1)
634            {
635                return -1;
636            }
637        } else
638        {
639            if (WebRtcAecm_ProcessBlock(aecm,
640                                        far_block_ptr,
641                                        near_noisy_block_ptr,
642                                        NULL,
643                                        outBlock) == -1)
644            {
645                return -1;
646            }
647        }
648
649        WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
650    }
651
652    // Stuff the out buffer if we have less than a frame to output.
653    // This should only happen for the first frame.
654    size = (int) WebRtc_available_read(aecm->outFrameBuf);
655    if (size < FRAME_LEN)
656    {
657        WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
658    }
659
660    // Obtain an output frame.
661    WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN);
662    if (out_ptr != out) {
663      // ReadBuffer() hasn't copied to |out| in this case.
664      memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
665    }
666
667    return 0;
668}
669
670// WebRtcAecm_AsymFilt(...)
671//
672// Performs asymmetric filtering.
673//
674// Inputs:
675//      - filtOld       : Previous filtered value.
676//      - inVal         : New input value.
677//      - stepSizePos   : Step size when we have a positive contribution.
678//      - stepSizeNeg   : Step size when we have a negative contribution.
679//
680// Output:
681//
682// Return: - Filtered value.
683//
684int16_t WebRtcAecm_AsymFilt(const int16_t filtOld, const int16_t inVal,
685                            const int16_t stepSizePos,
686                            const int16_t stepSizeNeg)
687{
688    int16_t retVal;
689
690    if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN))
691    {
692        return inVal;
693    }
694    retVal = filtOld;
695    if (filtOld > inVal)
696    {
697        retVal -= WEBRTC_SPL_RSHIFT_W16(filtOld - inVal, stepSizeNeg);
698    } else
699    {
700        retVal += WEBRTC_SPL_RSHIFT_W16(inVal - filtOld, stepSizePos);
701    }
702
703    return retVal;
704}
705
706// WebRtcAecm_CalcEnergies(...)
707//
708// This function calculates the log of energies for nearend, farend and estimated
709// echoes. There is also an update of energy decision levels, i.e. internal VAD.
710//
711//
712// @param  aecm         [i/o]   Handle of the AECM instance.
713// @param  far_spectrum [in]    Pointer to farend spectrum.
714// @param  far_q        [in]    Q-domain of farend spectrum.
715// @param  nearEner     [in]    Near end energy for current block in
716//                              Q(aecm->dfaQDomain).
717// @param  echoEst      [out]   Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
718//
719void WebRtcAecm_CalcEnergies(AecmCore_t * aecm,
720                             const uint16_t* far_spectrum,
721                             const int16_t far_q,
722                             const uint32_t nearEner,
723                             int32_t * echoEst)
724{
725    // Local variables
726    uint32_t tmpAdapt = 0;
727    uint32_t tmpStored = 0;
728    uint32_t tmpFar = 0;
729
730    int i;
731
732    int16_t zeros, frac;
733    int16_t tmp16;
734    int16_t increase_max_shifts = 4;
735    int16_t decrease_max_shifts = 11;
736    int16_t increase_min_shifts = 11;
737    int16_t decrease_min_shifts = 3;
738    int16_t kLogLowValue = WEBRTC_SPL_LSHIFT_W16(PART_LEN_SHIFT, 7);
739
740    // Get log of near end energy and store in buffer
741
742    // Shift buffer
743    memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
744            sizeof(int16_t) * (MAX_BUF_LEN - 1));
745
746    // Logarithm of integrated magnitude spectrum (nearEner)
747    tmp16 = kLogLowValue;
748    if (nearEner)
749    {
750        zeros = WebRtcSpl_NormU32(nearEner);
751        frac = (int16_t)WEBRTC_SPL_RSHIFT_U32(
752                              (WEBRTC_SPL_LSHIFT_U32(nearEner, zeros) & 0x7FFFFFFF),
753                              23);
754        // log2 in Q8
755        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
756        tmp16 -= WEBRTC_SPL_LSHIFT_W16(aecm->dfaNoisyQDomain, 8);
757    }
758    aecm->nearLogEnergy[0] = tmp16;
759    // END: Get log of near end energy
760
761    WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored);
762
763    // Shift buffers
764    memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
765            sizeof(int16_t) * (MAX_BUF_LEN - 1));
766    memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
767            sizeof(int16_t) * (MAX_BUF_LEN - 1));
768
769    // Logarithm of delayed far end energy
770    tmp16 = kLogLowValue;
771    if (tmpFar)
772    {
773        zeros = WebRtcSpl_NormU32(tmpFar);
774        frac = (int16_t)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpFar, zeros)
775                        & 0x7FFFFFFF), 23);
776        // log2 in Q8
777        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
778        tmp16 -= WEBRTC_SPL_LSHIFT_W16(far_q, 8);
779    }
780    aecm->farLogEnergy = tmp16;
781
782    // Logarithm of estimated echo energy through adapted channel
783    tmp16 = kLogLowValue;
784    if (tmpAdapt)
785    {
786        zeros = WebRtcSpl_NormU32(tmpAdapt);
787        frac = (int16_t)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpAdapt, zeros)
788                        & 0x7FFFFFFF), 23);
789        //log2 in Q8
790        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
791        tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8);
792    }
793    aecm->echoAdaptLogEnergy[0] = tmp16;
794
795    // Logarithm of estimated echo energy through stored channel
796    tmp16 = kLogLowValue;
797    if (tmpStored)
798    {
799        zeros = WebRtcSpl_NormU32(tmpStored);
800        frac = (int16_t)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpStored, zeros)
801                        & 0x7FFFFFFF), 23);
802        //log2 in Q8
803        tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
804        tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8);
805    }
806    aecm->echoStoredLogEnergy[0] = tmp16;
807
808    // Update farend energy levels (min, max, vad, mse)
809    if (aecm->farLogEnergy > FAR_ENERGY_MIN)
810    {
811        if (aecm->startupState == 0)
812        {
813            increase_max_shifts = 2;
814            decrease_min_shifts = 2;
815            increase_min_shifts = 8;
816        }
817
818        aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
819                                                 increase_min_shifts, decrease_min_shifts);
820        aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
821                                                 increase_max_shifts, decrease_max_shifts);
822        aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
823
824        // Dynamic VAD region size
825        tmp16 = 2560 - aecm->farEnergyMin;
826        if (tmp16 > 0)
827        {
828            tmp16 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, FAR_ENERGY_VAD_REGION, 9);
829        } else
830        {
831            tmp16 = 0;
832        }
833        tmp16 += FAR_ENERGY_VAD_REGION;
834
835        if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024))
836        {
837            // In startup phase or VAD update halted
838            aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
839        } else
840        {
841            if (aecm->farEnergyVAD > aecm->farLogEnergy)
842            {
843                aecm->farEnergyVAD += WEBRTC_SPL_RSHIFT_W16(aecm->farLogEnergy +
844                                                            tmp16 -
845                                                            aecm->farEnergyVAD,
846                                                            6);
847                aecm->vadUpdateCount = 0;
848            } else
849            {
850                aecm->vadUpdateCount++;
851            }
852        }
853        // Put MSE threshold higher than VAD
854        aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
855    }
856
857    // Update VAD variables
858    if (aecm->farLogEnergy > aecm->farEnergyVAD)
859    {
860        if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF))
861        {
862            // We are in startup or have significant dynamics in input speech level
863            aecm->currentVADValue = 1;
864        }
865    } else
866    {
867        aecm->currentVADValue = 0;
868    }
869    if ((aecm->currentVADValue) && (aecm->firstVAD))
870    {
871        aecm->firstVAD = 0;
872        if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0])
873        {
874            // The estimated echo has higher energy than the near end signal.
875            // This means that the initialization was too aggressive. Scale
876            // down by a factor 8
877            for (i = 0; i < PART_LEN1; i++)
878            {
879                aecm->channelAdapt16[i] >>= 3;
880            }
881            // Compensate the adapted echo energy level accordingly.
882            aecm->echoAdaptLogEnergy[0] -= (3 << 8);
883            aecm->firstVAD = 1;
884        }
885    }
886}
887
888// WebRtcAecm_CalcStepSize(...)
889//
890// This function calculates the step size used in channel estimation
891//
892//
893// @param  aecm  [in]    Handle of the AECM instance.
894// @param  mu    [out]   (Return value) Stepsize in log2(), i.e. number of shifts.
895//
896//
897int16_t WebRtcAecm_CalcStepSize(AecmCore_t * const aecm)
898{
899
900    int32_t tmp32;
901    int16_t tmp16;
902    int16_t mu = MU_MAX;
903
904    // Here we calculate the step size mu used in the
905    // following NLMS based Channel estimation algorithm
906    if (!aecm->currentVADValue)
907    {
908        // Far end energy level too low, no channel update
909        mu = 0;
910    } else if (aecm->startupState > 0)
911    {
912        if (aecm->farEnergyMin >= aecm->farEnergyMax)
913        {
914            mu = MU_MIN;
915        } else
916        {
917            tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
918            tmp32 = WEBRTC_SPL_MUL_16_16(tmp16, MU_DIFF);
919            tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
920            mu = MU_MIN - 1 - (int16_t)(tmp32);
921            // The -1 is an alternative to rounding. This way we get a larger
922            // stepsize, so we in some sense compensate for truncation in NLMS
923        }
924        if (mu < MU_MAX)
925        {
926            mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
927        }
928    }
929
930    return mu;
931}
932
933// WebRtcAecm_UpdateChannel(...)
934//
935// This function performs channel estimation. NLMS and decision on channel storage.
936//
937//
938// @param  aecm         [i/o]   Handle of the AECM instance.
939// @param  far_spectrum [in]    Absolute value of the farend signal in Q(far_q)
940// @param  far_q        [in]    Q-domain of the farend signal
941// @param  dfa          [in]    Absolute value of the nearend signal (Q[aecm->dfaQDomain])
942// @param  mu           [in]    NLMS step size.
943// @param  echoEst      [i/o]   Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
944//
945void WebRtcAecm_UpdateChannel(AecmCore_t * aecm,
946                              const uint16_t* far_spectrum,
947                              const int16_t far_q,
948                              const uint16_t * const dfa,
949                              const int16_t mu,
950                              int32_t * echoEst)
951{
952
953    uint32_t tmpU32no1, tmpU32no2;
954    int32_t tmp32no1, tmp32no2;
955    int32_t mseStored;
956    int32_t mseAdapt;
957
958    int i;
959
960    int16_t zerosFar, zerosNum, zerosCh, zerosDfa;
961    int16_t shiftChFar, shiftNum, shift2ResChan;
962    int16_t tmp16no1;
963    int16_t xfaQ, dfaQ;
964
965    // This is the channel estimation algorithm. It is base on NLMS but has a variable step
966    // length, which was calculated above.
967    if (mu)
968    {
969        for (i = 0; i < PART_LEN1; i++)
970        {
971            // Determine norm of channel and farend to make sure we don't get overflow in
972            // multiplication
973            zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
974            zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]);
975            if (zerosCh + zerosFar > 31)
976            {
977                // Multiplication is safe
978                tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i],
979                        far_spectrum[i]);
980                shiftChFar = 0;
981            } else
982            {
983                // We need to shift down before multiplication
984                shiftChFar = 32 - zerosCh - zerosFar;
985                tmpU32no1 = WEBRTC_SPL_UMUL_32_16(
986                    WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], shiftChFar),
987                    far_spectrum[i]);
988            }
989            // Determine Q-domain of numerator
990            zerosNum = WebRtcSpl_NormU32(tmpU32no1);
991            if (dfa[i])
992            {
993                zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]);
994            } else
995            {
996                zerosDfa = 32;
997            }
998            tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain -
999                RESOLUTION_CHANNEL32 - far_q + shiftChFar;
1000            if (zerosNum > tmp16no1 + 1)
1001            {
1002                xfaQ = tmp16no1;
1003                dfaQ = zerosDfa - 2;
1004            } else
1005            {
1006                xfaQ = zerosNum - 2;
1007                dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
1008                    shiftChFar + xfaQ;
1009            }
1010            // Add in the same Q-domain
1011            tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
1012            tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ);
1013            tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1;
1014            zerosNum = WebRtcSpl_NormW32(tmp32no1);
1015            if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q)))
1016            {
1017                //
1018                // Update is needed
1019                //
1020                // This is what we would like to compute
1021                //
1022                // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
1023                // tmp32norm = (i + 1)
1024                // aecm->channelAdapt[i] += (2^mu) * tmp32no1
1025                //                        / (tmp32norm * far_spectrum[i])
1026                //
1027
1028                // Make sure we don't get overflow in multiplication.
1029                if (zerosNum + zerosFar > 31)
1030                {
1031                    if (tmp32no1 > 0)
1032                    {
1033                        tmp32no2 = (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1,
1034                                                                        far_spectrum[i]);
1035                    } else
1036                    {
1037                        tmp32no2 = -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1,
1038                                                                         far_spectrum[i]);
1039                    }
1040                    shiftNum = 0;
1041                } else
1042                {
1043                    shiftNum = 32 - (zerosNum + zerosFar);
1044                    if (tmp32no1 > 0)
1045                    {
1046                        tmp32no2 = (int32_t)WEBRTC_SPL_UMUL_32_16(
1047                                WEBRTC_SPL_RSHIFT_W32(tmp32no1, shiftNum),
1048                                far_spectrum[i]);
1049                    } else
1050                    {
1051                        tmp32no2 = -(int32_t)WEBRTC_SPL_UMUL_32_16(
1052                                WEBRTC_SPL_RSHIFT_W32(-tmp32no1, shiftNum),
1053                                far_spectrum[i]);
1054                    }
1055                }
1056                // Normalize with respect to frequency bin
1057                tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
1058                // Make sure we are in the right Q-domain
1059                shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
1060                if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan)
1061                {
1062                    tmp32no2 = WEBRTC_SPL_WORD32_MAX;
1063                } else
1064                {
1065                    tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
1066                }
1067                aecm->channelAdapt32[i] = WEBRTC_SPL_ADD_SAT_W32(aecm->channelAdapt32[i],
1068                        tmp32no2);
1069                if (aecm->channelAdapt32[i] < 0)
1070                {
1071                    // We can never have negative channel gain
1072                    aecm->channelAdapt32[i] = 0;
1073                }
1074                aecm->channelAdapt16[i]
1075                        = (int16_t)WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], 16);
1076            }
1077        }
1078    }
1079    // END: Adaptive channel update
1080
1081    // Determine if we should store or restore the channel
1082    if ((aecm->startupState == 0) & (aecm->currentVADValue))
1083    {
1084        // During startup we store the channel every block,
1085        // and we recalculate echo estimate
1086        WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
1087    } else
1088    {
1089        if (aecm->farLogEnergy < aecm->farEnergyMSE)
1090        {
1091            aecm->mseChannelCount = 0;
1092        } else
1093        {
1094            aecm->mseChannelCount++;
1095        }
1096        // Enough data for validation. Store channel if we can.
1097        if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10))
1098        {
1099            // We have enough data.
1100            // Calculate MSE of "Adapt" and "Stored" versions.
1101            // It is actually not MSE, but average absolute error.
1102            mseStored = 0;
1103            mseAdapt = 0;
1104            for (i = 0; i < MIN_MSE_COUNT; i++)
1105            {
1106                tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i]
1107                        - (int32_t)aecm->nearLogEnergy[i]);
1108                tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
1109                mseStored += tmp32no2;
1110
1111                tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i]
1112                        - (int32_t)aecm->nearLogEnergy[i]);
1113                tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
1114                mseAdapt += tmp32no2;
1115            }
1116            if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt))
1117                    & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF
1118                            * aecm->mseAdaptOld)))
1119            {
1120                // The stored channel has a significantly lower MSE than the adaptive one for
1121                // two consecutive calculations. Reset the adaptive channel.
1122                WebRtcAecm_ResetAdaptiveChannel(aecm);
1123            } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt
1124                    < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold))
1125            {
1126                // The adaptive channel has a significantly lower MSE than the stored one.
1127                // The MSE for the adaptive channel has also been low for two consecutive
1128                // calculations. Store the adaptive channel.
1129                WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
1130
1131                // Update threshold
1132                if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX)
1133                {
1134                    aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
1135                } else
1136                {
1137                    aecm->mseThreshold += WEBRTC_SPL_MUL_16_16_RSFT(mseAdapt
1138                            - WEBRTC_SPL_MUL_16_16_RSFT(aecm->mseThreshold, 5, 3), 205, 8);
1139                }
1140
1141            }
1142
1143            // Reset counter
1144            aecm->mseChannelCount = 0;
1145
1146            // Store the MSE values.
1147            aecm->mseStoredOld = mseStored;
1148            aecm->mseAdaptOld = mseAdapt;
1149        }
1150    }
1151    // END: Determine if we should store or reset channel estimate.
1152}
1153
1154// CalcSuppressionGain(...)
1155//
1156// This function calculates the suppression gain that is used in the Wiener filter.
1157//
1158//
1159// @param  aecm     [i/n]   Handle of the AECM instance.
1160// @param  supGain  [out]   (Return value) Suppression gain with which to scale the noise
1161//                          level (Q14).
1162//
1163//
1164int16_t WebRtcAecm_CalcSuppressionGain(AecmCore_t * const aecm)
1165{
1166    int32_t tmp32no1;
1167
1168    int16_t supGain = SUPGAIN_DEFAULT;
1169    int16_t tmp16no1;
1170    int16_t dE = 0;
1171
1172    // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far
1173    // end energy and echo estimation error.
1174    // Adjust for the far end signal level. A low signal level indicates no far end signal,
1175    // hence we set the suppression gain to 0
1176    if (!aecm->currentVADValue)
1177    {
1178        supGain = 0;
1179    } else
1180    {
1181        // Adjust for possible double talk. If we have large variations in estimation error we
1182        // likely have double talk (or poor channel).
1183        tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET);
1184        dE = WEBRTC_SPL_ABS_W16(tmp16no1);
1185
1186        if (dE < ENERGY_DEV_TOL)
1187        {
1188            // Likely no double talk. The better estimation, the more we can suppress signal.
1189            // Update counters
1190            if (dE < SUPGAIN_EPC_DT)
1191            {
1192                tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffAB, dE);
1193                tmp32no1 += (SUPGAIN_EPC_DT >> 1);
1194                tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
1195                supGain = aecm->supGainErrParamA - tmp16no1;
1196            } else
1197            {
1198                tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffBD,
1199                                                (ENERGY_DEV_TOL - dE));
1200                tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
1201                tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL
1202                        - SUPGAIN_EPC_DT));
1203                supGain = aecm->supGainErrParamD + tmp16no1;
1204            }
1205        } else
1206        {
1207            // Likely in double talk. Use default value
1208            supGain = aecm->supGainErrParamD;
1209        }
1210    }
1211
1212    if (supGain > aecm->supGainOld)
1213    {
1214        tmp16no1 = supGain;
1215    } else
1216    {
1217        tmp16no1 = aecm->supGainOld;
1218    }
1219    aecm->supGainOld = supGain;
1220    if (tmp16no1 < aecm->supGain)
1221    {
1222        aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
1223    } else
1224    {
1225        aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
1226    }
1227
1228    // END: Update suppression gain
1229
1230    return aecm->supGain;
1231}
1232
1233void WebRtcAecm_BufferFarFrame(AecmCore_t* const aecm,
1234                               const int16_t* const farend,
1235                               const int farLen)
1236{
1237    int writeLen = farLen, writePos = 0;
1238
1239    // Check if the write position must be wrapped
1240    while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN)
1241    {
1242        // Write to remaining buffer space before wrapping
1243        writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
1244        memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
1245               sizeof(int16_t) * writeLen);
1246        aecm->farBufWritePos = 0;
1247        writePos = writeLen;
1248        writeLen = farLen - writeLen;
1249    }
1250
1251    memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
1252           sizeof(int16_t) * writeLen);
1253    aecm->farBufWritePos += writeLen;
1254}
1255
1256void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, int16_t * const farend,
1257                              const int farLen, const int knownDelay)
1258{
1259    int readLen = farLen;
1260    int readPos = 0;
1261    int delayChange = knownDelay - aecm->lastKnownDelay;
1262
1263    aecm->farBufReadPos -= delayChange;
1264
1265    // Check if delay forces a read position wrap
1266    while (aecm->farBufReadPos < 0)
1267    {
1268        aecm->farBufReadPos += FAR_BUF_LEN;
1269    }
1270    while (aecm->farBufReadPos > FAR_BUF_LEN - 1)
1271    {
1272        aecm->farBufReadPos -= FAR_BUF_LEN;
1273    }
1274
1275    aecm->lastKnownDelay = knownDelay;
1276
1277    // Check if read position must be wrapped
1278    while (aecm->farBufReadPos + readLen > FAR_BUF_LEN)
1279    {
1280
1281        // Read from remaining buffer space before wrapping
1282        readLen = FAR_BUF_LEN - aecm->farBufReadPos;
1283        memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
1284               sizeof(int16_t) * readLen);
1285        aecm->farBufReadPos = 0;
1286        readPos = readLen;
1287        readLen = farLen - readLen;
1288    }
1289    memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
1290           sizeof(int16_t) * readLen);
1291    aecm->farBufReadPos += readLen;
1292}
Note: See TracBrowser for help on using the repository browser.