| /* |
| * 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. |
| */ |
| |
| // Performs echo control (suppression) with fft routines in fixed-point. |
| |
| #ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_ |
| #define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_ |
| |
| extern "C" { |
| #include "webrtc/common_audio/ring_buffer.h" |
| #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" |
| } |
| #include "webrtc/modules/audio_processing/aecm/aecm_defines.h" |
| #include "webrtc/typedefs.h" |
| |
| #ifdef _MSC_VER // visual c++ |
| #define ALIGN8_BEG __declspec(align(8)) |
| #define ALIGN8_END |
| #else // gcc or icc |
| #define ALIGN8_BEG |
| #define ALIGN8_END __attribute__((aligned(8))) |
| #endif |
| |
| typedef struct { |
| int16_t real; |
| int16_t imag; |
| } ComplexInt16; |
| |
| typedef struct { |
| int farBufWritePos; |
| int farBufReadPos; |
| int knownDelay; |
| int lastKnownDelay; |
| int firstVAD; // Parameter to control poorly initialized channels |
| |
| RingBuffer* farFrameBuf; |
| RingBuffer* nearNoisyFrameBuf; |
| RingBuffer* nearCleanFrameBuf; |
| RingBuffer* outFrameBuf; |
| |
| int16_t farBuf[FAR_BUF_LEN]; |
| |
| int16_t mult; |
| uint32_t seed; |
| |
| // Delay estimation variables |
| void* delay_estimator_farend; |
| void* delay_estimator; |
| uint16_t currentDelay; |
| // Far end history variables |
| // TODO(bjornv): Replace |far_history| with ring_buffer. |
| uint16_t far_history[PART_LEN1 * MAX_DELAY]; |
| int far_history_pos; |
| int far_q_domains[MAX_DELAY]; |
| |
| int16_t nlpFlag; |
| int16_t fixedDelay; |
| |
| uint32_t totCount; |
| |
| int16_t dfaCleanQDomain; |
| int16_t dfaCleanQDomainOld; |
| int16_t dfaNoisyQDomain; |
| int16_t dfaNoisyQDomainOld; |
| |
| int16_t nearLogEnergy[MAX_BUF_LEN]; |
| int16_t farLogEnergy; |
| int16_t echoAdaptLogEnergy[MAX_BUF_LEN]; |
| int16_t echoStoredLogEnergy[MAX_BUF_LEN]; |
| |
| // The extra 16 or 32 bytes in the following buffers are for alignment based |
| // Neon code. |
| // It's designed this way since the current GCC compiler can't align a |
| // buffer in 16 or 32 byte boundaries properly. |
| int16_t channelStored_buf[PART_LEN1 + 8]; |
| int16_t channelAdapt16_buf[PART_LEN1 + 8]; |
| int32_t channelAdapt32_buf[PART_LEN1 + 8]; |
| int16_t xBuf_buf[PART_LEN2 + 16]; // farend |
| int16_t dBufClean_buf[PART_LEN2 + 16]; // nearend |
| int16_t dBufNoisy_buf[PART_LEN2 + 16]; // nearend |
| int16_t outBuf_buf[PART_LEN + 8]; |
| |
| // Pointers to the above buffers |
| int16_t *channelStored; |
| int16_t *channelAdapt16; |
| int32_t *channelAdapt32; |
| int16_t *xBuf; |
| int16_t *dBufClean; |
| int16_t *dBufNoisy; |
| int16_t *outBuf; |
| |
| int32_t echoFilt[PART_LEN1]; |
| int16_t nearFilt[PART_LEN1]; |
| int32_t noiseEst[PART_LEN1]; |
| int noiseEstTooLowCtr[PART_LEN1]; |
| int noiseEstTooHighCtr[PART_LEN1]; |
| int16_t noiseEstCtr; |
| int16_t cngMode; |
| |
| int32_t mseAdaptOld; |
| int32_t mseStoredOld; |
| int32_t mseThreshold; |
| |
| int16_t farEnergyMin; |
| int16_t farEnergyMax; |
| int16_t farEnergyMaxMin; |
| int16_t farEnergyVAD; |
| int16_t farEnergyMSE; |
| int currentVADValue; |
| int16_t vadUpdateCount; |
| |
| int16_t startupState; |
| int16_t mseChannelCount; |
| int16_t supGain; |
| int16_t supGainOld; |
| |
| int16_t supGainErrParamA; |
| int16_t supGainErrParamD; |
| int16_t supGainErrParamDiffAB; |
| int16_t supGainErrParamDiffBD; |
| |
| struct RealFFT* real_fft; |
| |
| #ifdef AEC_DEBUG |
| FILE *farFile; |
| FILE *nearFile; |
| FILE *outFile; |
| #endif |
| } AecmCore; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // WebRtcAecm_CreateCore() |
| // |
| // Allocates the memory needed by the AECM. The memory needs to be |
| // initialized separately using the WebRtcAecm_InitCore() function. |
| // Returns a pointer to the instance and a nullptr at failure. |
| AecmCore* WebRtcAecm_CreateCore(); |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // 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* const aecm, int samplingFreq); |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // WebRtcAecm_FreeCore(...) |
| // |
| // This function releases the memory allocated by WebRtcAecm_CreateCore() |
| // Input: |
| // - aecm : Pointer to the AECM instance |
| // |
| void WebRtcAecm_FreeCore(AecmCore* aecm); |
| |
| int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag); |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // WebRtcAecm_InitEchoPathCore(...) |
| // |
| // This function resets the echo channel adaptation with the specified channel. |
| // Input: |
| // - aecm : Pointer to the AECM instance |
| // - echo_path : Pointer to the data that should initialize the echo |
| // path |
| // |
| // Output: |
| // - aecm : Initialized instance |
| // |
| void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path); |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // 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 : |
| // |
| // |
| int WebRtcAecm_ProcessFrame(AecmCore* aecm, |
| const int16_t* farend, |
| const int16_t* nearendNoisy, |
| const int16_t* nearendClean, |
| int16_t* 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 : |
| // |
| // |
| int WebRtcAecm_ProcessBlock(AecmCore* aecm, |
| const int16_t* farend, |
| const int16_t* nearendNoisy, |
| const int16_t* noisyClean, |
| int16_t* 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* const aecm, |
| const int16_t* 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* const aecm, |
| int16_t* const farend, |
| const int farLen, |
| const int knownDelay); |
| |
| // All the functions below are intended to be private |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // WebRtcAecm_UpdateFarHistory() |
| // |
| // 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); |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // WebRtcAecm_AlignedFarend() |
| // |
| // 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); |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // WebRtcAecm_CalcSuppressionGain() |
| // |
| // This function calculates the suppression gain that is used in the |
| // Wiener filter. |
| // |
| // Inputs: |
| // - aecm : Pointer to the AECM instance. |
| // |
| // Return value: |
| // - supGain : Suppression gain with which to scale the noise |
| // level (Q14). |
| // |
| int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm); |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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. |
| // |
| // Inputs: |
| // - aecm : Pointer to the AECM instance. |
| // - far_spectrum : Pointer to farend spectrum. |
| // - far_q : Q-domain of farend spectrum. |
| // - nearEner : Near end energy for current block in |
| // Q(aecm->dfaQDomain). |
| // |
| // Output: |
| // - echoEst : 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); |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // WebRtcAecm_CalcStepSize() |
| // |
| // This function calculates the step size used in channel estimation |
| // |
| // Inputs: |
| // - aecm : Pointer to the AECM instance. |
| // |
| // Return value: |
| // - mu : Stepsize in log2(), i.e. number of shifts. |
| // |
| int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm); |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // WebRtcAecm_UpdateChannel(...) |
| // |
| // This function performs channel estimation. |
| // NLMS and decision on channel storage. |
| // |
| // Inputs: |
| // - aecm : Pointer to the AECM instance. |
| // - far_spectrum : Absolute value of the farend signal in Q(far_q) |
| // - far_q : Q-domain of the farend signal |
| // - dfa : Absolute value of the nearend signal |
| // (Q[aecm->dfaQDomain]) |
| // - mu : NLMS step size. |
| // Input/Output: |
| // - echoEst : 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); |
| |
| extern const int16_t WebRtcAecm_kCosTable[]; |
| extern const int16_t WebRtcAecm_kSinTable[]; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Some function pointers, for internal functions shared by ARM NEON and |
| // generic C code. |
| // |
| typedef void (*CalcLinearEnergies)(AecmCore* aecm, |
| const uint16_t* far_spectrum, |
| int32_t* echoEst, |
| uint32_t* far_energy, |
| uint32_t* echo_energy_adapt, |
| uint32_t* echo_energy_stored); |
| extern CalcLinearEnergies WebRtcAecm_CalcLinearEnergies; |
| |
| typedef void (*StoreAdaptiveChannel)(AecmCore* aecm, |
| const uint16_t* far_spectrum, |
| int32_t* echo_est); |
| extern StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; |
| |
| typedef void (*ResetAdaptiveChannel)(AecmCore* aecm); |
| extern ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; |
| |
| // For the above function pointers, functions for generic platforms are declared |
| // and defined as static in file aecm_core.c, while those for ARM Neon platforms |
| // are declared below and defined in file aecm_core_neon.c. |
| #if defined(WEBRTC_HAS_NEON) |
| void WebRtcAecm_CalcLinearEnergiesNeon(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); |
| |
| void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore* aecm, |
| const uint16_t* far_spectrum, |
| int32_t* echo_est); |
| |
| void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore* aecm); |
| #endif |
| |
| #if defined(MIPS32_LE) |
| void WebRtcAecm_CalcLinearEnergies_mips(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); |
| #if defined(MIPS_DSP_R1_LE) |
| void WebRtcAecm_StoreAdaptiveChannel_mips(AecmCore* aecm, |
| const uint16_t* far_spectrum, |
| int32_t* echo_est); |
| |
| void WebRtcAecm_ResetAdaptiveChannel_mips(AecmCore* aecm); |
| #endif |
| #endif |
| |
| #endif |