aboutsummaryrefslogtreecommitdiff
path: root/src/modules/audio_processing/aecm/main/source
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2011-07-11 19:16:26 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-07-11 19:16:26 -0700
commit81fb7e291baf261ed747baf4539e97a01a417125 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /src/modules/audio_processing/aecm/main/source
parent4e51691e58d8d32590b03c1951cb13de4d1c4758 (diff)
downloadwebrtc-81fb7e291baf261ed747baf4539e97a01a417125.tar.gz
Revert "Added webrtc audio processing library"
This reverts commit 4e51691e58d8d32590b03c1951cb13de4d1c4758
Diffstat (limited to 'src/modules/audio_processing/aecm/main/source')
-rw-r--r--src/modules/audio_processing/aecm/main/source/Android.mk52
-rw-r--r--src/modules/audio_processing/aecm/main/source/aecm.gyp43
-rw-r--r--src/modules/audio_processing/aecm/main/source/aecm_core.c2534
-rw-r--r--src/modules/audio_processing/aecm/main/source/aecm_core.h338
-rw-r--r--src/modules/audio_processing/aecm/main/source/echo_control_mobile.c733
5 files changed, 0 insertions, 3700 deletions
diff --git a/src/modules/audio_processing/aecm/main/source/Android.mk b/src/modules/audio_processing/aecm/main/source/Android.mk
deleted file mode 100644
index ec18258d29..0000000000
--- a/src/modules/audio_processing/aecm/main/source/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
-#
-# Use of this source code is governed by a BSD-style license
-# that can be found in the LICENSE file in the root of the source
-# tree. An additional intellectual property rights grant can be found
-# in the file PATENTS. All contributing project authors may
-# be found in the AUTHORS file in the root of the source tree.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_ARM_MODE := arm
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := libwebrtc_aecm
-LOCAL_MODULE_TAGS := optional
-LOCAL_GENERATED_SOURCES :=
-LOCAL_SRC_FILES := echo_control_mobile.c \
- aecm_core.c
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS :=
-MY_CFLAGS_C :=
-MY_DEFS := '-DNO_TCMALLOC' \
- '-DNO_HEAPCHECKER' \
- '-DWEBRTC_TARGET_PC' \
- '-DWEBRTC_LINUX' \
- '-DWEBRTC_THREAD_RR' \
- '-DWEBRTC_ANDROID' \
- '-DANDROID'
-LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../.. \
- $(LOCAL_PATH)/../interface \
- $(LOCAL_PATH)/../../../utility \
- $(LOCAL_PATH)/../../../../../common_audio/signal_processing_library/main/interface
-
-# Flags passed to only C++ (and not C) files.
-LOCAL_CPPFLAGS :=
-
-LOCAL_LDFLAGS :=
-
-LOCAL_STATIC_LIBRARIES :=
-
-LOCAL_SHARED_LIBRARIES := libcutils \
- libdl \
- libstlport
-LOCAL_ADDITIONAL_DEPENDENCIES :=
-
-include external/stlport/libstlport.mk
-include $(BUILD_STATIC_LIBRARY)
diff --git a/src/modules/audio_processing/aecm/main/source/aecm.gyp b/src/modules/audio_processing/aecm/main/source/aecm.gyp
deleted file mode 100644
index a535d2b294..0000000000
--- a/src/modules/audio_processing/aecm/main/source/aecm.gyp
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
-#
-# Use of this source code is governed by a BSD-style license
-# that can be found in the LICENSE file in the root of the source
-# tree. An additional intellectual property rights grant can be found
-# in the file PATENTS. All contributing project authors may
-# be found in the AUTHORS file in the root of the source tree.
-
-{
- 'includes': [
- '../../../../../common_settings.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'aecm',
- 'type': '<(library)',
- 'dependencies': [
- '../../../../../common_audio/signal_processing_library/main/source/spl.gyp:spl',
- '../../../utility/util.gyp:apm_util'
- ],
- 'include_dirs': [
- '../interface',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '../interface',
- ],
- },
- 'sources': [
- '../interface/echo_control_mobile.h',
- 'echo_control_mobile.c',
- 'aecm_core.c',
- 'aecm_core.h',
- ],
- },
- ],
-}
-
-# Local Variables:
-# tab-width:2
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/src/modules/audio_processing/aecm/main/source/aecm_core.c b/src/modules/audio_processing/aecm/main/source/aecm_core.c
deleted file mode 100644
index f17f1bf237..0000000000
--- a/src/modules/audio_processing/aecm/main/source/aecm_core.c
+++ /dev/null
@@ -1,2534 +0,0 @@
-/*
- * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include <stdlib.h>
-
-#include "aecm_core.h"
-#include "ring_buffer.h"
-#include "echo_control_mobile.h"
-#include "typedefs.h"
-
-// TODO(bjornv): Will be removed in final version.
-//#include <stdio.h>
-
-#ifdef ARM_WINM_LOG
-#include <stdio.h>
-#include <windows.h>
-#endif
-
-// BANDLAST - BANDFIRST must be < 32
-#define BANDFIRST 12 // Only bit BANDFIRST through bit BANDLAST are processed
-#define BANDLAST 43
-
-#ifdef ARM_WINM
-#define WebRtcSpl_AddSatW32(a,b) _AddSatInt(a,b)
-#define WebRtcSpl_SubSatW32(a,b) _SubSatInt(a,b)
-#endif
-// 16 instructions on most risc machines for 32-bit bitcount !
-
-#ifdef AEC_DEBUG
-FILE *dfile;
-FILE *testfile;
-#endif
-
-#ifdef AECM_SHORT
-
-// Square root of Hanning window in Q14
-static const WebRtc_Word16 kSqrtHanning[] =
-{
- 0, 804, 1606, 2404, 3196, 3981, 4756, 5520,
- 6270, 7005, 7723, 8423, 9102, 9760, 10394, 11003,
- 11585, 12140, 12665, 13160, 13623, 14053, 14449, 14811,
- 15137, 15426, 15679, 15893, 16069, 16207, 16305, 16364,
- 16384
-};
-
-#else
-
-// Square root of Hanning window in Q14
-static const WebRtc_Word16 kSqrtHanning[] = {0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
- 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019, 8364,
- 8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514, 11795, 12068, 12335,
- 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189, 14384, 14571, 14749, 14918,
- 15079, 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034, 16111, 16179, 16237,
- 16286, 16325, 16354, 16373, 16384};
-
-#endif
-
-//Q15 alpha = 0.99439986968132 const Factor for magnitude approximation
-static const WebRtc_UWord16 kAlpha1 = 32584;
-//Q15 beta = 0.12967166976970 const Factor for magnitude approximation
-static const WebRtc_UWord16 kBeta1 = 4249;
-//Q15 alpha = 0.94234827210087 const Factor for magnitude approximation
-static const WebRtc_UWord16 kAlpha2 = 30879;
-//Q15 beta = 0.33787806009150 const Factor for magnitude approximation
-static const WebRtc_UWord16 kBeta2 = 11072;
-//Q15 alpha = 0.82247698684306 const Factor for magnitude approximation
-static const WebRtc_UWord16 kAlpha3 = 26951;
-//Q15 beta = 0.57762063060713 const Factor for magnitude approximation
-static const WebRtc_UWord16 kBeta3 = 18927;
-
-// Initialization table for echo channel in 8 kHz
-static const WebRtc_Word16 kChannelStored8kHz[PART_LEN1] = {
- 2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418,
- 1451, 1506, 1562, 1644, 1726, 1804, 1882, 1918,
- 1953, 1982, 2010, 2025, 2040, 2034, 2027, 2021,
- 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683,
- 1635, 1604, 1572, 1545, 1517, 1481, 1444, 1405,
- 1367, 1331, 1294, 1270, 1245, 1239, 1233, 1247,
- 1260, 1282, 1303, 1338, 1373, 1407, 1441, 1470,
- 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649,
- 1676
-};
-
-// Initialization table for echo channel in 16 kHz
-static const WebRtc_Word16 kChannelStored16kHz[PART_LEN1] = {
- 2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882,
- 1953, 2010, 2040, 2027, 2014, 1980, 1869, 1732,
- 1635, 1572, 1517, 1444, 1367, 1294, 1245, 1233,
- 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621,
- 1676, 1741, 1802, 1861, 1921, 1983, 2040, 2102,
- 2170, 2265, 2375, 2515, 2651, 2781, 2922, 3075,
- 3253, 3471, 3738, 3976, 4151, 4258, 4308, 4288,
- 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484,
- 3153
-};
-
-#ifdef ARM_WINM_LOG
-HANDLE logFile = NULL;
-#endif
-
-static void WebRtcAecm_ComfortNoise(AecmCore_t* const aecm, const WebRtc_UWord16 * const dfa,
- WebRtc_Word16 * const outReal,
- WebRtc_Word16 * const outImag,
- const WebRtc_Word16 * const lambda);
-
-static __inline WebRtc_UWord32 WebRtcAecm_SetBit(WebRtc_UWord32 in, WebRtc_Word32 pos)
-{
- WebRtc_UWord32 mask, out;
-
- mask = WEBRTC_SPL_SHIFT_W32(1, pos);
- out = (in | mask);
-
- return out;
-}
-
-// WebRtcAecm_Hisser(...)
-//
-// This function compares the binary vector specvec with all rows of the binary matrix specmat
-// and counts per row the number of times they have the same value.
-// Input:
-// - specvec : binary "vector" that is stored in a long
-// - specmat : binary "matrix" that is stored as a vector of long
-// Output:
-// - bcount : "Vector" stored as a long, containing for each row the number of times
-// the matrix row and the input vector have the same value
-//
-//
-void WebRtcAecm_Hisser(const WebRtc_UWord32 specvec, const WebRtc_UWord32 * const specmat,
- WebRtc_UWord32 * const bcount)
-{
- int n;
- WebRtc_UWord32 a, b;
- register WebRtc_UWord32 tmp;
-
- a = specvec;
- // compare binary vector specvec with all rows of the binary matrix specmat
- for (n = 0; n < MAX_DELAY; n++)
- {
- b = specmat[n];
- a = (specvec ^ b);
- // Returns bit counts in tmp
- tmp = a - ((a >> 1) & 033333333333) - ((a >> 2) & 011111111111);
- tmp = ((tmp + (tmp >> 3)) & 030707070707);
- tmp = (tmp + (tmp >> 6));
- tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077;
-
- bcount[n] = tmp;
- }
-}
-
-// WebRtcAecm_BSpectrum(...)
-//
-// Computes the binary spectrum by comparing the input spectrum with a threshold spectrum.
-//
-// Input:
-// - spectrum : Spectrum of which the binary spectrum should be calculated.
-// - thresvec : Threshold spectrum with which the input spectrum is compared.
-// Return:
-// - out : Binary spectrum
-//
-WebRtc_UWord32 WebRtcAecm_BSpectrum(const WebRtc_UWord16 * const spectrum,
- const WebRtc_UWord16 * const thresvec)
-{
- int k;
- WebRtc_UWord32 out;
-
- out = 0;
- for (k = BANDFIRST; k <= BANDLAST; k++)
- {
- if (spectrum[k] > thresvec[k])
- {
- out = WebRtcAecm_SetBit(out, k - BANDFIRST);
- }
- }
-
- return out;
-}
-
-// WebRtcAecm_MedianEstimator(...)
-//
-// Calculates the median recursively.
-//
-// Input:
-// - newVal : new additional value
-// - medianVec : vector with current medians
-// - factor : factor for smoothing
-//
-// Output:
-// - medianVec : vector with updated median
-//
-int WebRtcAecm_MedianEstimator(const WebRtc_UWord16 newVal, WebRtc_UWord16 * const medianVec,
- const int factor)
-{
- WebRtc_Word32 median;
- WebRtc_Word32 diff;
-
- median = (WebRtc_Word32)medianVec[0];
-
- //median = median + ((newVal-median)>>factor);
- diff = (WebRtc_Word32)newVal - median;
- diff = WEBRTC_SPL_SHIFT_W32(diff, -factor);
- median = median + diff;
-
- medianVec[0] = (WebRtc_UWord16)median;
-
- return 0;
-}
-
-int WebRtcAecm_CreateCore(AecmCore_t **aecmInst)
-{
- AecmCore_t *aecm = malloc(sizeof(AecmCore_t));
- *aecmInst = aecm;
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (WebRtcApm_CreateBuffer(&aecm->farFrameBuf, FRAME_LEN + PART_LEN) == -1)
- {
- WebRtcAecm_FreeCore(aecm);
- aecm = NULL;
- return -1;
- }
-
- if (WebRtcApm_CreateBuffer(&aecm->nearNoisyFrameBuf, FRAME_LEN + PART_LEN) == -1)
- {
- WebRtcAecm_FreeCore(aecm);
- aecm = NULL;
- return -1;
- }
-
- if (WebRtcApm_CreateBuffer(&aecm->nearCleanFrameBuf, FRAME_LEN + PART_LEN) == -1)
- {
- WebRtcAecm_FreeCore(aecm);
- aecm = NULL;
- return -1;
- }
-
- if (WebRtcApm_CreateBuffer(&aecm->outFrameBuf, FRAME_LEN + PART_LEN) == -1)
- {
- WebRtcAecm_FreeCore(aecm);
- aecm = NULL;
- return -1;
- }
-
- return 0;
-}
-
-// WebRtcAecm_InitCore(...)
-//
-// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
-// Input:
-// - aecm : Pointer to the Echo Suppression instance
-// - samplingFreq : Sampling Frequency
-//
-// Output:
-// - aecm : Initialized instance
-//
-// Return value : 0 - Ok
-// -1 - Error
-//
-int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq)
-{
- int retVal = 0;
- WebRtc_Word16 i;
- WebRtc_Word16 tmp16;
-
- if (samplingFreq != 8000 && samplingFreq != 16000)
- {
- samplingFreq = 8000;
- retVal = -1;
- }
- // sanity check of sampling frequency
- aecm->mult = (WebRtc_Word16)samplingFreq / 8000;
-
- aecm->farBufWritePos = 0;
- aecm->farBufReadPos = 0;
- aecm->knownDelay = 0;
- aecm->lastKnownDelay = 0;
-
- WebRtcApm_InitBuffer(aecm->farFrameBuf);
- WebRtcApm_InitBuffer(aecm->nearNoisyFrameBuf);
- WebRtcApm_InitBuffer(aecm->nearCleanFrameBuf);
- WebRtcApm_InitBuffer(aecm->outFrameBuf);
-
- memset(aecm->xBuf, 0, sizeof(aecm->xBuf));
- memset(aecm->dBufClean, 0, sizeof(aecm->dBufClean));
- memset(aecm->dBufNoisy, 0, sizeof(aecm->dBufNoisy));
- memset(aecm->outBuf, 0, sizeof(WebRtc_Word16) * PART_LEN);
-
- aecm->seed = 666;
- aecm->totCount = 0;
-
- memset(aecm->xfaHistory, 0, sizeof(WebRtc_UWord16) * (PART_LEN1) * MAX_DELAY);
-
- aecm->delHistoryPos = MAX_DELAY;
-
- memset(aecm->medianYlogspec, 0, sizeof(WebRtc_UWord16) * PART_LEN1);
- memset(aecm->medianXlogspec, 0, sizeof(WebRtc_UWord16) * PART_LEN1);
- memset(aecm->medianBCount, 0, sizeof(WebRtc_UWord16) * MAX_DELAY);
- memset(aecm->bxHistory, 0, sizeof(aecm->bxHistory));
-
- // Initialize to reasonable values
- aecm->currentDelay = 8;
- aecm->previousDelay = 8;
- aecm->delayAdjust = 0;
-
- aecm->nlpFlag = 1;
- aecm->fixedDelay = -1;
-
- memset(aecm->xfaQDomainBuf, 0, sizeof(WebRtc_Word16) * MAX_DELAY);
- aecm->dfaCleanQDomain = 0;
- aecm->dfaCleanQDomainOld = 0;
- aecm->dfaNoisyQDomain = 0;
- aecm->dfaNoisyQDomainOld = 0;
-
- memset(aecm->nearLogEnergy, 0, sizeof(WebRtc_Word16) * MAX_BUF_LEN);
- memset(aecm->farLogEnergy, 0, sizeof(WebRtc_Word16) * MAX_BUF_LEN);
- memset(aecm->echoAdaptLogEnergy, 0, sizeof(WebRtc_Word16) * MAX_BUF_LEN);
- memset(aecm->echoStoredLogEnergy, 0, sizeof(WebRtc_Word16) * MAX_BUF_LEN);
-
- // Initialize the echo channels with a stored shape.
- if (samplingFreq == 8000)
- {
- memcpy(aecm->channelAdapt16, kChannelStored8kHz, sizeof(WebRtc_Word16) * PART_LEN1);
- }
- else
- {
- memcpy(aecm->channelAdapt16, kChannelStored16kHz, sizeof(WebRtc_Word16) * PART_LEN1);
- }
- memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(WebRtc_Word16) * PART_LEN1);
- for (i = 0; i < PART_LEN1; i++)
- {
- aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
- (WebRtc_Word32)(aecm->channelAdapt16[i]), 16);
- }
-
- memset(aecm->echoFilt, 0, sizeof(WebRtc_Word32) * PART_LEN1);
- memset(aecm->nearFilt, 0, sizeof(WebRtc_Word16) * PART_LEN1);
- aecm->noiseEstCtr = 0;
-
- aecm->cngMode = AecmTrue;
-
- // Increase the noise Q domain with increasing frequency, to correspond to the
- // expected energy levels.
- // Also shape the initial noise level with this consideration.
-#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
- for (i = 0; i < PART_LEN1; i++)
- {
- if (i < PART_LEN1 >> 2)
- {
- aecm->noiseEstQDomain[i] = 10;
- tmp16 = PART_LEN1 - i;
- aecm->noiseEst[i] = (tmp16 * tmp16) << 4;
- } else if (i < PART_LEN1 >> 1)
- {
- aecm->noiseEstQDomain[i] = 11;
- tmp16 = PART_LEN1 - i;
- aecm->noiseEst[i] = ((tmp16 * tmp16) << 4) << 1;
- } else
- {
- aecm->noiseEstQDomain[i] = 12;
- aecm->noiseEst[i] = aecm->noiseEst[(PART_LEN1 >> 1) - 1] << 1;
- }
- }
-#else
- for (i = 0; i < PART_LEN1 >> 2; i++)
- {
- aecm->noiseEstQDomain[i] = 10;
- tmp16 = PART_LEN1 - i;
- aecm->noiseEst[i] = (tmp16 * tmp16) << 4;
- }
- for (; i < PART_LEN1 >> 1; i++)
- {
- aecm->noiseEstQDomain[i] = 11;
- tmp16 = PART_LEN1 - i;
- aecm->noiseEst[i] = ((tmp16 * tmp16) << 4) << 1;
- }
- for (; i < PART_LEN1; i++)
- {
- aecm->noiseEstQDomain[i] = 12;
- aecm->noiseEst[i] = aecm->noiseEst[(PART_LEN1 >> 1) - 1] << 1;
- }
-#endif
-
- aecm->mseAdaptOld = 1000;
- aecm->mseStoredOld = 1000;
- aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
-
- aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
- aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
- aecm->farEnergyMaxMin = 0;
- aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the
- // beginning.
- aecm->farEnergyMSE = 0;
- aecm->currentVADValue = 0;
- aecm->vadUpdateCount = 0;
- aecm->firstVAD = 1;
-
- aecm->delayCount = 0;
- aecm->newDelayCorrData = 0;
- aecm->lastDelayUpdateCount = 0;
- memset(aecm->delayCorrelation, 0, sizeof(WebRtc_Word16) * ((CORR_MAX << 1) + 1));
-
- aecm->startupState = 0;
- aecm->mseChannelCount = 0;
- aecm->supGain = SUPGAIN_DEFAULT;
- aecm->supGainOld = SUPGAIN_DEFAULT;
- aecm->delayOffsetFlag = 0;
-
- memset(aecm->delayHistogram, 0, sizeof(aecm->delayHistogram));
- aecm->delayVadCount = 0;
- aecm->maxDelayHistIdx = 0;
- aecm->lastMinPos = 0;
-
- aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
- aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
- aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
- aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
-
- return 0;
-}
-
-int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag, int delayOffsetFlag)
-{
- aecm->nlpFlag = nlpFlag;
- aecm->fixedDelay = delay;
- aecm->delayOffsetFlag = delayOffsetFlag;
-
- return 0;
-}
-
-// WebRtcAecm_GetNewDelPos(...)
-//
-// Moves the pointer to the next entry. Returns to zero if max position reached.
-//
-// Input:
-// - aecm : Pointer to the AECM instance
-// Return:
-// - pos : New position in the history.
-//
-//
-WebRtc_Word16 WebRtcAecm_GetNewDelPos(AecmCore_t * const aecm)
-{
- WebRtc_Word16 pos;
-
- pos = aecm->delHistoryPos;
- pos++;
- if (pos >= MAX_DELAY)
- {
- pos = 0;
- }
- aecm->delHistoryPos = pos;
-
- return pos;
-}
-
-// WebRtcAecm_EstimateDelay(...)
-//
-// Estimate the delay of the echo signal.
-//
-// Inputs:
-// - aecm : Pointer to the AECM instance
-// - farSpec : Delayed farend magnitude spectrum
-// - nearSpec : Nearend magnitude spectrum
-// - stages : Q-domain of xxFIX and yyFIX (without dynamic Q-domain)
-// - xfaQ : normalization factor, i.e., Q-domain before FFT
-// Return:
-// - delay : Estimated delay
-//
-WebRtc_Word16 WebRtcAecm_EstimateDelay(AecmCore_t * const aecm,
- const WebRtc_UWord16 * const farSpec,
- const WebRtc_UWord16 * const nearSpec,
- const WebRtc_Word16 xfaQ)
-{
- WebRtc_UWord32 bxspectrum, byspectrum;
- WebRtc_UWord32 bcount[MAX_DELAY];
-
- int i, res;
-
- WebRtc_UWord16 xmean[PART_LEN1], ymean[PART_LEN1];
- WebRtc_UWord16 dtmp1;
- WebRtc_Word16 fcount[MAX_DELAY];
-
- //WebRtc_Word16 res;
- WebRtc_Word16 histpos;
- WebRtc_Word16 maxHistLvl;
- WebRtc_UWord16 *state;
- WebRtc_Word16 minpos = -1;
-
- enum
- {
- kVadCountThreshold = 25
- };
- enum
- {
- kMaxHistogram = 600
- };
-
- histpos = WebRtcAecm_GetNewDelPos(aecm);
-
- for (i = 0; i < PART_LEN1; i++)
- {
- aecm->xfaHistory[i][histpos] = farSpec[i];
-
- state = &(aecm->medianXlogspec[i]);
- res = WebRtcAecm_MedianEstimator(farSpec[i], state, 6);
-
- state = &(aecm->medianYlogspec[i]);
- res = WebRtcAecm_MedianEstimator(nearSpec[i], state, 6);
-
- // Mean:
- // FLOAT:
- // ymean = dtmp2/MAX_DELAY
- //
- // FIX:
- // input: dtmp2FIX in Q0
- // output: ymeanFIX in Q8
- // 20 = 1/MAX_DELAY in Q13 = 1/MAX_DELAY * 2^13
- xmean[i] = (aecm->medianXlogspec[i]);
- ymean[i] = (aecm->medianYlogspec[i]);
-
- }
- // Update Q-domain buffer
- aecm->xfaQDomainBuf[histpos] = xfaQ;
-
- // Get binary spectra
- // FLOAT:
- // bxspectrum = bspectrum(xlogspec, xmean);
- //
- // FIX:
- // input: xlogspecFIX,ylogspecFIX in Q8
- // xmeanFIX, ymeanFIX in Q8
- // output: unsigned long bxspectrum, byspectrum in Q0
- bxspectrum = WebRtcAecm_BSpectrum(farSpec, xmean);
- byspectrum = WebRtcAecm_BSpectrum(nearSpec, ymean);
-
- // Shift binary spectrum history
- memmove(&(aecm->bxHistory[1]), &(aecm->bxHistory[0]),
- (MAX_DELAY - 1) * sizeof(WebRtc_UWord32));
-
- aecm->bxHistory[0] = bxspectrum;
-
- // Compare with delayed spectra
- WebRtcAecm_Hisser(byspectrum, aecm->bxHistory, bcount);
-
- for (i = 0; i < MAX_DELAY; i++)
- {
- // Update sum
- // bcount is constrained to [0, 32], meaning we can smooth with a factor up to 2^11.
- dtmp1 = (WebRtc_UWord16)bcount[i];
- dtmp1 = WEBRTC_SPL_LSHIFT_W16(dtmp1, 9);
- state = &(aecm->medianBCount[i]);
- res = WebRtcAecm_MedianEstimator(dtmp1, state, 9);
- fcount[i] = (aecm->medianBCount[i]);
- }
-
- // Find minimum
- minpos = WebRtcSpl_MinIndexW16(fcount, MAX_DELAY);
-
- // If the farend has been active sufficiently long, begin accumulating a histogram
- // of the minimum positions. Search for the maximum bin to determine the delay.
- if (aecm->currentVADValue == 1)
- {
- if (aecm->delayVadCount >= kVadCountThreshold)
- {
- // Increment the histogram at the current minimum position.
- if (aecm->delayHistogram[minpos] < kMaxHistogram)
- {
- aecm->delayHistogram[minpos] += 3;
- }
-
-#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
- // Decrement the entire histogram.
- for (i = 0; i < MAX_DELAY; i++)
- {
- if (aecm->delayHistogram[i] > 0)
- {
- aecm->delayHistogram[i]--;
- }
- }
-
- // Select the histogram index corresponding to the maximum bin as the delay.
- maxHistLvl = 0;
- aecm->maxDelayHistIdx = 0;
- for (i = 0; i < MAX_DELAY; i++)
- {
- if (aecm->delayHistogram[i] > maxHistLvl)
- {
- maxHistLvl = aecm->delayHistogram[i];
- aecm->maxDelayHistIdx = i;
- }
- }
-#else
- maxHistLvl = 0;
- aecm->maxDelayHistIdx = 0;
-
- for (i = 0; i < MAX_DELAY; i++)
- {
- WebRtc_Word16 tempVar = aecm->delayHistogram[i];
-
- // Decrement the entire histogram.
- if (tempVar > 0)
- {
- tempVar--;
- aecm->delayHistogram[i] = tempVar;
-
- // Select the histogram index corresponding to the maximum bin as the delay.
- if (tempVar > maxHistLvl)
- {
- maxHistLvl = tempVar;
- aecm->maxDelayHistIdx = i;
- }
- }
- }
-#endif
- } else
- {
- aecm->delayVadCount++;
- }
- } else
- {
- aecm->delayVadCount = 0;
- }
-
- return aecm->maxDelayHistIdx;
-}
-
-int WebRtcAecm_FreeCore(AecmCore_t *aecm)
-{
- if (aecm == NULL)
- {
- return -1;
- }
-
- WebRtcApm_FreeBuffer(aecm->farFrameBuf);
- WebRtcApm_FreeBuffer(aecm->nearNoisyFrameBuf);
- WebRtcApm_FreeBuffer(aecm->nearCleanFrameBuf);
- WebRtcApm_FreeBuffer(aecm->outFrameBuf);
-
- free(aecm);
-
- return 0;
-}
-
-void WebRtcAecm_ProcessFrame(AecmCore_t * const aecm, const WebRtc_Word16 * const farend,
- const WebRtc_Word16 * const nearendNoisy,
- const WebRtc_Word16 * const nearendClean,
- WebRtc_Word16 * const out)
-{
- WebRtc_Word16 farBlock[PART_LEN];
- WebRtc_Word16 nearNoisyBlock[PART_LEN];
- WebRtc_Word16 nearCleanBlock[PART_LEN];
- WebRtc_Word16 outBlock[PART_LEN];
- WebRtc_Word16 farFrame[FRAME_LEN];
- int size = 0;
-
- // Buffer the current frame.
- // Fetch an older one corresponding to the delay.
- WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
- WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
-
- // Buffer the synchronized far and near frames,
- // to pass the smaller blocks individually.
- WebRtcApm_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
- WebRtcApm_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
- if (nearendClean != NULL)
- {
- WebRtcApm_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
- }
-
- // Process as many blocks as possible.
- while (WebRtcApm_get_buffer_size(aecm->farFrameBuf) >= PART_LEN)
- {
- WebRtcApm_ReadBuffer(aecm->farFrameBuf, farBlock, PART_LEN);
- WebRtcApm_ReadBuffer(aecm->nearNoisyFrameBuf, nearNoisyBlock, PART_LEN);
- if (nearendClean != NULL)
- {
- WebRtcApm_ReadBuffer(aecm->nearCleanFrameBuf, nearCleanBlock, PART_LEN);
- WebRtcAecm_ProcessBlock(aecm, farBlock, nearNoisyBlock, nearCleanBlock, outBlock);
- } else
- {
- WebRtcAecm_ProcessBlock(aecm, farBlock, nearNoisyBlock, NULL, outBlock);
- }
-
- WebRtcApm_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
- }
-
- // Stuff the out buffer if we have less than a frame to output.
- // This should only happen for the first frame.
- size = WebRtcApm_get_buffer_size(aecm->outFrameBuf);
- if (size < FRAME_LEN)
- {
- WebRtcApm_StuffBuffer(aecm->outFrameBuf, FRAME_LEN - size);
- }
-
- // Obtain an output frame.
- WebRtcApm_ReadBuffer(aecm->outFrameBuf, out, FRAME_LEN);
-}
-
-// WebRtcAecm_AsymFilt(...)
-//
-// Performs asymmetric filtering.
-//
-// Inputs:
-// - filtOld : Previous filtered value.
-// - inVal : New input value.
-// - stepSizePos : Step size when we have a positive contribution.
-// - stepSizeNeg : Step size when we have a negative contribution.
-//
-// Output:
-//
-// Return: - Filtered value.
-//
-WebRtc_Word16 WebRtcAecm_AsymFilt(const WebRtc_Word16 filtOld, const WebRtc_Word16 inVal,
- const WebRtc_Word16 stepSizePos,
- const WebRtc_Word16 stepSizeNeg)
-{
- WebRtc_Word16 retVal;
-
- if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN))
- {
- return inVal;
- }
- retVal = filtOld;
- if (filtOld > inVal)
- {
- retVal -= WEBRTC_SPL_RSHIFT_W16(filtOld - inVal, stepSizeNeg);
- } else
- {
- retVal += WEBRTC_SPL_RSHIFT_W16(inVal - filtOld, stepSizePos);
- }
-
- return retVal;
-}
-
-// WebRtcAecm_CalcEnergies(...)
-//
-// This function calculates the log of energies for nearend, farend and estimated
-// echoes. There is also an update of energy decision levels, i.e. internl VAD.
-//
-//
-// @param aecm [i/o] Handle of the AECM instance.
-// @param delayDiff [in] Delay position in farend buffer.
-// @param nearEner [in] Near end energy for current block (Q[aecm->dfaQDomain]).
-// @param echoEst [i/o] Estimated echo
-// (Q[aecm->xfaQDomain[delayDiff]+RESOLUTION_CHANNEL16]).
-//
-void WebRtcAecm_CalcEnergies(AecmCore_t * const aecm, const WebRtc_Word16 delayDiff,
- const WebRtc_UWord32 nearEner, WebRtc_Word32 * const echoEst)
-{
- // Local variables
- WebRtc_UWord32 tmpAdapt, tmpStored, tmpFar;
-
- int i;
-
- WebRtc_Word16 zeros, frac;
- WebRtc_Word16 tmp16;
- WebRtc_Word16 increase_max_shifts = 4;
- WebRtc_Word16 decrease_max_shifts = 11;
- WebRtc_Word16 increase_min_shifts = 11;
- WebRtc_Word16 decrease_min_shifts = 3;
-
- // Get log of near end energy and store in buffer
-
- // Shift buffer
- memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
- sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1));
-
- // Logarithm of integrated magnitude spectrum (nearEner)
- if (nearEner)
- {
- zeros = WebRtcSpl_NormU32(nearEner);
- frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(
- (WEBRTC_SPL_LSHIFT_U32(nearEner, zeros) & 0x7FFFFFFF),
- 23);
- // log2 in Q8
- aecm->nearLogEnergy[0] = WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
- aecm->nearLogEnergy[0] -= WEBRTC_SPL_LSHIFT_W16(aecm->dfaNoisyQDomain, 8);
- } else
- {
- aecm->nearLogEnergy[0] = 0;
- }
- aecm->nearLogEnergy[0] += WEBRTC_SPL_LSHIFT_W16(PART_LEN_SHIFT, 7);
- // END: Get log of near end energy
-
- // Get energy for the delayed far end signal and estimated
- // echo using both stored and adapted channels.
- tmpAdapt = 0;
- tmpStored = 0;
- tmpFar = 0;
-
- for (i = 0; i < PART_LEN1; i++)
- {
- // Get estimated echo energies for adaptive channel and stored channel
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- aecm->xfaHistory[i][delayDiff]);
- tmpFar += (WebRtc_UWord32)(aecm->xfaHistory[i][delayDiff]);
- tmpAdapt += WEBRTC_SPL_UMUL_16_16(aecm->channelAdapt16[i],
- aecm->xfaHistory[i][delayDiff]);
- tmpStored += (WebRtc_UWord32)echoEst[i];
- }
- // Shift buffers
- memmove(aecm->farLogEnergy + 1, aecm->farLogEnergy,
- sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1));
- memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
- sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1));
- memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
- sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1));
-
- // Logarithm of delayed far end energy
- if (tmpFar)
- {
- zeros = WebRtcSpl_NormU32(tmpFar);
- frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpFar, zeros)
- & 0x7FFFFFFF), 23);
- // log2 in Q8
- aecm->farLogEnergy[0] = WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
- aecm->farLogEnergy[0] -= WEBRTC_SPL_LSHIFT_W16(aecm->xfaQDomainBuf[delayDiff], 8);
- } else
- {
- aecm->farLogEnergy[0] = 0;
- }
- aecm->farLogEnergy[0] += WEBRTC_SPL_LSHIFT_W16(PART_LEN_SHIFT, 7);
-
- // Logarithm of estimated echo energy through adapted channel
- if (tmpAdapt)
- {
- zeros = WebRtcSpl_NormU32(tmpAdapt);
- frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpAdapt, zeros)
- & 0x7FFFFFFF), 23);
- //log2 in Q8
- aecm->echoAdaptLogEnergy[0] = WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
- aecm->echoAdaptLogEnergy[0]
- -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + aecm->xfaQDomainBuf[delayDiff], 8);
- } else
- {
- aecm->echoAdaptLogEnergy[0] = 0;
- }
- aecm->echoAdaptLogEnergy[0] += WEBRTC_SPL_LSHIFT_W16(PART_LEN_SHIFT, 7);
-
- // Logarithm of estimated echo energy through stored channel
- if (tmpStored)
- {
- zeros = WebRtcSpl_NormU32(tmpStored);
- frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpStored, zeros)
- & 0x7FFFFFFF), 23);
- //log2 in Q8
- aecm->echoStoredLogEnergy[0] = WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac;
- aecm->echoStoredLogEnergy[0]
- -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + aecm->xfaQDomainBuf[delayDiff], 8);
- } else
- {
- aecm->echoStoredLogEnergy[0] = 0;
- }
- aecm->echoStoredLogEnergy[0] += WEBRTC_SPL_LSHIFT_W16(PART_LEN_SHIFT, 7);
-
- // Update farend energy levels (min, max, vad, mse)
- if (aecm->farLogEnergy[0] > FAR_ENERGY_MIN)
- {
- if (aecm->startupState == 0)
- {
- increase_max_shifts = 2;
- decrease_min_shifts = 2;
- increase_min_shifts = 8;
- }
-
- aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy[0],
- increase_min_shifts, decrease_min_shifts);
- aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy[0],
- increase_max_shifts, decrease_max_shifts);
- aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
-
- // Dynamic VAD region size
- tmp16 = 2560 - aecm->farEnergyMin;
- if (tmp16 > 0)
- {
- tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, FAR_ENERGY_VAD_REGION, 9);
- } else
- {
- tmp16 = 0;
- }
- tmp16 += FAR_ENERGY_VAD_REGION;
-
- if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024))
- {
- // In startup phase or VAD update halted
- aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
- } else
- {
- if (aecm->farEnergyVAD > aecm->farLogEnergy[0])
- {
- aecm->farEnergyVAD += WEBRTC_SPL_RSHIFT_W16(aecm->farLogEnergy[0] + tmp16
- - aecm->farEnergyVAD, 6);
- aecm->vadUpdateCount = 0;
- } else
- {
- aecm->vadUpdateCount++;
- }
- }
- // Put MSE threshold higher than VAD
- aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
- }
-
- // Update VAD variables
- if (aecm->farLogEnergy[0] > aecm->farEnergyVAD)
- {
- if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF))
- {
- // We are in startup or have significant dynamics in input speech level
- aecm->currentVADValue = 1;
- }
- } else
- {
- aecm->currentVADValue = 0;
- }
- if ((aecm->currentVADValue) && (aecm->firstVAD))
- {
- aecm->firstVAD = 0;
- if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0])
- {
- // The estimated echo has higher energy than the near end signal. This means that
- // the initialization was too aggressive. Scale down by a factor 8
- for (i = 0; i < PART_LEN1; i++)
- {
- aecm->channelAdapt16[i] >>= 3;
- }
- // Compensate the adapted echo energy level accordingly.
- aecm->echoAdaptLogEnergy[0] -= (3 << 8);
- aecm->firstVAD = 1;
- }
- }
- // END: Energies of delayed far, echo estimates
- // TODO(bjornv): Will be removed in final version.
-#ifdef VAD_DATA
- fwrite(&(aecm->currentVADValue), sizeof(WebRtc_Word16), 1, aecm->vad_file);
- fwrite(&(aecm->currentDelay), sizeof(WebRtc_Word16), 1, aecm->delay_file);
- fwrite(&(aecm->farLogEnergy[0]), sizeof(WebRtc_Word16), 1, aecm->far_cur_file);
- fwrite(&(aecm->farEnergyMin), sizeof(WebRtc_Word16), 1, aecm->far_min_file);
- fwrite(&(aecm->farEnergyMax), sizeof(WebRtc_Word16), 1, aecm->far_max_file);
- fwrite(&(aecm->farEnergyVAD), sizeof(WebRtc_Word16), 1, aecm->far_vad_file);
-#endif
-}
-
-// WebRtcAecm_CalcStepSize(...)
-//
-// This function calculates the step size used in channel estimation
-//
-//
-// @param aecm [in] Handle of the AECM instance.
-// @param mu [out] (Return value) Stepsize in log2(), i.e. number of shifts.
-//
-//
-WebRtc_Word16 WebRtcAecm_CalcStepSize(AecmCore_t * const aecm)
-{
-
- WebRtc_Word32 tmp32;
- WebRtc_Word16 tmp16;
- WebRtc_Word16 mu;
-
- // Here we calculate the step size mu used in the
- // following NLMS based Channel estimation algorithm
- mu = MU_MAX;
- if (!aecm->currentVADValue)
- {
- // Far end energy level too low, no channel update
- mu = 0;
- } else if (aecm->startupState > 0)
- {
- if (aecm->farEnergyMin >= aecm->farEnergyMax)
- {
- mu = MU_MIN;
- } else
- {
- tmp16 = (aecm->farLogEnergy[0] - aecm->farEnergyMin);
- tmp32 = WEBRTC_SPL_MUL_16_16(tmp16, MU_DIFF);
- tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
- mu = MU_MIN - 1 - (WebRtc_Word16)(tmp32);
- // The -1 is an alternative to rounding. This way we get a larger
- // stepsize, so we in some sense compensate for truncation in NLMS
- }
- if (mu < MU_MAX)
- {
- mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
- }
- }
- // END: Update step size
-
- return mu;
-}
-
-// WebRtcAecm_UpdateChannel(...)
-//
-// This function performs channel estimation. NLMS and decision on channel storage.
-//
-//
-// @param aecm [i/o] Handle of the AECM instance.
-// @param dfa [in] Absolute value of the nearend signal (Q[aecm->dfaQDomain])
-// @param delayDiff [in] Delay position in farend buffer.
-// @param mu [in] NLMS step size.
-// @param echoEst [i/o] Estimated echo
-// (Q[aecm->xfaQDomain[delayDiff]+RESOLUTION_CHANNEL16]).
-//
-void WebRtcAecm_UpdateChannel(AecmCore_t * const aecm, const WebRtc_UWord16 * const dfa,
- const WebRtc_Word16 delayDiff, const WebRtc_Word16 mu,
- WebRtc_Word32 * const echoEst)
-{
-
- WebRtc_UWord32 tmpU32no1, tmpU32no2;
- WebRtc_Word32 tmp32no1, tmp32no2;
- WebRtc_Word32 mseStored;
- WebRtc_Word32 mseAdapt;
-
- int i;
-
- WebRtc_Word16 zerosFar, zerosNum, zerosCh, zerosDfa;
- WebRtc_Word16 shiftChFar, shiftNum, shift2ResChan;
- WebRtc_Word16 tmp16no1;
- WebRtc_Word16 xfaQ, dfaQ;
-
- // This is the channel estimation algorithm. It is base on NLMS but has a variable step
- // length, which was calculated above.
- if (mu)
- {
- for (i = 0; i < PART_LEN1; i++)
- {
- // Determine norm of channel and farend to make sure we don't get overflow in
- // multiplication
- zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
- zerosFar = WebRtcSpl_NormU32((WebRtc_UWord32)aecm->xfaHistory[i][delayDiff]);
- if (zerosCh + zerosFar > 31)
- {
- // Multiplication is safe
- tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i],
- aecm->xfaHistory[i][delayDiff]);
- shiftChFar = 0;
- } else
- {
- // We need to shift down before multiplication
- shiftChFar = 32 - zerosCh - zerosFar;
- tmpU32no1
- = WEBRTC_SPL_UMUL_32_16(WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i],
- shiftChFar),
- aecm->xfaHistory[i][delayDiff]);
- }
- // Determine Q-domain of numerator
- zerosNum = WebRtcSpl_NormU32(tmpU32no1);
- if (dfa[i])
- {
- zerosDfa = WebRtcSpl_NormU32((WebRtc_UWord32)dfa[i]);
- } else
- {
- zerosDfa = 32;
- }
- tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain - RESOLUTION_CHANNEL32
- - aecm->xfaQDomainBuf[delayDiff] + shiftChFar;
- if (zerosNum > tmp16no1 + 1)
- {
- xfaQ = tmp16no1;
- dfaQ = zerosDfa - 2;
- } else
- {
- xfaQ = zerosNum - 2;
- dfaQ = RESOLUTION_CHANNEL32 + aecm->xfaQDomainBuf[delayDiff]
- - aecm->dfaNoisyQDomain - shiftChFar + xfaQ;
- }
- // Add in the same Q-domain
- tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
- tmpU32no2 = WEBRTC_SPL_SHIFT_W32((WebRtc_UWord32)dfa[i], dfaQ);
- tmp32no1 = (WebRtc_Word32)tmpU32no2 - (WebRtc_Word32)tmpU32no1;
- zerosNum = WebRtcSpl_NormW32(tmp32no1);
- if ((tmp32no1) && (aecm->xfaHistory[i][delayDiff] > (CHANNEL_VAD
- << aecm->xfaQDomainBuf[delayDiff])))
- {
- //
- // Update is needed
- //
- // This is what we would like to compute
- //
- // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * aecm->xfaHistory[i][delayDiff])
- // tmp32norm = (i + 1)
- // aecm->channelAdapt[i] += (2^mu) * tmp32no1
- // / (tmp32norm * aecm->xfaHistory[i][delayDiff])
- //
-
- // Make sure we don't get overflow in multiplication.
- if (zerosNum + zerosFar > 31)
- {
- if (tmp32no1 > 0)
- {
- tmp32no2 = (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(tmp32no1,
- aecm->xfaHistory[i][delayDiff]);
- } else
- {
- tmp32no2 = -(WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(-tmp32no1,
- aecm->xfaHistory[i][delayDiff]);
- }
- shiftNum = 0;
- } else
- {
- shiftNum = 32 - (zerosNum + zerosFar);
- if (tmp32no1 > 0)
- {
- tmp32no2 = (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(
- WEBRTC_SPL_RSHIFT_W32(tmp32no1, shiftNum),
- aecm->xfaHistory[i][delayDiff]);
- } else
- {
- tmp32no2 = -(WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(
- WEBRTC_SPL_RSHIFT_W32(-tmp32no1, shiftNum),
- aecm->xfaHistory[i][delayDiff]);
- }
- }
- // Normalize with respect to frequency bin
- tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
- // Make sure we are in the right Q-domain
- shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
- if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan)
- {
- tmp32no2 = WEBRTC_SPL_WORD32_MAX;
- } else
- {
- tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
- }
- aecm->channelAdapt32[i] = WEBRTC_SPL_ADD_SAT_W32(aecm->channelAdapt32[i],
- tmp32no2);
- if (aecm->channelAdapt32[i] < 0)
- {
- // We can never have negative channel gain
- aecm->channelAdapt32[i] = 0;
- }
- aecm->channelAdapt16[i]
- = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], 16);
- }
- }
- }
- // END: Adaptive channel update
-
- // Determine if we should store or restore the channel
- if ((aecm->startupState == 0) & (aecm->currentVADValue))
- {
- // During startup we store the channel every block.
- memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(WebRtc_Word16) * PART_LEN1);
- // TODO(bjornv): Will be removed in final version.
-#ifdef STORE_CHANNEL_DATA
- fwrite(aecm->channelStored, sizeof(WebRtc_Word16), PART_LEN1, aecm->channel_file_init);
-#endif
- // Recalculate echo estimate
-#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
- for (i = 0; i < PART_LEN1; i++)
- {
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- aecm->xfaHistory[i][delayDiff]);
- }
-#else
- for (i = 0; i < PART_LEN; ) //assume PART_LEN is 4's multiples
-
- {
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- aecm->xfaHistory[i][delayDiff]);
- i++;
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- aecm->xfaHistory[i][delayDiff]);
- i++;
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- aecm->xfaHistory[i][delayDiff]);
- i++;
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- aecm->xfaHistory[i][delayDiff]);
- i++;
- }
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- aecm->xfaHistory[i][delayDiff]);
-#endif
- } else
- {
- if (aecm->farLogEnergy[0] < aecm->farEnergyMSE)
- {
- aecm->mseChannelCount = 0;
- aecm->delayCount = 0;
- } else
- {
- aecm->mseChannelCount++;
- aecm->delayCount++;
- }
- // Enough data for validation. Store channel if we can.
- if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10))
- {
- // We have enough data.
- // Calculate MSE of "Adapt" and "Stored" versions.
- // It is actually not MSE, but average absolute error.
- mseStored = 0;
- mseAdapt = 0;
- for (i = 0; i < MIN_MSE_COUNT; i++)
- {
- tmp32no1 = ((WebRtc_Word32)aecm->echoStoredLogEnergy[i]
- - (WebRtc_Word32)aecm->nearLogEnergy[i]);
- tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
- mseStored += tmp32no2;
-
- tmp32no1 = ((WebRtc_Word32)aecm->echoAdaptLogEnergy[i]
- - (WebRtc_Word32)aecm->nearLogEnergy[i]);
- tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
- mseAdapt += tmp32no2;
- }
- if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt))
- & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF
- * aecm->mseAdaptOld)))
- {
- // The stored channel has a significantly lower MSE than the adaptive one for
- // two consecutive calculations. Reset the adaptive channel.
- memcpy(aecm->channelAdapt16, aecm->channelStored,
- sizeof(WebRtc_Word16) * PART_LEN1);
- // Restore the W32 channel
-#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
- for (i = 0; i < PART_LEN1; i++)
- {
- aecm->channelAdapt32[i]
- = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)aecm->channelStored[i], 16);
- }
-#else
- for (i = 0; i < PART_LEN; ) //assume PART_LEN is 4's multiples
-
- {
- aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)aecm->channelStored[i], 16);
- i++;
- aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)aecm->channelStored[i], 16);
- i++;
- aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)aecm->channelStored[i], 16);
- i++;
- aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)aecm->channelStored[i], 16);
- i++;
- }
- aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)aecm->channelStored[i], 16);
-#endif
-
- } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt
- < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold))
- {
- // The adaptive channel has a significantly lower MSE than the stored one.
- // The MSE for the adaptive channel has also been low for two consecutive
- // calculations. Store the adaptive channel.
- memcpy(aecm->channelStored, aecm->channelAdapt16,
- sizeof(WebRtc_Word16) * PART_LEN1);
- // TODO(bjornv): Will be removed in final version.
-#ifdef STORE_CHANNEL_DATA
- fwrite(aecm->channelStored, sizeof(WebRtc_Word16), PART_LEN1,
- aecm->channel_file);
-#endif
-// Recalculate echo estimate
-#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
- for (i = 0; i < PART_LEN1; i++)
- {
- echoEst[i]
- = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], aecm->xfaHistory[i][delayDiff]);
- }
-#else
- for (i = 0; i < PART_LEN; ) //assume PART_LEN is 4's multiples
-
- {
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], aecm->xfaHistory[i][delayDiff]);
- i++;
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], aecm->xfaHistory[i][delayDiff]);
- i++;
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], aecm->xfaHistory[i][delayDiff]);
- i++;
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], aecm->xfaHistory[i][delayDiff]);
- i++;
- }
- echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], aecm->xfaHistory[i][delayDiff]);
-#endif
- // Update threshold
- if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX)
- {
- aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
- } else
- {
- aecm->mseThreshold += WEBRTC_SPL_MUL_16_16_RSFT(mseAdapt
- - WEBRTC_SPL_MUL_16_16_RSFT(aecm->mseThreshold, 5, 3), 205, 8);
- }
-
- }
-
- // Reset counter
- aecm->mseChannelCount = 0;
-
- // Store the MSE values.
- aecm->mseStoredOld = mseStored;
- aecm->mseAdaptOld = mseAdapt;
- }
- }
- // END: Determine if we should store or reset channel estimate.
-}
-
-// WebRtcAecm_CalcSuppressionGain(...)
-//
-// This function calculates the suppression gain that is used in the Wiener filter.
-//
-//
-// @param aecm [i/n] Handle of the AECM instance.
-// @param supGain [out] (Return value) Suppression gain with which to scale the noise
-// level (Q14).
-//
-//
-WebRtc_Word16 WebRtcAecm_CalcSuppressionGain(AecmCore_t * const aecm)
-{
- WebRtc_Word32 tmp32no1;
-
- WebRtc_Word16 supGain;
- WebRtc_Word16 tmp16no1;
- WebRtc_Word16 dE = 0;
-
- // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far
- // end energy and echo estimation error.
- supGain = SUPGAIN_DEFAULT;
- // Adjust for the far end signal level. A low signal level indicates no far end signal,
- // hence we set the suppression gain to 0
- if (!aecm->currentVADValue)
- {
- supGain = 0;
- } else
- {
- // Adjust for possible double talk. If we have large variations in estimation error we
- // likely have double talk (or poor channel).
- tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET);
- dE = WEBRTC_SPL_ABS_W16(tmp16no1);
-
- if (dE < ENERGY_DEV_TOL)
- {
- // Likely no double talk. The better estimation, the more we can suppress signal.
- // Update counters
- if (dE < SUPGAIN_EPC_DT)
- {
- tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffAB, dE);
- tmp32no1 += (SUPGAIN_EPC_DT >> 1);
- tmp16no1 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
- supGain = aecm->supGainErrParamA - tmp16no1;
- } else
- {
- tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffBD,
- (ENERGY_DEV_TOL - dE));
- tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
- tmp16no1 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL
- - SUPGAIN_EPC_DT));
- supGain = aecm->supGainErrParamD + tmp16no1;
- }
- } else
- {
- // Likely in double talk. Use default value
- supGain = aecm->supGainErrParamD;
- }
- }
-
- if (supGain > aecm->supGainOld)
- {
- tmp16no1 = supGain;
- } else
- {
- tmp16no1 = aecm->supGainOld;
- }
- aecm->supGainOld = supGain;
- if (tmp16no1 < aecm->supGain)
- {
- aecm->supGain += (WebRtc_Word16)((tmp16no1 - aecm->supGain) >> 4);
- } else
- {
- aecm->supGain += (WebRtc_Word16)((tmp16no1 - aecm->supGain) >> 4);
- }
-
- // END: Update suppression gain
-
- return aecm->supGain;
-}
-
-// WebRtcAecm_DelayCompensation(...)
-//
-// Secondary delay estimation that can be used as a backup or for validation. This function is
-// still under construction and not activated in current version.
-//
-//
-// @param aecm [i/o] Handle of the AECM instance.
-//
-//
-void WebRtcAecm_DelayCompensation(AecmCore_t * const aecm)
-{
- int i, j;
- WebRtc_Word32 delayMeanEcho[CORR_BUF_LEN];
- WebRtc_Word32 delayMeanNear[CORR_BUF_LEN];
- WebRtc_Word16 sumBitPattern, bitPatternEcho, bitPatternNear, maxPos, maxValue,
- maxValueLeft, maxValueRight;
-
- // Check delay (calculate the delay offset (if we can)).
- if ((aecm->startupState > 0) & (aecm->delayCount >= CORR_MAX_BUF) & aecm->delayOffsetFlag)
- {
- // Calculate mean values
- for (i = 0; i < CORR_BUF_LEN; i++)
- {
- delayMeanEcho[i] = 0;
- delayMeanNear[i] = 0;
-#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
- for (j = 0; j < CORR_WIDTH; j++)
- {
- delayMeanEcho[i] += (WebRtc_Word32)aecm->echoStoredLogEnergy[i + j];
- delayMeanNear[i] += (WebRtc_Word32)aecm->nearLogEnergy[i + j];
- }
-#else
- for (j = 0; j < CORR_WIDTH -1; )
- {
- delayMeanEcho[i] += (WebRtc_Word32)aecm->echoStoredLogEnergy[i + j];
- delayMeanNear[i] += (WebRtc_Word32)aecm->nearLogEnergy[i + j];
- j++;
- delayMeanEcho[i] += (WebRtc_Word32)aecm->echoStoredLogEnergy[i + j];
- delayMeanNear[i] += (WebRtc_Word32)aecm->nearLogEnergy[i + j];
- j++;
- }
- delayMeanEcho[i] += (WebRtc_Word32)aecm->echoStoredLogEnergy[i + j];
- delayMeanNear[i] += (WebRtc_Word32)aecm->nearLogEnergy[i + j];
-#endif
- }
- // Calculate correlation values
- for (i = 0; i < CORR_BUF_LEN; i++)
- {
- sumBitPattern = 0;
-#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
- for (j = 0; j < CORR_WIDTH; j++)
- {
- bitPatternEcho = (WebRtc_Word16)((WebRtc_Word32)aecm->echoStoredLogEnergy[i
- + j] * CORR_WIDTH > delayMeanEcho[i]);
- bitPatternNear = (WebRtc_Word16)((WebRtc_Word32)aecm->nearLogEnergy[CORR_MAX
- + j] * CORR_WIDTH > delayMeanNear[CORR_MAX]);
- sumBitPattern += !(bitPatternEcho ^ bitPatternNear);
- }
-#else
- for (j = 0; j < CORR_WIDTH -1; )
- {
- bitPatternEcho = (WebRtc_Word16)((WebRtc_Word32)aecm->echoStoredLogEnergy[i
- + j] * CORR_WIDTH > delayMeanEcho[i]);
- bitPatternNear = (WebRtc_Word16)((WebRtc_Word32)aecm->nearLogEnergy[CORR_MAX
- + j] * CORR_WIDTH > delayMeanNear[CORR_MAX]);
- sumBitPattern += !(bitPatternEcho ^ bitPatternNear);
- j++;
- bitPatternEcho = (WebRtc_Word16)((WebRtc_Word32)aecm->echoStoredLogEnergy[i
- + j] * CORR_WIDTH > delayMeanEcho[i]);
- bitPatternNear = (WebRtc_Word16)((WebRtc_Word32)aecm->nearLogEnergy[CORR_MAX
- + j] * CORR_WIDTH > delayMeanNear[CORR_MAX]);
- sumBitPattern += !(bitPatternEcho ^ bitPatternNear);
- j++;
- }
- bitPatternEcho = (WebRtc_Word16)((WebRtc_Word32)aecm->echoStoredLogEnergy[i + j]
- * CORR_WIDTH > delayMeanEcho[i]);
- bitPatternNear = (WebRtc_Word16)((WebRtc_Word32)aecm->nearLogEnergy[CORR_MAX + j]
- * CORR_WIDTH > delayMeanNear[CORR_MAX]);
- sumBitPattern += !(bitPatternEcho ^ bitPatternNear);
-#endif
- aecm->delayCorrelation[i] = sumBitPattern;
- }
- aecm->newDelayCorrData = 1; // Indicate we have new correlation data to evaluate
- }
- if ((aecm->startupState == 2) & (aecm->lastDelayUpdateCount > (CORR_WIDTH << 1))
- & aecm->newDelayCorrData)
- {
- // Find maximum value and maximum position as well as values on the sides.
- maxPos = 0;
- maxValue = aecm->delayCorrelation[0];
- maxValueLeft = maxValue;
- maxValueRight = aecm->delayCorrelation[CORR_DEV];
- for (i = 1; i < CORR_BUF_LEN; i++)
- {
- if (aecm->delayCorrelation[i] > maxValue)
- {
- maxValue = aecm->delayCorrelation[i];
- maxPos = i;
- if (maxPos < CORR_DEV)
- {
- maxValueLeft = aecm->delayCorrelation[0];
- maxValueRight = aecm->delayCorrelation[i + CORR_DEV];
- } else if (maxPos > (CORR_MAX << 1) - CORR_DEV)
- {
- maxValueLeft = aecm->delayCorrelation[i - CORR_DEV];
- maxValueRight = aecm->delayCorrelation[(CORR_MAX << 1)];
- } else
- {
- maxValueLeft = aecm->delayCorrelation[i - CORR_DEV];
- maxValueRight = aecm->delayCorrelation[i + CORR_DEV];
- }
- }
- }
- if ((maxPos > 0) & (maxPos < (CORR_MAX << 1)))
- {
- // Avoid maximum at boundaries. The maximum peak has to be higher than
- // CORR_MAX_LEVEL. It also has to be sharp, i.e. the value CORR_DEV bins off should
- // be CORR_MAX_LOW lower than the maximum.
- if ((maxValue > CORR_MAX_LEVEL) & (maxValueLeft < maxValue - CORR_MAX_LOW)
- & (maxValueRight < maxValue - CORR_MAX_LOW))
- {
- aecm->delayAdjust += CORR_MAX - maxPos;
- aecm->newDelayCorrData = 0;
- aecm->lastDelayUpdateCount = 0;
- }
- }
- }
- // END: "Check delay"
-}
-
-void WebRtcAecm_ProcessBlock(AecmCore_t * const aecm, const WebRtc_Word16 * const farend,
- const WebRtc_Word16 * const nearendNoisy,
- const WebRtc_Word16 * const nearendClean,
- WebRtc_Word16 * const output)
-{
- int i, j;
-
- WebRtc_UWord32 xfaSum;
- WebRtc_UWord32 dfaNoisySum;
- WebRtc_UWord32 echoEst32Gained;
- WebRtc_UWord32 tmpU32;
-
- WebRtc_Word32 tmp32no1;
- WebRtc_Word32 tmp32no2;
- WebRtc_Word32 echoEst32[PART_LEN1];
-
- WebRtc_UWord16 xfa[PART_LEN1];
- WebRtc_UWord16 dfaNoisy[PART_LEN1];
- WebRtc_UWord16 dfaClean[PART_LEN1];
- WebRtc_UWord16* ptrDfaClean = dfaClean;
-
- int outCFFT;
-
- WebRtc_Word16 fft[PART_LEN4];
-#if (defined ARM_WINM) || (defined ARM9E_GCC) || (defined ANDROID_AECOPT)
- WebRtc_Word16 postFft[PART_LEN4];
-#else
- WebRtc_Word16 postFft[PART_LEN2];
-#endif
- WebRtc_Word16 dfwReal[PART_LEN1];
- WebRtc_Word16 dfwImag[PART_LEN1];
- WebRtc_Word16 xfwReal[PART_LEN1];
- WebRtc_Word16 xfwImag[PART_LEN1];
- WebRtc_Word16 efwReal[PART_LEN1];
- WebRtc_Word16 efwImag[PART_LEN1];
- WebRtc_Word16 hnl[PART_LEN1];
- WebRtc_Word16 numPosCoef;
- WebRtc_Word16 nlpGain;
- WebRtc_Word16 delay, diff, diffMinusOne;
- WebRtc_Word16 tmp16no1;
- WebRtc_Word16 tmp16no2;
-#ifdef AECM_WITH_ABS_APPROX
- WebRtc_Word16 maxValue;
- WebRtc_Word16 minValue;
-#endif
- WebRtc_Word16 mu;
- WebRtc_Word16 supGain;
- WebRtc_Word16 zeros32, zeros16;
- WebRtc_Word16 zerosDBufNoisy, zerosDBufClean, zerosXBuf;
- WebRtc_Word16 resolutionDiff, qDomainDiff;
-
-#ifdef ARM_WINM_LOG_
- DWORD temp;
- static int flag0 = 0;
- __int64 freq, start, end, diff__;
- unsigned int milliseconds;
-#endif
-
-#ifdef AECM_WITH_ABS_APPROX
- WebRtc_UWord16 alpha, beta;
-#endif
-
- // Determine startup state. There are three states:
- // (0) the first CONV_LEN blocks
- // (1) another CONV_LEN blocks
- // (2) the rest
-
- if (aecm->startupState < 2)
- {
- aecm->startupState = (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2);
- }
- // END: Determine startup state
-
- // Buffer near and far end signals
- memcpy(aecm->xBuf + PART_LEN, farend, sizeof(WebRtc_Word16) * PART_LEN);
- memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(WebRtc_Word16) * PART_LEN);
- if (nearendClean != NULL)
- {
- memcpy(aecm->dBufClean + PART_LEN, nearendClean, sizeof(WebRtc_Word16) * PART_LEN);
- }
- // TODO(bjornv): Will be removed in final version.
-#ifdef VAD_DATA
- fwrite(aecm->xBuf, sizeof(WebRtc_Word16), PART_LEN, aecm->far_file);
-#endif
-
-#ifdef AECM_DYNAMIC_Q
- tmp16no1 = WebRtcSpl_MaxAbsValueW16(aecm->dBufNoisy, PART_LEN2);
- tmp16no2 = WebRtcSpl_MaxAbsValueW16(aecm->xBuf, PART_LEN2);
- zerosDBufNoisy = WebRtcSpl_NormW16(tmp16no1);
- zerosXBuf = WebRtcSpl_NormW16(tmp16no2);
-#else
- zerosDBufNoisy = 0;
- zerosXBuf = 0;
-#endif
- aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain;
- aecm->dfaNoisyQDomain = zerosDBufNoisy;
-
- if (nearendClean != NULL)
- {
-#ifdef AECM_DYNAMIC_Q
- tmp16no1 = WebRtcSpl_MaxAbsValueW16(aecm->dBufClean, PART_LEN2);
- zerosDBufClean = WebRtcSpl_NormW16(tmp16no1);
-#else
- zerosDBufClean = 0;
-#endif
- aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain;
- aecm->dfaCleanQDomain = zerosDBufClean;
- } else
- {
- zerosDBufClean = zerosDBufNoisy;
- aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld;
- aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain;
- }
-
-#ifdef ARM_WINM_LOG_
- // measure tick start
- QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
- QueryPerformanceCounter((LARGE_INTEGER*)&start);
-#endif
-
- // FFT of noisy near end signal
- for (i = 0; i < PART_LEN; i++)
- {
- j = WEBRTC_SPL_LSHIFT_W32(i, 1);
- // Window near end
- fft[j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((aecm->dBufNoisy[i]
- << zerosDBufNoisy), kSqrtHanning[i], 14);
- fft[PART_LEN2 + j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(
- (aecm->dBufNoisy[PART_LEN + i] << zerosDBufNoisy),
- kSqrtHanning[PART_LEN - i], 14);
- // Inserting zeros in imaginary parts
- fft[j + 1] = 0;
- fft[PART_LEN2 + j + 1] = 0;
- }
-
- // Fourier transformation of near end signal.
- // The result is scaled with 1/PART_LEN2, that is, the result is in Q(-6) for PART_LEN = 32
-
-#if (defined ARM_WINM) || (defined ARM9E_GCC) || (defined ANDROID_AECOPT)
- outCFFT = WebRtcSpl_ComplexFFT2(fft, postFft, PART_LEN_SHIFT, 1);
-
- // The imaginary part has to switch sign
- for(i = 1; i < PART_LEN2-1;)
- {
- postFft[i] = -postFft[i];
- i += 2;
- postFft[i] = -postFft[i];
- i += 2;
- }
-#else
- WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
- outCFFT = WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1);
-
- // Take only the first PART_LEN2 samples
- for (i = 0; i < PART_LEN2; i++)
- {
- postFft[i] = fft[i];
- }
- // The imaginary part has to switch sign
- for (i = 1; i < PART_LEN2;)
- {
- postFft[i] = -postFft[i];
- i += 2;
- }
-#endif
-
- // Extract imaginary and real part, calculate the magnitude for all frequency bins
- dfwImag[0] = 0;
- dfwImag[PART_LEN] = 0;
- dfwReal[0] = postFft[0];
-#if (defined ARM_WINM) || (defined ARM9E_GCC) || (defined ANDROID_AECOPT)
- dfwReal[PART_LEN] = postFft[PART_LEN2];
-#else
- dfwReal[PART_LEN] = fft[PART_LEN2];
-#endif
- dfaNoisy[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(dfwReal[0]);
- dfaNoisy[PART_LEN] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(dfwReal[PART_LEN]);
- dfaNoisySum = (WebRtc_UWord32)(dfaNoisy[0]);
- dfaNoisySum += (WebRtc_UWord32)(dfaNoisy[PART_LEN]);
-
- for (i = 1; i < PART_LEN; i++)
- {
- j = WEBRTC_SPL_LSHIFT_W32(i, 1);
- dfwReal[i] = postFft[j];
- dfwImag[i] = postFft[j + 1];
-
- if (dfwReal[i] == 0 || dfwImag[i] == 0)
- {
- dfaNoisy[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(dfwReal[i] + dfwImag[i]);
- } else
- {
- // Approximation for magnitude of complex fft output
- // magn = sqrt(real^2 + imag^2)
- // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
- //
- // The parameters alpha and beta are stored in Q15
-
- tmp16no1 = WEBRTC_SPL_ABS_W16(postFft[j]);
- tmp16no2 = WEBRTC_SPL_ABS_W16(postFft[j + 1]);
-
-#ifdef AECM_WITH_ABS_APPROX
- if(tmp16no1 > tmp16no2)
- {
- maxValue = tmp16no1;
- minValue = tmp16no2;
- } else
- {
- maxValue = tmp16no2;
- minValue = tmp16no1;
- }
-
- // Magnitude in Q-6
- if ((maxValue >> 2) > minValue)
- {
- alpha = kAlpha1;
- beta = kBeta1;
- } else if ((maxValue >> 1) > minValue)
- {
- alpha = kAlpha2;
- beta = kBeta2;
- } else
- {
- alpha = kAlpha3;
- beta = kBeta3;
- }
- tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(maxValue, alpha, 15);
- tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(minValue, beta, 15);
- dfaNoisy[i] = (WebRtc_UWord16)tmp16no1 + (WebRtc_UWord16)tmp16no2;
-#else
- tmp32no1 = WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1);
- tmp32no2 = WEBRTC_SPL_MUL_16_16(tmp16no2, tmp16no2);
- tmp32no2 = WEBRTC_SPL_ADD_SAT_W32(tmp32no1, tmp32no2);
- tmp32no1 = WebRtcSpl_Sqrt(tmp32no2);
- dfaNoisy[i] = (WebRtc_UWord16)tmp32no1;
-#endif
- }
- dfaNoisySum += (WebRtc_UWord32)dfaNoisy[i];
- }
- // END: FFT of noisy near end signal
-
- if (nearendClean == NULL)
- {
- ptrDfaClean = dfaNoisy;
- } else
- {
- // FFT of clean near end signal
- for (i = 0; i < PART_LEN; i++)
- {
- j = WEBRTC_SPL_LSHIFT_W32(i, 1);
- // Window near end
- fft[j]
- = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((aecm->dBufClean[i] << zerosDBufClean), kSqrtHanning[i], 14);
- fft[PART_LEN2 + j]
- = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((aecm->dBufClean[PART_LEN + i] << zerosDBufClean), kSqrtHanning[PART_LEN - i], 14);
- // Inserting zeros in imaginary parts
- fft[j + 1] = 0;
- fft[PART_LEN2 + j + 1] = 0;
- }
-
- // Fourier transformation of near end signal.
- // The result is scaled with 1/PART_LEN2, that is, in Q(-6) for PART_LEN = 32
-
-#if (defined ARM_WINM) || (defined ARM9E_GCC) || (defined ANDROID_AECOPT)
- outCFFT = WebRtcSpl_ComplexFFT2(fft, postFft, PART_LEN_SHIFT, 1);
-
- // The imaginary part has to switch sign
- for(i = 1; i < PART_LEN2-1;)
- {
- postFft[i] = -postFft[i];
- i += 2;
- postFft[i] = -postFft[i];
- i += 2;
- }
-#else
- WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
- outCFFT = WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1);
-
- // Take only the first PART_LEN2 samples
- for (i = 0; i < PART_LEN2; i++)
- {
- postFft[i] = fft[i];
- }
- // The imaginary part has to switch sign
- for (i = 1; i < PART_LEN2;)
- {
- postFft[i] = -postFft[i];
- i += 2;
- }
-#endif
-
- // Extract imaginary and real part, calculate the magnitude for all frequency bins
- dfwImag[0] = 0;
- dfwImag[PART_LEN] = 0;
- dfwReal[0] = postFft[0];
-#if (defined ARM_WINM) || (defined ARM9E_GCC) || (defined ANDROID_AECOPT)
- dfwReal[PART_LEN] = postFft[PART_LEN2];
-#else
- dfwReal[PART_LEN] = fft[PART_LEN2];
-#endif
- dfaClean[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(dfwReal[0]);
- dfaClean[PART_LEN] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(dfwReal[PART_LEN]);
-
- for (i = 1; i < PART_LEN; i++)
- {
- j = WEBRTC_SPL_LSHIFT_W32(i, 1);
- dfwReal[i] = postFft[j];
- dfwImag[i] = postFft[j + 1];
-
- if (dfwReal[i] == 0 || dfwImag[i] == 0)
- {
- dfaClean[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(dfwReal[i] + dfwImag[i]);
- } else
- {
- // Approximation for magnitude of complex fft output
- // magn = sqrt(real^2 + imag^2)
- // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
- //
- // The parameters alpha and beta are stored in Q15
-
- tmp16no1 = WEBRTC_SPL_ABS_W16(postFft[j]);
- tmp16no2 = WEBRTC_SPL_ABS_W16(postFft[j + 1]);
-
-#ifdef AECM_WITH_ABS_APPROX
- if(tmp16no1 > tmp16no2)
- {
- maxValue = tmp16no1;
- minValue = tmp16no2;
- } else
- {
- maxValue = tmp16no2;
- minValue = tmp16no1;
- }
-
- // Magnitude in Q-6
- if ((maxValue >> 2) > minValue)
- {
- alpha = kAlpha1;
- beta = kBeta1;
- } else if ((maxValue >> 1) > minValue)
- {
- alpha = kAlpha2;
- beta = kBeta2;
- } else
- {
- alpha = kAlpha3;
- beta = kBeta3;
- }
- tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(maxValue, alpha, 15);
- tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(minValue, beta, 15);
- dfaClean[i] = (WebRtc_UWord16)tmp16no1 + (WebRtc_UWord16)tmp16no2;
-#else
- tmp32no1 = WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1);
- tmp32no2 = WEBRTC_SPL_MUL_16_16(tmp16no2, tmp16no2);
- tmp32no2 = WEBRTC_SPL_ADD_SAT_W32(tmp32no1, tmp32no2);
- tmp32no1 = WebRtcSpl_Sqrt(tmp32no2);
- dfaClean[i] = (WebRtc_UWord16)tmp32no1;
-#endif
- }
- }
- }
- // END: FFT of clean near end signal
-
- // FFT of far end signal
- for (i = 0; i < PART_LEN; i++)
- {
- j = WEBRTC_SPL_LSHIFT_W32(i, 1);
- // Window farend
- fft[j]
- = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((aecm->xBuf[i] << zerosXBuf), kSqrtHanning[i], 14);
- fft[PART_LEN2 + j]
- = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((aecm->xBuf[PART_LEN + i] << zerosXBuf), kSqrtHanning[PART_LEN - i], 14);
- // Inserting zeros in imaginary parts
- fft[j + 1] = 0;
- fft[PART_LEN2 + j + 1] = 0;
- }
- // Fourier transformation of far end signal.
- // The result is scaled with 1/PART_LEN2, that is the result is in Q(-6) for PART_LEN = 32
-#if (defined ARM_WINM) || (defined ARM9E_GCC) || (defined ANDROID_AECOPT)
- outCFFT = WebRtcSpl_ComplexFFT2(fft, postFft, PART_LEN_SHIFT, 1);
-
- // The imaginary part has to switch sign
- for(i = 1; i < PART_LEN2-1;)
- {
- postFft[i] = -postFft[i];
- i += 2;
- postFft[i] = -postFft[i];
- i += 2;
- }
-#else
- WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
- outCFFT = WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1);
-
- // Take only the first PART_LEN2 samples
- for (i = 0; i < PART_LEN2; i++)
- {
- postFft[i] = fft[i];
- }
- // The imaginary part has to switch sign
- for (i = 1; i < PART_LEN2;)
- {
- postFft[i] = -postFft[i];
- i += 2;
- }
-#endif
-
- // Extract imaginary and real part, calculate the magnitude for all frequency bins
- xfwImag[0] = 0;
- xfwImag[PART_LEN] = 0;
- xfwReal[0] = postFft[0];
-#if (defined ARM_WINM) || (defined ARM9E_GCC) || (defined ANDROID_AECOPT)
- xfwReal[PART_LEN] = postFft[PART_LEN2];
-#else
- xfwReal[PART_LEN] = fft[PART_LEN2];
-#endif
- xfa[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(xfwReal[0]);
- xfa[PART_LEN] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(xfwReal[PART_LEN]);
- xfaSum = (WebRtc_UWord32)(xfa[0]) + (WebRtc_UWord32)(xfa[PART_LEN]);
-
- for (i = 1; i < PART_LEN; i++)
- {
- j = WEBRTC_SPL_LSHIFT_W32(i,1);
- xfwReal[i] = postFft[j];
- xfwImag[i] = postFft[j + 1];
-
- if (xfwReal[i] == 0 || xfwImag[i] == 0)
- {
- xfa[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(xfwReal[i] + xfwImag[i]);
- } else
- {
- // Approximation for magnitude of complex fft output
- // magn = sqrt(real^2 + imag^2)
- // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
- //
- // The parameters alpha and beta are stored in Q15
-
- tmp16no1 = WEBRTC_SPL_ABS_W16(postFft[j]);
- tmp16no2 = WEBRTC_SPL_ABS_W16(postFft[j + 1]);
-
-#ifdef AECM_WITH_ABS_APPROX
- if(tmp16no1 > xfwImag[i])
- {
- maxValue = tmp16no1;
- minValue = tmp16no2;
- } else
- {
- maxValue = tmp16no2;
- minValue = tmp16no1;
- }
- // Magnitude in Q-6
- if ((maxValue >> 2) > minValue)
- {
- alpha = kAlpha1;
- beta = kBeta1;
- } else if ((maxValue >> 1) > minValue)
- {
- alpha = kAlpha2;
- beta = kBeta2;
- } else
- {
- alpha = kAlpha3;
- beta = kBeta3;
- }
- tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(maxValue, alpha, 15);
- tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(minValue, beta, 15);
- xfa[i] = (WebRtc_UWord16)tmp16no1 + (WebRtc_UWord16)tmp16no2;
-#else
- tmp32no1 = WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1);
- tmp32no2 = WEBRTC_SPL_MUL_16_16(tmp16no2, tmp16no2);
- tmp32no2 = WEBRTC_SPL_ADD_SAT_W32(tmp32no1, tmp32no2);
- tmp32no1 = WebRtcSpl_Sqrt(tmp32no2);
- xfa[i] = (WebRtc_UWord16)tmp32no1;
-#endif
- }
- xfaSum += (WebRtc_UWord32)xfa[i];
- }
-
-#ifdef ARM_WINM_LOG_
- // measure tick end
- QueryPerformanceCounter((LARGE_INTEGER*)&end);
- diff__ = ((end - start) * 1000) / (freq/1000);
- milliseconds = (unsigned int)(diff__ & 0xffffffff);
- WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
-#endif
- // END: FFT of far end signal
-
- // Get the delay
-
- // Fixed delay estimation
- // input: dfaFIX, xfaFIX in Q-stages
- // output: delay in Q0
- //
- // comment on the fixed point accuracy of estimate_delayFIX
- // -> due to rounding the fixed point variables xfa and dfa contain a lot more zeros
- // than the corresponding floating point variables this results in big differences
- // between the floating point and the fixed point logarithmic spectra for small values
-#ifdef ARM_WINM_LOG_
- // measure tick start
- QueryPerformanceCounter((LARGE_INTEGER*)&start);
-#endif
-
- // Save far-end history and estimate delay
- delay = WebRtcAecm_EstimateDelay(aecm, xfa, dfaNoisy, zerosXBuf);
-
- if (aecm->fixedDelay >= 0)
- {
- // Use fixed delay
- delay = aecm->fixedDelay;
- }
-
- aecm->currentDelay = delay;
-
- if ((aecm->delayOffsetFlag) & (aecm->startupState > 0)) // If delay compensation is on
- {
- // If the delay estimate changed from previous block, update the offset
- if ((aecm->currentDelay != aecm->previousDelay) & !aecm->currentDelay
- & !aecm->previousDelay)
- {
- aecm->delayAdjust += (aecm->currentDelay - aecm->previousDelay);
- }
- // Compensate with the offset estimate
- aecm->currentDelay -= aecm->delayAdjust;
- aecm->previousDelay = delay;
- }
-
- diff = aecm->delHistoryPos - aecm->currentDelay;
- if (diff < 0)
- {
- diff = diff + MAX_DELAY;
- }
-
-#ifdef ARM_WINM_LOG_
- // measure tick end
- QueryPerformanceCounter((LARGE_INTEGER*)&end);
- diff__ = ((end - start) * 1000) / (freq/1000);
- milliseconds = (unsigned int)(diff__ & 0xffffffff);
- WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
-#endif
-
- // END: Get the delay
-
-#ifdef ARM_WINM_LOG_
- // measure tick start
- QueryPerformanceCounter((LARGE_INTEGER*)&start);
-#endif
- // Calculate log(energy) and update energy threshold levels
- WebRtcAecm_CalcEnergies(aecm, diff, dfaNoisySum, echoEst32);
-
- // Calculate stepsize
- mu = WebRtcAecm_CalcStepSize(aecm);
-
- // Update counters
- aecm->totCount++;
- aecm->lastDelayUpdateCount++;
-
- // This is the channel estimation algorithm.
- // It is base on NLMS but has a variable step length, which was calculated above.
- WebRtcAecm_UpdateChannel(aecm, dfaNoisy, diff, mu, echoEst32);
- WebRtcAecm_DelayCompensation(aecm);
- supGain = WebRtcAecm_CalcSuppressionGain(aecm);
-
-#ifdef ARM_WINM_LOG_
- // measure tick end
- QueryPerformanceCounter((LARGE_INTEGER*)&end);
- diff__ = ((end - start) * 1000) / (freq/1000);
- milliseconds = (unsigned int)(diff__ & 0xffffffff);
- WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
-#endif
-
-#ifdef ARM_WINM_LOG_
- // measure tick start
- QueryPerformanceCounter((LARGE_INTEGER*)&start);
-#endif
-
- // Calculate Wiener filter hnl[]
- numPosCoef = 0;
- diffMinusOne = diff - 1;
- if (diff == 0)
- {
- diffMinusOne = MAX_DELAY;
- }
- for (i = 0; i < PART_LEN1; i++)
- {
- // Far end signal through channel estimate in Q8
- // How much can we shift right to preserve resolution
- tmp32no1 = echoEst32[i] - aecm->echoFilt[i];
- aecm->echoFilt[i] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32no1, 50), 8);
-
- zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1;
- zeros16 = WebRtcSpl_NormW16(supGain) + 1;
- if (zeros32 + zeros16 > 16)
- {
- // Multiplication is safe
- // Result in Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+aecm->xfaQDomainBuf[diff])
- echoEst32Gained = WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32)aecm->echoFilt[i],
- (WebRtc_UWord16)supGain);
- resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
- resolutionDiff += (aecm->dfaCleanQDomain - aecm->xfaQDomainBuf[diff]);
- } else
- {
- tmp16no1 = 17 - zeros32 - zeros16;
- resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
- resolutionDiff += (aecm->dfaCleanQDomain - aecm->xfaQDomainBuf[diff]);
- if (zeros32 > tmp16no1)
- {
- echoEst32Gained = WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32)aecm->echoFilt[i],
- (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_W16(supGain,
- tmp16no1)); // Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
- } else
- {
- // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
- echoEst32Gained = WEBRTC_SPL_UMUL_32_16(
- (WebRtc_UWord32)WEBRTC_SPL_RSHIFT_W32(aecm->echoFilt[i], tmp16no1),
- (WebRtc_UWord16)supGain);
- }
- }
-
- zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]);
- if ((zeros16 < (aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld))
- & (aecm->nearFilt[i]))
- {
- tmp16no1 = WEBRTC_SPL_SHIFT_W16(aecm->nearFilt[i], zeros16);
- qDomainDiff = zeros16 - aecm->dfaCleanQDomain + aecm->dfaCleanQDomainOld;
- } else
- {
- tmp16no1 = WEBRTC_SPL_SHIFT_W16(aecm->nearFilt[i], aecm->dfaCleanQDomain
- - aecm->dfaCleanQDomainOld);
- qDomainDiff = 0;
- }
- tmp16no2 = WEBRTC_SPL_SHIFT_W16(ptrDfaClean[i], qDomainDiff);
- tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no2 - tmp16no1, 1, 4);
- tmp16no2 += tmp16no1;
- zeros16 = WebRtcSpl_NormW16(tmp16no2);
- if ((tmp16no2) & (-qDomainDiff > zeros16))
- {
- aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX;
- } else
- {
- aecm->nearFilt[i] = WEBRTC_SPL_SHIFT_W16(tmp16no2, -qDomainDiff);
- }
-
- // Wiener filter coefficients, resulting hnl in Q14
- if (echoEst32Gained == 0)
- {
- hnl[i] = ONE_Q14;
- } else if (aecm->nearFilt[i] == 0)
- {
- hnl[i] = 0;
- } else
- {
- // Multiply the suppression gain
- // Rounding
- echoEst32Gained += (WebRtc_UWord32)(aecm->nearFilt[i] >> 1);
- tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained, (WebRtc_UWord16)aecm->nearFilt[i]);
-
- // Current resolution is
- // Q-(RESOLUTION_CHANNEL + RESOLUTION_SUPGAIN - max(0, 17 - zeros16 - zeros32))
- // Make sure we are in Q14
- tmp32no1 = (WebRtc_Word32)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff);
- if (tmp32no1 > ONE_Q14)
- {
- hnl[i] = 0;
- } else if (tmp32no1 < 0)
- {
- hnl[i] = ONE_Q14;
- } else
- {
- // 1-echoEst/dfa
-#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
- hnl[i] = ONE_Q14 - (WebRtc_Word16)tmp32no1;
- if (hnl[i] < 0)
- {
- hnl[i] = 0;
- }
-#else
- hnl[i] = ((ONE_Q14 - (WebRtc_Word16)tmp32no1) > 0) ? (ONE_Q14 - (WebRtc_Word16)tmp32no1) : 0;
-#endif
- }
- }
- if (hnl[i])
- {
- numPosCoef++;
- }
- }
-
-#ifdef ARM_WINM_LOG_
- // measure tick end
- QueryPerformanceCounter((LARGE_INTEGER*)&end);
- diff__ = ((end - start) * 1000) / (freq/1000);
- milliseconds = (unsigned int)(diff__ & 0xffffffff);
- WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
-#endif
-
-#ifdef ARM_WINM_LOG_
- // measure tick start
- QueryPerformanceCounter((LARGE_INTEGER*)&start);
-#endif
-
- // Calculate NLP gain, result is in Q14
- for (i = 0; i < PART_LEN1; i++)
- {
- if (aecm->nlpFlag)
- {
- // Truncate values close to zero and one.
- if (hnl[i] > NLP_COMP_HIGH)
- {
- hnl[i] = ONE_Q14;
- } else if (hnl[i] < NLP_COMP_LOW)
- {
- hnl[i] = 0;
- }
-
- // Remove outliers
- if (numPosCoef < 3)
- {
- nlpGain = 0;
- } else
- {
- nlpGain = ONE_Q14;
- }
- // NLP
- if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14))
- {
- hnl[i] = ONE_Q14;
- } else
- {
- hnl[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(hnl[i], nlpGain, 14);
- }
- }
-
- // multiply with Wiener coefficients
- efwReal[i] = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfwReal[i], hnl[i],
- 14));
- efwImag[i] = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfwImag[i], hnl[i],
- 14));
- }
-
- if (aecm->cngMode == AecmTrue)
- {
- WebRtcAecm_ComfortNoise(aecm, ptrDfaClean, efwReal, efwImag, hnl);
- }
-
-#ifdef ARM_WINM_LOG_
- // measure tick end
- QueryPerformanceCounter((LARGE_INTEGER*)&end);
- diff__ = ((end - start) * 1000) / (freq/1000);
- milliseconds = (unsigned int)(diff__ & 0xffffffff);
- WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
-#endif
-
-#ifdef ARM_WINM_LOG_
- // measure tick start
- QueryPerformanceCounter((LARGE_INTEGER*)&start);
-#endif
-
- // Synthesis
- for (i = 1; i < PART_LEN; i++)
- {
- j = WEBRTC_SPL_LSHIFT_W32(i, 1);
- fft[j] = efwReal[i];
-
- // mirrored data, even
- fft[PART_LEN4 - j] = efwReal[i];
- fft[j + 1] = -efwImag[i];
-
- //mirrored data, odd
- fft[PART_LEN4 - (j - 1)] = efwImag[i];
- }
- fft[0] = efwReal[0];
- fft[1] = -efwImag[0];
-
- fft[PART_LEN2] = efwReal[PART_LEN];
- fft[PART_LEN2 + 1] = -efwImag[PART_LEN];
-
-#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
- // inverse FFT, result should be scaled with outCFFT
- WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
- outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1);
-
- //take only the real values and scale with outCFFT
- for (i = 0; i < PART_LEN2; i++)
- {
- j = WEBRTC_SPL_LSHIFT_W32(i, 1);
- fft[i] = fft[j];
- }
-#else
- outCFFT = WebRtcSpl_ComplexIFFT2(fft, postFft, PART_LEN_SHIFT, 1);
-
- //take only the real values and scale with outCFFT
- for(i = 0, j = 0; i < PART_LEN2;)
- {
- fft[i] = postFft[j];
- i += 1;
- j += 2;
- fft[i] = postFft[j];
- i += 1;
- j += 2;
- }
-#endif
-
- for (i = 0; i < PART_LEN; i++)
- {
- fft[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- fft[i],
- kSqrtHanning[i],
- 14);
- tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)fft[i],
- outCFFT - aecm->dfaCleanQDomain);
- fft[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
- tmp32no1 + aecm->outBuf[i],
- WEBRTC_SPL_WORD16_MIN);
- output[i] = fft[i];
-
- tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT(
- fft[PART_LEN + i],
- kSqrtHanning[PART_LEN - i],
- 14);
- tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1,
- outCFFT - aecm->dfaCleanQDomain);
- aecm->outBuf[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(
- WEBRTC_SPL_WORD16_MAX,
- tmp32no1,
- WEBRTC_SPL_WORD16_MIN);
- }
-
-#ifdef ARM_WINM_LOG_
- // measure tick end
- QueryPerformanceCounter((LARGE_INTEGER*)&end);
- diff__ = ((end - start) * 1000) / (freq/1000);
- milliseconds = (unsigned int)(diff__ & 0xffffffff);
- WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
-#endif
- // Copy the current block to the old position (outBuf is shifted elsewhere)
- memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN);
- memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN);
- if (nearendClean != NULL)
- {
- memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN);
- }
-}
-
-// Generate comfort noise and add to output signal.
-//
-// \param[in] aecm Handle of the AECM instance.
-// \param[in] dfa Absolute value of the nearend signal (Q[aecm->dfaQDomain]).
-// \param[in,out] outReal Real part of the output signal (Q[aecm->dfaQDomain]).
-// \param[in,out] outImag Imaginary part of the output signal (Q[aecm->dfaQDomain]).
-// \param[in] lambda Suppression gain with which to scale the noise level (Q14).
-//
-static void WebRtcAecm_ComfortNoise(AecmCore_t * const aecm, const WebRtc_UWord16 * const dfa,
- WebRtc_Word16 * const outReal,
- WebRtc_Word16 * const outImag,
- const WebRtc_Word16 * const lambda)
-{
- WebRtc_Word16 i;
- WebRtc_Word16 tmp16;
- WebRtc_Word32 tmp32;
-
- WebRtc_Word16 randW16[PART_LEN];
- WebRtc_Word16 uReal[PART_LEN1];
- WebRtc_Word16 uImag[PART_LEN1];
- WebRtc_Word32 outLShift32[PART_LEN1];
- WebRtc_Word16 noiseRShift16[PART_LEN1];
-
- WebRtc_Word16 shiftFromNearToNoise[PART_LEN1];
- WebRtc_Word16 minTrackShift;
- WebRtc_Word32 upper32;
- WebRtc_Word32 lower32;
-
- if (aecm->noiseEstCtr < 100)
- {
- // Track the minimum more quickly initially.
- aecm->noiseEstCtr++;
- minTrackShift = 7;
- } else
- {
- minTrackShift = 9;
- }
-
- // Estimate noise power.
- for (i = 0; i < PART_LEN1; i++)
- {
- shiftFromNearToNoise[i] = aecm->noiseEstQDomain[i] - aecm->dfaCleanQDomain;
-
- // Shift to the noise domain.
- tmp32 = (WebRtc_Word32)dfa[i];
- outLShift32[i] = WEBRTC_SPL_SHIFT_W32(tmp32, shiftFromNearToNoise[i]);
-
- if (outLShift32[i] < aecm->noiseEst[i])
- {
- // Track the minimum.
- aecm->noiseEst[i] += ((outLShift32[i] - aecm->noiseEst[i]) >> minTrackShift);
- } else
- {
- // Ramp slowly upwards until we hit the minimum again.
-
- // Avoid overflow.
- if (aecm->noiseEst[i] < 2146435583)
- {
- // Store the fractional portion.
- upper32 = (aecm->noiseEst[i] & 0xffff0000) >> 16;
- lower32 = aecm->noiseEst[i] & 0x0000ffff;
- upper32 = ((upper32 * 2049) >> 11);
- lower32 = ((lower32 * 2049) >> 11);
- aecm->noiseEst[i] = WEBRTC_SPL_ADD_SAT_W32(upper32 << 16, lower32);
- }
- }
- }
-
- for (i = 0; i < PART_LEN1; i++)
- {
- tmp32 = WEBRTC_SPL_SHIFT_W32(aecm->noiseEst[i], -shiftFromNearToNoise[i]);
- if (tmp32 > 32767)
- {
- tmp32 = 32767;
- aecm->noiseEst[i] = WEBRTC_SPL_SHIFT_W32(tmp32, shiftFromNearToNoise[i]);
- }
- noiseRShift16[i] = (WebRtc_Word16)tmp32;
-
- tmp16 = ONE_Q14 - lambda[i];
- noiseRShift16[i]
- = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, noiseRShift16[i], 14);
- }
-
- // Generate a uniform random array on [0 2^15-1].
- WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
-
- // Generate noise according to estimated energy.
- uReal[0] = 0; // Reject LF noise.
- uImag[0] = 0;
- for (i = 1; i < PART_LEN1; i++)
- {
- // Get a random index for the cos and sin tables over [0 359].
- tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(359, randW16[i - 1], 15);
-
- // Tables are in Q13.
- uReal[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(noiseRShift16[i],
- WebRtcSpl_kCosTable[tmp16], 13);
- uImag[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(-noiseRShift16[i],
- WebRtcSpl_kSinTable[tmp16], 13);
- }
- uImag[PART_LEN] = 0;
-
-#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT)
- for (i = 0; i < PART_LEN1; i++)
- {
- outReal[i] = WEBRTC_SPL_ADD_SAT_W16(outReal[i], uReal[i]);
- outImag[i] = WEBRTC_SPL_ADD_SAT_W16(outImag[i], uImag[i]);
- }
-#else
- for (i = 0; i < PART_LEN1 -1; )
- {
- outReal[i] = WEBRTC_SPL_ADD_SAT_W16(outReal[i], uReal[i]);
- outImag[i] = WEBRTC_SPL_ADD_SAT_W16(outImag[i], uImag[i]);
- i++;
-
- outReal[i] = WEBRTC_SPL_ADD_SAT_W16(outReal[i], uReal[i]);
- outImag[i] = WEBRTC_SPL_ADD_SAT_W16(outImag[i], uImag[i]);
- i++;
- }
- outReal[i] = WEBRTC_SPL_ADD_SAT_W16(outReal[i], uReal[i]);
- outImag[i] = WEBRTC_SPL_ADD_SAT_W16(outImag[i], uImag[i]);
-#endif
-}
-
-void WebRtcAecm_BufferFarFrame(AecmCore_t * const aecm, const WebRtc_Word16 * const farend,
- const int farLen)
-{
- int writeLen = farLen, writePos = 0;
-
- // Check if the write position must be wrapped
- while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN)
- {
- // Write to remaining buffer space before wrapping
- writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
- memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
- sizeof(WebRtc_Word16) * writeLen);
- aecm->farBufWritePos = 0;
- writePos = writeLen;
- writeLen = farLen - writeLen;
- }
-
- memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
- sizeof(WebRtc_Word16) * writeLen);
- aecm->farBufWritePos += writeLen;
-}
-
-void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, WebRtc_Word16 * const farend,
- const int farLen, const int knownDelay)
-{
- int readLen = farLen;
- int readPos = 0;
- int delayChange = knownDelay - aecm->lastKnownDelay;
-
- aecm->farBufReadPos -= delayChange;
-
- // Check if delay forces a read position wrap
- while (aecm->farBufReadPos < 0)
- {
- aecm->farBufReadPos += FAR_BUF_LEN;
- }
- while (aecm->farBufReadPos > FAR_BUF_LEN - 1)
- {
- aecm->farBufReadPos -= FAR_BUF_LEN;
- }
-
- aecm->lastKnownDelay = knownDelay;
-
- // Check if read position must be wrapped
- while (aecm->farBufReadPos + readLen > FAR_BUF_LEN)
- {
-
- // Read from remaining buffer space before wrapping
- readLen = FAR_BUF_LEN - aecm->farBufReadPos;
- memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
- sizeof(WebRtc_Word16) * readLen);
- aecm->farBufReadPos = 0;
- readPos = readLen;
- readLen = farLen - readLen;
- }
- memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
- sizeof(WebRtc_Word16) * readLen);
- aecm->farBufReadPos += readLen;
-}
diff --git a/src/modules/audio_processing/aecm/main/source/aecm_core.h b/src/modules/audio_processing/aecm/main/source/aecm_core.h
deleted file mode 100644
index 5defbe46c7..0000000000
--- a/src/modules/audio_processing/aecm/main/source/aecm_core.h
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// Performs echo control (suppression) with fft routines in fixed-point
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_CORE_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_CORE_H_
-
-#define AECM_DYNAMIC_Q // turn on/off dynamic Q-domain
-//#define AECM_WITH_ABS_APPROX
-//#define AECM_SHORT // for 32 sample partition length (otherwise 64)
-
-// TODO(bjornv): These defines will be removed in final version.
-//#define STORE_CHANNEL_DATA
-//#define VAD_DATA
-
-#include "typedefs.h"
-#include "signal_processing_library.h"
-// TODO(bjornv): Will be removed in final version.
-//#include <stdio.h>
-
-// Algorithm parameters
-
-#define FRAME_LEN 80 // Total frame length, 10 ms
-#ifdef AECM_SHORT
-
-#define PART_LEN 32 // Length of partition
-#define PART_LEN_SHIFT 6 // Length of (PART_LEN * 2) in base 2
-
-#else
-
-#define PART_LEN 64 // Length of partition
-#define PART_LEN_SHIFT 7 // Length of (PART_LEN * 2) in base 2
-
-#endif
-
-#define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients
-#define PART_LEN2 (PART_LEN << 1) // Length of partition * 2
-#define PART_LEN4 (PART_LEN << 2) // Length of partition * 4
-#define FAR_BUF_LEN PART_LEN4 // Length of buffers
-#define MAX_DELAY 100
-
-// Counter parameters
-#ifdef AECM_SHORT
-
-#define CONV_LEN 1024 // Convergence length used at startup
-#else
-
-#define CONV_LEN 512 // Convergence length used at startup
-#endif
-
-#define CONV_LEN2 (CONV_LEN << 1) // Convergence length * 2 used at startup
-// Energy parameters
-#define MAX_BUF_LEN 64 // History length of energy signals
-
-#define FAR_ENERGY_MIN 1025 // Lowest Far energy level: At least 2 in energy
-#define FAR_ENERGY_DIFF 929 // Allowed difference between max and min
-
-#define ENERGY_DEV_OFFSET 0 // The energy error offset in Q8
-#define ENERGY_DEV_TOL 400 // The energy estimation tolerance in Q8
-#define FAR_ENERGY_VAD_REGION 230 // Far VAD tolerance region
-// Stepsize parameters
-#define MU_MIN 10 // Min stepsize 2^-MU_MIN (far end energy dependent)
-#define MU_MAX 1 // Max stepsize 2^-MU_MAX (far end energy dependent)
-#define MU_DIFF 9 // MU_MIN - MU_MAX
-// Channel parameters
-#define MIN_MSE_COUNT 20 // Min number of consecutive blocks with enough far end
- // energy to compare channel estimates
-#define MIN_MSE_DIFF 29 // The ratio between adapted and stored channel to
- // accept a new storage (0.8 in Q-MSE_RESOLUTION)
-#define MSE_RESOLUTION 5 // MSE parameter resolution
-#define RESOLUTION_CHANNEL16 12 // W16 Channel in Q-RESOLUTION_CHANNEL16
-#define RESOLUTION_CHANNEL32 28 // W32 Channel in Q-RESOLUTION_CHANNEL
-#define CHANNEL_VAD 16 // Minimum energy in frequency band to update channel
-// Suppression gain parameters: SUPGAIN_ parameters in Q-(RESOLUTION_SUPGAIN)
-#define RESOLUTION_SUPGAIN 8 // Channel in Q-(RESOLUTION_SUPGAIN)
-#define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN) // Default suppression gain
-#define SUPGAIN_ERROR_PARAM_A 3072 // Estimation error parameter (Maximum gain) (8 in Q8)
-#define SUPGAIN_ERROR_PARAM_B 1536 // Estimation error parameter (Gain before going down)
-#define SUPGAIN_ERROR_PARAM_D SUPGAIN_DEFAULT // Estimation error parameter
- // (Should be the same as Default) (1 in Q8)
-#define SUPGAIN_EPC_DT 200 // = SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL
-// Defines for "check delay estimation"
-#define CORR_WIDTH 31 // Number of samples to correlate over.
-#define CORR_MAX 16 // Maximum correlation offset
-#define CORR_MAX_BUF 63
-#define CORR_DEV 4
-#define CORR_MAX_LEVEL 20
-#define CORR_MAX_LOW 4
-#define CORR_BUF_LEN (CORR_MAX << 1) + 1
-// Note that CORR_WIDTH + 2*CORR_MAX <= MAX_BUF_LEN
-
-#define ONE_Q14 (1 << 14)
-
-// NLP defines
-#define NLP_COMP_LOW 3277 // 0.2 in Q14
-#define NLP_COMP_HIGH ONE_Q14 // 1 in Q14
-
-typedef struct
-{
- int farBufWritePos;
- int farBufReadPos;
- int knownDelay;
- int lastKnownDelay;
- int firstVAD; // Parameter to control poorly initialized channels
-
- void *farFrameBuf;
- void *nearNoisyFrameBuf;
- void *nearCleanFrameBuf;
- void *outFrameBuf;
-
- WebRtc_Word16 xBuf[PART_LEN2]; // farend
- WebRtc_Word16 dBufClean[PART_LEN2]; // nearend
- WebRtc_Word16 dBufNoisy[PART_LEN2]; // nearend
- WebRtc_Word16 outBuf[PART_LEN];
-
- WebRtc_Word16 farBuf[FAR_BUF_LEN];
-
- WebRtc_Word16 mult;
- WebRtc_UWord32 seed;
-
- // Delay estimation variables
- WebRtc_UWord16 medianYlogspec[PART_LEN1];
- WebRtc_UWord16 medianXlogspec[PART_LEN1];
- WebRtc_UWord16 medianBCount[MAX_DELAY];
- WebRtc_UWord16 xfaHistory[PART_LEN1][MAX_DELAY];
- WebRtc_Word16 delHistoryPos;
- WebRtc_UWord32 bxHistory[MAX_DELAY];
- WebRtc_UWord16 currentDelay;
- WebRtc_UWord16 previousDelay;
- WebRtc_Word16 delayAdjust;
-
- WebRtc_Word16 nlpFlag;
- WebRtc_Word16 fixedDelay;
-
- WebRtc_UWord32 totCount;
-
- WebRtc_Word16 xfaQDomainBuf[MAX_DELAY];
- WebRtc_Word16 dfaCleanQDomain;
- WebRtc_Word16 dfaCleanQDomainOld;
- WebRtc_Word16 dfaNoisyQDomain;
- WebRtc_Word16 dfaNoisyQDomainOld;
-
- WebRtc_Word16 nearLogEnergy[MAX_BUF_LEN];
- WebRtc_Word16 farLogEnergy[MAX_BUF_LEN];
- WebRtc_Word16 echoAdaptLogEnergy[MAX_BUF_LEN];
- WebRtc_Word16 echoStoredLogEnergy[MAX_BUF_LEN];
-
- WebRtc_Word16 channelAdapt16[PART_LEN1];
- WebRtc_Word32 channelAdapt32[PART_LEN1];
- WebRtc_Word16 channelStored[PART_LEN1];
- WebRtc_Word32 echoFilt[PART_LEN1];
- WebRtc_Word16 nearFilt[PART_LEN1];
- WebRtc_Word32 noiseEst[PART_LEN1];
- WebRtc_Word16 noiseEstQDomain[PART_LEN1];
- WebRtc_Word16 noiseEstCtr;
- WebRtc_Word16 cngMode;
-
- WebRtc_Word32 mseAdaptOld;
- WebRtc_Word32 mseStoredOld;
- WebRtc_Word32 mseThreshold;
-
- WebRtc_Word16 farEnergyMin;
- WebRtc_Word16 farEnergyMax;
- WebRtc_Word16 farEnergyMaxMin;
- WebRtc_Word16 farEnergyVAD;
- WebRtc_Word16 farEnergyMSE;
- WebRtc_Word16 currentVADValue;
- WebRtc_Word16 vadUpdateCount;
-
- WebRtc_Word16 delayHistogram[MAX_DELAY];
- WebRtc_Word16 delayVadCount;
- WebRtc_Word16 maxDelayHistIdx;
- WebRtc_Word16 lastMinPos;
-
- WebRtc_Word16 startupState;
- WebRtc_Word16 mseChannelCount;
- WebRtc_Word16 delayCount;
- WebRtc_Word16 newDelayCorrData;
- WebRtc_Word16 lastDelayUpdateCount;
- WebRtc_Word16 delayCorrelation[CORR_BUF_LEN];
- WebRtc_Word16 supGain;
- WebRtc_Word16 supGainOld;
- WebRtc_Word16 delayOffsetFlag;
-
- WebRtc_Word16 supGainErrParamA;
- WebRtc_Word16 supGainErrParamD;
- WebRtc_Word16 supGainErrParamDiffAB;
- WebRtc_Word16 supGainErrParamDiffBD;
-
- // TODO(bjornv): Will be removed after final version has been committed.
-#ifdef VAD_DATA
- FILE *vad_file;
- FILE *delay_file;
- FILE *far_file;
- FILE *far_cur_file;
- FILE *far_min_file;
- FILE *far_max_file;
- FILE *far_vad_file;
-#endif
-
- // TODO(bjornv): Will be removed after final version has been committed.
-#ifdef STORE_CHANNEL_DATA
- FILE *channel_file;
- FILE *channel_file_init;
-#endif
-
-#ifdef AEC_DEBUG
- FILE *farFile;
- FILE *nearFile;
- FILE *outFile;
-#endif
-} AecmCore_t;
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// WebRtcAecm_CreateCore(...)
-//
-// Allocates the memory needed by the AECM. The memory needs to be
-// initialized separately using the WebRtcAecm_InitCore() function.
-//
-// Input:
-// - aecm : Instance that should be created
-//
-// Output:
-// - aecm : Created instance
-//
-// Return value : 0 - Ok
-// -1 - Error
-//
-int WebRtcAecm_CreateCore(AecmCore_t **aecm);
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// WebRtcAecm_InitCore(...)
-//
-// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
-// Input:
-// - aecm : Pointer to the AECM instance
-// - samplingFreq : Sampling Frequency
-//
-// Output:
-// - aecm : Initialized instance
-//
-// Return value : 0 - Ok
-// -1 - Error
-//
-int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq);
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// WebRtcAecm_FreeCore(...)
-//
-// This function releases the memory allocated by WebRtcAecm_CreateCore()
-// Input:
-// - aecm : Pointer to the AECM instance
-//
-// Return value : 0 - Ok
-// -1 - Error
-// 11001-11016: Error
-//
-int WebRtcAecm_FreeCore(AecmCore_t *aecm);
-
-int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag, int delayOffsetFlag);
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// WebRtcAecm_ProcessFrame(...)
-//
-// This function processes frames and sends blocks to WebRtcAecm_ProcessBlock(...)
-//
-// Inputs:
-// - aecm : Pointer to the AECM instance
-// - farend : In buffer containing one frame of echo signal
-// - nearendNoisy : In buffer containing one frame of nearend+echo signal without NS
-// - nearendClean : In buffer containing one frame of nearend+echo signal with NS
-//
-// Output:
-// - out : Out buffer, one frame of nearend signal :
-//
-//
-void WebRtcAecm_ProcessFrame(AecmCore_t * const aecm, const WebRtc_Word16 * const farend,
- const WebRtc_Word16 * const nearendNoisy,
- const WebRtc_Word16 * const nearendClean,
- WebRtc_Word16 * const out);
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// WebRtcAecm_ProcessBlock(...)
-//
-// This function is called for every block within one frame
-// This function is called by WebRtcAecm_ProcessFrame(...)
-//
-// Inputs:
-// - aecm : Pointer to the AECM instance
-// - farend : In buffer containing one block of echo signal
-// - nearendNoisy : In buffer containing one frame of nearend+echo signal without NS
-// - nearendClean : In buffer containing one frame of nearend+echo signal with NS
-//
-// Output:
-// - out : Out buffer, one block of nearend signal :
-//
-//
-void WebRtcAecm_ProcessBlock(AecmCore_t * const aecm, const WebRtc_Word16 * const farend,
- const WebRtc_Word16 * const nearendNoisy,
- const WebRtc_Word16 * const noisyClean,
- WebRtc_Word16 * const out);
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// WebRtcAecm_BufferFarFrame()
-//
-// Inserts a frame of data into farend buffer.
-//
-// Inputs:
-// - aecm : Pointer to the AECM instance
-// - farend : In buffer containing one frame of farend signal
-// - farLen : Length of frame
-//
-void WebRtcAecm_BufferFarFrame(AecmCore_t * const aecm, const WebRtc_Word16 * const farend,
- const int farLen);
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// WebRtcAecm_FetchFarFrame()
-//
-// Read the farend buffer to account for known delay
-//
-// Inputs:
-// - aecm : Pointer to the AECM instance
-// - farend : In buffer containing one frame of farend signal
-// - farLen : Length of frame
-// - knownDelay : known delay
-//
-void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, WebRtc_Word16 * const farend,
- const int farLen, const int knownDelay);
-
-#endif
diff --git a/src/modules/audio_processing/aecm/main/source/echo_control_mobile.c b/src/modules/audio_processing/aecm/main/source/echo_control_mobile.c
deleted file mode 100644
index f9d84f0c4b..0000000000
--- a/src/modules/audio_processing/aecm/main/source/echo_control_mobile.c
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include <stdlib.h>
-//#include <string.h>
-
-#include "echo_control_mobile.h"
-#include "aecm_core.h"
-#include "ring_buffer.h"
-#ifdef AEC_DEBUG
-#include <stdio.h>
-#endif
-#ifdef MAC_IPHONE_PRINT
-#include <time.h>
-#include <stdio.h>
-#elif defined ARM_WINM_LOG
-#include "windows.h"
-extern HANDLE logFile;
-#endif
-
-#define BUF_SIZE_FRAMES 50 // buffer size (frames)
-// Maximum length of resampled signal. Must be an integer multiple of frames
-// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
-// The factor of 2 handles wb, and the + 1 is as a safety margin
-#define MAX_RESAMP_LEN (5 * FRAME_LEN)
-
-static const int kBufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
-static const int kSampMsNb = 8; // samples per ms in nb
-// Target suppression levels for nlp modes
-// log{0.001, 0.00001, 0.00000001}
-static const int kInitCheck = 42;
-
-typedef struct
-{
- int sampFreq;
- int scSampFreq;
- short bufSizeStart;
- int knownDelay;
-
- // Stores the last frame added to the farend buffer
- short farendOld[2][FRAME_LEN];
- short initFlag; // indicates if AEC has been initialized
-
- // Variables used for averaging far end buffer size
- short counter;
- short sum;
- short firstVal;
- short checkBufSizeCtr;
-
- // Variables used for delay shifts
- short msInSndCardBuf;
- short filtDelay;
- int timeForDelayChange;
- int ECstartup;
- int checkBuffSize;
- int delayChange;
- short lastDelayDiff;
-
- WebRtc_Word16 echoMode;
-
-#ifdef AEC_DEBUG
- FILE *bufFile;
- FILE *delayFile;
- FILE *preCompFile;
- FILE *postCompFile;
-#endif // AEC_DEBUG
- // Structures
- void *farendBuf;
-
- int lastError;
-
- AecmCore_t *aecmCore;
-} aecmob_t;
-
-// Estimates delay to set the position of the farend buffer read pointer
-// (controlled by knownDelay)
-static int WebRtcAecm_EstBufDelay(aecmob_t *aecmInst, short msInSndCardBuf);
-
-// Stuffs the farend buffer if the estimated delay is too large
-static int WebRtcAecm_DelayComp(aecmob_t *aecmInst);
-
-WebRtc_Word32 WebRtcAecm_Create(void **aecmInst)
-{
- aecmob_t *aecm;
- if (aecmInst == NULL)
- {
- return -1;
- }
-
- aecm = malloc(sizeof(aecmob_t));
- *aecmInst = aecm;
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (WebRtcAecm_CreateCore(&aecm->aecmCore) == -1)
- {
- WebRtcAecm_Free(aecm);
- aecm = NULL;
- return -1;
- }
-
- if (WebRtcApm_CreateBuffer(&aecm->farendBuf, kBufSizeSamp) == -1)
- {
- WebRtcAecm_Free(aecm);
- aecm = NULL;
- return -1;
- }
-
- aecm->initFlag = 0;
- aecm->lastError = 0;
-
-#ifdef AEC_DEBUG
- aecm->aecmCore->farFile = fopen("aecFar.pcm","wb");
- aecm->aecmCore->nearFile = fopen("aecNear.pcm","wb");
- aecm->aecmCore->outFile = fopen("aecOut.pcm","wb");
- //aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb");
-
- aecm->bufFile = fopen("aecBuf.dat", "wb");
- aecm->delayFile = fopen("aecDelay.dat", "wb");
- aecm->preCompFile = fopen("preComp.pcm", "wb");
- aecm->postCompFile = fopen("postComp.pcm", "wb");
-#endif // AEC_DEBUG
- return 0;
-}
-
-WebRtc_Word32 WebRtcAecm_Free(void *aecmInst)
-{
- aecmob_t *aecm = aecmInst;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
-#ifdef AEC_DEBUG
- fclose(aecm->aecmCore->farFile);
- fclose(aecm->aecmCore->nearFile);
- fclose(aecm->aecmCore->outFile);
- //fclose(aecm->aecmCore->outLpFile);
-
- fclose(aecm->bufFile);
- fclose(aecm->delayFile);
- fclose(aecm->preCompFile);
- fclose(aecm->postCompFile);
-#endif // AEC_DEBUG
- WebRtcAecm_FreeCore(aecm->aecmCore);
- WebRtcApm_FreeBuffer(aecm->farendBuf);
- free(aecm);
-
- return 0;
-}
-
-WebRtc_Word32 WebRtcAecm_Init(void *aecmInst, WebRtc_Word32 sampFreq, WebRtc_Word32 scSampFreq)
-{
- aecmob_t *aecm = aecmInst;
- AecmConfig aecConfig;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (sampFreq != 8000 && sampFreq != 16000)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
- aecm->sampFreq = sampFreq;
-
- if (scSampFreq < 1 || scSampFreq > 96000)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
- aecm->scSampFreq = scSampFreq;
-
- // Initialize AECM core
- if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1)
- {
- aecm->lastError = AECM_UNSPECIFIED_ERROR;
- return -1;
- }
-
- // Initialize farend buffer
- if (WebRtcApm_InitBuffer(aecm->farendBuf) == -1)
- {
- aecm->lastError = AECM_UNSPECIFIED_ERROR;
- return -1;
- }
-
- aecm->initFlag = kInitCheck; // indicates that initialization has been done
-
- aecm->delayChange = 1;
-
- aecm->sum = 0;
- aecm->counter = 0;
- aecm->checkBuffSize = 1;
- aecm->firstVal = 0;
-
- aecm->ECstartup = 1;
- aecm->bufSizeStart = 0;
- aecm->checkBufSizeCtr = 0;
- aecm->filtDelay = 0;
- aecm->timeForDelayChange = 0;
- aecm->knownDelay = 0;
- aecm->lastDelayDiff = 0;
-
- memset(&aecm->farendOld[0][0], 0, 160);
-
- // Default settings.
- aecConfig.cngMode = AecmTrue;
- aecConfig.echoMode = 3;
-
- if (WebRtcAecm_set_config(aecm, aecConfig) == -1)
- {
- aecm->lastError = AECM_UNSPECIFIED_ERROR;
- return -1;
- }
-
- return 0;
-}
-
-WebRtc_Word32 WebRtcAecm_BufferFarend(void *aecmInst, const WebRtc_Word16 *farend,
- WebRtc_Word16 nrOfSamples)
-{
- aecmob_t *aecm = aecmInst;
- WebRtc_Word32 retVal = 0;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (farend == NULL)
- {
- aecm->lastError = AECM_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (aecm->initFlag != kInitCheck)
- {
- aecm->lastError = AECM_UNINITIALIZED_ERROR;
- return -1;
- }
-
- if (nrOfSamples != 80 && nrOfSamples != 160)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
-
- // TODO: Is this really a good idea?
- if (!aecm->ECstartup)
- {
- WebRtcAecm_DelayComp(aecm);
- }
-
- WebRtcApm_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
-
- return retVal;
-}
-
-WebRtc_Word32 WebRtcAecm_Process(void *aecmInst, const WebRtc_Word16 *nearendNoisy,
- const WebRtc_Word16 *nearendClean, WebRtc_Word16 *out,
- WebRtc_Word16 nrOfSamples, WebRtc_Word16 msInSndCardBuf)
-{
- aecmob_t *aecm = aecmInst;
- WebRtc_Word32 retVal = 0;
- short i;
- short farend[FRAME_LEN];
- short nmbrOfFilledBuffers;
- short nBlocks10ms;
- short nFrames;
-#ifdef AEC_DEBUG
- short msInAECBuf;
-#endif
-
-#ifdef ARM_WINM_LOG
- __int64 freq, start, end, diff;
- unsigned int milliseconds;
- DWORD temp;
-#elif defined MAC_IPHONE_PRINT
- // double endtime = 0, starttime = 0;
- struct timeval starttime;
- struct timeval endtime;
- static long int timeused = 0;
- static int timecount = 0;
-#endif
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (nearendNoisy == NULL)
- {
- aecm->lastError = AECM_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (out == NULL)
- {
- aecm->lastError = AECM_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (aecm->initFlag != kInitCheck)
- {
- aecm->lastError = AECM_UNINITIALIZED_ERROR;
- return -1;
- }
-
- if (nrOfSamples != 80 && nrOfSamples != 160)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
-
- if (msInSndCardBuf < 0)
- {
- msInSndCardBuf = 0;
- aecm->lastError = AECM_BAD_PARAMETER_WARNING;
- retVal = -1;
- } else if (msInSndCardBuf > 500)
- {
- msInSndCardBuf = 500;
- aecm->lastError = AECM_BAD_PARAMETER_WARNING;
- retVal = -1;
- }
- msInSndCardBuf += 10;
- aecm->msInSndCardBuf = msInSndCardBuf;
-
- nFrames = nrOfSamples / FRAME_LEN;
- nBlocks10ms = nFrames / aecm->aecmCore->mult;
-
- if (aecm->ECstartup)
- {
- if (nearendClean == NULL)
- {
- memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
- } else
- {
- memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
- }
-
- nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecm->farendBuf) / FRAME_LEN;
- // The AECM is in the start up mode
- // AECM is disabled until the soundcard buffer and farend buffers are OK
-
- // Mechanism to ensure that the soundcard buffer is reasonably stable.
- if (aecm->checkBuffSize)
- {
- aecm->checkBufSizeCtr++;
- // Before we fill up the far end buffer we require the amount of data on the
- // sound card to be stable (+/-8 ms) compared to the first value. This
- // comparison is made during the following 4 consecutive frames. If it seems
- // to be stable then we start to fill up the far end buffer.
-
- if (aecm->counter == 0)
- {
- aecm->firstVal = aecm->msInSndCardBuf;
- aecm->sum = 0;
- }
-
- if (abs(aecm->firstVal - aecm->msInSndCardBuf)
- < WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb))
- {
- aecm->sum += aecm->msInSndCardBuf;
- aecm->counter++;
- } else
- {
- aecm->counter = 0;
- }
-
- if (aecm->counter * nBlocks10ms >= 6)
- {
- // The farend buffer size is determined in blocks of 80 samples
- // Use 75% of the average value of the soundcard buffer
- aecm->bufSizeStart
- = WEBRTC_SPL_MIN((3 * aecm->sum
- * aecm->aecmCore->mult) / (aecm->counter * 40), BUF_SIZE_FRAMES);
- // buffersize has now been determined
- aecm->checkBuffSize = 0;
- }
-
- if (aecm->checkBufSizeCtr * nBlocks10ms > 50)
- {
- // for really bad sound cards, don't disable echocanceller for more than 0.5 sec
- aecm->bufSizeStart = WEBRTC_SPL_MIN((3 * aecm->msInSndCardBuf
- * aecm->aecmCore->mult) / 40, BUF_SIZE_FRAMES);
- aecm->checkBuffSize = 0;
- }
- }
-
- // if checkBuffSize changed in the if-statement above
- if (!aecm->checkBuffSize)
- {
- // soundcard buffer is now reasonably stable
- // When the far end buffer is filled with approximately the same amount of
- // data as the amount on the sound card we end the start up phase and start
- // to cancel echoes.
-
- if (nmbrOfFilledBuffers == aecm->bufSizeStart)
- {
- aecm->ECstartup = 0; // Enable the AECM
- } else if (nmbrOfFilledBuffers > aecm->bufSizeStart)
- {
- WebRtcApm_FlushBuffer(
- aecm->farendBuf,
- WebRtcApm_get_buffer_size(aecm->farendBuf)
- - aecm->bufSizeStart * FRAME_LEN);
- aecm->ECstartup = 0;
- }
- }
-
- } else
- {
- // AECM is enabled
-
- // Note only 1 block supported for nb and 2 blocks for wb
- for (i = 0; i < nFrames; i++)
- {
- nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecm->farendBuf) / FRAME_LEN;
-
- // Check that there is data in the far end buffer
- if (nmbrOfFilledBuffers > 0)
- {
- // Get the next 80 samples from the farend buffer
- WebRtcApm_ReadBuffer(aecm->farendBuf, farend, FRAME_LEN);
-
- // Always store the last frame for use when we run out of data
- memcpy(&(aecm->farendOld[i][0]), farend, FRAME_LEN * sizeof(short));
- } else
- {
- // We have no data so we use the last played frame
- memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
- }
-
- // Call buffer delay estimator when all data is extracted,
- // i,e. i = 0 for NB and i = 1 for WB
- if ((i == 0 && aecm->sampFreq == 8000) || (i == 1 && aecm->sampFreq == 16000))
- {
- WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
- }
-
-#ifdef ARM_WINM_LOG
- // measure tick start
- QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
- QueryPerformanceCounter((LARGE_INTEGER*)&start);
-#elif defined MAC_IPHONE_PRINT
- // starttime = clock()/(double)CLOCKS_PER_SEC;
- gettimeofday(&starttime, NULL);
-#endif
- // Call the AECM
- /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
- &out[FRAME_LEN * i], aecm->knownDelay);*/
- if (nearendClean == NULL)
- {
- WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearendNoisy[FRAME_LEN * i],
- NULL, &out[FRAME_LEN * i]);
- } else
- {
- WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearendNoisy[FRAME_LEN * i],
- &nearendClean[FRAME_LEN * i], &out[FRAME_LEN * i]);
- }
-
-#ifdef ARM_WINM_LOG
-
- // measure tick end
- QueryPerformanceCounter((LARGE_INTEGER*)&end);
-
- if(end > start)
- {
- diff = ((end - start) * 1000) / (freq/1000);
- milliseconds = (unsigned int)(diff & 0xffffffff);
- WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
- }
-#elif defined MAC_IPHONE_PRINT
- // endtime = clock()/(double)CLOCKS_PER_SEC;
- // printf("%f\n", endtime - starttime);
-
- gettimeofday(&endtime, NULL);
-
- if( endtime.tv_usec > starttime.tv_usec)
- {
- timeused += endtime.tv_usec - starttime.tv_usec;
- } else
- {
- timeused += endtime.tv_usec + 1000000 - starttime.tv_usec;
- }
-
- if(++timecount == 1000)
- {
- timecount = 0;
- printf("AEC: %ld\n", timeused);
- timeused = 0;
- }
-#endif
-
- }
- }
-
-#ifdef AEC_DEBUG
- msInAECBuf = WebRtcApm_get_buffer_size(aecm->farendBuf) / (kSampMsNb*aecm->aecmCore->mult);
- fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
- fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
-#endif
-
- return retVal;
-}
-
-WebRtc_Word32 WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
-{
- aecmob_t *aecm = aecmInst;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (aecm->initFlag != kInitCheck)
- {
- aecm->lastError = AECM_UNINITIALIZED_ERROR;
- return -1;
- }
-
- if (config.cngMode != AecmFalse && config.cngMode != AecmTrue)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
- aecm->aecmCore->cngMode = config.cngMode;
-
- if (config.echoMode < 0 || config.echoMode > 4)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
- aecm->echoMode = config.echoMode;
-
- if (aecm->echoMode == 0)
- {
- aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
- aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
- aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
- aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
- aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 3)
- - (SUPGAIN_ERROR_PARAM_B >> 3);
- aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 3)
- - (SUPGAIN_ERROR_PARAM_D >> 3);
- } else if (aecm->echoMode == 1)
- {
- aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
- aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
- aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
- aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
- aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 2)
- - (SUPGAIN_ERROR_PARAM_B >> 2);
- aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 2)
- - (SUPGAIN_ERROR_PARAM_D >> 2);
- } else if (aecm->echoMode == 2)
- {
- aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
- aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
- aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
- aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
- aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 1)
- - (SUPGAIN_ERROR_PARAM_B >> 1);
- aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 1)
- - (SUPGAIN_ERROR_PARAM_D >> 1);
- } else if (aecm->echoMode == 3)
- {
- aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
- aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
- aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
- aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
- aecm->aecmCore->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
- aecm->aecmCore->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
- } else if (aecm->echoMode == 4)
- {
- aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
- aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
- aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
- aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
- aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A << 1)
- - (SUPGAIN_ERROR_PARAM_B << 1);
- aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B << 1)
- - (SUPGAIN_ERROR_PARAM_D << 1);
- }
-
- return 0;
-}
-
-WebRtc_Word32 WebRtcAecm_get_config(void *aecmInst, AecmConfig *config)
-{
- aecmob_t *aecm = aecmInst;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (config == NULL)
- {
- aecm->lastError = AECM_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (aecm->initFlag != kInitCheck)
- {
- aecm->lastError = AECM_UNINITIALIZED_ERROR;
- return -1;
- }
-
- config->cngMode = aecm->aecmCore->cngMode;
- config->echoMode = aecm->echoMode;
-
- return 0;
-}
-
-WebRtc_Word32 WebRtcAecm_get_version(WebRtc_Word8 *versionStr, WebRtc_Word16 len)
-{
- const char version[] = "AECM 1.2.0";
- const short versionLen = (short)strlen(version) + 1; // +1 for null-termination
-
- if (versionStr == NULL)
- {
- return -1;
- }
-
- if (versionLen > len)
- {
- return -1;
- }
-
- strncpy(versionStr, version, versionLen);
- return 0;
-}
-
-WebRtc_Word32 WebRtcAecm_get_error_code(void *aecmInst)
-{
- aecmob_t *aecm = aecmInst;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- return aecm->lastError;
-}
-
-static int WebRtcAecm_EstBufDelay(aecmob_t *aecm, short msInSndCardBuf)
-{
- short delayNew, nSampFar, nSampSndCard;
- short diff;
-
- nSampFar = WebRtcApm_get_buffer_size(aecm->farendBuf);
- nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
-
- delayNew = nSampSndCard - nSampFar;
-
- if (delayNew < FRAME_LEN)
- {
- WebRtcApm_FlushBuffer(aecm->farendBuf, FRAME_LEN);
- delayNew += FRAME_LEN;
- }
-
- aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
-
- diff = aecm->filtDelay - aecm->knownDelay;
- if (diff > 224)
- {
- if (aecm->lastDelayDiff < 96)
- {
- aecm->timeForDelayChange = 0;
- } else
- {
- aecm->timeForDelayChange++;
- }
- } else if (diff < 96 && aecm->knownDelay > 0)
- {
- if (aecm->lastDelayDiff > 224)
- {
- aecm->timeForDelayChange = 0;
- } else
- {
- aecm->timeForDelayChange++;
- }
- } else
- {
- aecm->timeForDelayChange = 0;
- }
- aecm->lastDelayDiff = diff;
-
- if (aecm->timeForDelayChange > 25)
- {
- aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
- }
- return 0;
-}
-
-static int WebRtcAecm_DelayComp(aecmob_t *aecm)
-{
- int nSampFar, nSampSndCard, delayNew, nSampAdd;
- const int maxStuffSamp = 10 * FRAME_LEN;
-
- nSampFar = WebRtcApm_get_buffer_size(aecm->farendBuf);
- nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
- delayNew = nSampSndCard - nSampFar;
-
- if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult)
- {
- // The difference of the buffer sizes is larger than the maximum
- // allowed known delay. Compensate by stuffing the buffer.
- nSampAdd = (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar),
- FRAME_LEN));
- nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
-
- WebRtcApm_StuffBuffer(aecm->farendBuf, nSampAdd);
- aecm->delayChange = 1; // the delay needs to be updated
- }
-
- return 0;
-}