Index: webrtc/modules/audio_processing/aecm/aecm_core.c |
diff --git a/webrtc/modules/audio_processing/aecm/aecm_core.c b/webrtc/modules/audio_processing/aecm/aecm_core.c |
deleted file mode 100644 |
index 6bf1cf7f3eff1c55b780545ec1c4878e0b0e073d..0000000000000000000000000000000000000000 |
--- a/webrtc/modules/audio_processing/aecm/aecm_core.c |
+++ /dev/null |
@@ -1,1233 +0,0 @@ |
-/* |
- * Copyright (c) 2012 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 "webrtc/modules/audio_processing/aecm/aecm_core.h" |
- |
-#include <assert.h> |
-#include <stddef.h> |
-#include <stdlib.h> |
- |
-#include "webrtc/common_audio/ring_buffer.h" |
-#include "webrtc/common_audio/signal_processing/include/real_fft.h" |
-#include "webrtc/modules/audio_processing/aecm/echo_control_mobile.h" |
-#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h" |
-#include "webrtc/system_wrappers/include/compile_assert_c.h" |
-#include "webrtc/system_wrappers/include/cpu_features_wrapper.h" |
-#include "webrtc/typedefs.h" |
- |
-#ifdef AEC_DEBUG |
-FILE *dfile; |
-FILE *testfile; |
-#endif |
- |
-const int16_t WebRtcAecm_kCosTable[] = { |
- 8192, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112, |
- 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834, |
- 7791, 7745, 7697, 7647, 7595, 7540, 7483, 7424, 7362, |
- 7299, 7233, 7164, 7094, 7021, 6947, 6870, 6791, 6710, |
- 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991, 5892, |
- 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, |
- 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, |
- 3719, 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667, |
- 2531, 2395, 2258, 2120, 1981, 1842, 1703, 1563, 1422, |
- 1281, 1140, 998, 856, 713, 571, 428, 285, 142, |
- 0, -142, -285, -428, -571, -713, -856, -998, -1140, |
- -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395, |
- -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591, |
- -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698, |
- -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690, |
- -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542, |
- -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233, |
- -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, |
- -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067, |
- -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190, |
- -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112, |
- -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834, |
- -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362, |
- -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710, |
- -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892, |
- -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930, |
- -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845, |
- -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667, |
- -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, |
- -1281, -1140, -998, -856, -713, -571, -428, -285, -142, |
- 0, 142, 285, 428, 571, 713, 856, 998, 1140, |
- 1281, 1422, 1563, 1703, 1842, 1981, 2120, 2258, 2395, |
- 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591, |
- 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698, |
- 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586, 5690, |
- 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542, |
- 6627, 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233, |
- 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745, |
- 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067, |
- 8091, 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190 |
-}; |
- |
-const int16_t WebRtcAecm_kSinTable[] = { |
- 0, 142, 285, 428, 571, 713, 856, 998, |
- 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120, |
- 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200, |
- 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219, |
- 4341, 4461, 4580, 4698, 4815, 4930, 5043, 5155, |
- 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991, |
- 6087, 6182, 6275, 6366, 6455, 6542, 6627, 6710, |
- 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299, |
- 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745, |
- 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, |
- 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180, |
- 8187, 8190, 8191, 8190, 8187, 8180, 8172, 8160, |
- 8147, 8130, 8112, 8091, 8067, 8041, 8012, 7982, |
- 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647, |
- 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, |
- 7094, 7021, 6947, 6870, 6791, 6710, 6627, 6542, |
- 6455, 6366, 6275, 6182, 6087, 5991, 5892, 5792, |
- 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, |
- 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, |
- 3845, 3719, 3591, 3462, 3331, 3200, 3068, 2935, |
- 2801, 2667, 2531, 2395, 2258, 2120, 1981, 1842, |
- 1703, 1563, 1422, 1281, 1140, 998, 856, 713, |
- 571, 428, 285, 142, 0, -142, -285, -428, |
- -571, -713, -856, -998, -1140, -1281, -1422, -1563, |
- -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667, |
- -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, |
- -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698, |
- -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, |
- -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366, |
- -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021, |
- -7094, -7164, -7233, -7299, -7362, -7424, -7483, -7540, |
- -7595, -7647, -7697, -7745, -7791, -7834, -7874, -7912, |
- -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130, |
- -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190, |
- -8187, -8180, -8172, -8160, -8147, -8130, -8112, -8091, |
- -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834, |
- -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, |
- -7362, -7299, -7233, -7164, -7094, -7021, -6947, -6870, |
- -6791, -6710, -6627, -6542, -6455, -6366, -6275, -6182, |
- -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374, |
- -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461, |
- -4341, -4219, -4096, -3971, -3845, -3719, -3591, -3462, |
- -3331, -3200, -3068, -2935, -2801, -2667, -2531, -2395, |
- -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281, |
- -1140, -998, -856, -713, -571, -428, -285, -142 |
-}; |
- |
-// Initialization table for echo channel in 8 kHz |
-static const int16_t 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 int16_t 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 |
-}; |
- |
-// Moves the pointer to the next entry and inserts |far_spectrum| and |
-// corresponding Q-domain in its buffer. |
-// |
-// Inputs: |
-// - self : Pointer to the delay estimation instance |
-// - far_spectrum : Pointer to the far end spectrum |
-// - far_q : Q-domain of far end spectrum |
-// |
-void WebRtcAecm_UpdateFarHistory(AecmCore* self, |
- uint16_t* far_spectrum, |
- int far_q) { |
- // Get new buffer position |
- self->far_history_pos++; |
- if (self->far_history_pos >= MAX_DELAY) { |
- self->far_history_pos = 0; |
- } |
- // Update Q-domain buffer |
- self->far_q_domains[self->far_history_pos] = far_q; |
- // Update far end spectrum buffer |
- memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]), |
- far_spectrum, |
- sizeof(uint16_t) * PART_LEN1); |
-} |
- |
-// Returns a pointer to the far end spectrum aligned to current near end |
-// spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been |
-// called before AlignedFarend(...). Otherwise, you get the pointer to the |
-// previous frame. The memory is only valid until the next call of |
-// WebRtc_DelayEstimatorProcessFix(...). |
-// |
-// Inputs: |
-// - self : Pointer to the AECM instance. |
-// - delay : Current delay estimate. |
-// |
-// Output: |
-// - far_q : The Q-domain of the aligned far end spectrum |
-// |
-// Return value: |
-// - far_spectrum : Pointer to the aligned far end spectrum |
-// NULL - Error |
-// |
-const uint16_t* WebRtcAecm_AlignedFarend(AecmCore* self, |
- int* far_q, |
- int delay) { |
- int buffer_position = 0; |
- assert(self != NULL); |
- buffer_position = self->far_history_pos - delay; |
- |
- // Check buffer position |
- if (buffer_position < 0) { |
- buffer_position += MAX_DELAY; |
- } |
- // Get Q-domain |
- *far_q = self->far_q_domains[buffer_position]; |
- // Return far end spectrum |
- return &(self->far_history[buffer_position * PART_LEN1]); |
-} |
- |
-// Declare function pointers. |
-CalcLinearEnergies WebRtcAecm_CalcLinearEnergies; |
-StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; |
-ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; |
- |
-AecmCore* WebRtcAecm_CreateCore() { |
- AecmCore* aecm = malloc(sizeof(AecmCore)); |
- |
- aecm->farFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, |
- sizeof(int16_t)); |
- if (!aecm->farFrameBuf) |
- { |
- WebRtcAecm_FreeCore(aecm); |
- return NULL; |
- } |
- |
- aecm->nearNoisyFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, |
- sizeof(int16_t)); |
- if (!aecm->nearNoisyFrameBuf) |
- { |
- WebRtcAecm_FreeCore(aecm); |
- return NULL; |
- } |
- |
- aecm->nearCleanFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, |
- sizeof(int16_t)); |
- if (!aecm->nearCleanFrameBuf) |
- { |
- WebRtcAecm_FreeCore(aecm); |
- return NULL; |
- } |
- |
- aecm->outFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, |
- sizeof(int16_t)); |
- if (!aecm->outFrameBuf) |
- { |
- WebRtcAecm_FreeCore(aecm); |
- return NULL; |
- } |
- |
- aecm->delay_estimator_farend = WebRtc_CreateDelayEstimatorFarend(PART_LEN1, |
- MAX_DELAY); |
- if (aecm->delay_estimator_farend == NULL) { |
- WebRtcAecm_FreeCore(aecm); |
- return NULL; |
- } |
- aecm->delay_estimator = |
- WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0); |
- if (aecm->delay_estimator == NULL) { |
- WebRtcAecm_FreeCore(aecm); |
- return NULL; |
- } |
- // TODO(bjornv): Explicitly disable robust delay validation until no |
- // performance regression has been established. Then remove the line. |
- WebRtc_enable_robust_validation(aecm->delay_estimator, 0); |
- |
- aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT); |
- if (aecm->real_fft == NULL) { |
- WebRtcAecm_FreeCore(aecm); |
- return NULL; |
- } |
- |
- // Init some aecm pointers. 16 and 32 byte alignment is only necessary |
- // for Neon code currently. |
- aecm->xBuf = (int16_t*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31); |
- aecm->dBufClean = (int16_t*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31); |
- aecm->dBufNoisy = (int16_t*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31); |
- aecm->outBuf = (int16_t*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15); |
- aecm->channelStored = (int16_t*) (((uintptr_t) |
- aecm->channelStored_buf + 15) & ~ 15); |
- aecm->channelAdapt16 = (int16_t*) (((uintptr_t) |
- aecm->channelAdapt16_buf + 15) & ~ 15); |
- aecm->channelAdapt32 = (int32_t*) (((uintptr_t) |
- aecm->channelAdapt32_buf + 31) & ~ 31); |
- |
- return aecm; |
-} |
- |
-void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path) { |
- int i = 0; |
- |
- // Reset the stored channel |
- memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1); |
- // Reset the adapted channels |
- memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1); |
- for (i = 0; i < PART_LEN1; i++) |
- { |
- aecm->channelAdapt32[i] = (int32_t)aecm->channelAdapt16[i] << 16; |
- } |
- |
- // Reset channel storing variables |
- aecm->mseAdaptOld = 1000; |
- aecm->mseStoredOld = 1000; |
- aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX; |
- aecm->mseChannelCount = 0; |
-} |
- |
-static void CalcLinearEnergiesC(AecmCore* aecm, |
- const uint16_t* far_spectrum, |
- int32_t* echo_est, |
- uint32_t* far_energy, |
- uint32_t* echo_energy_adapt, |
- uint32_t* echo_energy_stored) { |
- int i; |
- |
- // Get energy for the delayed far end signal and estimated |
- // echo using both stored and adapted channels. |
- for (i = 0; i < PART_LEN1; i++) |
- { |
- echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], |
- far_spectrum[i]); |
- (*far_energy) += (uint32_t)(far_spectrum[i]); |
- *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i]; |
- (*echo_energy_stored) += (uint32_t)echo_est[i]; |
- } |
-} |
- |
-static void StoreAdaptiveChannelC(AecmCore* aecm, |
- const uint16_t* far_spectrum, |
- int32_t* echo_est) { |
- int i; |
- |
- // During startup we store the channel every block. |
- memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(int16_t) * PART_LEN1); |
- // Recalculate echo estimate |
- for (i = 0; i < PART_LEN; i += 4) |
- { |
- echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], |
- far_spectrum[i]); |
- echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1], |
- far_spectrum[i + 1]); |
- echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2], |
- far_spectrum[i + 2]); |
- echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3], |
- far_spectrum[i + 3]); |
- } |
- echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], |
- far_spectrum[i]); |
-} |
- |
-static void ResetAdaptiveChannelC(AecmCore* aecm) { |
- int i; |
- |
- // 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(int16_t) * PART_LEN1); |
- // Restore the W32 channel |
- for (i = 0; i < PART_LEN; i += 4) |
- { |
- aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16; |
- aecm->channelAdapt32[i + 1] = (int32_t)aecm->channelStored[i + 1] << 16; |
- aecm->channelAdapt32[i + 2] = (int32_t)aecm->channelStored[i + 2] << 16; |
- aecm->channelAdapt32[i + 3] = (int32_t)aecm->channelStored[i + 3] << 16; |
- } |
- aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16; |
-} |
- |
-// Initialize function pointers for ARM Neon platform. |
-#if (defined WEBRTC_DETECT_NEON || defined WEBRTC_HAS_NEON) |
-static void WebRtcAecm_InitNeon(void) |
-{ |
- WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannelNeon; |
- WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannelNeon; |
- WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergiesNeon; |
-} |
-#endif |
- |
-// Initialize function pointers for MIPS platform. |
-#if defined(MIPS32_LE) |
-static void WebRtcAecm_InitMips(void) |
-{ |
-#if defined(MIPS_DSP_R1_LE) |
- WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannel_mips; |
- WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannel_mips; |
-#endif |
- WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergies_mips; |
-} |
-#endif |
- |
-// 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* const aecm, int samplingFreq) { |
- int i = 0; |
- int32_t tmp32 = PART_LEN1 * PART_LEN1; |
- int16_t tmp16 = PART_LEN1; |
- |
- if (samplingFreq != 8000 && samplingFreq != 16000) |
- { |
- samplingFreq = 8000; |
- return -1; |
- } |
- // sanity check of sampling frequency |
- aecm->mult = (int16_t)samplingFreq / 8000; |
- |
- aecm->farBufWritePos = 0; |
- aecm->farBufReadPos = 0; |
- aecm->knownDelay = 0; |
- aecm->lastKnownDelay = 0; |
- |
- WebRtc_InitBuffer(aecm->farFrameBuf); |
- WebRtc_InitBuffer(aecm->nearNoisyFrameBuf); |
- WebRtc_InitBuffer(aecm->nearCleanFrameBuf); |
- WebRtc_InitBuffer(aecm->outFrameBuf); |
- |
- memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf)); |
- memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf)); |
- memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf)); |
- memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf)); |
- |
- aecm->seed = 666; |
- aecm->totCount = 0; |
- |
- if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) { |
- return -1; |
- } |
- if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) { |
- return -1; |
- } |
- // Set far end histories to zero |
- memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY); |
- memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY); |
- aecm->far_history_pos = MAX_DELAY; |
- |
- aecm->nlpFlag = 1; |
- aecm->fixedDelay = -1; |
- |
- aecm->dfaCleanQDomain = 0; |
- aecm->dfaCleanQDomainOld = 0; |
- aecm->dfaNoisyQDomain = 0; |
- aecm->dfaNoisyQDomainOld = 0; |
- |
- memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy)); |
- aecm->farLogEnergy = 0; |
- memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy)); |
- memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy)); |
- |
- // Initialize the echo channels with a stored shape. |
- if (samplingFreq == 8000) |
- { |
- WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz); |
- } |
- else |
- { |
- WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz); |
- } |
- |
- memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt)); |
- memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt)); |
- aecm->noiseEstCtr = 0; |
- |
- aecm->cngMode = AecmTrue; |
- |
- memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr)); |
- memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr)); |
- // Shape the initial noise level to an approximate pink noise. |
- for (i = 0; i < (PART_LEN1 >> 1) - 1; i++) |
- { |
- aecm->noiseEst[i] = (tmp32 << 8); |
- tmp16--; |
- tmp32 -= (int32_t)((tmp16 << 1) + 1); |
- } |
- for (; i < PART_LEN1; i++) |
- { |
- aecm->noiseEst[i] = (tmp32 << 8); |
- } |
- |
- 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->startupState = 0; |
- aecm->supGain = SUPGAIN_DEFAULT; |
- aecm->supGainOld = SUPGAIN_DEFAULT; |
- |
- 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; |
- |
- // Assert a preprocessor definition at compile-time. It's an assumption |
- // used in assembly code, so check the assembly files before any change. |
- COMPILE_ASSERT(PART_LEN % 16 == 0); |
- |
- // Initialize function pointers. |
- WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC; |
- WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC; |
- WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC; |
- |
-#ifdef WEBRTC_DETECT_NEON |
- uint64_t features = WebRtc_GetCPUFeaturesARM(); |
- if ((features & kCPUFeatureNEON) != 0) |
- { |
- WebRtcAecm_InitNeon(); |
- } |
-#elif defined(WEBRTC_HAS_NEON) |
- WebRtcAecm_InitNeon(); |
-#endif |
- |
-#if defined(MIPS32_LE) |
- WebRtcAecm_InitMips(); |
-#endif |
- return 0; |
-} |
- |
-// TODO(bjornv): This function is currently not used. Add support for these |
-// parameters from a higher level |
-int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag) { |
- aecm->nlpFlag = nlpFlag; |
- aecm->fixedDelay = delay; |
- |
- return 0; |
-} |
- |
-void WebRtcAecm_FreeCore(AecmCore* aecm) { |
- if (aecm == NULL) { |
- return; |
- } |
- |
- WebRtc_FreeBuffer(aecm->farFrameBuf); |
- WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf); |
- WebRtc_FreeBuffer(aecm->nearCleanFrameBuf); |
- WebRtc_FreeBuffer(aecm->outFrameBuf); |
- |
- WebRtc_FreeDelayEstimator(aecm->delay_estimator); |
- WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend); |
- WebRtcSpl_FreeRealFFT(aecm->real_fft); |
- |
- free(aecm); |
-} |
- |
-int WebRtcAecm_ProcessFrame(AecmCore* aecm, |
- const int16_t* farend, |
- const int16_t* nearendNoisy, |
- const int16_t* nearendClean, |
- int16_t* out) { |
- int16_t outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary. |
- int16_t* outBlock = (int16_t*) (((uintptr_t) outBlock_buf + 15) & ~ 15); |
- |
- int16_t farFrame[FRAME_LEN]; |
- const int16_t* out_ptr = NULL; |
- 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. |
- WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN); |
- WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN); |
- if (nearendClean != NULL) |
- { |
- WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN); |
- } |
- |
- // Process as many blocks as possible. |
- while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN) |
- { |
- int16_t far_block[PART_LEN]; |
- const int16_t* far_block_ptr = NULL; |
- int16_t near_noisy_block[PART_LEN]; |
- const int16_t* near_noisy_block_ptr = NULL; |
- |
- WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block, |
- PART_LEN); |
- WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf, |
- (void**) &near_noisy_block_ptr, |
- near_noisy_block, |
- PART_LEN); |
- if (nearendClean != NULL) |
- { |
- int16_t near_clean_block[PART_LEN]; |
- const int16_t* near_clean_block_ptr = NULL; |
- |
- WebRtc_ReadBuffer(aecm->nearCleanFrameBuf, |
- (void**) &near_clean_block_ptr, |
- near_clean_block, |
- PART_LEN); |
- if (WebRtcAecm_ProcessBlock(aecm, |
- far_block_ptr, |
- near_noisy_block_ptr, |
- near_clean_block_ptr, |
- outBlock) == -1) |
- { |
- return -1; |
- } |
- } else |
- { |
- if (WebRtcAecm_ProcessBlock(aecm, |
- far_block_ptr, |
- near_noisy_block_ptr, |
- NULL, |
- outBlock) == -1) |
- { |
- return -1; |
- } |
- } |
- |
- WebRtc_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 = (int) WebRtc_available_read(aecm->outFrameBuf); |
- if (size < FRAME_LEN) |
- { |
- WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN); |
- } |
- |
- // Obtain an output frame. |
- WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN); |
- if (out_ptr != out) { |
- // ReadBuffer() hasn't copied to |out| in this case. |
- memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t)); |
- } |
- |
- return 0; |
-} |
- |
-// 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. |
-// |
-int16_t WebRtcAecm_AsymFilt(const int16_t filtOld, const int16_t inVal, |
- const int16_t stepSizePos, |
- const int16_t stepSizeNeg) |
-{ |
- int16_t retVal; |
- |
- if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN)) |
- { |
- return inVal; |
- } |
- retVal = filtOld; |
- if (filtOld > inVal) |
- { |
- retVal -= (filtOld - inVal) >> stepSizeNeg; |
- } else |
- { |
- retVal += (inVal - filtOld) >> stepSizePos; |
- } |
- |
- return retVal; |
-} |
- |
-// ExtractFractionPart(a, zeros) |
-// |
-// returns the fraction part of |a|, with |zeros| number of leading zeros, as an |
-// int16_t scaled to Q8. There is no sanity check of |a| in the sense that the |
-// number of zeros match. |
-static int16_t ExtractFractionPart(uint32_t a, int zeros) { |
- return (int16_t)(((a << zeros) & 0x7FFFFFFF) >> 23); |
-} |
- |
-// Calculates and returns the log of |energy| in Q8. The input |energy| is |
-// supposed to be in Q(|q_domain|). |
-static int16_t LogOfEnergyInQ8(uint32_t energy, int q_domain) { |
- static const int16_t kLogLowValue = PART_LEN_SHIFT << 7; |
- int16_t log_energy_q8 = kLogLowValue; |
- if (energy > 0) { |
- int zeros = WebRtcSpl_NormU32(energy); |
- int16_t frac = ExtractFractionPart(energy, zeros); |
- // log2 of |energy| in Q8. |
- log_energy_q8 += ((31 - zeros) << 8) + frac - (q_domain << 8); |
- } |
- return log_energy_q8; |
-} |
- |
-// 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. internal VAD. |
-// |
-// |
-// @param aecm [i/o] Handle of the AECM instance. |
-// @param far_spectrum [in] Pointer to farend spectrum. |
-// @param far_q [in] Q-domain of farend spectrum. |
-// @param nearEner [in] Near end energy for current block in |
-// Q(aecm->dfaQDomain). |
-// @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16). |
-// |
-void WebRtcAecm_CalcEnergies(AecmCore* aecm, |
- const uint16_t* far_spectrum, |
- const int16_t far_q, |
- const uint32_t nearEner, |
- int32_t* echoEst) { |
- // Local variables |
- uint32_t tmpAdapt = 0; |
- uint32_t tmpStored = 0; |
- uint32_t tmpFar = 0; |
- |
- int i; |
- |
- int16_t tmp16; |
- int16_t increase_max_shifts = 4; |
- int16_t decrease_max_shifts = 11; |
- int16_t increase_min_shifts = 11; |
- int16_t decrease_min_shifts = 3; |
- |
- // Get log of near end energy and store in buffer |
- |
- // Shift buffer |
- memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy, |
- sizeof(int16_t) * (MAX_BUF_LEN - 1)); |
- |
- // Logarithm of integrated magnitude spectrum (nearEner) |
- aecm->nearLogEnergy[0] = LogOfEnergyInQ8(nearEner, aecm->dfaNoisyQDomain); |
- |
- WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored); |
- |
- // Shift buffers |
- memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy, |
- sizeof(int16_t) * (MAX_BUF_LEN - 1)); |
- memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy, |
- sizeof(int16_t) * (MAX_BUF_LEN - 1)); |
- |
- // Logarithm of delayed far end energy |
- aecm->farLogEnergy = LogOfEnergyInQ8(tmpFar, far_q); |
- |
- // Logarithm of estimated echo energy through adapted channel |
- aecm->echoAdaptLogEnergy[0] = LogOfEnergyInQ8(tmpAdapt, |
- RESOLUTION_CHANNEL16 + far_q); |
- |
- // Logarithm of estimated echo energy through stored channel |
- aecm->echoStoredLogEnergy[0] = |
- LogOfEnergyInQ8(tmpStored, RESOLUTION_CHANNEL16 + far_q); |
- |
- // Update farend energy levels (min, max, vad, mse) |
- if (aecm->farLogEnergy > 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, |
- increase_min_shifts, decrease_min_shifts); |
- aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy, |
- increase_max_shifts, decrease_max_shifts); |
- aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin); |
- |
- // Dynamic VAD region size |
- tmp16 = 2560 - aecm->farEnergyMin; |
- if (tmp16 > 0) |
- { |
- tmp16 = (int16_t)((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) |
- { |
- aecm->farEnergyVAD += |
- (aecm->farLogEnergy + 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 > 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; |
- } |
- } |
-} |
- |
-// 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. |
-// |
-// |
-int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm) { |
- int32_t tmp32; |
- int16_t tmp16; |
- int16_t mu = MU_MAX; |
- |
- // Here we calculate the step size mu used in the |
- // following NLMS based Channel estimation algorithm |
- 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 - aecm->farEnergyMin); |
- tmp32 = tmp16 * MU_DIFF; |
- tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin); |
- mu = MU_MIN - 1 - (int16_t)(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 |
- } |
- } |
- |
- 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 far_spectrum [in] Absolute value of the farend signal in Q(far_q) |
-// @param far_q [in] Q-domain of the farend signal |
-// @param dfa [in] Absolute value of the nearend signal (Q[aecm->dfaQDomain]) |
-// @param mu [in] NLMS step size. |
-// @param echoEst [i/o] Estimated echo in Q(far_q+RESOLUTION_CHANNEL16). |
-// |
-void WebRtcAecm_UpdateChannel(AecmCore* aecm, |
- const uint16_t* far_spectrum, |
- const int16_t far_q, |
- const uint16_t* const dfa, |
- const int16_t mu, |
- int32_t* echoEst) { |
- uint32_t tmpU32no1, tmpU32no2; |
- int32_t tmp32no1, tmp32no2; |
- int32_t mseStored; |
- int32_t mseAdapt; |
- |
- int i; |
- |
- int16_t zerosFar, zerosNum, zerosCh, zerosDfa; |
- int16_t shiftChFar, shiftNum, shift2ResChan; |
- int16_t tmp16no1; |
- int16_t 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((uint32_t)far_spectrum[i]); |
- if (zerosCh + zerosFar > 31) |
- { |
- // Multiplication is safe |
- tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i], |
- far_spectrum[i]); |
- shiftChFar = 0; |
- } else |
- { |
- // We need to shift down before multiplication |
- shiftChFar = 32 - zerosCh - zerosFar; |
- tmpU32no1 = (aecm->channelAdapt32[i] >> shiftChFar) * |
- far_spectrum[i]; |
- } |
- // Determine Q-domain of numerator |
- zerosNum = WebRtcSpl_NormU32(tmpU32no1); |
- if (dfa[i]) |
- { |
- zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]); |
- } else |
- { |
- zerosDfa = 32; |
- } |
- tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain - |
- RESOLUTION_CHANNEL32 - far_q + shiftChFar; |
- if (zerosNum > tmp16no1 + 1) |
- { |
- xfaQ = tmp16no1; |
- dfaQ = zerosDfa - 2; |
- } else |
- { |
- xfaQ = zerosNum - 2; |
- dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain - |
- shiftChFar + xfaQ; |
- } |
- // Add in the same Q-domain |
- tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ); |
- tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ); |
- tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1; |
- zerosNum = WebRtcSpl_NormW32(tmp32no1); |
- if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q))) |
- { |
- // |
- // Update is needed |
- // |
- // This is what we would like to compute |
- // |
- // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i]) |
- // tmp32norm = (i + 1) |
- // aecm->channelAdapt[i] += (2^mu) * tmp32no1 |
- // / (tmp32norm * far_spectrum[i]) |
- // |
- |
- // Make sure we don't get overflow in multiplication. |
- if (zerosNum + zerosFar > 31) |
- { |
- if (tmp32no1 > 0) |
- { |
- tmp32no2 = (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1, |
- far_spectrum[i]); |
- } else |
- { |
- tmp32no2 = -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1, |
- far_spectrum[i]); |
- } |
- shiftNum = 0; |
- } else |
- { |
- shiftNum = 32 - (zerosNum + zerosFar); |
- if (tmp32no1 > 0) |
- { |
- tmp32no2 = (tmp32no1 >> shiftNum) * far_spectrum[i]; |
- } else |
- { |
- tmp32no2 = -((-tmp32no1 >> shiftNum) * far_spectrum[i]); |
- } |
- } |
- // 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] = |
- WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2); |
- if (aecm->channelAdapt32[i] < 0) |
- { |
- // We can never have negative channel gain |
- aecm->channelAdapt32[i] = 0; |
- } |
- aecm->channelAdapt16[i] = |
- (int16_t)(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, |
- // and we recalculate echo estimate |
- WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst); |
- } else |
- { |
- if (aecm->farLogEnergy < aecm->farEnergyMSE) |
- { |
- aecm->mseChannelCount = 0; |
- } else |
- { |
- aecm->mseChannelCount++; |
- } |
- // 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 = ((int32_t)aecm->echoStoredLogEnergy[i] |
- - (int32_t)aecm->nearLogEnergy[i]); |
- tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1); |
- mseStored += tmp32no2; |
- |
- tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i] |
- - (int32_t)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. |
- WebRtcAecm_ResetAdaptiveChannel(aecm); |
- } 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. |
- WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst); |
- |
- // Update threshold |
- if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX) |
- { |
- aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld); |
- } else |
- { |
- int scaled_threshold = aecm->mseThreshold * 5 / 8; |
- aecm->mseThreshold += |
- ((mseAdapt - scaled_threshold) * 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. |
-} |
- |
-// 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). |
-// |
-// |
-int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm) { |
- int32_t tmp32no1; |
- |
- int16_t supGain = SUPGAIN_DEFAULT; |
- int16_t tmp16no1; |
- int16_t 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. |
- // 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 = aecm->supGainErrParamDiffAB * dE; |
- tmp32no1 += (SUPGAIN_EPC_DT >> 1); |
- tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT); |
- supGain = aecm->supGainErrParamA - tmp16no1; |
- } else |
- { |
- tmp32no1 = aecm->supGainErrParamDiffBD * (ENERGY_DEV_TOL - dE); |
- tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1); |
- tmp16no1 = (int16_t)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 += (int16_t)((tmp16no1 - aecm->supGain) >> 4); |
- } else |
- { |
- aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4); |
- } |
- |
- // END: Update suppression gain |
- |
- return aecm->supGain; |
-} |
- |
-void WebRtcAecm_BufferFarFrame(AecmCore* const aecm, |
- const int16_t* 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(int16_t) * writeLen); |
- aecm->farBufWritePos = 0; |
- writePos = writeLen; |
- writeLen = farLen - writeLen; |
- } |
- |
- memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos, |
- sizeof(int16_t) * writeLen); |
- aecm->farBufWritePos += writeLen; |
-} |
- |
-void WebRtcAecm_FetchFarFrame(AecmCore* const aecm, |
- int16_t* 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(int16_t) * readLen); |
- aecm->farBufReadPos = 0; |
- readPos = readLen; |
- readLen = farLen - readLen; |
- } |
- memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos, |
- sizeof(int16_t) * readLen); |
- aecm->farBufReadPos += readLen; |
-} |