1e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org/*
2e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org *
4e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org */
10e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
11e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#include "webrtc/modules/audio_processing/aecm/aecm_core.h"
12e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
13e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#include <assert.h>
14e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#include <stddef.h>
15e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#include <stdlib.h>
16e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
176b6301588ef2d7b5f5d442aa95bef442a43ead53andrew@webrtc.org#include "webrtc/common_audio/ring_buffer.h"
18e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#include "webrtc/common_audio/signal_processing/include/real_fft.h"
199b72af94cd61782ada88f777b07854daf9657bb2Henrik Kjellander#include "webrtc/modules/audio_processing/aecm/echo_control_mobile.h"
20e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
2198f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/compile_assert_c.h"
2298f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
23e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#include "webrtc/typedefs.h"
24e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
25e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org// Square root of Hanning window in Q14.
26cb7f8ce2df7564546936d3041a96ccc86a90f988Andrew MacDonald#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
27e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org// Table is defined in an ARM assembly file.
28e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.orgextern const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END;
29e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#else
30e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.orgstatic const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = {
31e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
32e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224,
33e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040,
34e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514,
35e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553,
36e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079,
37e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034,
38e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384
39e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org};
40e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#endif
41e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
42e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#ifdef AECM_WITH_ABS_APPROX
43e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//Q15 alpha = 0.99439986968132  const Factor for magnitude approximation
44e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.orgstatic const uint16_t kAlpha1 = 32584;
45e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//Q15 beta = 0.12967166976970   const Factor for magnitude approximation
46e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.orgstatic const uint16_t kBeta1 = 4249;
47e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//Q15 alpha = 0.94234827210087  const Factor for magnitude approximation
48e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.orgstatic const uint16_t kAlpha2 = 30879;
49e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//Q15 beta = 0.33787806009150   const Factor for magnitude approximation
50e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.orgstatic const uint16_t kBeta2 = 11072;
51e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//Q15 alpha = 0.82247698684306  const Factor for magnitude approximation
52e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.orgstatic const uint16_t kAlpha3 = 26951;
53e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//Q15 beta = 0.57762063060713   const Factor for magnitude approximation
54e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.orgstatic const uint16_t kBeta3 = 18927;
55e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#endif
56e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
57e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.orgstatic const int16_t kNoiseEstQDomain = 15;
58e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.orgstatic const int16_t kNoiseEstIncCount = 5;
59e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
60e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.orgstatic void ComfortNoise(AecmCore* aecm,
61e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                         const uint16_t* dfa,
62e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                         ComplexInt16* out,
63e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                         const int16_t* lambda);
64e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
65e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.orgstatic void WindowAndFFT(AecmCore* aecm,
66e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                         int16_t* fft,
67e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                         const int16_t* time_signal,
68e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                         ComplexInt16* freq_signal,
69e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                         int time_signal_scaling) {
70e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int i = 0;
71e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
72e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // FFT of signal
73e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  for (i = 0; i < PART_LEN; i++) {
74e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // Window time domain signal and insert into real part of
75e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // transformation array |fft|
76b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org    int16_t scaled_time_signal = time_signal[i] << time_signal_scaling;
77b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org    fft[i] = (int16_t)((scaled_time_signal * WebRtcAecm_kSqrtHanning[i]) >> 14);
78b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org    scaled_time_signal = time_signal[i + PART_LEN] << time_signal_scaling;
79b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org    fft[PART_LEN + i] = (int16_t)((
80b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org        scaled_time_signal * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14);
81e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
82e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
83e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Do forward FFT, then take only the first PART_LEN complex samples,
84e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // and change signs of the imaginary parts.
85e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  WebRtcSpl_RealForwardFFT(aecm->real_fft, fft, (int16_t*)freq_signal);
86e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  for (i = 0; i < PART_LEN; i++) {
87e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    freq_signal[i].imag = -freq_signal[i].imag;
88e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
89e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org}
90e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
91e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.orgstatic void InverseFFTAndWindow(AecmCore* aecm,
92e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                int16_t* fft,
93e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                                ComplexInt16* efw,
94e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                int16_t* output,
95e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                                const int16_t* nearendClean) {
96e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int i, j, outCFFT;
97e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t tmp32no1;
98e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Reuse |efw| for the inverse FFT output after transferring
99e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // the contents to |fft|.
100e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t* ifft_out = (int16_t*)efw;
101e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
102e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Synthesis
103e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  for (i = 1, j = 2; i < PART_LEN; i += 1, j += 2) {
104e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    fft[j] = efw[i].real;
105e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    fft[j + 1] = -efw[i].imag;
106e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
107e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  fft[0] = efw[0].real;
108e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  fft[1] = -efw[0].imag;
109e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
110e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  fft[PART_LEN2] = efw[PART_LEN].real;
111e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  fft[PART_LEN2 + 1] = -efw[PART_LEN].imag;
112e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
113e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Inverse FFT. Keep outCFFT to scale the samples in the next block.
114e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  outCFFT = WebRtcSpl_RealInverseFFT(aecm->real_fft, fft, ifft_out);
115e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  for (i = 0; i < PART_LEN; i++) {
116e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    ifft_out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
117e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                    ifft_out[i], WebRtcAecm_kSqrtHanning[i], 14);
118e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    tmp32no1 = WEBRTC_SPL_SHIFT_W32((int32_t)ifft_out[i],
119e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                     outCFFT - aecm->dfaCleanQDomain);
120e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    output[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
121e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                        tmp32no1 + aecm->outBuf[i],
122e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                        WEBRTC_SPL_WORD16_MIN);
123e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
124b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org    tmp32no1 = (ifft_out[PART_LEN + i] *
125b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org        WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14;
126e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1,
127e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                    outCFFT - aecm->dfaCleanQDomain);
128e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    aecm->outBuf[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
129e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                                tmp32no1,
130e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                                WEBRTC_SPL_WORD16_MIN);
131e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
132e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
133e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Copy the current block to the old position
134e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // (aecm->outBuf is shifted elsewhere)
135e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(int16_t) * PART_LEN);
136e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  memcpy(aecm->dBufNoisy,
137e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org         aecm->dBufNoisy + PART_LEN,
138e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org         sizeof(int16_t) * PART_LEN);
139e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (nearendClean != NULL)
140e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
141e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    memcpy(aecm->dBufClean,
142e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org           aecm->dBufClean + PART_LEN,
143e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org           sizeof(int16_t) * PART_LEN);
144e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
145e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org}
146e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
147e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org// Transforms a time domain signal into the frequency domain, outputting the
148e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org// complex valued signal, absolute value and sum of absolute values.
149e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//
150e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org// time_signal          [in]    Pointer to time domain signal
151e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org// freq_signal_real     [out]   Pointer to real part of frequency domain array
152e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org// freq_signal_imag     [out]   Pointer to imaginary part of frequency domain
153e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//                              array
154e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org// freq_signal_abs      [out]   Pointer to absolute value of frequency domain
155e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//                              array
156e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org// freq_signal_sum_abs  [out]   Pointer to the sum of all absolute values in
157e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//                              the frequency domain array
158e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org// return value                 The Q-domain of current frequency values
159e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org//
160e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.orgstatic int TimeToFrequencyDomain(AecmCore* aecm,
161e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                 const int16_t* time_signal,
162e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                                 ComplexInt16* freq_signal,
163e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                 uint16_t* freq_signal_abs,
164e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                                 uint32_t* freq_signal_sum_abs) {
165e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int i = 0;
166e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int time_signal_scaling = 0;
167e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
168e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t tmp32no1 = 0;
169e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t tmp32no2 = 0;
170e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
171e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // In fft_buf, +16 for 32-byte alignment.
172e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t fft_buf[PART_LEN4 + 16];
173e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t *fft = (int16_t *) (((uintptr_t) fft_buf + 31) & ~31);
174e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
175e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t tmp16no1;
176e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#ifndef WEBRTC_ARCH_ARM_V7
177e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t tmp16no2;
178e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#endif
179e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#ifdef AECM_WITH_ABS_APPROX
180e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t max_value = 0;
181e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t min_value = 0;
182e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint16_t alpha = 0;
183e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint16_t beta = 0;
184e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#endif
185e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
186e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#ifdef AECM_DYNAMIC_Q
187e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2);
188e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  time_signal_scaling = WebRtcSpl_NormW16(tmp16no1);
189e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#endif
190e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
191e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  WindowAndFFT(aecm, fft, time_signal, freq_signal, time_signal_scaling);
192e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
193e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Extract imaginary and real part, calculate the magnitude for
194e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // all frequency bins
195e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  freq_signal[0].imag = 0;
196e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  freq_signal[PART_LEN].imag = 0;
197e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  freq_signal_abs[0] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[0].real);
198e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  freq_signal_abs[PART_LEN] = (uint16_t)WEBRTC_SPL_ABS_W16(
199e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                freq_signal[PART_LEN].real);
200e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  (*freq_signal_sum_abs) = (uint32_t)(freq_signal_abs[0]) +
201e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                           (uint32_t)(freq_signal_abs[PART_LEN]);
202e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
203e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  for (i = 1; i < PART_LEN; i++)
204e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
205e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    if (freq_signal[i].real == 0)
206e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
207e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
208e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
209e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    else if (freq_signal[i].imag == 0)
210e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
211e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].real);
212e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
213e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    else
214e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
215e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Approximation for magnitude of complex fft output
216e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // magn = sqrt(real^2 + imag^2)
217e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
218e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      //
219e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // The parameters alpha and beta are stored in Q15
220e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
221e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#ifdef AECM_WITH_ABS_APPROX
222e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
223e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
224e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
225e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      if(tmp16no1 > tmp16no2)
226e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
227e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        max_value = tmp16no1;
228e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        min_value = tmp16no2;
229e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      } else
230e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
231e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        max_value = tmp16no2;
232e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        min_value = tmp16no1;
233e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
234e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
235e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Magnitude in Q(-6)
236e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      if ((max_value >> 2) > min_value)
237e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
238e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        alpha = kAlpha1;
239e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        beta = kBeta1;
240e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      } else if ((max_value >> 1) > min_value)
241e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
242e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        alpha = kAlpha2;
243e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        beta = kBeta2;
244e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      } else
245e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
246e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        alpha = kAlpha3;
247e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        beta = kBeta3;
248e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
249b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org      tmp16no1 = (int16_t)((max_value * alpha) >> 15);
250b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org      tmp16no2 = (int16_t)((min_value * beta) >> 15);
251e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      freq_signal_abs[i] = (uint16_t)tmp16no1 + (uint16_t)tmp16no2;
252e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#else
253e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#ifdef WEBRTC_ARCH_ARM_V7
254e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      __asm __volatile(
255e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        "smulbb %[tmp32no1], %[real], %[real]\n\t"
256e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        "smlabb %[tmp32no2], %[imag], %[imag], %[tmp32no1]\n\t"
257aafd7a88c50b21ab2ac56e9a53ba3f04c199f625bjornv@webrtc.org        :[tmp32no1]"+&r"(tmp32no1),
258e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org         [tmp32no2]"=r"(tmp32no2)
259e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        :[real]"r"(freq_signal[i].real),
260e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org         [imag]"r"(freq_signal[i].imag)
261e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      );
262e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#else
263e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
264e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
265758d6d431ef527130ab95cd20f0e42bb543d6da8bjornv@webrtc.org      tmp32no1 = tmp16no1 * tmp16no1;
266758d6d431ef527130ab95cd20f0e42bb543d6da8bjornv@webrtc.org      tmp32no2 = tmp16no2 * tmp16no2;
2676e71d17bc98d3b179f55fd4fd42dc5c53b7787dcbjornv@webrtc.org      tmp32no2 = WebRtcSpl_AddSatW32(tmp32no1, tmp32no2);
268e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#endif // WEBRTC_ARCH_ARM_V7
269e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2);
270e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
271e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      freq_signal_abs[i] = (uint16_t)tmp32no1;
272e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org#endif // AECM_WITH_ABS_APPROX
273e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
274e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    (*freq_signal_sum_abs) += (uint32_t)freq_signal_abs[i];
275e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
276e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
277e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  return time_signal_scaling;
278e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org}
279e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
280e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.orgint WebRtcAecm_ProcessBlock(AecmCore* aecm,
281e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                            const int16_t* farend,
282e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                            const int16_t* nearendNoisy,
283e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                            const int16_t* nearendClean,
284e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                            int16_t* output) {
285e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int i;
286e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
287e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint32_t xfaSum;
288e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint32_t dfaNoisySum;
289e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint32_t dfaCleanSum;
290e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint32_t echoEst32Gained;
291e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint32_t tmpU32;
292e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
293e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t tmp32no1;
294e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
295e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint16_t xfa[PART_LEN1];
296e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint16_t dfaNoisy[PART_LEN1];
297e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint16_t dfaClean[PART_LEN1];
298e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uint16_t* ptrDfaClean = dfaClean;
299e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  const uint16_t* far_spectrum_ptr = NULL;
300e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
301e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // 32 byte aligned buffers (with +8 or +16).
302e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org  // TODO(kma): define fft with ComplexInt16.
303e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe.
304e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t echoEst32_buf[PART_LEN1 + 8];
305e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t dfw_buf[PART_LEN2 + 8];
306e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t efw_buf[PART_LEN2 + 8];
307e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
308e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t* fft = (int16_t*) (((uintptr_t) fft_buf + 31) & ~ 31);
309e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t* echoEst32 = (int32_t*) (((uintptr_t) echoEst32_buf + 31) & ~ 31);
310e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org  ComplexInt16* dfw = (ComplexInt16*)(((uintptr_t)dfw_buf + 31) & ~31);
311e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org  ComplexInt16* efw = (ComplexInt16*)(((uintptr_t)efw_buf + 31) & ~31);
312e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
313e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t hnl[PART_LEN1];
314e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t numPosCoef = 0;
315e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t nlpGain = ONE_Q14;
316e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int delay;
317e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t tmp16no1;
318e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t tmp16no2;
319e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t mu;
320e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t supGain;
321e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t zeros32, zeros16;
322e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t zerosDBufNoisy, zerosDBufClean, zerosXBuf;
323e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int far_q;
324c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org  int16_t resolutionDiff, qDomainDiff, dfa_clean_q_domain_diff;
325e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
326e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  const int kMinPrefBand = 4;
327e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  const int kMaxPrefBand = 24;
328e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t avgHnl32 = 0;
329e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
330e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Determine startup state. There are three states:
331e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // (0) the first CONV_LEN blocks
332e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // (1) another CONV_LEN blocks
333e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // (2) the rest
334e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
335e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (aecm->startupState < 2)
336e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
337e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    aecm->startupState = (aecm->totCount >= CONV_LEN) +
338e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                         (aecm->totCount >= CONV_LEN2);
339e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
340e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // END: Determine startup state
341e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
342e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Buffer near and far end signals
343e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  memcpy(aecm->xBuf + PART_LEN, farend, sizeof(int16_t) * PART_LEN);
344e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(int16_t) * PART_LEN);
345e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (nearendClean != NULL)
346e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
347e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    memcpy(aecm->dBufClean + PART_LEN,
348e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org           nearendClean,
349e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org           sizeof(int16_t) * PART_LEN);
350e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
351e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
352e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Transform far end signal from time domain to frequency domain.
353e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  far_q = TimeToFrequencyDomain(aecm,
354e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                aecm->xBuf,
355e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                dfw,
356e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                xfa,
357e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                &xfaSum);
358e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
359e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Transform noisy near end signal from time domain to frequency domain.
360e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  zerosDBufNoisy = TimeToFrequencyDomain(aecm,
361e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                         aecm->dBufNoisy,
362e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                         dfw,
363e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                         dfaNoisy,
364e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                         &dfaNoisySum);
365e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain;
366e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  aecm->dfaNoisyQDomain = (int16_t)zerosDBufNoisy;
367e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
368e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
369e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (nearendClean == NULL)
370e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
371e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    ptrDfaClean = dfaNoisy;
372e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld;
373e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain;
374e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    dfaCleanSum = dfaNoisySum;
375e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  } else
376e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
377e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // Transform clean near end signal from time domain to frequency domain.
378e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    zerosDBufClean = TimeToFrequencyDomain(aecm,
379e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                           aecm->dBufClean,
380e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                           dfw,
381e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                           dfaClean,
382e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                           &dfaCleanSum);
383e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain;
384e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    aecm->dfaCleanQDomain = (int16_t)zerosDBufClean;
385e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
386e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
387e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Get the delay
388e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Save far-end history and estimate delay
389e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  WebRtcAecm_UpdateFarHistory(aecm, xfa, far_q);
390e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend,
391e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                               xfa,
392e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                               PART_LEN1,
393e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                               far_q) == -1) {
394e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    return -1;
395e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
396e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator,
397e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                          dfaNoisy,
398e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                          PART_LEN1,
399e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                          zerosDBufNoisy);
400e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (delay == -1)
401e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
402e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    return -1;
403e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
404e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  else if (delay == -2)
405e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
406e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // If the delay is unknown, we assume zero.
407e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // NOTE: this will have to be adjusted if we ever add lookahead.
408e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    delay = 0;
409e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
410e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
411e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (aecm->fixedDelay >= 0)
412e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
413e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // Use fixed delay
414e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    delay = aecm->fixedDelay;
415e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
416e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
417e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Get aligned far end spectrum
418e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  far_spectrum_ptr = WebRtcAecm_AlignedFarend(aecm, &far_q, delay);
419e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  zerosXBuf = (int16_t) far_q;
420e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (far_spectrum_ptr == NULL)
421e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
422e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    return -1;
423e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
424e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
425e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Calculate log(energy) and update energy threshold levels
426e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  WebRtcAecm_CalcEnergies(aecm,
427e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                          far_spectrum_ptr,
428e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                          zerosXBuf,
429e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                          dfaNoisySum,
430e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                          echoEst32);
431e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
432e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Calculate stepsize
433e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  mu = WebRtcAecm_CalcStepSize(aecm);
434e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
435e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Update counters
436e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  aecm->totCount++;
437e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
438e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // This is the channel estimation algorithm.
439e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // It is base on NLMS but has a variable step length,
440e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // which was calculated above.
441e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  WebRtcAecm_UpdateChannel(aecm,
442e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                           far_spectrum_ptr,
443e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                           zerosXBuf,
444e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                           dfaNoisy,
445e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                           mu,
446e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                           echoEst32);
447e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  supGain = WebRtcAecm_CalcSuppressionGain(aecm);
448e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
449e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
450e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Calculate Wiener filter hnl[]
451e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  for (i = 0; i < PART_LEN1; i++)
452e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
453e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // Far end signal through channel estimate in Q8
454e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // How much can we shift right to preserve resolution
455e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    tmp32no1 = echoEst32[i] - aecm->echoFilt[i];
456926707b167e9bfb876c7c903dcefc41c84e5fedbbjornv@webrtc.org    aecm->echoFilt[i] += (tmp32no1 * 50) >> 8;
457e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
458e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1;
459e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    zeros16 = WebRtcSpl_NormW16(supGain) + 1;
460e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    if (zeros32 + zeros16 > 16)
461e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
462e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Multiplication is safe
463e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Result in
464e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+
465e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      //   aecm->xfaQDomainBuf[diff])
466e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
467e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                              (uint16_t)supGain);
468e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
469e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
470e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    } else
471e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
472e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      tmp16no1 = 17 - zeros32 - zeros16;
473e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 -
474e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                       RESOLUTION_SUPGAIN;
475e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
476e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      if (zeros32 > tmp16no1)
477e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
478e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
479d4fe8248621223b12fd2e3907c7c19e0f6837a26bjornv@webrtc.org                                                supGain >> tmp16no1);
480e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      } else
481e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
482e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
483f87c0aff7f222174916091da8071d0c57cbe5125bjornv@webrtc.org        echoEst32Gained = (aecm->echoFilt[i] >> tmp16no1) * supGain;
484e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
485e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
486e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
487e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]);
488c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org    assert(zeros16 >= 0);  // |zeros16| is a norm, hence non-negative.
489c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org    dfa_clean_q_domain_diff = aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld;
490c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org    if (zeros16 < dfa_clean_q_domain_diff && aecm->nearFilt[i]) {
491c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org      tmp16no1 = aecm->nearFilt[i] << zeros16;
492c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org      qDomainDiff = zeros16 - dfa_clean_q_domain_diff;
493c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org      tmp16no2 = ptrDfaClean[i] >> -qDomainDiff;
494c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org    } else {
495c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org      tmp16no1 = dfa_clean_q_domain_diff < 0
496c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org          ? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff
497c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org          : aecm->nearFilt[i] << dfa_clean_q_domain_diff;
498e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      qDomainDiff = 0;
499c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org      tmp16no2 = ptrDfaClean[i];
500e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
501e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    tmp32no1 = (int32_t)(tmp16no2 - tmp16no1);
502f87c0aff7f222174916091da8071d0c57cbe5125bjornv@webrtc.org    tmp16no2 = (int16_t)(tmp32no1 >> 4);
503e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    tmp16no2 += tmp16no1;
504e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    zeros16 = WebRtcSpl_NormW16(tmp16no2);
505c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org    if ((tmp16no2) & (-qDomainDiff > zeros16)) {
506e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX;
507c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org    } else {
508c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org      aecm->nearFilt[i] = qDomainDiff < 0 ? tmp16no2 << -qDomainDiff
509c0ba4392f18f083839673c97f3f63015a72a8bb5bjornv@webrtc.org                                          : tmp16no2 >> qDomainDiff;
510e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
511e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
512e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // Wiener filter coefficients, resulting hnl in Q14
513e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    if (echoEst32Gained == 0)
514e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
515e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      hnl[i] = ONE_Q14;
516e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    } else if (aecm->nearFilt[i] == 0)
517e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
518e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      hnl[i] = 0;
519e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    } else
520e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
521e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Multiply the suppression gain
522e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Rounding
523e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      echoEst32Gained += (uint32_t)(aecm->nearFilt[i] >> 1);
524e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained,
525e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                   (uint16_t)aecm->nearFilt[i]);
526e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
527e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Current resolution is
528e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN- max(0,17-zeros16- zeros32))
529e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Make sure we are in Q14
530e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      tmp32no1 = (int32_t)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff);
531e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      if (tmp32no1 > ONE_Q14)
532e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
533e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        hnl[i] = 0;
534e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      } else if (tmp32no1 < 0)
535e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
536e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        hnl[i] = ONE_Q14;
537e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      } else
538e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
539e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // 1-echoEst/dfa
540e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        hnl[i] = ONE_Q14 - (int16_t)tmp32no1;
541e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        if (hnl[i] < 0)
542e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        {
543e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org          hnl[i] = 0;
544e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        }
545e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
546e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
547e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    if (hnl[i])
548e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
549e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      numPosCoef++;
550e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
551e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
552e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Only in wideband. Prevent the gain in upper band from being larger than
553e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // in lower band.
554e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (aecm->mult == 2)
555e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
556e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause
557e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    //               speech distortion in double-talk.
558e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    for (i = 0; i < PART_LEN1; i++)
559e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
560b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org      hnl[i] = (int16_t)((hnl[i] * hnl[i]) >> 14);
561e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
562e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
563e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    for (i = kMinPrefBand; i <= kMaxPrefBand; i++)
564e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
565e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      avgHnl32 += (int32_t)hnl[i];
566e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
567e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    assert(kMaxPrefBand - kMinPrefBand + 1 > 0);
568e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1);
569e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
570e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    for (i = kMaxPrefBand; i < PART_LEN1; i++)
571e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
572e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      if (hnl[i] > (int16_t)avgHnl32)
573e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
574e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        hnl[i] = (int16_t)avgHnl32;
575e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
576e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
577e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
578e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
579e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Calculate NLP gain, result is in Q14
580e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (aecm->nlpFlag)
581e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
582e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    for (i = 0; i < PART_LEN1; i++)
583e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
584e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Truncate values close to zero and one.
585e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      if (hnl[i] > NLP_COMP_HIGH)
586e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
587e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        hnl[i] = ONE_Q14;
588e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      } else if (hnl[i] < NLP_COMP_LOW)
589e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
590e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        hnl[i] = 0;
591e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
592e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
593e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Remove outliers
594e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      if (numPosCoef < 3)
595e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
596e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        nlpGain = 0;
597e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      } else
598e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
599e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        nlpGain = ONE_Q14;
600e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
601e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
602e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // NLP
603e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14))
604e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
605e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        hnl[i] = ONE_Q14;
606e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      } else
607e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
608b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org        hnl[i] = (int16_t)((hnl[i] * nlpGain) >> 14);
609e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
610e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
611e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // multiply with Wiener coefficients
612e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      efw[i].real = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
613e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                                                   hnl[i], 14));
614e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      efw[i].imag = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
615e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                                                   hnl[i], 14));
616e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
617e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
618e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  else
619e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
620e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // multiply with Wiener coefficients
621e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    for (i = 0; i < PART_LEN1; i++)
622e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
623e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      efw[i].real = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
624e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                                                   hnl[i], 14));
625e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      efw[i].imag = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
626e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                                                                   hnl[i], 14));
627e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
628e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
629e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
630e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (aecm->cngMode == AecmTrue)
631e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
632e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    ComfortNoise(aecm, ptrDfaClean, efw, hnl);
633e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
634e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
635e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  InverseFFTAndWindow(aecm, fft, efw, output, nearendClean);
636e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
637e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  return 0;
638e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org}
639e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
640e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.orgstatic void ComfortNoise(AecmCore* aecm,
641e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                         const uint16_t* dfa,
642e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                         ComplexInt16* out,
643e468bc9e604213054e5fc73431ee127ebe0211a8pbos@webrtc.org                         const int16_t* lambda) {
644e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t i;
645e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t tmp16;
646e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t tmp32;
647e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
648e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t randW16[PART_LEN];
649e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t uReal[PART_LEN1];
650e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t uImag[PART_LEN1];
651e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int32_t outLShift32;
652e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t noiseRShift16[PART_LEN1];
653e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
654e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain;
655e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  int16_t minTrackShift;
656e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
657e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  assert(shiftFromNearToNoise >= 0);
658e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  assert(shiftFromNearToNoise < 16);
659e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
660e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  if (aecm->noiseEstCtr < 100)
661e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
662e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // Track the minimum more quickly initially.
663e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    aecm->noiseEstCtr++;
664e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    minTrackShift = 6;
665e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  } else
666e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
667e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    minTrackShift = 9;
668e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
669e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
670e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Estimate noise power.
671e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  for (i = 0; i < PART_LEN1; i++)
672e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
673e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // Shift to the noise domain.
674e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    tmp32 = (int32_t)dfa[i];
675750423c7227be04acf65472af0ee57ce47376fcbbjornv@webrtc.org    outLShift32 = tmp32 << shiftFromNearToNoise;
676e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
677e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    if (outLShift32 < aecm->noiseEst[i])
678e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
679e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Reset "too low" counter
680e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      aecm->noiseEstTooLowCtr[i] = 0;
681e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Track the minimum.
682e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      if (aecm->noiseEst[i] < (1 << minTrackShift))
683e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
684e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // For small values, decrease noiseEst[i] every
685e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // |kNoiseEstIncCount| block. The regular approach below can not
686e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // go further down due to truncation.
687e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        aecm->noiseEstTooHighCtr[i]++;
688e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount)
689e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        {
690e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org          aecm->noiseEst[i]--;
691e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org          aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter
692e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        }
693e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
694e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      else
695e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
696e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32)
697e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org                              >> minTrackShift);
698e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
699e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    } else
700e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
701e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Reset "too high" counter
702e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      aecm->noiseEstTooHighCtr[i] = 0;
703e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      // Ramp slowly upwards until we hit the minimum again.
704e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      if ((aecm->noiseEst[i] >> 19) > 0)
705e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
706e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // Avoid overflow.
707e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // Multiplication with 2049 will cause wrap around. Scale
708e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // down first and then multiply
709e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        aecm->noiseEst[i] >>= 11;
710e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        aecm->noiseEst[i] *= 2049;
711e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
712e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      else if ((aecm->noiseEst[i] >> 11) > 0)
713e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
714e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // Large enough for relative increase
715e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        aecm->noiseEst[i] *= 2049;
716e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        aecm->noiseEst[i] >>= 11;
717e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
718e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      else
719e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      {
720e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // Make incremental increases based on size every
721e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        // |kNoiseEstIncCount| block
722e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        aecm->noiseEstTooLowCtr[i]++;
723e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount)
724e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        {
725e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org          aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1;
726e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org          aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
727e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org        }
728e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      }
729e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
730e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
731e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
732e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  for (i = 0; i < PART_LEN1; i++)
733e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
734f87c0aff7f222174916091da8071d0c57cbe5125bjornv@webrtc.org    tmp32 = aecm->noiseEst[i] >> shiftFromNearToNoise;
735e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    if (tmp32 > 32767)
736e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    {
737e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org      tmp32 = 32767;
738750423c7227be04acf65472af0ee57ce47376fcbbjornv@webrtc.org      aecm->noiseEst[i] = tmp32 << shiftFromNearToNoise;
739e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    }
740e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    noiseRShift16[i] = (int16_t)tmp32;
741e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
742e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    tmp16 = ONE_Q14 - lambda[i];
743b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org    noiseRShift16[i] = (int16_t)((tmp16 * noiseRShift16[i]) >> 14);
744e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
745e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
746e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Generate a uniform random array on [0 2^15-1].
747e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
748e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
749e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  // Generate noise according to estimated energy.
750e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uReal[0] = 0; // Reject LF noise.
751e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uImag[0] = 0;
752e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  for (i = 1; i < PART_LEN1; i++)
753e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
754e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // Get a random index for the cos and sin tables over [0 359].
755b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org    tmp16 = (int16_t)((359 * randW16[i - 1]) >> 15);
756e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
757e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org    // Tables are in Q13.
758b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org    uReal[i] = (int16_t)((noiseRShift16[i] * WebRtcAecm_kCosTable[tmp16]) >>
759b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org        13);
760b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org    uImag[i] = (int16_t)((-noiseRShift16[i] * WebRtcAecm_kSinTable[tmp16]) >>
761b38b009d216bc6fc45934d8dafa9e7489ec8e91abjornv@webrtc.org        13);
762e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
763e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  uImag[PART_LEN] = 0;
764e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
765e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  for (i = 0; i < PART_LEN1; i++)
766e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  {
7676e71d17bc98d3b179f55fd4fd42dc5c53b7787dcbjornv@webrtc.org    out[i].real = WebRtcSpl_AddSatW16(out[i].real, uReal[i]);
7686e71d17bc98d3b179f55fd4fd42dc5c53b7787dcbjornv@webrtc.org    out[i].imag = WebRtcSpl_AddSatW16(out[i].imag, uImag[i]);
769e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org  }
770e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org}
771e03cafaebc767b2deb4d6350158e82afb6c6d3c4andrew@webrtc.org
772