├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── aecm ├── aecm_core.cc ├── aecm_core.h ├── aecm_core_c.cc ├── aecm_core_mips.cc ├── aecm_core_neon.cc ├── aecm_defines.h ├── complex_fft.c ├── delay_estimator.cc ├── delay_estimator.h ├── delay_estimator_wrapper.cc ├── delay_estimator_wrapper.h ├── echo_control_mobile.cc ├── echo_control_mobile.h ├── real_fft.c ├── real_fft.h ├── ring_buffer.c ├── ring_buffer.h ├── signal_processing_library.cc ├── signal_processing_library.h ├── spl_inl.h ├── spl_inl_armv7.h └── spl_inl_mips.h ├── dr_wav.h ├── main.cc └── timing.h /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .idea/ 3 | 4 | cmake-build-debug/ 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.4) 2 | project(aecm) 3 | if (MSVC) 4 | if (CMAKE_BUILD_TYPE STREQUAL "Debug") 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ") 6 | else () 7 | set(CMAKE_BUILD_TYPE "Release") 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:fast /Gy /Oi /Oy /O2 /Ot /Zi /EHsc ") 9 | endif () 10 | ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS) 11 | else () 12 | if (CMAKE_BUILD_TYPE STREQUAL "Debug") 13 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -Wall -Wno-unused-variable") 14 | else (CMAKE_BUILD_TYPE STREQUAL "Debug") 15 | set(CMAKE_BUILD_TYPE "Release") 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O2") 17 | endif (CMAKE_BUILD_TYPE STREQUAL "Debug") 18 | endif () 19 | 20 | file(GLOB AECM_SRC 21 | ${CMAKE_CURRENT_LIST_DIR}/aecm/*.c 22 | ${CMAKE_CURRENT_LIST_DIR}/aecm/*.cc 23 | ) 24 | #list(FILTER AECM_SRC EXCLUDE REGEX ".*aecm_core_c.cc$") 25 | list(FILTER AECM_SRC EXCLUDE REGEX ".*aecm_core_neon.cc$") 26 | list(FILTER AECM_SRC EXCLUDE REGEX ".*aecm_core_mips.cc$") 27 | set(AECM_COMPILE_CODE ${AECM_SRC}) 28 | 29 | add_executable(aecm_run main.cc ${AECM_COMPILE_CODE}) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ============================ 2 | Copyright (c) 2011, The WebRTC project authors. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in 13 | the documentation and/or other materials provided with the 14 | distribution. 15 | 16 | * Neither the name of Google nor the names of its contributors may 17 | be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebRTC_AECM 2 | Acoustic Echo Canceller for Mobile Module Port From WebRTC 3 | 4 | # Donating 5 | 6 | If you found this project useful, consider buying me a coffee 7 | 8 | Buy Me A Coffee 9 | -------------------------------------------------------------------------------- /aecm/aecm_core.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | // Performs echo control (suppression) with fft routines in fixed-point. 12 | 13 | #ifndef MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_ 14 | #define MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_ 15 | 16 | #include 17 | 18 | extern "C" { 19 | #include "ring_buffer.h" 20 | #include "signal_processing_library.h" 21 | } 22 | 23 | #include "aecm_defines.h" 24 | 25 | struct RealFFT; 26 | 27 | 28 | #ifdef _MSC_VER // visual c++ 29 | #define ALIGN8_BEG __declspec(align(8)) 30 | #define ALIGN8_END 31 | #else // gcc or icc 32 | #define ALIGN8_BEG 33 | #define ALIGN8_END __attribute__((aligned(8))) 34 | #endif 35 | 36 | typedef struct { 37 | int16_t real; 38 | int16_t imag; 39 | } ComplexInt16; 40 | 41 | typedef struct { 42 | int farBufWritePos; 43 | int farBufReadPos; 44 | int knownDelay; 45 | int lastKnownDelay; 46 | int firstVAD; // Parameter to control poorly initialized channels 47 | 48 | RingBuffer *farFrameBuf; 49 | RingBuffer *nearNoisyFrameBuf; 50 | RingBuffer *nearCleanFrameBuf; 51 | RingBuffer *outFrameBuf; 52 | 53 | int16_t farBuf[FAR_BUF_LEN]; 54 | 55 | int16_t mult; 56 | uint32_t seed; 57 | 58 | // Delay estimation variables 59 | void *delay_estimator_farend; 60 | void *delay_estimator; 61 | uint16_t currentDelay; 62 | // Far end history variables 63 | // TODO(bjornv): Replace |far_history| with ring_buffer. 64 | uint16_t far_history[PART_LEN1 * MAX_DELAY]; 65 | int far_history_pos; 66 | int far_q_domains[MAX_DELAY]; 67 | 68 | int16_t nlpFlag; 69 | int16_t fixedDelay; 70 | 71 | uint32_t totCount; 72 | 73 | int16_t dfaCleanQDomain; 74 | int16_t dfaCleanQDomainOld; 75 | int16_t dfaNoisyQDomain; 76 | int16_t dfaNoisyQDomainOld; 77 | 78 | int16_t nearLogEnergy[MAX_BUF_LEN]; 79 | int16_t farLogEnergy; 80 | int16_t echoAdaptLogEnergy[MAX_BUF_LEN]; 81 | int16_t echoStoredLogEnergy[MAX_BUF_LEN]; 82 | 83 | // The extra 16 or 32 bytes in the following buffers are for alignment based 84 | // Neon code. 85 | // It's designed this way since the current GCC compiler can't align a 86 | // buffer in 16 or 32 byte boundaries properly. 87 | int16_t channelStored_buf[PART_LEN1 + 8]; 88 | int16_t channelAdapt16_buf[PART_LEN1 + 8]; 89 | int32_t channelAdapt32_buf[PART_LEN1 + 8]; 90 | int16_t xBuf_buf[PART_LEN2 + 16]; // farend 91 | int16_t dBufClean_buf[PART_LEN2 + 16]; // nearend 92 | int16_t dBufNoisy_buf[PART_LEN2 + 16]; // nearend 93 | int16_t outBuf_buf[PART_LEN + 8]; 94 | 95 | // Pointers to the above buffers 96 | int16_t *channelStored; 97 | int16_t *channelAdapt16; 98 | int32_t *channelAdapt32; 99 | int16_t *xBuf; 100 | int16_t *dBufClean; 101 | int16_t *dBufNoisy; 102 | int16_t *outBuf; 103 | 104 | int32_t echoFilt[PART_LEN1]; 105 | int16_t nearFilt[PART_LEN1]; 106 | int32_t noiseEst[PART_LEN1]; 107 | int noiseEstTooLowCtr[PART_LEN1]; 108 | int noiseEstTooHighCtr[PART_LEN1]; 109 | int16_t noiseEstCtr; 110 | int16_t cngMode; 111 | 112 | int32_t mseAdaptOld; 113 | int32_t mseStoredOld; 114 | int32_t mseThreshold; 115 | 116 | int16_t farEnergyMin; 117 | int16_t farEnergyMax; 118 | int16_t farEnergyMaxMin; 119 | int16_t farEnergyVAD; 120 | int16_t farEnergyMSE; 121 | int currentVADValue; 122 | int16_t vadUpdateCount; 123 | 124 | int16_t startupState; 125 | int16_t mseChannelCount; 126 | int16_t supGain; 127 | int16_t supGainOld; 128 | 129 | int16_t supGainErrParamA; 130 | int16_t supGainErrParamD; 131 | int16_t supGainErrParamDiffAB; 132 | int16_t supGainErrParamDiffBD; 133 | 134 | struct RealFFT *real_fft; 135 | 136 | #ifdef AEC_DEBUG 137 | FILE* farFile; 138 | FILE* nearFile; 139 | FILE* outFile; 140 | #endif 141 | } AecmCore; 142 | 143 | //////////////////////////////////////////////////////////////////////////////// 144 | // WebRtcAecm_CreateCore() 145 | // 146 | // Allocates the memory needed by the AECM. The memory needs to be 147 | // initialized separately using the WebRtcAecm_InitCore() function. 148 | // Returns a pointer to the instance and a nullptr at failure. 149 | AecmCore *WebRtcAecm_CreateCore(); 150 | 151 | //////////////////////////////////////////////////////////////////////////////// 152 | // WebRtcAecm_InitCore(...) 153 | // 154 | // This function initializes the AECM instant created with 155 | // WebRtcAecm_CreateCore() 156 | // Input: 157 | // - aecm : Pointer to the AECM instance 158 | // - samplingFreq : Sampling Frequency 159 | // 160 | // Output: 161 | // - aecm : Initialized instance 162 | // 163 | // Return value : 0 - Ok 164 | // -1 - Error 165 | // 166 | int WebRtcAecm_InitCore(AecmCore *const aecm, int samplingFreq); 167 | 168 | //////////////////////////////////////////////////////////////////////////////// 169 | // WebRtcAecm_FreeCore(...) 170 | // 171 | // This function releases the memory allocated by WebRtcAecm_CreateCore() 172 | // Input: 173 | // - aecm : Pointer to the AECM instance 174 | // 175 | void WebRtcAecm_FreeCore(AecmCore *aecm); 176 | 177 | int WebRtcAecm_Control(AecmCore *aecm, int delay, int nlpFlag); 178 | 179 | //////////////////////////////////////////////////////////////////////////////// 180 | // WebRtcAecm_InitEchoPathCore(...) 181 | // 182 | // This function resets the echo channel adaptation with the specified channel. 183 | // Input: 184 | // - aecm : Pointer to the AECM instance 185 | // - echo_path : Pointer to the data that should initialize the echo 186 | // path 187 | // 188 | // Output: 189 | // - aecm : Initialized instance 190 | // 191 | void WebRtcAecm_InitEchoPathCore(AecmCore *aecm, const int16_t *echo_path); 192 | 193 | //////////////////////////////////////////////////////////////////////////////// 194 | // WebRtcAecm_ProcessFrame(...) 195 | // 196 | // This function processes frames and sends blocks to 197 | // WebRtcAecm_ProcessBlock(...) 198 | // 199 | // Inputs: 200 | // - aecm : Pointer to the AECM instance 201 | // - farend : In buffer containing one frame of echo signal 202 | // - nearendNoisy : In buffer containing one frame of nearend+echo signal 203 | // without NS 204 | // - nearendClean : In buffer containing one frame of nearend+echo signal 205 | // with NS 206 | // 207 | // Output: 208 | // - out : Out buffer, one frame of nearend signal : 209 | // 210 | // 211 | int WebRtcAecm_ProcessFrame(AecmCore *aecm, 212 | const int16_t *farend, 213 | const int16_t *nearendNoisy, 214 | const int16_t *nearendClean, 215 | int16_t *out); 216 | 217 | //////////////////////////////////////////////////////////////////////////////// 218 | // WebRtcAecm_ProcessBlock(...) 219 | // 220 | // This function is called for every block within one frame 221 | // This function is called by WebRtcAecm_ProcessFrame(...) 222 | // 223 | // Inputs: 224 | // - aecm : Pointer to the AECM instance 225 | // - farend : In buffer containing one block of echo signal 226 | // - nearendNoisy : In buffer containing one frame of nearend+echo signal 227 | // without NS 228 | // - nearendClean : In buffer containing one frame of nearend+echo signal 229 | // with NS 230 | // 231 | // Output: 232 | // - out : Out buffer, one block of nearend signal : 233 | // 234 | // 235 | int WebRtcAecm_ProcessBlock(AecmCore *aecm, 236 | const int16_t *farend, 237 | const int16_t *nearendNoisy, 238 | const int16_t *noisyClean, 239 | int16_t *out); 240 | 241 | //////////////////////////////////////////////////////////////////////////////// 242 | // WebRtcAecm_BufferFarFrame() 243 | // 244 | // Inserts a frame of data into farend buffer. 245 | // 246 | // Inputs: 247 | // - aecm : Pointer to the AECM instance 248 | // - farend : In buffer containing one frame of farend signal 249 | // - farLen : Length of frame 250 | // 251 | void WebRtcAecm_BufferFarFrame(AecmCore *const aecm, 252 | const int16_t *const farend, 253 | const int farLen); 254 | 255 | //////////////////////////////////////////////////////////////////////////////// 256 | // WebRtcAecm_FetchFarFrame() 257 | // 258 | // Read the farend buffer to account for known delay 259 | // 260 | // Inputs: 261 | // - aecm : Pointer to the AECM instance 262 | // - farend : In buffer containing one frame of farend signal 263 | // - farLen : Length of frame 264 | // - knownDelay : known delay 265 | // 266 | void WebRtcAecm_FetchFarFrame(AecmCore *const aecm, 267 | int16_t *const farend, 268 | const int farLen, 269 | const int knownDelay); 270 | 271 | // All the functions below are intended to be private 272 | 273 | //////////////////////////////////////////////////////////////////////////////// 274 | // WebRtcAecm_UpdateFarHistory() 275 | // 276 | // Moves the pointer to the next entry and inserts |far_spectrum| and 277 | // corresponding Q-domain in its buffer. 278 | // 279 | // Inputs: 280 | // - self : Pointer to the delay estimation instance 281 | // - far_spectrum : Pointer to the far end spectrum 282 | // - far_q : Q-domain of far end spectrum 283 | // 284 | void WebRtcAecm_UpdateFarHistory(AecmCore *self, 285 | uint16_t *far_spectrum, 286 | int far_q); 287 | 288 | //////////////////////////////////////////////////////////////////////////////// 289 | // WebRtcAecm_AlignedFarend() 290 | // 291 | // Returns a pointer to the far end spectrum aligned to current near end 292 | // spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been 293 | // called before AlignedFarend(...). Otherwise, you get the pointer to the 294 | // previous frame. The memory is only valid until the next call of 295 | // WebRtc_DelayEstimatorProcessFix(...). 296 | // 297 | // Inputs: 298 | // - self : Pointer to the AECM instance. 299 | // - delay : Current delay estimate. 300 | // 301 | // Output: 302 | // - far_q : The Q-domain of the aligned far end spectrum 303 | // 304 | // Return value: 305 | // - far_spectrum : Pointer to the aligned far end spectrum 306 | // NULL - Error 307 | // 308 | const uint16_t *WebRtcAecm_AlignedFarend(AecmCore *self, int *far_q, int delay); 309 | 310 | /////////////////////////////////////////////////////////////////////////////// 311 | // WebRtcAecm_CalcSuppressionGain() 312 | // 313 | // This function calculates the suppression gain that is used in the 314 | // Wiener filter. 315 | // 316 | // Inputs: 317 | // - aecm : Pointer to the AECM instance. 318 | // 319 | // Return value: 320 | // - supGain : Suppression gain with which to scale the noise 321 | // level (Q14). 322 | // 323 | int16_t WebRtcAecm_CalcSuppressionGain(AecmCore *const aecm); 324 | 325 | /////////////////////////////////////////////////////////////////////////////// 326 | // WebRtcAecm_CalcEnergies() 327 | // 328 | // This function calculates the log of energies for nearend, farend and 329 | // estimated echoes. There is also an update of energy decision levels, 330 | // i.e. internal VAD. 331 | // 332 | // Inputs: 333 | // - aecm : Pointer to the AECM instance. 334 | // - far_spectrum : Pointer to farend spectrum. 335 | // - far_q : Q-domain of farend spectrum. 336 | // - nearEner : Near end energy for current block in 337 | // Q(aecm->dfaQDomain). 338 | // 339 | // Output: 340 | // - echoEst : Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16). 341 | // 342 | void WebRtcAecm_CalcEnergies(AecmCore *aecm, 343 | const uint16_t *far_spectrum, 344 | const int16_t far_q, 345 | const uint32_t nearEner, 346 | int32_t *echoEst); 347 | 348 | /////////////////////////////////////////////////////////////////////////////// 349 | // WebRtcAecm_CalcStepSize() 350 | // 351 | // This function calculates the step size used in channel estimation 352 | // 353 | // Inputs: 354 | // - aecm : Pointer to the AECM instance. 355 | // 356 | // Return value: 357 | // - mu : Stepsize in log2(), i.e. number of shifts. 358 | // 359 | int16_t WebRtcAecm_CalcStepSize(AecmCore *const aecm); 360 | 361 | /////////////////////////////////////////////////////////////////////////////// 362 | // WebRtcAecm_UpdateChannel(...) 363 | // 364 | // This function performs channel estimation. 365 | // NLMS and decision on channel storage. 366 | // 367 | // Inputs: 368 | // - aecm : Pointer to the AECM instance. 369 | // - far_spectrum : Absolute value of the farend signal in Q(far_q) 370 | // - far_q : Q-domain of the farend signal 371 | // - dfa : Absolute value of the nearend signal 372 | // (Q[aecm->dfaQDomain]) 373 | // - mu : NLMS step size. 374 | // Input/Output: 375 | // - echoEst : Estimated echo in Q(far_q+RESOLUTION_CHANNEL16). 376 | // 377 | void WebRtcAecm_UpdateChannel(AecmCore *aecm, 378 | const uint16_t *far_spectrum, 379 | const int16_t far_q, 380 | const uint16_t *const dfa, 381 | const int16_t mu, 382 | int32_t *echoEst); 383 | 384 | extern const int16_t WebRtcAecm_kCosTable[]; 385 | extern const int16_t WebRtcAecm_kSinTable[]; 386 | 387 | /////////////////////////////////////////////////////////////////////////////// 388 | // Some function pointers, for internal functions shared by ARM NEON and 389 | // generic C code. 390 | // 391 | typedef void (*CalcLinearEnergies)(AecmCore *aecm, 392 | const uint16_t *far_spectrum, 393 | int32_t *echoEst, 394 | uint32_t *far_energy, 395 | uint32_t *echo_energy_adapt, 396 | uint32_t *echo_energy_stored); 397 | 398 | extern CalcLinearEnergies WebRtcAecm_CalcLinearEnergies; 399 | 400 | typedef void (*StoreAdaptiveChannel)(AecmCore *aecm, 401 | const uint16_t *far_spectrum, 402 | int32_t *echo_est); 403 | 404 | extern StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; 405 | 406 | typedef void (*ResetAdaptiveChannel)(AecmCore *aecm); 407 | 408 | extern ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; 409 | 410 | // For the above function pointers, functions for generic platforms are declared 411 | // and defined as static in file aecm_core.c, while those for ARM Neon platforms 412 | // are declared below and defined in file aecm_core_neon.c. 413 | #if defined(WEBRTC_HAS_NEON) 414 | void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm, 415 | const uint16_t* far_spectrum, 416 | int32_t* echo_est, 417 | uint32_t* far_energy, 418 | uint32_t* echo_energy_adapt, 419 | uint32_t* echo_energy_stored); 420 | 421 | void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore* aecm, 422 | const uint16_t* far_spectrum, 423 | int32_t* echo_est); 424 | 425 | void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore* aecm); 426 | #endif 427 | 428 | #if defined(MIPS32_LE) 429 | void WebRtcAecm_CalcLinearEnergies_mips(AecmCore* aecm, 430 | const uint16_t* far_spectrum, 431 | int32_t* echo_est, 432 | uint32_t* far_energy, 433 | uint32_t* echo_energy_adapt, 434 | uint32_t* echo_energy_stored); 435 | #if defined(MIPS_DSP_R1_LE) 436 | void WebRtcAecm_StoreAdaptiveChannel_mips(AecmCore* aecm, 437 | const uint16_t* far_spectrum, 438 | int32_t* echo_est); 439 | 440 | void WebRtcAecm_ResetAdaptiveChannel_mips(AecmCore* aecm); 441 | #endif 442 | #endif 443 | 444 | 445 | #endif 446 | -------------------------------------------------------------------------------- /aecm/aecm_core_c.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include 12 | 13 | #include "aecm_core.h" 14 | 15 | extern "C" { 16 | #include "real_fft.h" 17 | } 18 | 19 | #include "echo_control_mobile.h" 20 | #include "delay_estimator_wrapper.h" 21 | 22 | 23 | // Square root of Hanning window in Q14. 24 | static const ALIGN8_BEG int16_t 25 | WebRtcAecm_kSqrtHanning[] 26 | ALIGN8_END = { 27 | 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172, 3562, 3951, 28 | 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019, 29 | 8364, 8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514, 30 | 11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189, 31 | 14384, 14571, 14749, 14918, 15079, 15231, 15373, 15506, 15631, 15746, 15851, 32 | 15947, 16034, 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384}; 33 | 34 | #ifdef AECM_WITH_ABS_APPROX 35 | // Q15 alpha = 0.99439986968132 const Factor for magnitude approximation 36 | static const uint16_t kAlpha1 = 32584; 37 | // Q15 beta = 0.12967166976970 const Factor for magnitude approximation 38 | static const uint16_t kBeta1 = 4249; 39 | // Q15 alpha = 0.94234827210087 const Factor for magnitude approximation 40 | static const uint16_t kAlpha2 = 30879; 41 | // Q15 beta = 0.33787806009150 const Factor for magnitude approximation 42 | static const uint16_t kBeta2 = 11072; 43 | // Q15 alpha = 0.82247698684306 const Factor for magnitude approximation 44 | static const uint16_t kAlpha3 = 26951; 45 | // Q15 beta = 0.57762063060713 const Factor for magnitude approximation 46 | static const uint16_t kBeta3 = 18927; 47 | #endif 48 | 49 | static const int16_t kNoiseEstQDomain = 15; 50 | static const int16_t kNoiseEstIncCount = 5; 51 | 52 | static void ComfortNoise(AecmCore *aecm, 53 | const uint16_t *dfa, 54 | ComplexInt16 *out, 55 | const int16_t *lambda) { 56 | int16_t i; 57 | int16_t tmp16; 58 | int32_t tmp32; 59 | 60 | int16_t randW16[PART_LEN]; 61 | int16_t uReal[PART_LEN1]; 62 | int16_t uImag[PART_LEN1]; 63 | int32_t outLShift32; 64 | int16_t noiseRShift16[PART_LEN1]; 65 | 66 | int16_t shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain; 67 | int16_t minTrackShift; 68 | 69 | RTC_DCHECK_GE(shiftFromNearToNoise, 0); 70 | RTC_DCHECK_LT(shiftFromNearToNoise, 16); 71 | 72 | if (aecm->noiseEstCtr < 100) { 73 | // Track the minimum more quickly initially. 74 | aecm->noiseEstCtr++; 75 | minTrackShift = 6; 76 | } else { 77 | minTrackShift = 9; 78 | } 79 | 80 | // Estimate noise power. 81 | for (i = 0; i < PART_LEN1; i++) { 82 | // Shift to the noise domain. 83 | tmp32 = (int32_t) dfa[i]; 84 | outLShift32 = tmp32 << shiftFromNearToNoise; 85 | 86 | if (outLShift32 < aecm->noiseEst[i]) { 87 | // Reset "too low" counter 88 | aecm->noiseEstTooLowCtr[i] = 0; 89 | // Track the minimum. 90 | if (aecm->noiseEst[i] < (1 << minTrackShift)) { 91 | // For small values, decrease noiseEst[i] every 92 | // |kNoiseEstIncCount| block. The regular approach below can not 93 | // go further down due to truncation. 94 | aecm->noiseEstTooHighCtr[i]++; 95 | if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount) { 96 | aecm->noiseEst[i]--; 97 | aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter 98 | } 99 | } else { 100 | aecm->noiseEst[i] -= 101 | ((aecm->noiseEst[i] - outLShift32) >> minTrackShift); 102 | } 103 | } else { 104 | // Reset "too high" counter 105 | aecm->noiseEstTooHighCtr[i] = 0; 106 | // Ramp slowly upwards until we hit the minimum again. 107 | if ((aecm->noiseEst[i] >> 19) > 0) { 108 | // Avoid overflow. 109 | // Multiplication with 2049 will cause wrap around. Scale 110 | // down first and then multiply 111 | aecm->noiseEst[i] >>= 11; 112 | aecm->noiseEst[i] *= 2049; 113 | } else if ((aecm->noiseEst[i] >> 11) > 0) { 114 | // Large enough for relative increase 115 | aecm->noiseEst[i] *= 2049; 116 | aecm->noiseEst[i] >>= 11; 117 | } else { 118 | // Make incremental increases based on size every 119 | // |kNoiseEstIncCount| block 120 | aecm->noiseEstTooLowCtr[i]++; 121 | if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) { 122 | aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1; 123 | aecm->noiseEstTooLowCtr[i] = 0; // Reset counter 124 | } 125 | } 126 | } 127 | } 128 | 129 | for (i = 0; i < PART_LEN1; i++) { 130 | tmp32 = aecm->noiseEst[i] >> shiftFromNearToNoise; 131 | if (tmp32 > 32767) { 132 | tmp32 = 32767; 133 | aecm->noiseEst[i] = tmp32 << shiftFromNearToNoise; 134 | } 135 | noiseRShift16[i] = (int16_t) 136 | tmp32; 137 | 138 | tmp16 = ONE_Q14 - lambda[i]; 139 | noiseRShift16[i] = (int16_t) ((tmp16 * noiseRShift16[i]) >> 14); 140 | } 141 | 142 | // Generate a uniform random array on [0 2^15-1]. 143 | WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed); 144 | 145 | // Generate noise according to estimated energy. 146 | uReal[0] = 0; // Reject LF noise. 147 | uImag[0] = 0; 148 | for (i = 1; i < PART_LEN1; i++) { 149 | // Get a random index for the cos and sin tables over [0 359]. 150 | tmp16 = (int16_t) ((359 * randW16[i - 1]) >> 15); 151 | 152 | // Tables are in Q13. 153 | uReal[i] = 154 | (int16_t) ((noiseRShift16[i] * WebRtcAecm_kCosTable[tmp16]) >> 13); 155 | uImag[i] = 156 | (int16_t) ((-noiseRShift16[i] * WebRtcAecm_kSinTable[tmp16]) >> 13); 157 | } 158 | uImag[PART_LEN] = 0; 159 | 160 | for (i = 0; i < PART_LEN1; i++) { 161 | out[i].real = WebRtcSpl_AddSatW16(out[i].real, uReal[i]); 162 | out[i].imag = WebRtcSpl_AddSatW16(out[i].imag, uImag[i]); 163 | } 164 | } 165 | 166 | static void WindowAndFFT(AecmCore *aecm, 167 | int16_t *fft, 168 | const int16_t *time_signal, 169 | ComplexInt16 *freq_signal, 170 | int time_signal_scaling) { 171 | int i = 0; 172 | 173 | // FFT of signal 174 | for (i = 0; i < PART_LEN; i++) { 175 | // Window time domain signal and insert into real part of 176 | // transformation array |fft| 177 | int16_t scaled_time_signal = time_signal[i] * (1 << time_signal_scaling); 178 | fft[i] = (int16_t) ((scaled_time_signal * WebRtcAecm_kSqrtHanning[i]) >> 14); 179 | scaled_time_signal = time_signal[i + PART_LEN] * (1 << time_signal_scaling); 180 | fft[PART_LEN + i] = (int16_t) ( 181 | (scaled_time_signal * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14); 182 | } 183 | 184 | // Do forward FFT, then take only the first PART_LEN complex samples, 185 | // and change signs of the imaginary parts. 186 | WebRtcSpl_RealForwardFFT(aecm->real_fft, fft, (int16_t *) 187 | freq_signal); 188 | for (i = 0; i < PART_LEN; i++) { 189 | freq_signal[i].imag = -freq_signal[i].imag; 190 | } 191 | } 192 | 193 | static void InverseFFTAndWindow(AecmCore *aecm, 194 | int16_t *fft, 195 | ComplexInt16 *efw, 196 | int16_t *output, 197 | const int16_t *nearendClean) { 198 | int i, j, outCFFT; 199 | int32_t tmp32no1; 200 | // Reuse |efw| for the inverse FFT output after transferring 201 | // the contents to |fft|. 202 | int16_t *ifft_out = (int16_t *) 203 | efw; 204 | 205 | // Synthesis 206 | for (i = 1, j = 2; i < PART_LEN; i += 1, j += 2) { 207 | fft[j] = efw[i].real; 208 | fft[j + 1] = -efw[i].imag; 209 | } 210 | fft[0] = efw[0].real; 211 | fft[1] = -efw[0].imag; 212 | 213 | fft[PART_LEN2] = efw[PART_LEN].real; 214 | fft[PART_LEN2 + 1] = -efw[PART_LEN].imag; 215 | 216 | // Inverse FFT. Keep outCFFT to scale the samples in the next block. 217 | outCFFT = WebRtcSpl_RealInverseFFT(aecm->real_fft, fft, ifft_out); 218 | for (i = 0; i < PART_LEN; i++) { 219 | ifft_out[i] = (int16_t) 220 | WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( 221 | ifft_out[i], WebRtcAecm_kSqrtHanning[i], 14); 222 | tmp32no1 = WEBRTC_SPL_SHIFT_W32((int32_t) ifft_out[i], 223 | outCFFT - aecm->dfaCleanQDomain); 224 | output[i] = (int16_t) 225 | WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, 226 | tmp32no1 + aecm->outBuf[i], 227 | WEBRTC_SPL_WORD16_MIN); 228 | 229 | tmp32no1 = 230 | (ifft_out[PART_LEN + i] * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14; 231 | tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, outCFFT - aecm->dfaCleanQDomain); 232 | aecm->outBuf[i] = (int16_t) 233 | WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, tmp32no1, 234 | WEBRTC_SPL_WORD16_MIN); 235 | } 236 | 237 | // Copy the current block to the old position 238 | // (aecm->outBuf is shifted elsewhere) 239 | memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(int16_t) * PART_LEN); 240 | memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN, 241 | sizeof(int16_t) * PART_LEN); 242 | if (nearendClean != NULL) { 243 | memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN, 244 | sizeof(int16_t) * PART_LEN); 245 | } 246 | } 247 | 248 | // Transforms a time domain signal into the frequency domain, outputting the 249 | // complex valued signal, absolute value and sum of absolute values. 250 | // 251 | // time_signal [in] Pointer to time domain signal 252 | // freq_signal_real [out] Pointer to real part of frequency domain array 253 | // freq_signal_imag [out] Pointer to imaginary part of frequency domain 254 | // array 255 | // freq_signal_abs [out] Pointer to absolute value of frequency domain 256 | // array 257 | // freq_signal_sum_abs [out] Pointer to the sum of all absolute values in 258 | // the frequency domain array 259 | // return value The Q-domain of current frequency values 260 | // 261 | static int TimeToFrequencyDomain(AecmCore *aecm, 262 | const int16_t *time_signal, 263 | ComplexInt16 *freq_signal, 264 | uint16_t *freq_signal_abs, 265 | uint32_t *freq_signal_sum_abs) { 266 | int i = 0; 267 | int time_signal_scaling = 0; 268 | 269 | int32_t tmp32no1 = 0; 270 | int32_t tmp32no2 = 0; 271 | 272 | // In fft_buf, +16 for 32-byte alignment. 273 | int16_t fft_buf[PART_LEN4 + 16]; 274 | int16_t *fft = (int16_t *) (((uintptr_t) fft_buf + 31) & ~31); 275 | 276 | int16_t tmp16no1; 277 | #ifndef WEBRTC_ARCH_ARM_V7 278 | int16_t tmp16no2; 279 | #endif 280 | #ifdef AECM_WITH_ABS_APPROX 281 | int16_t max_value = 0; 282 | int16_t min_value = 0; 283 | uint16_t alpha = 0; 284 | uint16_t beta = 0; 285 | #endif 286 | 287 | #ifdef AECM_DYNAMIC_Q 288 | tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2); 289 | time_signal_scaling = WebRtcSpl_NormW16(tmp16no1); 290 | #endif 291 | 292 | WindowAndFFT(aecm, fft, time_signal, freq_signal, time_signal_scaling); 293 | 294 | // Extract imaginary and real part, calculate the magnitude for 295 | // all frequency bins 296 | freq_signal[0].imag = 0; 297 | freq_signal[PART_LEN].imag = 0; 298 | freq_signal_abs[0] = (uint16_t) WEBRTC_SPL_ABS_W16(freq_signal[0].real); 299 | freq_signal_abs[PART_LEN] = 300 | (uint16_t) WEBRTC_SPL_ABS_W16(freq_signal[PART_LEN].real); 301 | (*freq_signal_sum_abs) = 302 | (uint32_t) (freq_signal_abs[0]) + (uint32_t) (freq_signal_abs[PART_LEN]); 303 | 304 | for (i = 1; i < PART_LEN; i++) { 305 | if (freq_signal[i].real == 0) { 306 | freq_signal_abs[i] = (uint16_t) WEBRTC_SPL_ABS_W16(freq_signal[i].imag); 307 | } else if (freq_signal[i].imag == 0) { 308 | freq_signal_abs[i] = (uint16_t) WEBRTC_SPL_ABS_W16(freq_signal[i].real); 309 | } else { 310 | // Approximation for magnitude of complex fft output 311 | // magn = sqrt(real^2 + imag^2) 312 | // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|) 313 | // 314 | // The parameters alpha and beta are stored in Q15 315 | 316 | #ifdef AECM_WITH_ABS_APPROX 317 | tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real); 318 | tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag); 319 | 320 | if (tmp16no1 > tmp16no2) { 321 | max_value = tmp16no1; 322 | min_value = tmp16no2; 323 | } else { 324 | max_value = tmp16no2; 325 | min_value = tmp16no1; 326 | } 327 | 328 | // Magnitude in Q(-6) 329 | if ((max_value >> 2) > min_value) { 330 | alpha = kAlpha1; 331 | beta = kBeta1; 332 | } else if ((max_value >> 1) > min_value) { 333 | alpha = kAlpha2; 334 | beta = kBeta2; 335 | } else { 336 | alpha = kAlpha3; 337 | beta = kBeta3; 338 | } 339 | tmp16no1 = (int16_t)((max_value * alpha) >> 15); 340 | tmp16no2 = (int16_t)((min_value * beta) >> 15); 341 | freq_signal_abs[i] = (uint16_t)tmp16no1 + (uint16_t)tmp16no2; 342 | #else 343 | #ifdef WEBRTC_ARCH_ARM_V7 344 | __asm __volatile( 345 | "smulbb %[tmp32no1], %[real], %[real]\n\t" 346 | "smlabb %[tmp32no2], %[imag], %[imag], %[tmp32no1]\n\t" 347 | : [tmp32no1] "+&r"(tmp32no1), [tmp32no2] "=r"(tmp32no2) 348 | : [real] "r"(freq_signal[i].real), [imag] "r"(freq_signal[i].imag)); 349 | #else 350 | tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real); 351 | tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag); 352 | tmp32no1 = tmp16no1 * tmp16no1; 353 | tmp32no2 = tmp16no2 * tmp16no2; 354 | tmp32no2 = WebRtcSpl_AddSatW32(tmp32no1, tmp32no2); 355 | #endif // WEBRTC_ARCH_ARM_V7 356 | tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2); 357 | 358 | freq_signal_abs[i] = (uint16_t) tmp32no1; 359 | #endif // AECM_WITH_ABS_APPROX 360 | } 361 | (*freq_signal_sum_abs) += (uint32_t) freq_signal_abs[i]; 362 | } 363 | 364 | return time_signal_scaling; 365 | } 366 | 367 | // bugs.webrtc.org/8200 368 | int WebRtcAecm_ProcessBlock(AecmCore *aecm, const int16_t *farend, const int16_t *nearendNoisy, 369 | const int16_t *nearendClean, int16_t *output) { 370 | int i; 371 | 372 | uint32_t xfaSum; 373 | uint32_t dfaNoisySum; 374 | uint32_t dfaCleanSum; 375 | uint32_t echoEst32Gained; 376 | uint32_t tmpU32; 377 | 378 | int32_t tmp32no1; 379 | 380 | uint16_t xfa[PART_LEN1]; 381 | uint16_t dfaNoisy[PART_LEN1]; 382 | uint16_t dfaClean[PART_LEN1]; 383 | uint16_t *ptrDfaClean = dfaClean; 384 | const uint16_t *far_spectrum_ptr = NULL; 385 | 386 | // 32 byte aligned buffers (with +8 or +16). 387 | // TODO(kma): define fft with ComplexInt16. 388 | int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe. 389 | int32_t echoEst32_buf[PART_LEN1 + 8]; 390 | int32_t dfw_buf[PART_LEN2 + 8]; 391 | int32_t efw_buf[PART_LEN2 + 8]; 392 | 393 | int16_t *fft = (int16_t *) (((uintptr_t) fft_buf + 31) & ~31); 394 | int32_t *echoEst32 = (int32_t *) (((uintptr_t) echoEst32_buf + 31) & ~31); 395 | ComplexInt16 *dfw = (ComplexInt16 *) (((uintptr_t) dfw_buf + 31) & ~31); 396 | ComplexInt16 *efw = (ComplexInt16 *) (((uintptr_t) efw_buf + 31) & ~31); 397 | 398 | int16_t hnl[PART_LEN1]; 399 | int16_t numPosCoef = 0; 400 | int16_t nlpGain = ONE_Q14; 401 | int delay; 402 | int16_t tmp16no1; 403 | int16_t tmp16no2; 404 | int16_t mu; 405 | int16_t supGain; 406 | int16_t zeros32, zeros16; 407 | int16_t zerosDBufNoisy, zerosDBufClean, zerosXBuf; 408 | int far_q; 409 | int16_t resolutionDiff, qDomainDiff, dfa_clean_q_domain_diff; 410 | 411 | const int kMinPrefBand = 4; 412 | const int kMaxPrefBand = 24; 413 | int32_t avgHnl32 = 0; 414 | 415 | // Determine startup state. There are three states: 416 | // (0) the first CONV_LEN blocks 417 | // (1) another CONV_LEN blocks 418 | // (2) the rest 419 | 420 | if (aecm->startupState < 2) { 421 | aecm-> 422 | startupState = 423 | (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2); 424 | } 425 | // END: Determine startup state 426 | 427 | // Buffer near and far end signals 428 | memcpy(aecm 429 | ->xBuf + PART_LEN, farend, sizeof(int16_t) * PART_LEN); 430 | memcpy(aecm 431 | ->dBufNoisy + PART_LEN, nearendNoisy, sizeof(int16_t) * PART_LEN); 432 | if (nearendClean != NULL) { 433 | memcpy(aecm 434 | ->dBufClean + PART_LEN, nearendClean, 435 | sizeof(int16_t) * PART_LEN); 436 | } 437 | 438 | // Transform far end signal from time domain to frequency domain. 439 | far_q = TimeToFrequencyDomain(aecm, aecm->xBuf, dfw, xfa, &xfaSum); 440 | 441 | // Transform noisy near end signal from time domain to frequency domain. 442 | zerosDBufNoisy = 443 | TimeToFrequencyDomain(aecm, aecm->dBufNoisy, dfw, dfaNoisy, &dfaNoisySum); 444 | aecm-> 445 | dfaNoisyQDomainOld = aecm->dfaNoisyQDomain; 446 | aecm-> 447 | dfaNoisyQDomain = (int16_t) zerosDBufNoisy; 448 | 449 | if (nearendClean == NULL) { 450 | ptrDfaClean = dfaNoisy; 451 | aecm-> 452 | dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld; 453 | aecm-> 454 | dfaCleanQDomain = aecm->dfaNoisyQDomain; 455 | dfaCleanSum = dfaNoisySum; 456 | } else { 457 | // Transform clean near end signal from time domain to frequency domain. 458 | zerosDBufClean = TimeToFrequencyDomain(aecm, aecm->dBufClean, dfw, dfaClean, 459 | &dfaCleanSum); 460 | aecm-> 461 | dfaCleanQDomainOld = aecm->dfaCleanQDomain; 462 | aecm-> 463 | dfaCleanQDomain = (int16_t) zerosDBufClean; 464 | } 465 | 466 | // Get the delay 467 | // Save far-end history and estimate delay 468 | WebRtcAecm_UpdateFarHistory(aecm, xfa, far_q 469 | ); 470 | if (WebRtc_AddFarSpectrumFix(aecm 471 | ->delay_estimator_farend, xfa, PART_LEN1, 472 | far_q) == -1) { 473 | return -1; 474 | } 475 | delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator, dfaNoisy, 476 | PART_LEN1, zerosDBufNoisy); 477 | if (delay == -1) { 478 | return -1; 479 | } else if (delay == -2) { 480 | // If the delay is unknown, we assume zero. 481 | // NOTE: this will have to be adjusted if we ever add lookahead. 482 | delay = 0; 483 | } 484 | 485 | if (aecm->fixedDelay >= 0) { 486 | // Use fixed delay 487 | delay = aecm->fixedDelay; 488 | } 489 | 490 | // Get aligned far end spectrum 491 | far_spectrum_ptr = WebRtcAecm_AlignedFarend(aecm, &far_q, delay); 492 | zerosXBuf = (int16_t) far_q; 493 | if (far_spectrum_ptr == NULL) { 494 | return -1; 495 | } 496 | 497 | // Calculate log(energy) and update energy threshold levels 498 | WebRtcAecm_CalcEnergies(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisySum, 499 | echoEst32 500 | ); 501 | 502 | // Calculate stepsize 503 | mu = WebRtcAecm_CalcStepSize(aecm); 504 | 505 | // Update counters 506 | aecm->totCount++; 507 | 508 | // This is the channel estimation algorithm. 509 | // It is base on NLMS but has a variable step length, 510 | // which was calculated above. 511 | WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu, 512 | echoEst32 513 | ); 514 | supGain = WebRtcAecm_CalcSuppressionGain(aecm); 515 | 516 | // Calculate Wiener filter hnl[] 517 | for ( 518 | i = 0; 519 | i < PART_LEN1; 520 | i++) { 521 | // Far end signal through channel estimate in Q8 522 | // How much can we shift right to preserve resolution 523 | tmp32no1 = echoEst32[i] - aecm->echoFilt[i]; 524 | aecm->echoFilt[i] += (int32_t) ((int64_t{tmp32no1} 525 | * 50) >> 8); 526 | 527 | zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1; 528 | zeros16 = WebRtcSpl_NormW16(supGain) + 1; 529 | if (zeros32 + zeros16 > 16) { 530 | // Multiplication is safe 531 | // Result in 532 | // Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+ 533 | // aecm->xfaQDomainBuf[diff]) 534 | echoEst32Gained = 535 | WEBRTC_SPL_UMUL_32_16((uint32_t) aecm->echoFilt[i], (uint16_t) supGain); 536 | resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN; 537 | resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); 538 | } else { 539 | tmp16no1 = 17 - zeros32 - zeros16; 540 | resolutionDiff = 541 | 14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN; 542 | resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); 543 | if (zeros32 > tmp16no1) { 544 | echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t) aecm->echoFilt[i], 545 | supGain >> tmp16no1); 546 | } else { 547 | // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16) 548 | echoEst32Gained = (aecm->echoFilt[i] >> tmp16no1) * supGain; 549 | } 550 | } 551 | 552 | zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]); 553 | RTC_DCHECK_GE(zeros16, 554 | 0); // |zeros16| is a norm, hence non-negative. 555 | dfa_clean_q_domain_diff = aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld; 556 | if (zeros16 < dfa_clean_q_domain_diff && aecm->nearFilt[i]) { 557 | tmp16no1 = aecm->nearFilt[i] * (1 << zeros16); 558 | qDomainDiff = zeros16 - dfa_clean_q_domain_diff; 559 | tmp16no2 = ptrDfaClean[i] >> -qDomainDiff; 560 | } else { 561 | tmp16no1 = dfa_clean_q_domain_diff < 0 562 | ? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff 563 | : aecm->nearFilt[i] * (1 << dfa_clean_q_domain_diff); 564 | qDomainDiff = 0; 565 | tmp16no2 = ptrDfaClean[i]; 566 | } 567 | tmp32no1 = (int32_t) (tmp16no2 - tmp16no1); 568 | tmp16no2 = (int16_t) (tmp32no1 >> 4); 569 | tmp16no2 += 570 | tmp16no1; 571 | zeros16 = WebRtcSpl_NormW16(tmp16no2); 572 | if ((tmp16no2) & (-qDomainDiff > zeros16)) { 573 | aecm->nearFilt[i] = 574 | WEBRTC_SPL_WORD16_MAX; 575 | } else { 576 | aecm->nearFilt[i] = qDomainDiff < 0 ? tmp16no2 * (1 << -qDomainDiff) 577 | : tmp16no2 >> 578 | qDomainDiff; 579 | } 580 | 581 | // Wiener filter coefficients, resulting hnl in Q14 582 | if (echoEst32Gained == 0) { 583 | hnl[i] = 584 | ONE_Q14; 585 | } else if (aecm->nearFilt[i] == 0) { 586 | hnl[i] = 0; 587 | } else { 588 | // Multiply the suppression gain 589 | // Rounding 590 | echoEst32Gained += (uint32_t) (aecm->nearFilt[i] >> 1); 591 | tmpU32 = 592 | WebRtcSpl_DivU32U16(echoEst32Gained, (uint16_t) aecm->nearFilt[i]); 593 | 594 | // Current resolution is 595 | // Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN- max(0,17-zeros16- zeros32)) 596 | // Make sure we are in Q14 597 | tmp32no1 = (int32_t) WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff); 598 | if (tmp32no1 > ONE_Q14) { 599 | hnl[i] = 0; 600 | } else if (tmp32no1 < 0) { 601 | hnl[i] = 602 | ONE_Q14; 603 | } else { 604 | // 1-echoEst/dfa 605 | hnl[i] = ONE_Q14 - (int16_t) 606 | tmp32no1; 607 | if (hnl[i] < 0) { 608 | hnl[i] = 0; 609 | } 610 | } 611 | } 612 | if (hnl[i]) { 613 | numPosCoef++; 614 | } 615 | } 616 | // Only in wideband. Prevent the gain in upper band from being larger than 617 | // in lower band. 618 | if (aecm->mult == 2) { 619 | // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause 620 | // speech distortion in double-talk. 621 | for ( 622 | i = 0; 623 | i < PART_LEN1; 624 | i++) { 625 | hnl[i] = (int16_t) ((hnl[i] * hnl[i]) >> 14); 626 | } 627 | 628 | for ( 629 | i = kMinPrefBand; 630 | i <= 631 | kMaxPrefBand; 632 | i++) { 633 | avgHnl32 += (int32_t) hnl[i]; 634 | } 635 | RTC_DCHECK_GT(kMaxPrefBand 636 | -kMinPrefBand + 1, 0); 637 | avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1); 638 | 639 | for ( 640 | i = kMaxPrefBand; 641 | i < PART_LEN1; 642 | i++) { 643 | if (hnl[i] > (int16_t) avgHnl32) { 644 | hnl[i] = (int16_t) 645 | avgHnl32; 646 | } 647 | } 648 | } 649 | 650 | // Calculate NLP gain, result is in Q14 651 | if (aecm->nlpFlag) { 652 | for ( 653 | i = 0; 654 | i < PART_LEN1; 655 | i++) { 656 | // Truncate values close to zero and one. 657 | if (hnl[i] > NLP_COMP_HIGH) { 658 | hnl[i] = 659 | ONE_Q14; 660 | } else if (hnl[i] < NLP_COMP_LOW) { 661 | hnl[i] = 0; 662 | } 663 | 664 | // Remove outliers 665 | if (numPosCoef < 3) { 666 | nlpGain = 0; 667 | } else { 668 | nlpGain = ONE_Q14; 669 | } 670 | 671 | // NLP 672 | if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14)) { 673 | hnl[i] = 674 | ONE_Q14; 675 | } else { 676 | hnl[i] = (int16_t) ((hnl[i] * nlpGain) >> 14); 677 | } 678 | 679 | // multiply with Wiener coefficients 680 | efw[i]. 681 | real = (int16_t) ( 682 | WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14)); 683 | efw[i]. 684 | imag = (int16_t) ( 685 | WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14)); 686 | } 687 | } else { 688 | // multiply with Wiener coefficients 689 | for ( 690 | i = 0; 691 | i < PART_LEN1; 692 | i++) { 693 | efw[i]. 694 | real = (int16_t) ( 695 | WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14)); 696 | efw[i]. 697 | imag = (int16_t) ( 698 | WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14)); 699 | } 700 | } 701 | 702 | if (aecm->cngMode == AecmTrue) { 703 | ComfortNoise(aecm, ptrDfaClean, efw, hnl 704 | ); 705 | } 706 | 707 | InverseFFTAndWindow(aecm, fft, efw, output, nearendClean 708 | ); 709 | 710 | return 0; 711 | } 712 | -------------------------------------------------------------------------------- /aecm/aecm_core_neon.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include 12 | 13 | #include "real_fft.h" 14 | #include "aecm_core.h" 15 | #include "signal_processing_library.h" 16 | 17 | 18 | 19 | // TODO(kma): Re-write the corresponding assembly file, the offset 20 | // generating script and makefile, to replace these C functions. 21 | 22 | static inline void AddLanes(uint32_t *ptr, uint32x4_t v) { 23 | #if defined(WEBRTC_ARCH_ARM64) 24 | *(ptr) = vaddvq_u32(v); 25 | #else 26 | uint32x2_t tmp_v; 27 | tmp_v = vadd_u32(vget_low_u32(v), vget_high_u32(v)); 28 | tmp_v = vpadd_u32(tmp_v, tmp_v); 29 | *(ptr) = vget_lane_u32(tmp_v, 0); 30 | #endif 31 | } 32 | 33 | 34 | void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore *aecm, 35 | const uint16_t *far_spectrum, 36 | int32_t *echo_est, 37 | uint32_t *far_energy, 38 | uint32_t *echo_energy_adapt, 39 | uint32_t *echo_energy_stored) { 40 | int16_t *start_stored_p = aecm->channelStored; 41 | int16_t *start_adapt_p = aecm->channelAdapt16; 42 | int32_t *echo_est_p = echo_est; 43 | const int16_t *end_stored_p = aecm->channelStored + PART_LEN; 44 | const uint16_t *far_spectrum_p = far_spectrum; 45 | int16x8_t store_v, adapt_v; 46 | uint16x8_t spectrum_v; 47 | uint32x4_t echo_est_v_low, echo_est_v_high; 48 | uint32x4_t far_energy_v, echo_stored_v, echo_adapt_v; 49 | 50 | far_energy_v = vdupq_n_u32(0); 51 | echo_adapt_v = vdupq_n_u32(0); 52 | echo_stored_v = vdupq_n_u32(0); 53 | 54 | // Get energy for the delayed far end signal and estimated 55 | // echo using both stored and adapted channels. 56 | // The C code: 57 | // for (i = 0; i < PART_LEN1; i++) { 58 | // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], 59 | // far_spectrum[i]); 60 | // (*far_energy) += (uint32_t)(far_spectrum[i]); 61 | // *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i]; 62 | // (*echo_energy_stored) += (uint32_t)echo_est[i]; 63 | // } 64 | while (start_stored_p < end_stored_p) { 65 | spectrum_v = vld1q_u16(far_spectrum_p); 66 | adapt_v = vld1q_s16(start_adapt_p); 67 | store_v = vld1q_s16(start_stored_p); 68 | 69 | far_energy_v = vaddw_u16(far_energy_v, vget_low_u16(spectrum_v)); 70 | far_energy_v = vaddw_u16(far_energy_v, vget_high_u16(spectrum_v)); 71 | 72 | echo_est_v_low = vmull_u16(vreinterpret_u16_s16(vget_low_s16(store_v)), 73 | vget_low_u16(spectrum_v)); 74 | echo_est_v_high = vmull_u16(vreinterpret_u16_s16(vget_high_s16(store_v)), 75 | vget_high_u16(spectrum_v)); 76 | vst1q_s32(echo_est_p, vreinterpretq_s32_u32(echo_est_v_low)); 77 | vst1q_s32(echo_est_p + 4, vreinterpretq_s32_u32(echo_est_v_high)); 78 | 79 | echo_stored_v = vaddq_u32(echo_est_v_low, echo_stored_v); 80 | echo_stored_v = vaddq_u32(echo_est_v_high, echo_stored_v); 81 | 82 | echo_adapt_v = 83 | vmlal_u16(echo_adapt_v, vreinterpret_u16_s16(vget_low_s16(adapt_v)), 84 | vget_low_u16(spectrum_v)); 85 | echo_adapt_v = 86 | vmlal_u16(echo_adapt_v, vreinterpret_u16_s16(vget_high_s16(adapt_v)), 87 | vget_high_u16(spectrum_v)); 88 | 89 | start_stored_p += 8; 90 | start_adapt_p += 8; 91 | far_spectrum_p += 8; 92 | echo_est_p += 8; 93 | } 94 | 95 | AddLanes(far_energy, far_energy_v); 96 | AddLanes(echo_energy_stored, echo_stored_v); 97 | AddLanes(echo_energy_adapt, echo_adapt_v); 98 | 99 | echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN], 100 | far_spectrum[PART_LEN]); 101 | *echo_energy_stored += (uint32_t) echo_est[PART_LEN]; 102 | *far_energy += (uint32_t) far_spectrum[PART_LEN]; 103 | *echo_energy_adapt += aecm->channelAdapt16[PART_LEN] * far_spectrum[PART_LEN]; 104 | } 105 | 106 | void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore *aecm, 107 | const uint16_t *far_spectrum, 108 | int32_t *echo_est) { 109 | RTC_DCHECK_EQ(0, (uintptr_t) echo_est % 32); 110 | RTC_DCHECK_EQ(0, (uintptr_t) aecm->channelStored % 16); 111 | RTC_DCHECK_EQ(0, (uintptr_t) aecm->channelAdapt16 % 16); 112 | 113 | // This is C code of following optimized code. 114 | // During startup we store the channel every block. 115 | // memcpy(aecm->channelStored, 116 | // aecm->channelAdapt16, 117 | // sizeof(int16_t) * PART_LEN1); 118 | // Recalculate echo estimate 119 | // for (i = 0; i < PART_LEN; i += 4) { 120 | // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], 121 | // far_spectrum[i]); 122 | // echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1], 123 | // far_spectrum[i + 1]); 124 | // echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2], 125 | // far_spectrum[i + 2]); 126 | // echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3], 127 | // far_spectrum[i + 3]); 128 | // } 129 | // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], 130 | // far_spectrum[i]); 131 | const uint16_t *far_spectrum_p = far_spectrum; 132 | int16_t *start_adapt_p = aecm->channelAdapt16; 133 | int16_t *start_stored_p = aecm->channelStored; 134 | const int16_t *end_stored_p = aecm->channelStored + PART_LEN; 135 | int32_t *echo_est_p = echo_est; 136 | 137 | uint16x8_t far_spectrum_v; 138 | int16x8_t adapt_v; 139 | uint32x4_t echo_est_v_low, echo_est_v_high; 140 | 141 | while (start_stored_p < end_stored_p) { 142 | far_spectrum_v = vld1q_u16(far_spectrum_p); 143 | adapt_v = vld1q_s16(start_adapt_p); 144 | 145 | vst1q_s16(start_stored_p, adapt_v); 146 | 147 | echo_est_v_low = vmull_u16(vget_low_u16(far_spectrum_v), 148 | vget_low_u16(vreinterpretq_u16_s16(adapt_v))); 149 | echo_est_v_high = vmull_u16(vget_high_u16(far_spectrum_v), 150 | vget_high_u16(vreinterpretq_u16_s16(adapt_v))); 151 | 152 | vst1q_s32(echo_est_p, vreinterpretq_s32_u32(echo_est_v_low)); 153 | vst1q_s32(echo_est_p + 4, vreinterpretq_s32_u32(echo_est_v_high)); 154 | 155 | far_spectrum_p += 8; 156 | start_adapt_p += 8; 157 | start_stored_p += 8; 158 | echo_est_p += 8; 159 | } 160 | aecm->channelStored[PART_LEN] = aecm->channelAdapt16[PART_LEN]; 161 | echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN], 162 | far_spectrum[PART_LEN]); 163 | } 164 | 165 | void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore *aecm) { 166 | RTC_DCHECK_EQ(0, (uintptr_t) aecm->channelStored % 16); 167 | RTC_DCHECK_EQ(0, (uintptr_t) aecm->channelAdapt16 % 16); 168 | RTC_DCHECK_EQ(0, (uintptr_t) aecm->channelAdapt32 % 32); 169 | 170 | // The C code of following optimized code. 171 | // for (i = 0; i < PART_LEN1; i++) { 172 | // aecm->channelAdapt16[i] = aecm->channelStored[i]; 173 | // aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32( 174 | // (int32_t)aecm->channelStored[i], 16); 175 | // } 176 | 177 | int16_t *start_stored_p = aecm->channelStored; 178 | int16_t *start_adapt16_p = aecm->channelAdapt16; 179 | int32_t *start_adapt32_p = aecm->channelAdapt32; 180 | const int16_t *end_stored_p = start_stored_p + PART_LEN; 181 | 182 | int16x8_t stored_v; 183 | int32x4_t adapt32_v_low, adapt32_v_high; 184 | 185 | while (start_stored_p < end_stored_p) { 186 | stored_v = vld1q_s16(start_stored_p); 187 | vst1q_s16(start_adapt16_p, stored_v); 188 | 189 | adapt32_v_low = vshll_n_s16(vget_low_s16(stored_v), 16); 190 | adapt32_v_high = vshll_n_s16(vget_high_s16(stored_v), 16); 191 | 192 | vst1q_s32(start_adapt32_p, adapt32_v_low); 193 | vst1q_s32(start_adapt32_p + 4, adapt32_v_high); 194 | 195 | start_stored_p += 8; 196 | start_adapt16_p += 8; 197 | start_adapt32_p += 8; 198 | } 199 | aecm->channelAdapt16[PART_LEN] = aecm->channelStored[PART_LEN]; 200 | aecm->channelAdapt32[PART_LEN] = (int32_t) aecm->channelStored[PART_LEN] << 16; 201 | } 202 | -------------------------------------------------------------------------------- /aecm/aecm_defines.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_ 12 | #define MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_ 13 | 14 | #define AECM_DYNAMIC_Q /* Turn on/off dynamic Q-domain. */ 15 | 16 | /* Algorithm parameters */ 17 | #define FRAME_LEN 80 /* Total frame length, 10 ms. */ 18 | 19 | #define PART_LEN 64 /* Length of partition. */ 20 | #define PART_LEN_SHIFT 7 /* Length of (PART_LEN * 2) in base 2. */ 21 | 22 | #define PART_LEN1 (PART_LEN + 1) /* Unique fft coefficients. */ 23 | #define PART_LEN2 (PART_LEN << 1) /* Length of partition * 2. */ 24 | #define PART_LEN4 (PART_LEN << 2) /* Length of partition * 4. */ 25 | #define FAR_BUF_LEN PART_LEN4 /* Length of buffers. */ 26 | #define MAX_DELAY 100 27 | 28 | /* Counter parameters */ 29 | #define CONV_LEN 512 /* Convergence length used at startup. */ 30 | #define CONV_LEN2 (CONV_LEN << 1) /* Used at startup. */ 31 | 32 | /* Energy parameters */ 33 | #define MAX_BUF_LEN 64 /* History length of energy signals. */ 34 | #define FAR_ENERGY_MIN 1025 /* Lowest Far energy level: At least 2 */ 35 | /* in energy. */ 36 | #define FAR_ENERGY_DIFF 929 /* Allowed difference between max */ 37 | /* and min. */ 38 | #define ENERGY_DEV_OFFSET 0 /* The energy error offset in Q8. */ 39 | #define ENERGY_DEV_TOL 400 /* The energy estimation tolerance (Q8). */ 40 | #define FAR_ENERGY_VAD_REGION 230 /* Far VAD tolerance region. */ 41 | 42 | /* Stepsize parameters */ 43 | #define MU_MIN 10 /* Min stepsize 2^-MU_MIN (far end energy */ 44 | /* dependent). */ 45 | #define MU_MAX 1 /* Max stepsize 2^-MU_MAX (far end energy */ 46 | /* dependent). */ 47 | #define MU_DIFF 9 /* MU_MIN - MU_MAX */ 48 | 49 | /* Channel parameters */ 50 | #define MIN_MSE_COUNT 20 /* Min number of consecutive blocks with enough */ 51 | /* far end energy to compare channel estimates. */ 52 | #define MIN_MSE_DIFF 29 /* The ratio between adapted and stored channel to */ 53 | /* accept a new storage (0.8 in Q-MSE_RESOLUTION). */ 54 | #define MSE_RESOLUTION 5 /* MSE parameter resolution. */ 55 | #define RESOLUTION_CHANNEL16 12 /* W16 Channel in Q-RESOLUTION_CHANNEL16. */ 56 | #define RESOLUTION_CHANNEL32 28 /* W32 Channel in Q-RESOLUTION_CHANNEL. */ 57 | #define CHANNEL_VAD 16 /* Minimum energy in frequency band */ 58 | /* to update channel. */ 59 | 60 | /* Suppression gain parameters: SUPGAIN parameters in Q-(RESOLUTION_SUPGAIN). */ 61 | #define RESOLUTION_SUPGAIN 8 /* Channel in Q-(RESOLUTION_SUPGAIN). */ 62 | #define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN) /* Default. */ 63 | #define SUPGAIN_ERROR_PARAM_A 3072 /* Estimation error parameter */ 64 | /* (Maximum gain) (8 in Q8). */ 65 | #define SUPGAIN_ERROR_PARAM_B 1536 /* Estimation error parameter */ 66 | /* (Gain before going down). */ 67 | #define SUPGAIN_ERROR_PARAM_D SUPGAIN_DEFAULT /* Estimation error parameter */ 68 | /* (Should be the same as Default) (1 in Q8). */ 69 | #define SUPGAIN_EPC_DT 200 /* SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL */ 70 | 71 | /* Defines for "check delay estimation" */ 72 | #define CORR_WIDTH 31 /* Number of samples to correlate over. */ 73 | #define CORR_MAX 16 /* Maximum correlation offset. */ 74 | #define CORR_MAX_BUF 63 75 | #define CORR_DEV 4 76 | #define CORR_MAX_LEVEL 20 77 | #define CORR_MAX_LOW 4 78 | #define CORR_BUF_LEN (CORR_MAX << 1) + 1 79 | /* Note that CORR_WIDTH + 2*CORR_MAX <= MAX_BUF_LEN. */ 80 | 81 | #define ONE_Q14 (1 << 14) 82 | 83 | /* NLP defines */ 84 | #define NLP_COMP_LOW 3277 /* 0.2 in Q14 */ 85 | #define NLP_COMP_HIGH ONE_Q14 /* 1 in Q14 */ 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /aecm/complex_fft.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | 12 | /* 13 | * This file contains the function WebRtcSpl_ComplexFFT(). 14 | * The description header can be found in signal_processing_library.h 15 | * 16 | */ 17 | 18 | #include "signal_processing_library.h" 19 | 20 | #define CFFTSFT 14 21 | #define CFFTRND 1 22 | #define CFFTRND2 16384 23 | 24 | #define CIFFTSFT 14 25 | #define CIFFTRND 1 26 | 27 | 28 | static const int16_t kSinTable1024[] = { 29 | 0, 201, 402, 603, 804, 1005, 1206, 1406, 1607, 30 | 1808, 2009, 2209, 2410, 2610, 2811, 3011, 3211, 3411, 31 | 3611, 3811, 4011, 4210, 4409, 4608, 4807, 5006, 5205, 32 | 5403, 5601, 5799, 5997, 6195, 6392, 6589, 6786, 6982, 33 | 7179, 7375, 7571, 7766, 7961, 8156, 8351, 8545, 8739, 34 | 8932, 9126, 9319, 9511, 9703, 9895, 10087, 10278, 10469, 35 | 10659, 10849, 11038, 11227, 11416, 11604, 11792, 11980, 12166, 36 | 12353, 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827, 37 | 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268, 15446, 38 | 15623, 15799, 15975, 16150, 16325, 16499, 16672, 16845, 17017, 39 | 17189, 17360, 17530, 17699, 17868, 18036, 18204, 18371, 18537, 40 | 18702, 18867, 19031, 19194, 19357, 19519, 19680, 19840, 20000, 41 | 20159, 20317, 20474, 20631, 20787, 20942, 21096, 21249, 21402, 42 | 21554, 21705, 21855, 22004, 22153, 22301, 22448, 22594, 22739, 43 | 22883, 23027, 23169, 23311, 23452, 23592, 23731, 23869, 24006, 44 | 24143, 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201, 45 | 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198, 26318, 46 | 26437, 26556, 26673, 26789, 26905, 27019, 27132, 27244, 27355, 47 | 27466, 27575, 27683, 27790, 27896, 28001, 28105, 28208, 28309, 48 | 28410, 28510, 28608, 28706, 28802, 28897, 28992, 29085, 29177, 49 | 29268, 29358, 29446, 29534, 29621, 29706, 29790, 29873, 29955, 50 | 30036, 30116, 30195, 30272, 30349, 30424, 30498, 30571, 30643, 51 | 30713, 30783, 30851, 30918, 30984, 31049, 31113, 31175, 31236, 52 | 31297, 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735, 53 | 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097, 32137, 54 | 32176, 32213, 32249, 32284, 32318, 32350, 32382, 32412, 32441, 55 | 32468, 32495, 32520, 32544, 32567, 32588, 32609, 32628, 32646, 56 | 32662, 32678, 32692, 32705, 32717, 32727, 32736, 32744, 32751, 57 | 32757, 32761, 32764, 32766, 32767, 32766, 32764, 32761, 32757, 58 | 32751, 32744, 32736, 32727, 32717, 32705, 32692, 32678, 32662, 59 | 32646, 32628, 32609, 32588, 32567, 32544, 32520, 32495, 32468, 60 | 32441, 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176, 61 | 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833, 31785, 62 | 31735, 31684, 31633, 31580, 31525, 31470, 31413, 31356, 31297, 63 | 31236, 31175, 31113, 31049, 30984, 30918, 30851, 30783, 30713, 64 | 30643, 30571, 30498, 30424, 30349, 30272, 30195, 30116, 30036, 65 | 29955, 29873, 29790, 29706, 29621, 29534, 29446, 29358, 29268, 66 | 29177, 29085, 28992, 28897, 28802, 28706, 28608, 28510, 28410, 67 | 28309, 28208, 28105, 28001, 27896, 27790, 27683, 27575, 27466, 68 | 27355, 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437, 69 | 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456, 25329, 70 | 25201, 25072, 24942, 24811, 24679, 24546, 24413, 24278, 24143, 71 | 24006, 23869, 23731, 23592, 23452, 23311, 23169, 23027, 22883, 72 | 22739, 22594, 22448, 22301, 22153, 22004, 21855, 21705, 21554, 73 | 21402, 21249, 21096, 20942, 20787, 20631, 20474, 20317, 20159, 74 | 20000, 19840, 19680, 19519, 19357, 19194, 19031, 18867, 18702, 75 | 18537, 18371, 18204, 18036, 17868, 17699, 17530, 17360, 17189, 76 | 17017, 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623, 77 | 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191, 14009, 78 | 13827, 13645, 13462, 13278, 13094, 12909, 12724, 12539, 12353, 79 | 12166, 11980, 11792, 11604, 11416, 11227, 11038, 10849, 10659, 80 | 10469, 10278, 10087, 9895, 9703, 9511, 9319, 9126, 8932, 81 | 8739, 8545, 8351, 8156, 7961, 7766, 7571, 7375, 7179, 82 | 6982, 6786, 6589, 6392, 6195, 5997, 5799, 5601, 5403, 83 | 5205, 5006, 4807, 4608, 4409, 4210, 4011, 3811, 3611, 84 | 3411, 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808, 85 | 1607, 1406, 1206, 1005, 804, 603, 402, 201, 0, 86 | -201, -402, -603, -804, -1005, -1206, -1406, -1607, -1808, 87 | -2009, -2209, -2410, -2610, -2811, -3011, -3211, -3411, -3611, 88 | -3811, -4011, -4210, -4409, -4608, -4807, -5006, -5205, -5403, 89 | -5601, -5799, -5997, -6195, -6392, -6589, -6786, -6982, -7179, 90 | -7375, -7571, -7766, -7961, -8156, -8351, -8545, -8739, -8932, 91 | -9126, -9319, -9511, -9703, -9895, -10087, -10278, -10469, -10659, 92 | -10849, -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353, 93 | -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, -14009, 94 | -14191, -14372, -14552, -14732, -14911, -15090, -15268, -15446, -15623, 95 | -15799, -15975, -16150, -16325, -16499, -16672, -16845, -17017, -17189, 96 | -17360, -17530, -17699, -17868, -18036, -18204, -18371, -18537, -18702, 97 | -18867, -19031, -19194, -19357, -19519, -19680, -19840, -20000, -20159, 98 | -20317, -20474, -20631, -20787, -20942, -21096, -21249, -21402, -21554, 99 | -21705, -21855, -22004, -22153, -22301, -22448, -22594, -22739, -22883, 100 | -23027, -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143, 101 | -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201, -25329, 102 | -25456, -25582, -25707, -25831, -25954, -26077, -26198, -26318, -26437, 103 | -26556, -26673, -26789, -26905, -27019, -27132, -27244, -27355, -27466, 104 | -27575, -27683, -27790, -27896, -28001, -28105, -28208, -28309, -28410, 105 | -28510, -28608, -28706, -28802, -28897, -28992, -29085, -29177, -29268, 106 | -29358, -29446, -29534, -29621, -29706, -29790, -29873, -29955, -30036, 107 | -30116, -30195, -30272, -30349, -30424, -30498, -30571, -30643, -30713, 108 | -30783, -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297, 109 | -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, -31785, 110 | -31833, -31880, -31926, -31970, -32014, -32056, -32097, -32137, -32176, 111 | -32213, -32249, -32284, -32318, -32350, -32382, -32412, -32441, -32468, 112 | -32495, -32520, -32544, -32567, -32588, -32609, -32628, -32646, -32662, 113 | -32678, -32692, -32705, -32717, -32727, -32736, -32744, -32751, -32757, 114 | -32761, -32764, -32766, -32767, -32766, -32764, -32761, -32757, -32751, 115 | -32744, -32736, -32727, -32717, -32705, -32692, -32678, -32662, -32646, 116 | -32628, -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441, 117 | -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176, -32137, 118 | -32097, -32056, -32014, -31970, -31926, -31880, -31833, -31785, -31735, 119 | -31684, -31633, -31580, -31525, -31470, -31413, -31356, -31297, -31236, 120 | -31175, -31113, -31049, -30984, -30918, -30851, -30783, -30713, -30643, 121 | -30571, -30498, -30424, -30349, -30272, -30195, -30116, -30036, -29955, 122 | -29873, -29790, -29706, -29621, -29534, -29446, -29358, -29268, -29177, 123 | -29085, -28992, -28897, -28802, -28706, -28608, -28510, -28410, -28309, 124 | -28208, -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355, 125 | -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, -26318, 126 | -26198, -26077, -25954, -25831, -25707, -25582, -25456, -25329, -25201, 127 | -25072, -24942, -24811, -24679, -24546, -24413, -24278, -24143, -24006, 128 | -23869, -23731, -23592, -23452, -23311, -23169, -23027, -22883, -22739, 129 | -22594, -22448, -22301, -22153, -22004, -21855, -21705, -21554, -21402, 130 | -21249, -21096, -20942, -20787, -20631, -20474, -20317, -20159, -20000, 131 | -19840, -19680, -19519, -19357, -19194, -19031, -18867, -18702, -18537, 132 | -18371, -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017, 133 | -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623, -15446, 134 | -15268, -15090, -14911, -14732, -14552, -14372, -14191, -14009, -13827, 135 | -13645, -13462, -13278, -13094, -12909, -12724, -12539, -12353, -12166, 136 | -11980, -11792, -11604, -11416, -11227, -11038, -10849, -10659, -10469, 137 | -10278, -10087, -9895, -9703, -9511, -9319, -9126, -8932, -8739, 138 | -8545, -8351, -8156, -7961, -7766, -7571, -7375, -7179, -6982, 139 | -6786, -6589, -6392, -6195, -5997, -5799, -5601, -5403, -5205, 140 | -5006, -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411, 141 | -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808, -1607, 142 | -1406, -1206, -1005, -804, -603, -402, -201}; 143 | 144 | 145 | /* Tables for data buffer indexes that are bit reversed and thus need to be 146 | * swapped. Note that, index_7[{0, 2, 4, ...}] are for the left side of the swap 147 | * operations, while index_7[{1, 3, 5, ...}] are for the right side of the 148 | * operation. Same for index_8. 149 | */ 150 | 151 | /* Indexes for the case of stages == 7. */ 152 | static const int16_t index_7[112] = { 153 | 1, 64, 2, 32, 3, 96, 4, 16, 5, 80, 6, 48, 7, 112, 9, 72, 10, 40, 11, 104, 154 | 12, 24, 13, 88, 14, 56, 15, 120, 17, 68, 18, 36, 19, 100, 21, 84, 22, 52, 155 | 23, 116, 25, 76, 26, 44, 27, 108, 29, 92, 30, 60, 31, 124, 33, 66, 35, 98, 156 | 37, 82, 38, 50, 39, 114, 41, 74, 43, 106, 45, 90, 46, 58, 47, 122, 49, 70, 157 | 51, 102, 53, 86, 55, 118, 57, 78, 59, 110, 61, 94, 63, 126, 67, 97, 69, 158 | 81, 71, 113, 75, 105, 77, 89, 79, 121, 83, 101, 87, 117, 91, 109, 95, 125, 159 | 103, 115, 111, 123 160 | }; 161 | 162 | /* Indexes for the case of stages == 8. */ 163 | static const int16_t index_8[240] = { 164 | 1, 128, 2, 64, 3, 192, 4, 32, 5, 160, 6, 96, 7, 224, 8, 16, 9, 144, 10, 80, 165 | 11, 208, 12, 48, 13, 176, 14, 112, 15, 240, 17, 136, 18, 72, 19, 200, 20, 166 | 40, 21, 168, 22, 104, 23, 232, 25, 152, 26, 88, 27, 216, 28, 56, 29, 184, 167 | 30, 120, 31, 248, 33, 132, 34, 68, 35, 196, 37, 164, 38, 100, 39, 228, 41, 168 | 148, 42, 84, 43, 212, 44, 52, 45, 180, 46, 116, 47, 244, 49, 140, 50, 76, 169 | 51, 204, 53, 172, 54, 108, 55, 236, 57, 156, 58, 92, 59, 220, 61, 188, 62, 170 | 124, 63, 252, 65, 130, 67, 194, 69, 162, 70, 98, 71, 226, 73, 146, 74, 82, 171 | 75, 210, 77, 178, 78, 114, 79, 242, 81, 138, 83, 202, 85, 170, 86, 106, 87, 172 | 234, 89, 154, 91, 218, 93, 186, 94, 122, 95, 250, 97, 134, 99, 198, 101, 173 | 166, 103, 230, 105, 150, 107, 214, 109, 182, 110, 118, 111, 246, 113, 142, 174 | 115, 206, 117, 174, 119, 238, 121, 158, 123, 222, 125, 190, 127, 254, 131, 175 | 193, 133, 161, 135, 225, 137, 145, 139, 209, 141, 177, 143, 241, 147, 201, 176 | 149, 169, 151, 233, 155, 217, 157, 185, 159, 249, 163, 197, 167, 229, 171, 177 | 213, 173, 181, 175, 245, 179, 205, 183, 237, 187, 221, 191, 253, 199, 227, 178 | 203, 211, 207, 243, 215, 235, 223, 251, 239, 247 179 | }; 180 | 181 | void WebRtcSpl_ComplexBitReverse(int16_t *__restrict complex_data, int stages) { 182 | /* For any specific value of stages, we know exactly the indexes that are 183 | * bit reversed. Currently (Feb. 2012) in WebRTC the only possible values of 184 | * stages are 7 and 8, so we use tables to save unnecessary iterations and 185 | * calculations for these two cases. 186 | */ 187 | if (stages == 7 || stages == 8) { 188 | int m = 0; 189 | int length = 112; 190 | const int16_t *index = index_7; 191 | 192 | if (stages == 8) { 193 | length = 240; 194 | index = index_8; 195 | } 196 | 197 | /* Decimation in time. Swap the elements with bit-reversed indexes. */ 198 | for (m = 0; m < length; m += 2) { 199 | /* We declare a int32_t* type pointer, to load both the 16-bit real 200 | * and imaginary elements from complex_data in one instruction, reducing 201 | * complexity. 202 | */ 203 | int32_t *complex_data_ptr = (int32_t *) complex_data; 204 | int32_t temp = 0; 205 | 206 | temp = complex_data_ptr[index[m]]; /* Real and imaginary */ 207 | complex_data_ptr[index[m]] = complex_data_ptr[index[m + 1]]; 208 | complex_data_ptr[index[m + 1]] = temp; 209 | } 210 | } else { 211 | int m = 0, mr = 0, l = 0; 212 | int n = 1 << stages; 213 | int nn = n - 1; 214 | 215 | /* Decimation in time - re-order data */ 216 | for (m = 1; m <= nn; ++m) { 217 | int32_t *complex_data_ptr = (int32_t *) complex_data; 218 | int32_t temp = 0; 219 | 220 | /* Find out indexes that are bit-reversed. */ 221 | l = n; 222 | do { 223 | l >>= 1; 224 | } while (l > nn - mr); 225 | mr = (mr & (l - 1)) + l; 226 | 227 | if (mr <= m) { 228 | continue; 229 | } 230 | 231 | /* Swap the elements with bit-reversed indexes. 232 | * This is similar to the loop in the stages == 7 or 8 cases. 233 | */ 234 | temp = complex_data_ptr[m]; /* Real and imaginary */ 235 | complex_data_ptr[m] = complex_data_ptr[mr]; 236 | complex_data_ptr[mr] = temp; 237 | } 238 | } 239 | } 240 | 241 | int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode) { 242 | int i, j, l, k, istep, n, m; 243 | int16_t wr, wi; 244 | int32_t tr32, ti32, qr32, qi32; 245 | 246 | /* The 1024-value is a constant given from the size of kSinTable1024[], 247 | * and should not be changed depending on the input parameter 'stages' 248 | */ 249 | n = 1 << stages; 250 | if (n > 1024) 251 | return -1; 252 | 253 | l = 1; 254 | k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change 255 | depending on the input parameter 'stages' */ 256 | 257 | if (mode == 0) { 258 | // mode==0: Low-complexity and Low-accuracy mode 259 | while (l < n) { 260 | istep = l << 1; 261 | 262 | for (m = 0; m < l; ++m) { 263 | j = m << k; 264 | 265 | /* The 256-value is a constant given as 1/4 of the size of 266 | * kSinTable1024[], and should not be changed depending on the input 267 | * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 268 | */ 269 | wr = kSinTable1024[j + 256]; 270 | wi = -kSinTable1024[j]; 271 | 272 | for (i = m; i < n; i += istep) { 273 | j = i + l; 274 | 275 | tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15; 276 | 277 | ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15; 278 | 279 | qr32 = (int32_t) frfi[2 * i]; 280 | qi32 = (int32_t) frfi[2 * i + 1]; 281 | frfi[2 * j] = (int16_t) ((qr32 - tr32) >> 1); 282 | frfi[2 * j + 1] = (int16_t) ((qi32 - ti32) >> 1); 283 | frfi[2 * i] = (int16_t) ((qr32 + tr32) >> 1); 284 | frfi[2 * i + 1] = (int16_t) ((qi32 + ti32) >> 1); 285 | } 286 | } 287 | 288 | --k; 289 | l = istep; 290 | 291 | } 292 | 293 | } else { 294 | // mode==1: High-complexity and High-accuracy mode 295 | while (l < n) { 296 | istep = l << 1; 297 | 298 | for (m = 0; m < l; ++m) { 299 | j = m << k; 300 | 301 | /* The 256-value is a constant given as 1/4 of the size of 302 | * kSinTable1024[], and should not be changed depending on the input 303 | * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 304 | */ 305 | wr = kSinTable1024[j + 256]; 306 | wi = -kSinTable1024[j]; 307 | 308 | #ifdef WEBRTC_ARCH_ARM_V7 309 | int32_t wri = 0; 310 | __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) : 311 | "r"((int32_t)wr), "r"((int32_t)wi)); 312 | #endif 313 | 314 | for (i = m; i < n; i += istep) { 315 | j = i + l; 316 | 317 | #ifdef WEBRTC_ARCH_ARM_V7 318 | register int32_t frfi_r; 319 | __asm __volatile( 320 | "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd]," 321 | " lsl #16\n\t" 322 | "smlsd %[tr32], %[wri], %[frfi_r], %[cfftrnd]\n\t" 323 | "smladx %[ti32], %[wri], %[frfi_r], %[cfftrnd]\n\t" 324 | :[frfi_r]"=&r"(frfi_r), 325 | [tr32]"=&r"(tr32), 326 | [ti32]"=r"(ti32) 327 | :[frfi_even]"r"((int32_t)frfi[2*j]), 328 | [frfi_odd]"r"((int32_t)frfi[2*j +1]), 329 | [wri]"r"(wri), 330 | [cfftrnd]"r"(CFFTRND)); 331 | #else 332 | tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CFFTRND; 333 | 334 | ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CFFTRND; 335 | #endif 336 | 337 | tr32 >>= 15 - CFFTSFT; 338 | ti32 >>= 15 - CFFTSFT; 339 | 340 | qr32 = ((int32_t) frfi[2 * i]) * (1 << CFFTSFT); 341 | qi32 = ((int32_t) frfi[2 * i + 1]) * (1 << CFFTSFT); 342 | 343 | frfi[2 * j] = (int16_t) ( 344 | (qr32 - tr32 + CFFTRND2) >> (1 + CFFTSFT)); 345 | frfi[2 * j + 1] = (int16_t) ( 346 | (qi32 - ti32 + CFFTRND2) >> (1 + CFFTSFT)); 347 | frfi[2 * i] = (int16_t) ( 348 | (qr32 + tr32 + CFFTRND2) >> (1 + CFFTSFT)); 349 | frfi[2 * i + 1] = (int16_t) ( 350 | (qi32 + ti32 + CFFTRND2) >> (1 + CFFTSFT)); 351 | } 352 | } 353 | 354 | --k; 355 | l = istep; 356 | } 357 | } 358 | return 0; 359 | } 360 | 361 | int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode) { 362 | size_t i, j, l, istep, n, m; 363 | int k, scale, shift; 364 | int16_t wr, wi; 365 | int32_t tr32, ti32, qr32, qi32; 366 | int32_t tmp32, round2; 367 | 368 | /* The 1024-value is a constant given from the size of kSinTable1024[], 369 | * and should not be changed depending on the input parameter 'stages' 370 | */ 371 | n = ((size_t) 1) << stages; 372 | if (n > 1024) 373 | return -1; 374 | 375 | scale = 0; 376 | 377 | l = 1; 378 | k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change 379 | depending on the input parameter 'stages' */ 380 | 381 | while (l < n) { 382 | // variable scaling, depending upon data 383 | shift = 0; 384 | round2 = 8192; 385 | 386 | tmp32 = WebRtcSpl_MaxAbsValueW16(frfi, 2 * n); 387 | if (tmp32 > 13573) { 388 | shift++; 389 | scale++; 390 | round2 <<= 1; 391 | } 392 | if (tmp32 > 27146) { 393 | shift++; 394 | scale++; 395 | round2 <<= 1; 396 | } 397 | 398 | istep = l << 1; 399 | 400 | if (mode == 0) { 401 | // mode==0: Low-complexity and Low-accuracy mode 402 | for (m = 0; m < l; ++m) { 403 | j = m << k; 404 | 405 | /* The 256-value is a constant given as 1/4 of the size of 406 | * kSinTable1024[], and should not be changed depending on the input 407 | * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 408 | */ 409 | wr = kSinTable1024[j + 256]; 410 | wi = kSinTable1024[j]; 411 | 412 | for (i = m; i < n; i += istep) { 413 | j = i + l; 414 | 415 | tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15; 416 | 417 | ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15; 418 | 419 | qr32 = (int32_t) frfi[2 * i]; 420 | qi32 = (int32_t) frfi[2 * i + 1]; 421 | frfi[2 * j] = (int16_t) ((qr32 - tr32) >> shift); 422 | frfi[2 * j + 1] = (int16_t) ((qi32 - ti32) >> shift); 423 | frfi[2 * i] = (int16_t) ((qr32 + tr32) >> shift); 424 | frfi[2 * i + 1] = (int16_t) ((qi32 + ti32) >> shift); 425 | } 426 | } 427 | } else { 428 | // mode==1: High-complexity and High-accuracy mode 429 | 430 | for (m = 0; m < l; ++m) { 431 | j = m << k; 432 | 433 | /* The 256-value is a constant given as 1/4 of the size of 434 | * kSinTable1024[], and should not be changed depending on the input 435 | * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 436 | */ 437 | wr = kSinTable1024[j + 256]; 438 | wi = kSinTable1024[j]; 439 | 440 | #ifdef WEBRTC_ARCH_ARM_V7 441 | int32_t wri = 0; 442 | __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) : 443 | "r"((int32_t)wr), "r"((int32_t)wi)); 444 | #endif 445 | 446 | for (i = m; i < n; i += istep) { 447 | j = i + l; 448 | 449 | #ifdef WEBRTC_ARCH_ARM_V7 450 | register int32_t frfi_r; 451 | __asm __volatile( 452 | "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t" 453 | "smlsd %[tr32], %[wri], %[frfi_r], %[cifftrnd]\n\t" 454 | "smladx %[ti32], %[wri], %[frfi_r], %[cifftrnd]\n\t" 455 | :[frfi_r]"=&r"(frfi_r), 456 | [tr32]"=&r"(tr32), 457 | [ti32]"=r"(ti32) 458 | :[frfi_even]"r"((int32_t)frfi[2*j]), 459 | [frfi_odd]"r"((int32_t)frfi[2*j +1]), 460 | [wri]"r"(wri), 461 | [cifftrnd]"r"(CIFFTRND) 462 | ); 463 | #else 464 | 465 | tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CIFFTRND; 466 | 467 | ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CIFFTRND; 468 | #endif 469 | tr32 >>= 15 - CIFFTSFT; 470 | ti32 >>= 15 - CIFFTSFT; 471 | 472 | qr32 = ((int32_t) frfi[2 * i]) * (1 << CIFFTSFT); 473 | qi32 = ((int32_t) frfi[2 * i + 1]) * (1 << CIFFTSFT); 474 | 475 | frfi[2 * j] = (int16_t) ( 476 | (qr32 - tr32 + round2) >> (shift + CIFFTSFT)); 477 | frfi[2 * j + 1] = (int16_t) ( 478 | (qi32 - ti32 + round2) >> (shift + CIFFTSFT)); 479 | frfi[2 * i] = (int16_t) ( 480 | (qr32 + tr32 + round2) >> (shift + CIFFTSFT)); 481 | frfi[2 * i + 1] = (int16_t) ( 482 | (qi32 + ti32 + round2) >> (shift + CIFFTSFT)); 483 | } 484 | } 485 | 486 | } 487 | --k; 488 | l = istep; 489 | } 490 | return scale; 491 | } 492 | -------------------------------------------------------------------------------- /aecm/delay_estimator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | // Performs delay estimation on binary converted spectra. 12 | // The return value is 0 - OK and -1 - Error, unless otherwise stated. 13 | 14 | #ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ 15 | #define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ 16 | 17 | #include 18 | 19 | 20 | static const int32_t kMaxBitCountsQ9 = (32 << 9); // 32 matching bits in Q9. 21 | 22 | typedef struct { 23 | // Pointer to bit counts. 24 | int *far_bit_counts; 25 | // Binary history variables. 26 | uint32_t *binary_far_history; 27 | int history_size; 28 | } BinaryDelayEstimatorFarend; 29 | 30 | typedef struct { 31 | // Pointer to bit counts. 32 | int32_t *mean_bit_counts; 33 | // Array only used locally in ProcessBinarySpectrum() but whose size is 34 | // determined at run-time. 35 | int32_t *bit_counts; 36 | 37 | // Binary history variables. 38 | uint32_t *binary_near_history; 39 | int near_history_size; 40 | int history_size; 41 | 42 | // Delay estimation variables. 43 | int32_t minimum_probability; 44 | int last_delay_probability; 45 | 46 | // Delay memory. 47 | int last_delay; 48 | 49 | // Robust validation 50 | int robust_validation_enabled; 51 | int allowed_offset; 52 | int last_candidate_delay; 53 | int compare_delay; 54 | int candidate_hits; 55 | float *histogram; 56 | float last_delay_histogram; 57 | 58 | // For dynamically changing the lookahead when using SoftReset...(). 59 | int lookahead; 60 | 61 | // Far-end binary spectrum history buffer etc. 62 | BinaryDelayEstimatorFarend *farend; 63 | } BinaryDelayEstimator; 64 | 65 | // Releases the memory allocated by 66 | // WebRtc_CreateBinaryDelayEstimatorFarend(...). 67 | // Input: 68 | // - self : Pointer to the binary delay estimation far-end 69 | // instance which is the return value of 70 | // WebRtc_CreateBinaryDelayEstimatorFarend(). 71 | // 72 | void WebRtc_FreeBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend *self); 73 | 74 | // Allocates the memory needed by the far-end part of the binary delay 75 | // estimation. The memory needs to be initialized separately through 76 | // WebRtc_InitBinaryDelayEstimatorFarend(...). 77 | // 78 | // Inputs: 79 | // - history_size : Size of the far-end binary spectrum history. 80 | // 81 | // Return value: 82 | // - BinaryDelayEstimatorFarend* 83 | // : Created |handle|. If the memory can't be allocated 84 | // or if any of the input parameters are invalid NULL 85 | // is returned. 86 | // 87 | BinaryDelayEstimatorFarend *WebRtc_CreateBinaryDelayEstimatorFarend( 88 | int history_size); 89 | 90 | // Re-allocates the buffers. 91 | // 92 | // Inputs: 93 | // - self : Pointer to the binary estimation far-end instance 94 | // which is the return value of 95 | // WebRtc_CreateBinaryDelayEstimatorFarend(). 96 | // - history_size : Size of the far-end binary spectrum history. 97 | // 98 | // Return value: 99 | // - history_size : The history size allocated. 100 | int WebRtc_AllocateFarendBufferMemory(BinaryDelayEstimatorFarend *self, 101 | int history_size); 102 | 103 | // Initializes the delay estimation far-end instance created with 104 | // WebRtc_CreateBinaryDelayEstimatorFarend(...). 105 | // 106 | // Input: 107 | // - self : Pointer to the delay estimation far-end instance. 108 | // 109 | // Output: 110 | // - self : Initialized far-end instance. 111 | // 112 | void WebRtc_InitBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend *self); 113 | 114 | // Soft resets the delay estimation far-end instance created with 115 | // WebRtc_CreateBinaryDelayEstimatorFarend(...). 116 | // 117 | // Input: 118 | // - delay_shift : The amount of blocks to shift history buffers. 119 | // 120 | void WebRtc_SoftResetBinaryDelayEstimatorFarend( 121 | BinaryDelayEstimatorFarend *self, 122 | int delay_shift); 123 | 124 | // Adds the binary far-end spectrum to the internal far-end history buffer. This 125 | // spectrum is used as reference when calculating the delay using 126 | // WebRtc_ProcessBinarySpectrum(). 127 | // 128 | // Inputs: 129 | // - self : Pointer to the delay estimation far-end 130 | // instance. 131 | // - binary_far_spectrum : Far-end binary spectrum. 132 | // 133 | // Output: 134 | // - self : Updated far-end instance. 135 | // 136 | void WebRtc_AddBinaryFarSpectrum(BinaryDelayEstimatorFarend *self, 137 | uint32_t binary_far_spectrum); 138 | 139 | // Releases the memory allocated by WebRtc_CreateBinaryDelayEstimator(...). 140 | // 141 | // Note that BinaryDelayEstimator utilizes BinaryDelayEstimatorFarend, but does 142 | // not take ownership of it, hence the BinaryDelayEstimator has to be torn down 143 | // before the far-end. 144 | // 145 | // Input: 146 | // - self : Pointer to the binary delay estimation instance 147 | // which is the return value of 148 | // WebRtc_CreateBinaryDelayEstimator(). 149 | // 150 | void WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator *self); 151 | 152 | // Allocates the memory needed by the binary delay estimation. The memory needs 153 | // to be initialized separately through WebRtc_InitBinaryDelayEstimator(...). 154 | // 155 | // See WebRtc_CreateDelayEstimator(..) in delay_estimator_wrapper.c for detailed 156 | // description. 157 | BinaryDelayEstimator *WebRtc_CreateBinaryDelayEstimator( 158 | BinaryDelayEstimatorFarend *farend, 159 | int max_lookahead); 160 | 161 | // Re-allocates |history_size| dependent buffers. The far-end buffers will be 162 | // updated at the same time if needed. 163 | // 164 | // Input: 165 | // - self : Pointer to the binary estimation instance which is 166 | // the return value of 167 | // WebRtc_CreateBinaryDelayEstimator(). 168 | // - history_size : Size of the history buffers. 169 | // 170 | // Return value: 171 | // - history_size : The history size allocated. 172 | int WebRtc_AllocateHistoryBufferMemory(BinaryDelayEstimator *self, 173 | int history_size); 174 | 175 | // Initializes the delay estimation instance created with 176 | // WebRtc_CreateBinaryDelayEstimator(...). 177 | // 178 | // Input: 179 | // - self : Pointer to the delay estimation instance. 180 | // 181 | // Output: 182 | // - self : Initialized instance. 183 | // 184 | void WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator *self); 185 | 186 | // Soft resets the delay estimation instance created with 187 | // WebRtc_CreateBinaryDelayEstimator(...). 188 | // 189 | // Input: 190 | // - delay_shift : The amount of blocks to shift history buffers. 191 | // 192 | // Return value: 193 | // - actual_shifts : The actual number of shifts performed. 194 | // 195 | int WebRtc_SoftResetBinaryDelayEstimator(BinaryDelayEstimator *self, 196 | int delay_shift); 197 | 198 | // Estimates and returns the delay between the binary far-end and binary near- 199 | // end spectra. It is assumed the binary far-end spectrum has been added using 200 | // WebRtc_AddBinaryFarSpectrum() prior to this call. The value will be offset by 201 | // the lookahead (i.e. the lookahead should be subtracted from the returned 202 | // value). 203 | // 204 | // Inputs: 205 | // - self : Pointer to the delay estimation instance. 206 | // - binary_near_spectrum : Near-end binary spectrum of the current block. 207 | // 208 | // Output: 209 | // - self : Updated instance. 210 | // 211 | // Return value: 212 | // - delay : >= 0 - Calculated delay value. 213 | // -2 - Insufficient data for estimation. 214 | // 215 | int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator *self, 216 | uint32_t binary_near_spectrum); 217 | 218 | // Returns the last calculated delay updated by the function 219 | // WebRtc_ProcessBinarySpectrum(...). 220 | // 221 | // Input: 222 | // - self : Pointer to the delay estimation instance. 223 | // 224 | // Return value: 225 | // - delay : >= 0 - Last calculated delay value 226 | // -2 - Insufficient data for estimation. 227 | // 228 | int WebRtc_binary_last_delay(BinaryDelayEstimator *self); 229 | 230 | // Returns the estimation quality of the last calculated delay updated by the 231 | // function WebRtc_ProcessBinarySpectrum(...). The estimation quality is a value 232 | // in the interval [0, 1]. The higher the value, the better the quality. 233 | // 234 | // Return value: 235 | // - delay_quality : >= 0 - Estimation quality of last calculated 236 | // delay value. 237 | float WebRtc_binary_last_delay_quality(BinaryDelayEstimator *self); 238 | 239 | // Updates the |mean_value| recursively with a step size of 2^-|factor|. This 240 | // function is used internally in the Binary Delay Estimator as well as the 241 | // Fixed point wrapper. 242 | // 243 | // Inputs: 244 | // - new_value : The new value the mean should be updated with. 245 | // - factor : The step size, in number of right shifts. 246 | // 247 | // Input/Output: 248 | // - mean_value : Pointer to the mean value. 249 | // 250 | void WebRtc_MeanEstimatorFix(int32_t new_value, 251 | int factor, 252 | int32_t *mean_value); 253 | 254 | 255 | #endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ 256 | -------------------------------------------------------------------------------- /aecm/delay_estimator_wrapper.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "delay_estimator_wrapper.h" 12 | 13 | #include 14 | #include 15 | 16 | #include "delay_estimator.h" 17 | 18 | #include "signal_processing_library.h" 19 | 20 | typedef union { 21 | float float_; 22 | int32_t int32_; 23 | } SpectrumType; 24 | 25 | typedef struct { 26 | // Pointers to mean values of spectrum. 27 | SpectrumType *mean_far_spectrum; 28 | // |mean_far_spectrum| initialization indicator. 29 | int far_spectrum_initialized; 30 | 31 | int spectrum_size; 32 | 33 | // Far-end part of binary spectrum based delay estimation. 34 | BinaryDelayEstimatorFarend *binary_farend; 35 | } DelayEstimatorFarend; 36 | 37 | typedef struct { 38 | // Pointers to mean values of spectrum. 39 | SpectrumType *mean_near_spectrum; 40 | // |mean_near_spectrum| initialization indicator. 41 | int near_spectrum_initialized; 42 | 43 | int spectrum_size; 44 | 45 | // Binary spectrum based delay estimator 46 | BinaryDelayEstimator *binary_handle; 47 | } DelayEstimator; 48 | // Only bit |kBandFirst| through bit |kBandLast| are processed and 49 | // |kBandFirst| - |kBandLast| must be < 32. 50 | enum { 51 | kBandFirst = 12 52 | }; 53 | enum { 54 | kBandLast = 43 55 | }; 56 | 57 | static __inline uint32_t SetBit(uint32_t in, int pos) { 58 | uint32_t mask = (1 << pos); 59 | uint32_t out = (in | mask); 60 | 61 | return out; 62 | } 63 | 64 | // Calculates the mean recursively. Same version as WebRtc_MeanEstimatorFix(), 65 | // but for float. 66 | // 67 | // Inputs: 68 | // - new_value : New additional value. 69 | // - scale : Scale for smoothing (should be less than 1.0). 70 | // 71 | // Input/Output: 72 | // - mean_value : Pointer to the mean value for updating. 73 | // 74 | static void MeanEstimatorFloat(float new_value, 75 | float scale, 76 | float *mean_value) { 77 | RTC_DCHECK_LT(scale, 1.0f); 78 | *mean_value += (new_value - *mean_value) * scale; 79 | } 80 | 81 | // Computes the binary spectrum by comparing the input |spectrum| with a 82 | // |threshold_spectrum|. Float and fixed point versions. 83 | // 84 | // Inputs: 85 | // - spectrum : Spectrum of which the binary spectrum should be 86 | // calculated. 87 | // - threshold_spectrum : Threshold spectrum with which the input 88 | // spectrum is compared. 89 | // Return: 90 | // - out : Binary spectrum. 91 | // 92 | static uint32_t BinarySpectrumFix(const uint16_t *spectrum, 93 | SpectrumType *threshold_spectrum, 94 | int q_domain, 95 | int *threshold_initialized) { 96 | int i = kBandFirst; 97 | uint32_t out = 0; 98 | 99 | RTC_DCHECK_LT(q_domain, 16); 100 | 101 | if (!(*threshold_initialized)) { 102 | // Set the |threshold_spectrum| to half the input |spectrum| as starting 103 | // value. This speeds up the convergence. 104 | for (i = kBandFirst; i <= kBandLast; i++) { 105 | if (spectrum[i] > 0) { 106 | // Convert input spectrum from Q(|q_domain|) to Q15. 107 | int32_t spectrum_q15 = ((int32_t) spectrum[i]) << (15 - q_domain); 108 | threshold_spectrum[i].int32_ = (spectrum_q15 >> 1); 109 | *threshold_initialized = 1; 110 | } 111 | } 112 | } 113 | for (i = kBandFirst; i <= kBandLast; i++) { 114 | // Convert input spectrum from Q(|q_domain|) to Q15. 115 | int32_t spectrum_q15 = ((int32_t) spectrum[i]) << (15 - q_domain); 116 | // Update the |threshold_spectrum|. 117 | WebRtc_MeanEstimatorFix(spectrum_q15, 6, &(threshold_spectrum[i].int32_)); 118 | // Convert |spectrum| at current frequency bin to a binary value. 119 | if (spectrum_q15 > threshold_spectrum[i].int32_) { 120 | out = SetBit(out, i - kBandFirst); 121 | } 122 | } 123 | 124 | return out; 125 | } 126 | 127 | static uint32_t BinarySpectrumFloat(const float *spectrum, 128 | SpectrumType *threshold_spectrum, 129 | int *threshold_initialized) { 130 | int i = kBandFirst; 131 | uint32_t out = 0; 132 | const float kScale = 1 / 64.0; 133 | 134 | if (!(*threshold_initialized)) { 135 | // Set the |threshold_spectrum| to half the input |spectrum| as starting 136 | // value. This speeds up the convergence. 137 | for (i = kBandFirst; i <= kBandLast; i++) { 138 | if (spectrum[i] > 0.0f) { 139 | threshold_spectrum[i].float_ = (spectrum[i] / 2); 140 | *threshold_initialized = 1; 141 | } 142 | } 143 | } 144 | 145 | for (i = kBandFirst; i <= kBandLast; i++) { 146 | // Update the |threshold_spectrum|. 147 | MeanEstimatorFloat(spectrum[i], kScale, &(threshold_spectrum[i].float_)); 148 | // Convert |spectrum| at current frequency bin to a binary value. 149 | if (spectrum[i] > threshold_spectrum[i].float_) { 150 | out = SetBit(out, i - kBandFirst); 151 | } 152 | } 153 | 154 | return out; 155 | } 156 | 157 | void WebRtc_FreeDelayEstimatorFarend(void *handle) { 158 | DelayEstimatorFarend *self = (DelayEstimatorFarend *) handle; 159 | 160 | if (handle == NULL) { 161 | return; 162 | } 163 | 164 | free(self->mean_far_spectrum); 165 | self->mean_far_spectrum = NULL; 166 | 167 | WebRtc_FreeBinaryDelayEstimatorFarend(self->binary_farend); 168 | self->binary_farend = NULL; 169 | 170 | free(self); 171 | } 172 | 173 | void *WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size) { 174 | DelayEstimatorFarend *self = NULL; 175 | 176 | // Check if the sub band used in the delay estimation is small enough to fit 177 | // the binary spectra in a uint32_t. 178 | static_assert(kBandLast - kBandFirst < 32, ""); 179 | 180 | if (spectrum_size >= kBandLast) { 181 | self = static_cast( 182 | malloc(sizeof(DelayEstimatorFarend))); 183 | } 184 | 185 | if (self != NULL) { 186 | int memory_fail = 0; 187 | 188 | // Allocate memory for the binary far-end spectrum handling. 189 | self->binary_farend = WebRtc_CreateBinaryDelayEstimatorFarend(history_size); 190 | memory_fail |= (self->binary_farend == NULL); 191 | 192 | // Allocate memory for spectrum buffers. 193 | self->mean_far_spectrum = static_cast( 194 | malloc(spectrum_size * sizeof(SpectrumType))); 195 | memory_fail |= (self->mean_far_spectrum == NULL); 196 | 197 | self->spectrum_size = spectrum_size; 198 | 199 | if (memory_fail) { 200 | WebRtc_FreeDelayEstimatorFarend(self); 201 | self = NULL; 202 | } 203 | } 204 | 205 | return self; 206 | } 207 | 208 | int WebRtc_InitDelayEstimatorFarend(void *handle) { 209 | DelayEstimatorFarend *self = (DelayEstimatorFarend *) handle; 210 | 211 | if (self == NULL) { 212 | return -1; 213 | } 214 | 215 | // Initialize far-end part of binary delay estimator. 216 | WebRtc_InitBinaryDelayEstimatorFarend(self->binary_farend); 217 | 218 | // Set averaged far and near end spectra to zero. 219 | memset(self->mean_far_spectrum, 0, 220 | sizeof(SpectrumType) * self->spectrum_size); 221 | // Reset initialization indicators. 222 | self->far_spectrum_initialized = 0; 223 | 224 | return 0; 225 | } 226 | 227 | void WebRtc_SoftResetDelayEstimatorFarend(void *handle, int delay_shift) { 228 | DelayEstimatorFarend *self = (DelayEstimatorFarend *) handle; 229 | RTC_DCHECK(self); 230 | WebRtc_SoftResetBinaryDelayEstimatorFarend(self->binary_farend, delay_shift); 231 | } 232 | 233 | int WebRtc_AddFarSpectrumFix(void *handle, 234 | const uint16_t *far_spectrum, 235 | int spectrum_size, 236 | int far_q) { 237 | DelayEstimatorFarend *self = (DelayEstimatorFarend *) handle; 238 | uint32_t binary_spectrum = 0; 239 | 240 | if (self == NULL) { 241 | return -1; 242 | } 243 | if (far_spectrum == NULL) { 244 | // Empty far end spectrum. 245 | return -1; 246 | } 247 | if (spectrum_size != self->spectrum_size) { 248 | // Data sizes don't match. 249 | return -1; 250 | } 251 | if (far_q > 15) { 252 | // If |far_q| is larger than 15 we cannot guarantee no wrap around. 253 | return -1; 254 | } 255 | 256 | // Get binary spectrum. 257 | binary_spectrum = BinarySpectrumFix(far_spectrum, self->mean_far_spectrum, 258 | far_q, &(self->far_spectrum_initialized)); 259 | WebRtc_AddBinaryFarSpectrum(self->binary_farend, binary_spectrum); 260 | 261 | return 0; 262 | } 263 | 264 | int WebRtc_AddFarSpectrumFloat(void *handle, 265 | const float *far_spectrum, 266 | int spectrum_size) { 267 | DelayEstimatorFarend *self = (DelayEstimatorFarend *) handle; 268 | uint32_t binary_spectrum = 0; 269 | 270 | if (self == NULL) { 271 | return -1; 272 | } 273 | if (far_spectrum == NULL) { 274 | // Empty far end spectrum. 275 | return -1; 276 | } 277 | if (spectrum_size != self->spectrum_size) { 278 | // Data sizes don't match. 279 | return -1; 280 | } 281 | 282 | // Get binary spectrum. 283 | binary_spectrum = BinarySpectrumFloat(far_spectrum, self->mean_far_spectrum, 284 | &(self->far_spectrum_initialized)); 285 | WebRtc_AddBinaryFarSpectrum(self->binary_farend, binary_spectrum); 286 | 287 | return 0; 288 | } 289 | 290 | void WebRtc_FreeDelayEstimator(void *handle) { 291 | DelayEstimator *self = (DelayEstimator *) handle; 292 | 293 | if (handle == NULL) { 294 | return; 295 | } 296 | 297 | free(self->mean_near_spectrum); 298 | self->mean_near_spectrum = NULL; 299 | 300 | WebRtc_FreeBinaryDelayEstimator(self->binary_handle); 301 | self->binary_handle = NULL; 302 | 303 | free(self); 304 | } 305 | 306 | void *WebRtc_CreateDelayEstimator(void *farend_handle, int max_lookahead) { 307 | DelayEstimator *self = NULL; 308 | DelayEstimatorFarend *farend = (DelayEstimatorFarend *) farend_handle; 309 | 310 | if (farend_handle != NULL) { 311 | self = static_cast(malloc(sizeof(DelayEstimator))); 312 | } 313 | 314 | if (self != NULL) { 315 | int memory_fail = 0; 316 | 317 | // Allocate memory for the farend spectrum handling. 318 | self->binary_handle = 319 | WebRtc_CreateBinaryDelayEstimator(farend->binary_farend, max_lookahead); 320 | memory_fail |= (self->binary_handle == NULL); 321 | 322 | // Allocate memory for spectrum buffers. 323 | self->mean_near_spectrum = static_cast( 324 | malloc(farend->spectrum_size * sizeof(SpectrumType))); 325 | memory_fail |= (self->mean_near_spectrum == NULL); 326 | 327 | self->spectrum_size = farend->spectrum_size; 328 | 329 | if (memory_fail) { 330 | WebRtc_FreeDelayEstimator(self); 331 | self = NULL; 332 | } 333 | } 334 | 335 | return self; 336 | } 337 | 338 | int WebRtc_InitDelayEstimator(void *handle) { 339 | DelayEstimator *self = (DelayEstimator *) handle; 340 | 341 | if (self == NULL) { 342 | return -1; 343 | } 344 | 345 | // Initialize binary delay estimator. 346 | WebRtc_InitBinaryDelayEstimator(self->binary_handle); 347 | 348 | // Set averaged far and near end spectra to zero. 349 | memset(self->mean_near_spectrum, 0, 350 | sizeof(SpectrumType) * self->spectrum_size); 351 | // Reset initialization indicators. 352 | self->near_spectrum_initialized = 0; 353 | 354 | return 0; 355 | } 356 | 357 | int WebRtc_SoftResetDelayEstimator(void *handle, int delay_shift) { 358 | DelayEstimator *self = (DelayEstimator *) handle; 359 | RTC_DCHECK(self); 360 | return WebRtc_SoftResetBinaryDelayEstimator(self->binary_handle, delay_shift); 361 | } 362 | 363 | int WebRtc_set_history_size(void *handle, int history_size) { 364 | DelayEstimator *self = static_cast(handle); 365 | 366 | if ((self == NULL) || (history_size <= 1)) { 367 | return -1; 368 | } 369 | return WebRtc_AllocateHistoryBufferMemory(self->binary_handle, history_size); 370 | } 371 | 372 | int WebRtc_history_size(const void *handle) { 373 | const DelayEstimator *self = static_cast(handle); 374 | 375 | if (self == NULL) { 376 | return -1; 377 | } 378 | if (self->binary_handle->farend->history_size != 379 | self->binary_handle->history_size) { 380 | // Non matching history sizes. 381 | return -1; 382 | } 383 | return self->binary_handle->history_size; 384 | } 385 | 386 | int WebRtc_set_lookahead(void *handle, int lookahead) { 387 | DelayEstimator *self = (DelayEstimator *) handle; 388 | RTC_DCHECK(self); 389 | RTC_DCHECK(self->binary_handle); 390 | if ((lookahead > self->binary_handle->near_history_size - 1) || 391 | (lookahead < 0)) { 392 | return -1; 393 | } 394 | self->binary_handle->lookahead = lookahead; 395 | return self->binary_handle->lookahead; 396 | } 397 | 398 | int WebRtc_lookahead(void *handle) { 399 | DelayEstimator *self = (DelayEstimator *) handle; 400 | RTC_DCHECK(self); 401 | RTC_DCHECK(self->binary_handle); 402 | return self->binary_handle->lookahead; 403 | } 404 | 405 | int WebRtc_set_allowed_offset(void *handle, int allowed_offset) { 406 | DelayEstimator *self = (DelayEstimator *) handle; 407 | 408 | if ((self == NULL) || (allowed_offset < 0)) { 409 | return -1; 410 | } 411 | self->binary_handle->allowed_offset = allowed_offset; 412 | return 0; 413 | } 414 | 415 | int WebRtc_get_allowed_offset(const void *handle) { 416 | const DelayEstimator *self = (const DelayEstimator *) handle; 417 | 418 | if (self == NULL) { 419 | return -1; 420 | } 421 | return self->binary_handle->allowed_offset; 422 | } 423 | 424 | int WebRtc_enable_robust_validation(void *handle, int enable) { 425 | DelayEstimator *self = (DelayEstimator *) handle; 426 | 427 | if (self == NULL) { 428 | return -1; 429 | } 430 | if ((enable < 0) || (enable > 1)) { 431 | return -1; 432 | } 433 | RTC_DCHECK(self->binary_handle); 434 | self->binary_handle->robust_validation_enabled = enable; 435 | return 0; 436 | } 437 | 438 | int WebRtc_is_robust_validation_enabled(const void *handle) { 439 | const DelayEstimator *self = (const DelayEstimator *) handle; 440 | 441 | if (self == NULL) { 442 | return -1; 443 | } 444 | return self->binary_handle->robust_validation_enabled; 445 | } 446 | 447 | int WebRtc_DelayEstimatorProcessFix(void *handle, 448 | const uint16_t *near_spectrum, 449 | int spectrum_size, 450 | int near_q) { 451 | DelayEstimator *self = (DelayEstimator *) handle; 452 | uint32_t binary_spectrum = 0; 453 | 454 | if (self == NULL) { 455 | return -1; 456 | } 457 | if (near_spectrum == NULL) { 458 | // Empty near end spectrum. 459 | return -1; 460 | } 461 | if (spectrum_size != self->spectrum_size) { 462 | // Data sizes don't match. 463 | return -1; 464 | } 465 | if (near_q > 15) { 466 | // If |near_q| is larger than 15 we cannot guarantee no wrap around. 467 | return -1; 468 | } 469 | 470 | // Get binary spectra. 471 | binary_spectrum = 472 | BinarySpectrumFix(near_spectrum, self->mean_near_spectrum, near_q, 473 | &(self->near_spectrum_initialized)); 474 | 475 | return WebRtc_ProcessBinarySpectrum(self->binary_handle, binary_spectrum); 476 | } 477 | 478 | int WebRtc_DelayEstimatorProcessFloat(void *handle, 479 | const float *near_spectrum, 480 | int spectrum_size) { 481 | DelayEstimator *self = (DelayEstimator *) handle; 482 | uint32_t binary_spectrum = 0; 483 | 484 | if (self == NULL) { 485 | return -1; 486 | } 487 | if (near_spectrum == NULL) { 488 | // Empty near end spectrum. 489 | return -1; 490 | } 491 | if (spectrum_size != self->spectrum_size) { 492 | // Data sizes don't match. 493 | return -1; 494 | } 495 | 496 | // Get binary spectrum. 497 | binary_spectrum = BinarySpectrumFloat(near_spectrum, self->mean_near_spectrum, 498 | &(self->near_spectrum_initialized)); 499 | 500 | return WebRtc_ProcessBinarySpectrum(self->binary_handle, binary_spectrum); 501 | } 502 | 503 | int WebRtc_last_delay(void *handle) { 504 | DelayEstimator *self = (DelayEstimator *) handle; 505 | 506 | if (self == NULL) { 507 | return -1; 508 | } 509 | 510 | return WebRtc_binary_last_delay(self->binary_handle); 511 | } 512 | 513 | float WebRtc_last_delay_quality(void *handle) { 514 | DelayEstimator *self = (DelayEstimator *) handle; 515 | RTC_DCHECK(self); 516 | return WebRtc_binary_last_delay_quality(self->binary_handle); 517 | } 518 | -------------------------------------------------------------------------------- /aecm/delay_estimator_wrapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | // Performs delay estimation on block by block basis. 12 | // The return value is 0 - OK and -1 - Error, unless otherwise stated. 13 | 14 | #ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_ 15 | #define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_ 16 | 17 | #include 18 | 19 | 20 | // Releases the memory allocated by WebRtc_CreateDelayEstimatorFarend(...) 21 | void WebRtc_FreeDelayEstimatorFarend(void *handle); 22 | 23 | // Allocates the memory needed by the far-end part of the delay estimation. The 24 | // memory needs to be initialized separately through 25 | // WebRtc_InitDelayEstimatorFarend(...). 26 | // 27 | // Inputs: 28 | // - spectrum_size : Size of the spectrum used both in far-end and 29 | // near-end. Used to allocate memory for spectrum 30 | // specific buffers. 31 | // - history_size : The far-end history buffer size. A change in buffer 32 | // size can be forced with WebRtc_set_history_size(). 33 | // Note that the maximum delay which can be estimated is 34 | // determined together with WebRtc_set_lookahead(). 35 | // 36 | // Return value: 37 | // - void* : Created |handle|. If the memory can't be allocated or 38 | // if any of the input parameters are invalid NULL is 39 | // returned. 40 | void *WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size); 41 | 42 | // Initializes the far-end part of the delay estimation instance returned by 43 | // WebRtc_CreateDelayEstimatorFarend(...) 44 | int WebRtc_InitDelayEstimatorFarend(void *handle); 45 | 46 | // Soft resets the far-end part of the delay estimation instance returned by 47 | // WebRtc_CreateDelayEstimatorFarend(...). 48 | // Input: 49 | // - delay_shift : The amount of blocks to shift history buffers. 50 | void WebRtc_SoftResetDelayEstimatorFarend(void *handle, int delay_shift); 51 | 52 | // Adds the far-end spectrum to the far-end history buffer. This spectrum is 53 | // used as reference when calculating the delay using 54 | // WebRtc_ProcessSpectrum(). 55 | // 56 | // Inputs: 57 | // - far_spectrum : Far-end spectrum. 58 | // - spectrum_size : The size of the data arrays (same for both far- and 59 | // near-end). 60 | // - far_q : The Q-domain of the far-end data. 61 | // 62 | // Output: 63 | // - handle : Updated far-end instance. 64 | // 65 | int WebRtc_AddFarSpectrumFix(void *handle, 66 | const uint16_t *far_spectrum, 67 | int spectrum_size, 68 | int far_q); 69 | 70 | // See WebRtc_AddFarSpectrumFix() for description. 71 | int WebRtc_AddFarSpectrumFloat(void *handle, 72 | const float *far_spectrum, 73 | int spectrum_size); 74 | 75 | // Releases the memory allocated by WebRtc_CreateDelayEstimator(...) 76 | void WebRtc_FreeDelayEstimator(void *handle); 77 | 78 | // Allocates the memory needed by the delay estimation. The memory needs to be 79 | // initialized separately through WebRtc_InitDelayEstimator(...). 80 | // 81 | // Inputs: 82 | // - farend_handle : Pointer to the far-end part of the delay estimation 83 | // instance created prior to this call using 84 | // WebRtc_CreateDelayEstimatorFarend(). 85 | // 86 | // Note that WebRtc_CreateDelayEstimator does not take 87 | // ownership of |farend_handle|, which has to be torn 88 | // down properly after this instance. 89 | // 90 | // - max_lookahead : Maximum amount of non-causal lookahead allowed. The 91 | // actual amount of lookahead used can be controlled by 92 | // WebRtc_set_lookahead(...). The default |lookahead| is 93 | // set to |max_lookahead| at create time. Use 94 | // WebRtc_set_lookahead(...) before start if a different 95 | // value is desired. 96 | // 97 | // Using lookahead can detect cases in which a near-end 98 | // signal occurs before the corresponding far-end signal. 99 | // It will delay the estimate for the current block by an 100 | // equal amount, and the returned values will be offset 101 | // by it. 102 | // 103 | // A value of zero is the typical no-lookahead case. 104 | // This also represents the minimum delay which can be 105 | // estimated. 106 | // 107 | // Note that the effective range of delay estimates is 108 | // [-|lookahead|,... ,|history_size|-|lookahead|) 109 | // where |history_size| is set through 110 | // WebRtc_set_history_size(). 111 | // 112 | // Return value: 113 | // - void* : Created |handle|. If the memory can't be allocated or 114 | // if any of the input parameters are invalid NULL is 115 | // returned. 116 | void *WebRtc_CreateDelayEstimator(void *farend_handle, int max_lookahead); 117 | 118 | // Initializes the delay estimation instance returned by 119 | // WebRtc_CreateDelayEstimator(...) 120 | int WebRtc_InitDelayEstimator(void *handle); 121 | 122 | // Soft resets the delay estimation instance returned by 123 | // WebRtc_CreateDelayEstimator(...) 124 | // Input: 125 | // - delay_shift : The amount of blocks to shift history buffers. 126 | // 127 | // Return value: 128 | // - actual_shifts : The actual number of shifts performed. 129 | int WebRtc_SoftResetDelayEstimator(void *handle, int delay_shift); 130 | 131 | // Sets the effective |history_size| used. Valid values from 2. We simply need 132 | // at least two delays to compare to perform an estimate. If |history_size| is 133 | // changed, buffers are reallocated filling in with zeros if necessary. 134 | // Note that changing the |history_size| affects both buffers in far-end and 135 | // near-end. Hence it is important to change all DelayEstimators that use the 136 | // same reference far-end, to the same |history_size| value. 137 | // Inputs: 138 | // - handle : Pointer to the delay estimation instance. 139 | // - history_size : Effective history size to be used. 140 | // Return value: 141 | // - new_history_size : The new history size used. If the memory was not able 142 | // to be allocated 0 is returned. 143 | int WebRtc_set_history_size(void *handle, int history_size); 144 | 145 | // Returns the history_size currently used. 146 | // Input: 147 | // - handle : Pointer to the delay estimation instance. 148 | int WebRtc_history_size(const void *handle); 149 | 150 | // Sets the amount of |lookahead| to use. Valid values are [0, max_lookahead] 151 | // where |max_lookahead| was set at create time through 152 | // WebRtc_CreateDelayEstimator(...). 153 | // 154 | // Input: 155 | // - handle : Pointer to the delay estimation instance. 156 | // - lookahead : The amount of lookahead to be used. 157 | // 158 | // Return value: 159 | // - new_lookahead : The actual amount of lookahead set, unless |handle| is 160 | // a NULL pointer or |lookahead| is invalid, for which an 161 | // error is returned. 162 | int WebRtc_set_lookahead(void *handle, int lookahead); 163 | 164 | // Returns the amount of lookahead we currently use. 165 | // Input: 166 | // - handle : Pointer to the delay estimation instance. 167 | int WebRtc_lookahead(void *handle); 168 | 169 | // Sets the |allowed_offset| used in the robust validation scheme. If the 170 | // delay estimator is used in an echo control component, this parameter is 171 | // related to the filter length. In principle |allowed_offset| should be set to 172 | // the echo control filter length minus the expected echo duration, i.e., the 173 | // delay offset the echo control can handle without quality regression. The 174 | // default value, used if not set manually, is zero. Note that |allowed_offset| 175 | // has to be non-negative. 176 | // Inputs: 177 | // - handle : Pointer to the delay estimation instance. 178 | // - allowed_offset : The amount of delay offset, measured in partitions, 179 | // the echo control filter can handle. 180 | int WebRtc_set_allowed_offset(void *handle, int allowed_offset); 181 | 182 | // Returns the |allowed_offset| in number of partitions. 183 | int WebRtc_get_allowed_offset(const void *handle); 184 | 185 | // Enables/Disables a robust validation functionality in the delay estimation. 186 | // This is by default set to disabled at create time. The state is preserved 187 | // over a reset. 188 | // Inputs: 189 | // - handle : Pointer to the delay estimation instance. 190 | // - enable : Enable (1) or disable (0) this feature. 191 | int WebRtc_enable_robust_validation(void *handle, int enable); 192 | 193 | // Returns 1 if robust validation is enabled and 0 if disabled. 194 | int WebRtc_is_robust_validation_enabled(const void *handle); 195 | 196 | // Estimates and returns the delay between the far-end and near-end blocks. The 197 | // value will be offset by the lookahead (i.e. the lookahead should be 198 | // subtracted from the returned value). 199 | // Inputs: 200 | // - handle : Pointer to the delay estimation instance. 201 | // - near_spectrum : Pointer to the near-end spectrum data of the current 202 | // block. 203 | // - spectrum_size : The size of the data arrays (same for both far- and 204 | // near-end). 205 | // - near_q : The Q-domain of the near-end data. 206 | // 207 | // Output: 208 | // - handle : Updated instance. 209 | // 210 | // Return value: 211 | // - delay : >= 0 - Calculated delay value. 212 | // -1 - Error. 213 | // -2 - Insufficient data for estimation. 214 | int WebRtc_DelayEstimatorProcessFix(void *handle, 215 | const uint16_t *near_spectrum, 216 | int spectrum_size, 217 | int near_q); 218 | 219 | // See WebRtc_DelayEstimatorProcessFix() for description. 220 | int WebRtc_DelayEstimatorProcessFloat(void *handle, 221 | const float *near_spectrum, 222 | int spectrum_size); 223 | 224 | // Returns the last calculated delay updated by the function 225 | // WebRtc_DelayEstimatorProcess(...). 226 | // 227 | // Input: 228 | // - handle : Pointer to the delay estimation instance. 229 | // 230 | // Return value: 231 | // - delay : >= 0 - Last calculated delay value. 232 | // -1 - Error. 233 | // -2 - Insufficient data for estimation. 234 | int WebRtc_last_delay(void *handle); 235 | 236 | // Returns the estimation quality/probability of the last calculated delay 237 | // updated by the function WebRtc_DelayEstimatorProcess(...). The estimation 238 | // quality is a value in the interval [0, 1]. The higher the value, the better 239 | // the quality. 240 | // 241 | // Return value: 242 | // - delay_quality : >= 0 - Estimation quality of last calculated delay. 243 | float WebRtc_last_delay_quality(void *handle); 244 | 245 | 246 | #endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_ 247 | -------------------------------------------------------------------------------- /aecm/echo_control_mobile.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "echo_control_mobile.h" 12 | 13 | #ifdef AEC_DEBUG 14 | #include 15 | #endif 16 | 17 | #include 18 | #include 19 | 20 | extern "C" { 21 | #include "ring_buffer.h" 22 | #include "signal_processing_library.h" 23 | #include "aecm_defines.h" 24 | } 25 | 26 | #include "aecm_core.h" 27 | 28 | 29 | #define BUF_SIZE_FRAMES 50 // buffer size (frames) 30 | // Maximum length of resampled signal. Must be an integer multiple of frames 31 | // (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN 32 | // The factor of 2 handles wb, and the + 1 is as a safety margin 33 | #define MAX_RESAMP_LEN (5 * FRAME_LEN) 34 | 35 | static const size_t kBufSizeSamp = 36 | BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples) 37 | static const int kSampMsNb = 8; // samples per ms in nb 38 | // Target suppression levels for nlp modes 39 | // log{0.001, 0.00001, 0.00000001} 40 | static const int kInitCheck = 42; 41 | 42 | typedef struct { 43 | int sampFreq; 44 | int scSampFreq; 45 | short bufSizeStart; 46 | int knownDelay; 47 | 48 | // Stores the last frame added to the farend buffer 49 | short farendOld[2][FRAME_LEN]; 50 | short initFlag; // indicates if AEC has been initialized 51 | 52 | // Variables used for averaging far end buffer size 53 | short counter; 54 | short sum; 55 | short firstVal; 56 | short checkBufSizeCtr; 57 | 58 | // Variables used for delay shifts 59 | short msInSndCardBuf; 60 | short filtDelay; 61 | int timeForDelayChange; 62 | int ECstartup; 63 | int checkBuffSize; 64 | int delayChange; 65 | short lastDelayDiff; 66 | 67 | int16_t echoMode; 68 | 69 | #ifdef AEC_DEBUG 70 | FILE* bufFile; 71 | FILE* delayFile; 72 | FILE* preCompFile; 73 | FILE* postCompFile; 74 | #endif // AEC_DEBUG 75 | // Structures 76 | RingBuffer *farendBuf; 77 | 78 | AecmCore *aecmCore; 79 | } AecMobile; 80 | 81 | 82 | // Estimates delay to set the position of the farend buffer read pointer 83 | // (controlled by knownDelay) 84 | static int WebRtcAecm_EstBufDelay(AecMobile *aecm, short msInSndCardBuf); 85 | 86 | // Stuffs the farend buffer if the estimated delay is too large 87 | static int WebRtcAecm_DelayComp(AecMobile *aecm); 88 | 89 | void *WebRtcAecm_Create() { 90 | // Allocate zero-filled memory. 91 | AecMobile *aecm = static_cast(calloc(1, sizeof(AecMobile))); 92 | 93 | aecm->aecmCore = WebRtcAecm_CreateCore(); 94 | if (!aecm->aecmCore) { 95 | WebRtcAecm_Free(aecm); 96 | return NULL; 97 | } 98 | 99 | aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp, sizeof(int16_t)); 100 | if (!aecm->farendBuf) { 101 | WebRtcAecm_Free(aecm); 102 | return NULL; 103 | } 104 | 105 | #ifdef AEC_DEBUG 106 | aecm->aecmCore->farFile = fopen("aecFar.pcm", "wb"); 107 | aecm->aecmCore->nearFile = fopen("aecNear.pcm", "wb"); 108 | aecm->aecmCore->outFile = fopen("aecOut.pcm", "wb"); 109 | // aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb"); 110 | 111 | aecm->bufFile = fopen("aecBuf.dat", "wb"); 112 | aecm->delayFile = fopen("aecDelay.dat", "wb"); 113 | aecm->preCompFile = fopen("preComp.pcm", "wb"); 114 | aecm->postCompFile = fopen("postComp.pcm", "wb"); 115 | #endif // AEC_DEBUG 116 | return aecm; 117 | } 118 | 119 | void WebRtcAecm_Free(void *aecmInst) { 120 | AecMobile *aecm = static_cast(aecmInst); 121 | 122 | if (aecm == NULL) { 123 | return; 124 | } 125 | 126 | #ifdef AEC_DEBUG 127 | fclose(aecm->aecmCore->farFile); 128 | fclose(aecm->aecmCore->nearFile); 129 | fclose(aecm->aecmCore->outFile); 130 | // fclose(aecm->aecmCore->outLpFile); 131 | 132 | fclose(aecm->bufFile); 133 | fclose(aecm->delayFile); 134 | fclose(aecm->preCompFile); 135 | fclose(aecm->postCompFile); 136 | #endif // AEC_DEBUG 137 | WebRtcAecm_FreeCore(aecm->aecmCore); 138 | WebRtc_FreeBuffer(aecm->farendBuf); 139 | free(aecm); 140 | } 141 | 142 | int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq) { 143 | AecMobile *aecm = static_cast(aecmInst); 144 | AecmConfig aecConfig; 145 | 146 | if (aecm == NULL) { 147 | return -1; 148 | } 149 | 150 | if (sampFreq != 8000 && sampFreq != 16000) { 151 | return AECM_BAD_PARAMETER_ERROR; 152 | } 153 | aecm->sampFreq = sampFreq; 154 | 155 | // Initialize AECM core 156 | if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1) { 157 | return AECM_UNSPECIFIED_ERROR; 158 | } 159 | 160 | // Initialize farend buffer 161 | WebRtc_InitBuffer(aecm->farendBuf); 162 | 163 | aecm->initFlag = kInitCheck; // indicates that initialization has been done 164 | 165 | aecm->delayChange = 1; 166 | 167 | aecm->sum = 0; 168 | aecm->counter = 0; 169 | aecm->checkBuffSize = 1; 170 | aecm->firstVal = 0; 171 | 172 | aecm->ECstartup = 1; 173 | aecm->bufSizeStart = 0; 174 | aecm->checkBufSizeCtr = 0; 175 | aecm->filtDelay = 0; 176 | aecm->timeForDelayChange = 0; 177 | aecm->knownDelay = 0; 178 | aecm->lastDelayDiff = 0; 179 | 180 | memset(&aecm->farendOld, 0, sizeof(aecm->farendOld)); 181 | 182 | // Default settings. 183 | aecConfig.cngMode = AecmTrue; 184 | aecConfig.echoMode = 3; 185 | 186 | if (WebRtcAecm_set_config(aecm, aecConfig) == -1) { 187 | return AECM_UNSPECIFIED_ERROR; 188 | } 189 | 190 | return 0; 191 | } 192 | 193 | // Returns any error that is caused when buffering the 194 | // farend signal. 195 | int32_t WebRtcAecm_GetBufferFarendError(void *aecmInst, 196 | const int16_t *farend, 197 | size_t nrOfSamples) { 198 | AecMobile *aecm = static_cast(aecmInst); 199 | 200 | if (aecm == NULL) 201 | return -1; 202 | 203 | if (farend == NULL) 204 | return AECM_NULL_POINTER_ERROR; 205 | 206 | if (aecm->initFlag != kInitCheck) 207 | return AECM_UNINITIALIZED_ERROR; 208 | 209 | if (nrOfSamples != 80 && nrOfSamples != 160) 210 | return AECM_BAD_PARAMETER_ERROR; 211 | 212 | return 0; 213 | } 214 | 215 | int32_t WebRtcAecm_BufferFarend(void *aecmInst, 216 | const int16_t *farend, 217 | size_t nrOfSamples) { 218 | AecMobile *aecm = static_cast(aecmInst); 219 | 220 | const int32_t err = 221 | WebRtcAecm_GetBufferFarendError(aecmInst, farend, nrOfSamples); 222 | 223 | if (err != 0) 224 | return err; 225 | 226 | // TODO(unknown): Is this really a good idea? 227 | if (!aecm->ECstartup) { 228 | WebRtcAecm_DelayComp(aecm); 229 | } 230 | 231 | WebRtc_WriteBuffer(aecm->farendBuf, farend, nrOfSamples); 232 | 233 | return 0; 234 | } 235 | 236 | int32_t WebRtcAecm_Process(void *aecmInst, 237 | const int16_t *nearendNoisy, 238 | const int16_t *nearendClean, 239 | int16_t *out, 240 | size_t nrOfSamples, 241 | int16_t msInSndCardBuf) { 242 | AecMobile *aecm = static_cast(aecmInst); 243 | int32_t retVal = 0; 244 | size_t i; 245 | short nmbrOfFilledBuffers; 246 | size_t nBlocks10ms; 247 | size_t nFrames; 248 | #ifdef AEC_DEBUG 249 | short msInAECBuf; 250 | #endif 251 | 252 | if (aecm == NULL) { 253 | return -1; 254 | } 255 | 256 | if (nearendNoisy == NULL) { 257 | return AECM_NULL_POINTER_ERROR; 258 | } 259 | 260 | if (out == NULL) { 261 | return AECM_NULL_POINTER_ERROR; 262 | } 263 | 264 | if (aecm->initFlag != kInitCheck) { 265 | return AECM_UNINITIALIZED_ERROR; 266 | } 267 | 268 | if (nrOfSamples != 80 && nrOfSamples != 160) { 269 | return AECM_BAD_PARAMETER_ERROR; 270 | } 271 | 272 | if (msInSndCardBuf < 0) { 273 | msInSndCardBuf = 0; 274 | retVal = AECM_BAD_PARAMETER_WARNING; 275 | } else if (msInSndCardBuf > 500) { 276 | msInSndCardBuf = 500; 277 | retVal = AECM_BAD_PARAMETER_WARNING; 278 | } 279 | msInSndCardBuf += 10; 280 | aecm->msInSndCardBuf = msInSndCardBuf; 281 | 282 | nFrames = nrOfSamples / FRAME_LEN; 283 | nBlocks10ms = nFrames / aecm->aecmCore->mult; 284 | 285 | if (aecm->ECstartup) { 286 | if (nearendClean == NULL) { 287 | if (out != nearendNoisy) { 288 | memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples); 289 | } 290 | } else if (out != nearendClean) { 291 | memcpy(out, nearendClean, sizeof(short) * nrOfSamples); 292 | } 293 | 294 | nmbrOfFilledBuffers = 295 | (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN; 296 | // The AECM is in the start up mode 297 | // AECM is disabled until the soundcard buffer and farend buffers are OK 298 | 299 | // Mechanism to ensure that the soundcard buffer is reasonably stable. 300 | if (aecm->checkBuffSize) { 301 | aecm->checkBufSizeCtr++; 302 | // Before we fill up the far end buffer we require the amount of data on 303 | // the sound card to be stable (+/-8 ms) compared to the first value. This 304 | // comparison is made during the following 4 consecutive frames. If it 305 | // seems to be stable then we start to fill up the far end buffer. 306 | 307 | if (aecm->counter == 0) { 308 | aecm->firstVal = aecm->msInSndCardBuf; 309 | aecm->sum = 0; 310 | } 311 | 312 | if (abs(aecm->firstVal - aecm->msInSndCardBuf) < 313 | WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb)) { 314 | aecm->sum += aecm->msInSndCardBuf; 315 | aecm->counter++; 316 | } else { 317 | aecm->counter = 0; 318 | } 319 | 320 | if (aecm->counter * nBlocks10ms >= 6) { 321 | // The farend buffer size is determined in blocks of 80 samples 322 | // Use 75% of the average value of the soundcard buffer 323 | aecm->bufSizeStart = WEBRTC_SPL_MIN( 324 | (3 * aecm->sum * aecm->aecmCore->mult) / (aecm->counter * 40), 325 | BUF_SIZE_FRAMES); 326 | // buffersize has now been determined 327 | aecm->checkBuffSize = 0; 328 | } 329 | 330 | if (aecm->checkBufSizeCtr * nBlocks10ms > 50) { 331 | // for really bad sound cards, don't disable echocanceller for more than 332 | // 0.5 sec 333 | aecm->bufSizeStart = WEBRTC_SPL_MIN( 334 | (3 * aecm->msInSndCardBuf * aecm->aecmCore->mult) / 40, 335 | BUF_SIZE_FRAMES); 336 | aecm->checkBuffSize = 0; 337 | } 338 | } 339 | 340 | // if checkBuffSize changed in the if-statement above 341 | if (!aecm->checkBuffSize) { 342 | // soundcard buffer is now reasonably stable 343 | // When the far end buffer is filled with approximately the same amount of 344 | // data as the amount on the sound card we end the start up phase and 345 | // start to cancel echoes. 346 | 347 | if (nmbrOfFilledBuffers == aecm->bufSizeStart) { 348 | aecm->ECstartup = 0; // Enable the AECM 349 | } else if (nmbrOfFilledBuffers > aecm->bufSizeStart) { 350 | WebRtc_MoveReadPtr(aecm->farendBuf, 351 | (int) WebRtc_available_read(aecm->farendBuf) - 352 | (int) aecm->bufSizeStart * FRAME_LEN); 353 | aecm->ECstartup = 0; 354 | } 355 | } 356 | 357 | } else { 358 | // AECM is enabled 359 | 360 | // Note only 1 block supported for nb and 2 blocks for wb 361 | for (i = 0; i < nFrames; i++) { 362 | int16_t farend[FRAME_LEN]; 363 | const int16_t *farend_ptr = NULL; 364 | 365 | nmbrOfFilledBuffers = 366 | (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN; 367 | 368 | // Check that there is data in the far end buffer 369 | if (nmbrOfFilledBuffers > 0) { 370 | // Get the next 80 samples from the farend buffer 371 | WebRtc_ReadBuffer(aecm->farendBuf, (void **) &farend_ptr, farend, 372 | FRAME_LEN); 373 | 374 | // Always store the last frame for use when we run out of data 375 | memcpy(&(aecm->farendOld[i][0]), farend_ptr, FRAME_LEN * sizeof(short)); 376 | } else { 377 | // We have no data so we use the last played frame 378 | memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short)); 379 | farend_ptr = farend; 380 | } 381 | 382 | // Call buffer delay estimator when all data is extracted, 383 | // i,e. i = 0 for NB and i = 1 for WB 384 | if ((i == 0 && aecm->sampFreq == 8000) || 385 | (i == 1 && aecm->sampFreq == 16000)) { 386 | WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf); 387 | } 388 | 389 | // Call the AECM 390 | /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i], 391 | &out[FRAME_LEN * i], aecm->knownDelay);*/ 392 | if (WebRtcAecm_ProcessFrame( 393 | aecm->aecmCore, farend_ptr, &nearendNoisy[FRAME_LEN * i], 394 | (nearendClean ? &nearendClean[FRAME_LEN * i] : NULL), 395 | &out[FRAME_LEN * i]) == -1) 396 | return -1; 397 | } 398 | } 399 | 400 | #ifdef AEC_DEBUG 401 | msInAECBuf = (short)WebRtc_available_read(aecm->farendBuf) / 402 | (kSampMsNb * aecm->aecmCore->mult); 403 | fwrite(&msInAECBuf, 2, 1, aecm->bufFile); 404 | fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile); 405 | #endif 406 | 407 | return retVal; 408 | } 409 | 410 | int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config) { 411 | AecMobile *aecm = static_cast(aecmInst); 412 | 413 | if (aecm == NULL) { 414 | return -1; 415 | } 416 | 417 | if (aecm->initFlag != kInitCheck) { 418 | return AECM_UNINITIALIZED_ERROR; 419 | } 420 | 421 | if (config.cngMode != AecmFalse && config.cngMode != AecmTrue) { 422 | return AECM_BAD_PARAMETER_ERROR; 423 | } 424 | aecm->aecmCore->cngMode = config.cngMode; 425 | 426 | if (config.echoMode < 0 || config.echoMode > 4) { 427 | return AECM_BAD_PARAMETER_ERROR; 428 | } 429 | aecm->echoMode = config.echoMode; 430 | 431 | if (aecm->echoMode == 0) { 432 | aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3; 433 | aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3; 434 | aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3; 435 | aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3; 436 | aecm->aecmCore->supGainErrParamDiffAB = 437 | (SUPGAIN_ERROR_PARAM_A >> 3) - (SUPGAIN_ERROR_PARAM_B >> 3); 438 | aecm->aecmCore->supGainErrParamDiffBD = 439 | (SUPGAIN_ERROR_PARAM_B >> 3) - (SUPGAIN_ERROR_PARAM_D >> 3); 440 | } else if (aecm->echoMode == 1) { 441 | aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2; 442 | aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2; 443 | aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2; 444 | aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2; 445 | aecm->aecmCore->supGainErrParamDiffAB = 446 | (SUPGAIN_ERROR_PARAM_A >> 2) - (SUPGAIN_ERROR_PARAM_B >> 2); 447 | aecm->aecmCore->supGainErrParamDiffBD = 448 | (SUPGAIN_ERROR_PARAM_B >> 2) - (SUPGAIN_ERROR_PARAM_D >> 2); 449 | } else if (aecm->echoMode == 2) { 450 | aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1; 451 | aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1; 452 | aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1; 453 | aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1; 454 | aecm->aecmCore->supGainErrParamDiffAB = 455 | (SUPGAIN_ERROR_PARAM_A >> 1) - (SUPGAIN_ERROR_PARAM_B >> 1); 456 | aecm->aecmCore->supGainErrParamDiffBD = 457 | (SUPGAIN_ERROR_PARAM_B >> 1) - (SUPGAIN_ERROR_PARAM_D >> 1); 458 | } else if (aecm->echoMode == 3) { 459 | aecm->aecmCore->supGain = SUPGAIN_DEFAULT; 460 | aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT; 461 | aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A; 462 | aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D; 463 | aecm->aecmCore->supGainErrParamDiffAB = 464 | SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B; 465 | aecm->aecmCore->supGainErrParamDiffBD = 466 | SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D; 467 | } else if (aecm->echoMode == 4) { 468 | aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1; 469 | aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1; 470 | aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1; 471 | aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1; 472 | aecm->aecmCore->supGainErrParamDiffAB = 473 | (SUPGAIN_ERROR_PARAM_A << 1) - (SUPGAIN_ERROR_PARAM_B << 1); 474 | aecm->aecmCore->supGainErrParamDiffBD = 475 | (SUPGAIN_ERROR_PARAM_B << 1) - (SUPGAIN_ERROR_PARAM_D << 1); 476 | } 477 | 478 | return 0; 479 | } 480 | 481 | int32_t WebRtcAecm_InitEchoPath(void *aecmInst, 482 | const void *echo_path, 483 | size_t size_bytes) { 484 | AecMobile *aecm = static_cast(aecmInst); 485 | const int16_t *echo_path_ptr = static_cast(echo_path); 486 | 487 | if (aecmInst == NULL) { 488 | return -1; 489 | } 490 | if (echo_path == NULL) { 491 | return AECM_NULL_POINTER_ERROR; 492 | } 493 | if (size_bytes != WebRtcAecm_echo_path_size_bytes()) { 494 | // Input channel size does not match the size of AECM 495 | return AECM_BAD_PARAMETER_ERROR; 496 | } 497 | if (aecm->initFlag != kInitCheck) { 498 | return AECM_UNINITIALIZED_ERROR; 499 | } 500 | 501 | WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr); 502 | 503 | return 0; 504 | } 505 | 506 | int32_t WebRtcAecm_GetEchoPath(void *aecmInst, 507 | void *echo_path, 508 | size_t size_bytes) { 509 | AecMobile *aecm = static_cast(aecmInst); 510 | int16_t *echo_path_ptr = static_cast(echo_path); 511 | 512 | if (aecmInst == NULL) { 513 | return -1; 514 | } 515 | if (echo_path == NULL) { 516 | return AECM_NULL_POINTER_ERROR; 517 | } 518 | if (size_bytes != WebRtcAecm_echo_path_size_bytes()) { 519 | // Input channel size does not match the size of AECM 520 | return AECM_BAD_PARAMETER_ERROR; 521 | } 522 | if (aecm->initFlag != kInitCheck) { 523 | return AECM_UNINITIALIZED_ERROR; 524 | } 525 | 526 | memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes); 527 | return 0; 528 | } 529 | 530 | size_t WebRtcAecm_echo_path_size_bytes() { 531 | return (PART_LEN1 * sizeof(int16_t)); 532 | } 533 | 534 | static int WebRtcAecm_EstBufDelay(AecMobile *aecm, short msInSndCardBuf) { 535 | short delayNew, nSampSndCard; 536 | short nSampFar = (short) WebRtc_available_read(aecm->farendBuf); 537 | short diff; 538 | 539 | nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult; 540 | 541 | delayNew = nSampSndCard - nSampFar; 542 | 543 | if (delayNew < FRAME_LEN) { 544 | WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN); 545 | delayNew += FRAME_LEN; 546 | } 547 | 548 | aecm->filtDelay = 549 | WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10); 550 | 551 | diff = aecm->filtDelay - aecm->knownDelay; 552 | if (diff > 224) { 553 | if (aecm->lastDelayDiff < 96) { 554 | aecm->timeForDelayChange = 0; 555 | } else { 556 | aecm->timeForDelayChange++; 557 | } 558 | } else if (diff < 96 && aecm->knownDelay > 0) { 559 | if (aecm->lastDelayDiff > 224) { 560 | aecm->timeForDelayChange = 0; 561 | } else { 562 | aecm->timeForDelayChange++; 563 | } 564 | } else { 565 | aecm->timeForDelayChange = 0; 566 | } 567 | aecm->lastDelayDiff = diff; 568 | 569 | if (aecm->timeForDelayChange > 25) { 570 | aecm->knownDelay = WEBRTC_SPL_MAX((int) aecm->filtDelay - 160, 0); 571 | } 572 | return 0; 573 | } 574 | 575 | static int WebRtcAecm_DelayComp(AecMobile *aecm) { 576 | int nSampFar = (int) WebRtc_available_read(aecm->farendBuf); 577 | int nSampSndCard, delayNew, nSampAdd; 578 | const int maxStuffSamp = 10 * FRAME_LEN; 579 | 580 | nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult; 581 | delayNew = nSampSndCard - nSampFar; 582 | 583 | if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult) { 584 | // The difference of the buffer sizes is larger than the maximum 585 | // allowed known delay. Compensate by stuffing the buffer. 586 | nSampAdd = (WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar), FRAME_LEN)); 587 | nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp); 588 | 589 | WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd); 590 | aecm->delayChange = 1; // the delay needs to be updated 591 | } 592 | 593 | return 0; 594 | } 595 | -------------------------------------------------------------------------------- /aecm/echo_control_mobile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef MODULES_AUDIO_PROCESSING_AECM_ECHO_CONTROL_MOBILE_H_ 12 | #define MODULES_AUDIO_PROCESSING_AECM_ECHO_CONTROL_MOBILE_H_ 13 | 14 | #include 15 | #include 16 | 17 | 18 | enum { 19 | AecmFalse = 0, AecmTrue 20 | }; 21 | 22 | // Errors 23 | #define AECM_UNSPECIFIED_ERROR 12000 24 | #define AECM_UNSUPPORTED_FUNCTION_ERROR 12001 25 | #define AECM_UNINITIALIZED_ERROR 12002 26 | #define AECM_NULL_POINTER_ERROR 12003 27 | #define AECM_BAD_PARAMETER_ERROR 12004 28 | 29 | // Warnings 30 | #define AECM_BAD_PARAMETER_WARNING 12100 31 | 32 | typedef struct { 33 | int16_t cngMode; // AECM_FALSE, AECM_TRUE (default) 34 | int16_t echoMode; // 0, 1, 2, 3 (default), 4 35 | } AecmConfig; 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | /* 42 | * Allocates the memory needed by the AECM. The memory needs to be 43 | * initialized separately using the WebRtcAecm_Init() function. 44 | * Returns a pointer to the instance and a nullptr at failure. 45 | */ 46 | void *WebRtcAecm_Create(); 47 | 48 | /* 49 | * This function releases the memory allocated by WebRtcAecm_Create() 50 | * 51 | * Inputs Description 52 | * ------------------------------------------------------------------- 53 | * void* aecmInst Pointer to the AECM instance 54 | */ 55 | void WebRtcAecm_Free(void *aecmInst); 56 | 57 | /* 58 | * Initializes an AECM instance. 59 | * 60 | * Inputs Description 61 | * ------------------------------------------------------------------- 62 | * void* aecmInst Pointer to the AECM instance 63 | * int32_t sampFreq Sampling frequency of data 64 | * 65 | * Outputs Description 66 | * ------------------------------------------------------------------- 67 | * int32_t return 0: OK 68 | * 1200-12004,12100: error/warning 69 | */ 70 | int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq); 71 | 72 | /* 73 | * Inserts an 80 or 160 sample block of data into the farend buffer. 74 | * 75 | * Inputs Description 76 | * ------------------------------------------------------------------- 77 | * void* aecmInst Pointer to the AECM instance 78 | * int16_t* farend In buffer containing one frame of 79 | * farend signal 80 | * int16_t nrOfSamples Number of samples in farend buffer 81 | * 82 | * Outputs Description 83 | * ------------------------------------------------------------------- 84 | * int32_t return 0: OK 85 | * 1200-12004,12100: error/warning 86 | */ 87 | int32_t WebRtcAecm_BufferFarend(void *aecmInst, 88 | const int16_t *farend, 89 | size_t nrOfSamples); 90 | 91 | /* 92 | * Reports any errors that would arise when buffering a farend buffer. 93 | * 94 | * Inputs Description 95 | * ------------------------------------------------------------------- 96 | * void* aecmInst Pointer to the AECM instance 97 | * int16_t* farend In buffer containing one frame of 98 | * farend signal 99 | * int16_t nrOfSamples Number of samples in farend buffer 100 | * 101 | * Outputs Description 102 | * ------------------------------------------------------------------- 103 | * int32_t return 0: OK 104 | * 1200-12004,12100: error/warning 105 | */ 106 | int32_t WebRtcAecm_GetBufferFarendError(void *aecmInst, 107 | const int16_t *farend, 108 | size_t nrOfSamples); 109 | 110 | /* 111 | * Runs the AECM on an 80 or 160 sample blocks of data. 112 | * 113 | * Inputs Description 114 | * ------------------------------------------------------------------- 115 | * void* aecmInst Pointer to the AECM instance 116 | * int16_t* nearendNoisy In buffer containing one frame of 117 | * reference nearend+echo signal. If 118 | * noise reduction is active, provide 119 | * the noisy signal here. 120 | * int16_t* nearendClean In buffer containing one frame of 121 | * nearend+echo signal. If noise 122 | * reduction is active, provide the 123 | * clean signal here. Otherwise pass a 124 | * NULL pointer. 125 | * int16_t nrOfSamples Number of samples in nearend buffer 126 | * int16_t msInSndCardBuf Delay estimate for sound card and 127 | * system buffers 128 | * 129 | * Outputs Description 130 | * ------------------------------------------------------------------- 131 | * int16_t* out Out buffer, one frame of processed nearend 132 | * int32_t return 0: OK 133 | * 1200-12004,12100: error/warning 134 | */ 135 | int32_t WebRtcAecm_Process(void *aecmInst, 136 | const int16_t *nearendNoisy, 137 | const int16_t *nearendClean, 138 | int16_t *out, 139 | size_t nrOfSamples, 140 | int16_t msInSndCardBuf); 141 | 142 | /* 143 | * This function enables the user to set certain parameters on-the-fly 144 | * 145 | * Inputs Description 146 | * ------------------------------------------------------------------- 147 | * void* aecmInst Pointer to the AECM instance 148 | * AecmConfig config Config instance that contains all 149 | * properties to be set 150 | * 151 | * Outputs Description 152 | * ------------------------------------------------------------------- 153 | * int32_t return 0: OK 154 | * 1200-12004,12100: error/warning 155 | */ 156 | int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config); 157 | 158 | /* 159 | * This function enables the user to set the echo path on-the-fly. 160 | * 161 | * Inputs Description 162 | * ------------------------------------------------------------------- 163 | * void* aecmInst Pointer to the AECM instance 164 | * void* echo_path Pointer to the echo path to be set 165 | * size_t size_bytes Size in bytes of the echo path 166 | * 167 | * Outputs Description 168 | * ------------------------------------------------------------------- 169 | * int32_t return 0: OK 170 | * 1200-12004,12100: error/warning 171 | */ 172 | int32_t WebRtcAecm_InitEchoPath(void *aecmInst, 173 | const void *echo_path, 174 | size_t size_bytes); 175 | 176 | /* 177 | * This function enables the user to get the currently used echo path 178 | * on-the-fly 179 | * 180 | * Inputs Description 181 | * ------------------------------------------------------------------- 182 | * void* aecmInst Pointer to the AECM instance 183 | * void* echo_path Pointer to echo path 184 | * size_t size_bytes Size in bytes of the echo path 185 | * 186 | * Outputs Description 187 | * ------------------------------------------------------------------- 188 | * int32_t return 0: OK 189 | * 1200-12004,12100: error/warning 190 | */ 191 | int32_t WebRtcAecm_GetEchoPath(void *aecmInst, 192 | void *echo_path, 193 | size_t size_bytes); 194 | 195 | /* 196 | * This function enables the user to get the echo path size in bytes 197 | * 198 | * Outputs Description 199 | * ------------------------------------------------------------------- 200 | * size_t return Size in bytes 201 | */ 202 | size_t WebRtcAecm_echo_path_size_bytes(); 203 | 204 | #ifdef __cplusplus 205 | } 206 | #endif 207 | 208 | 209 | #endif // MODULES_AUDIO_PROCESSING_AECM_ECHO_CONTROL_MOBILE_H_ 210 | -------------------------------------------------------------------------------- /aecm/real_fft.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "real_fft.h" 12 | 13 | #include 14 | 15 | #include "signal_processing_library.h" 16 | 17 | struct RealFFT { 18 | int order; 19 | }; 20 | 21 | struct RealFFT *WebRtcSpl_CreateRealFFT(int order) { 22 | struct RealFFT *self = NULL; 23 | 24 | if (order > kMaxFFTOrder || order < 0) { 25 | return NULL; 26 | } 27 | 28 | self = malloc(sizeof(struct RealFFT)); 29 | if (self == NULL) { 30 | return NULL; 31 | } 32 | self->order = order; 33 | 34 | return self; 35 | } 36 | 37 | void WebRtcSpl_FreeRealFFT(struct RealFFT *self) { 38 | if (self != NULL) { 39 | free(self); 40 | } 41 | } 42 | 43 | // The C version FFT functions (i.e. WebRtcSpl_RealForwardFFT and 44 | // WebRtcSpl_RealInverseFFT) are real-valued FFT wrappers for complex-valued 45 | // FFT implementation in SPL. 46 | 47 | int WebRtcSpl_RealForwardFFT(struct RealFFT *self, 48 | const int16_t *real_data_in, 49 | int16_t *complex_data_out) { 50 | int i = 0; 51 | int j = 0; 52 | int result = 0; 53 | int n = 1 << self->order; 54 | // The complex-value FFT implementation needs a buffer to hold 2^order 55 | // 16-bit COMPLEX numbers, for both time and frequency data. 56 | int16_t complex_buffer[2 << kMaxFFTOrder]; 57 | 58 | // Insert zeros to the imaginary parts for complex forward FFT input. 59 | for (i = 0, j = 0; i < n; i += 1, j += 2) { 60 | complex_buffer[j] = real_data_in[i]; 61 | complex_buffer[j + 1] = 0; 62 | } 63 | 64 | WebRtcSpl_ComplexBitReverse(complex_buffer, self->order); 65 | result = WebRtcSpl_ComplexFFT(complex_buffer, self->order, 1); 66 | 67 | // For real FFT output, use only the first N + 2 elements from 68 | // complex forward FFT. 69 | memcpy(complex_data_out, complex_buffer, sizeof(int16_t) * (n + 2)); 70 | 71 | return result; 72 | } 73 | 74 | int WebRtcSpl_RealInverseFFT(struct RealFFT *self, 75 | const int16_t *complex_data_in, 76 | int16_t *real_data_out) { 77 | int i = 0; 78 | int j = 0; 79 | int result = 0; 80 | int n = 1 << self->order; 81 | // Create the buffer specific to complex-valued FFT implementation. 82 | int16_t complex_buffer[2 << kMaxFFTOrder]; 83 | 84 | // For n-point FFT, first copy the first n + 2 elements into complex 85 | // FFT, then construct the remaining n - 2 elements by real FFT's 86 | // conjugate-symmetric properties. 87 | memcpy(complex_buffer, complex_data_in, sizeof(int16_t) * (n + 2)); 88 | for (i = n + 2; i < 2 * n; i += 2) { 89 | complex_buffer[i] = complex_data_in[2 * n - i]; 90 | complex_buffer[i + 1] = -complex_data_in[2 * n - i + 1]; 91 | } 92 | 93 | WebRtcSpl_ComplexBitReverse(complex_buffer, self->order); 94 | result = WebRtcSpl_ComplexIFFT(complex_buffer, self->order, 1); 95 | 96 | // Strip out the imaginary parts of the complex inverse FFT output. 97 | for (i = 0, j = 0; i < n; i += 1, j += 2) { 98 | real_data_out[i] = complex_buffer[j]; 99 | } 100 | 101 | return result; 102 | } 103 | -------------------------------------------------------------------------------- /aecm/real_fft.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ 12 | #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ 13 | 14 | #include 15 | 16 | // For ComplexFFT(), the maximum fft order is 10; 17 | // WebRTC APM uses orders of only 7 and 8. 18 | enum { 19 | kMaxFFTOrder = 10 20 | }; 21 | 22 | struct RealFFT; 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | struct RealFFT *WebRtcSpl_CreateRealFFT(int order); 29 | 30 | void WebRtcSpl_FreeRealFFT(struct RealFFT *self); 31 | 32 | // Compute an FFT for a real-valued signal of length of 2^order, 33 | // where 1 < order <= MAX_FFT_ORDER. Transform length is determined by the 34 | // specification structure, which must be initialized prior to calling the FFT 35 | // function with WebRtcSpl_CreateRealFFT(). 36 | // The relationship between the input and output sequences can 37 | // be expressed in terms of the DFT, i.e.: 38 | // x[n] = (2^(-scalefactor)/N) . SUM[k=0,...,N-1] X[k].e^(jnk.2.pi/N) 39 | // n=0,1,2,...N-1 40 | // N=2^order. 41 | // The conjugate-symmetric output sequence is represented using a CCS vector, 42 | // which is of length N+2, and is organized as follows: 43 | // Index: 0 1 2 3 4 5 . . . N-2 N-1 N N+1 44 | // Component: R0 0 R1 I1 R2 I2 . . . R[N/2-1] I[N/2-1] R[N/2] 0 45 | // where R[n] and I[n], respectively, denote the real and imaginary components 46 | // for FFT bin 'n'. Bins are numbered from 0 to N/2, where N is the FFT length. 47 | // Bin index 0 corresponds to the DC component, and bin index N/2 corresponds to 48 | // the foldover frequency. 49 | // 50 | // Input Arguments: 51 | // self - pointer to preallocated and initialized FFT specification structure. 52 | // real_data_in - the input signal. For an ARM Neon platform, it must be 53 | // aligned on a 32-byte boundary. 54 | // 55 | // Output Arguments: 56 | // complex_data_out - the output complex signal with (2^order + 2) 16-bit 57 | // elements. For an ARM Neon platform, it must be different 58 | // from real_data_in, and aligned on a 32-byte boundary. 59 | // 60 | // Return Value: 61 | // 0 - FFT calculation is successful. 62 | // -1 - Error with bad arguments (null pointers). 63 | int WebRtcSpl_RealForwardFFT(struct RealFFT *self, 64 | const int16_t *real_data_in, 65 | int16_t *complex_data_out); 66 | 67 | // Compute the inverse FFT for a conjugate-symmetric input sequence of length of 68 | // 2^order, where 1 < order <= MAX_FFT_ORDER. Transform length is determined by 69 | // the specification structure, which must be initialized prior to calling the 70 | // FFT function with WebRtcSpl_CreateRealFFT(). 71 | // For a transform of length M, the input sequence is represented using a packed 72 | // CCS vector of length M+2, which is explained in the comments for 73 | // WebRtcSpl_RealForwardFFTC above. 74 | // 75 | // Input Arguments: 76 | // self - pointer to preallocated and initialized FFT specification structure. 77 | // complex_data_in - the input complex signal with (2^order + 2) 16-bit 78 | // elements. For an ARM Neon platform, it must be aligned on 79 | // a 32-byte boundary. 80 | // 81 | // Output Arguments: 82 | // real_data_out - the output real signal. For an ARM Neon platform, it must 83 | // be different to complex_data_in, and aligned on a 32-byte 84 | // boundary. 85 | // 86 | // Return Value: 87 | // 0 or a positive number - a value that the elements in the |real_data_out| 88 | // should be shifted left with in order to get 89 | // correct physical values. 90 | // -1 - Error with bad arguments (null pointers). 91 | int WebRtcSpl_RealInverseFFT(struct RealFFT *self, 92 | const int16_t *complex_data_in, 93 | int16_t *real_data_out); 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif 98 | 99 | #endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ 100 | -------------------------------------------------------------------------------- /aecm/ring_buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | // A ring buffer to hold arbitrary data. Provides no thread safety. Unless 12 | // otherwise specified, functions return 0 on success and -1 on error. 13 | 14 | #include "ring_buffer.h" 15 | 16 | #include 17 | #include 18 | 19 | // Get address of region(s) from which we can read data. 20 | // If the region is contiguous, |data_ptr_bytes_2| will be zero. 21 | // If non-contiguous, |data_ptr_bytes_2| will be the size in bytes of the second 22 | // region. Returns room available to be read or |element_count|, whichever is 23 | // smaller. 24 | static size_t GetBufferReadRegions(RingBuffer *buf, 25 | size_t element_count, 26 | void **data_ptr_1, 27 | size_t *data_ptr_bytes_1, 28 | void **data_ptr_2, 29 | size_t *data_ptr_bytes_2) { 30 | 31 | const size_t readable_elements = WebRtc_available_read(buf); 32 | const size_t read_elements = (readable_elements < element_count ? 33 | readable_elements : element_count); 34 | const size_t margin = buf->element_count - buf->read_pos; 35 | 36 | // Check to see if read is not contiguous. 37 | if (read_elements > margin) { 38 | // Write data in two blocks that wrap the buffer. 39 | *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; 40 | *data_ptr_bytes_1 = margin * buf->element_size; 41 | *data_ptr_2 = buf->data; 42 | *data_ptr_bytes_2 = (read_elements - margin) * buf->element_size; 43 | } else { 44 | *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; 45 | *data_ptr_bytes_1 = read_elements * buf->element_size; 46 | *data_ptr_2 = NULL; 47 | *data_ptr_bytes_2 = 0; 48 | } 49 | 50 | return read_elements; 51 | } 52 | 53 | RingBuffer *WebRtc_CreateBuffer(size_t element_count, size_t element_size) { 54 | RingBuffer *self = NULL; 55 | if (element_count == 0 || element_size == 0) { 56 | return NULL; 57 | } 58 | 59 | self = malloc(sizeof(RingBuffer)); 60 | if (!self) { 61 | return NULL; 62 | } 63 | 64 | self->data = malloc(element_count * element_size); 65 | if (!self->data) { 66 | free(self); 67 | self = NULL; 68 | return NULL; 69 | } 70 | 71 | self->element_count = element_count; 72 | self->element_size = element_size; 73 | WebRtc_InitBuffer(self); 74 | 75 | return self; 76 | } 77 | 78 | void WebRtc_InitBuffer(RingBuffer *self) { 79 | self->read_pos = 0; 80 | self->write_pos = 0; 81 | self->rw_wrap = SAME_WRAP; 82 | 83 | // Initialize buffer to zeros 84 | memset(self->data, 0, self->element_count * self->element_size); 85 | } 86 | 87 | void WebRtc_FreeBuffer(void *handle) { 88 | RingBuffer *self = (RingBuffer *) handle; 89 | if (!self) { 90 | return; 91 | } 92 | 93 | free(self->data); 94 | free(self); 95 | } 96 | 97 | size_t WebRtc_ReadBuffer(RingBuffer *self, 98 | void **data_ptr, 99 | void *data, 100 | size_t element_count) { 101 | 102 | if (self == NULL) { 103 | return 0; 104 | } 105 | if (data == NULL) { 106 | return 0; 107 | } 108 | 109 | { 110 | void *buf_ptr_1 = NULL; 111 | void *buf_ptr_2 = NULL; 112 | size_t buf_ptr_bytes_1 = 0; 113 | size_t buf_ptr_bytes_2 = 0; 114 | const size_t read_count = GetBufferReadRegions(self, 115 | element_count, 116 | &buf_ptr_1, 117 | &buf_ptr_bytes_1, 118 | &buf_ptr_2, 119 | &buf_ptr_bytes_2); 120 | if (buf_ptr_bytes_2 > 0) { 121 | // We have a wrap around when reading the buffer. Copy the buffer data to 122 | // |data| and point to it. 123 | memcpy(data, buf_ptr_1, buf_ptr_bytes_1); 124 | memcpy(((char *) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2); 125 | buf_ptr_1 = data; 126 | } else if (!data_ptr) { 127 | // No wrap, but a memcpy was requested. 128 | memcpy(data, buf_ptr_1, buf_ptr_bytes_1); 129 | } 130 | if (data_ptr) { 131 | // |buf_ptr_1| == |data| in the case of a wrap. 132 | *data_ptr = read_count == 0 ? NULL : buf_ptr_1; 133 | } 134 | 135 | // Update read position 136 | WebRtc_MoveReadPtr(self, (int) read_count); 137 | 138 | return read_count; 139 | } 140 | } 141 | 142 | size_t WebRtc_WriteBuffer(RingBuffer *self, 143 | const void *data, 144 | size_t element_count) { 145 | if (!self) { 146 | return 0; 147 | } 148 | if (!data) { 149 | return 0; 150 | } 151 | 152 | { 153 | const size_t free_elements = WebRtc_available_write(self); 154 | const size_t write_elements = (free_elements < element_count ? free_elements 155 | : element_count); 156 | size_t n = write_elements; 157 | const size_t margin = self->element_count - self->write_pos; 158 | 159 | if (write_elements > margin) { 160 | // Buffer wrap around when writing. 161 | memcpy(self->data + self->write_pos * self->element_size, 162 | data, margin * self->element_size); 163 | self->write_pos = 0; 164 | n -= margin; 165 | self->rw_wrap = DIFF_WRAP; 166 | } 167 | memcpy(self->data + self->write_pos * self->element_size, 168 | ((const char *) data) + ((write_elements - n) * self->element_size), 169 | n * self->element_size); 170 | self->write_pos += n; 171 | 172 | return write_elements; 173 | } 174 | } 175 | 176 | int WebRtc_MoveReadPtr(RingBuffer *self, int element_count) { 177 | if (!self) { 178 | return 0; 179 | } 180 | 181 | { 182 | // We need to be able to take care of negative changes, hence use "int" 183 | // instead of "size_t". 184 | const int free_elements = (int) WebRtc_available_write(self); 185 | const int readable_elements = (int) WebRtc_available_read(self); 186 | int read_pos = (int) self->read_pos; 187 | 188 | if (element_count > readable_elements) { 189 | element_count = readable_elements; 190 | } 191 | if (element_count < -free_elements) { 192 | element_count = -free_elements; 193 | } 194 | 195 | read_pos += element_count; 196 | if (read_pos > (int) self->element_count) { 197 | // Buffer wrap around. Restart read position and wrap indicator. 198 | read_pos -= (int) self->element_count; 199 | self->rw_wrap = SAME_WRAP; 200 | } 201 | if (read_pos < 0) { 202 | // Buffer wrap around. Restart read position and wrap indicator. 203 | read_pos += (int) self->element_count; 204 | self->rw_wrap = DIFF_WRAP; 205 | } 206 | 207 | self->read_pos = (size_t) read_pos; 208 | 209 | return element_count; 210 | } 211 | } 212 | 213 | size_t WebRtc_available_read(const RingBuffer *self) { 214 | if (!self) { 215 | return 0; 216 | } 217 | 218 | if (self->rw_wrap == SAME_WRAP) { 219 | return self->write_pos - self->read_pos; 220 | } else { 221 | return self->element_count - self->read_pos + self->write_pos; 222 | } 223 | } 224 | 225 | size_t WebRtc_available_write(const RingBuffer *self) { 226 | if (!self) { 227 | return 0; 228 | } 229 | 230 | return self->element_count - WebRtc_available_read(self); 231 | } 232 | -------------------------------------------------------------------------------- /aecm/ring_buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | // A ring buffer to hold arbitrary data. Provides no thread safety. Unless 12 | // otherwise specified, functions return 0 on success and -1 on error. 13 | 14 | #ifndef COMMON_AUDIO_RING_BUFFER_H_ 15 | #define COMMON_AUDIO_RING_BUFFER_H_ 16 | 17 | // TODO(alessiob): Used by AEC, AECm and AudioRingBuffer. Remove when possible. 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #include // size_t 24 | 25 | enum Wrap { 26 | SAME_WRAP, DIFF_WRAP 27 | }; 28 | 29 | typedef struct RingBuffer { 30 | size_t read_pos; 31 | size_t write_pos; 32 | size_t element_count; 33 | size_t element_size; 34 | enum Wrap rw_wrap; 35 | char *data; 36 | } RingBuffer; 37 | 38 | // Creates and initializes the buffer. Returns null on failure. 39 | RingBuffer *WebRtc_CreateBuffer(size_t element_count, size_t element_size); 40 | 41 | void WebRtc_InitBuffer(RingBuffer *handle); 42 | 43 | void WebRtc_FreeBuffer(void *handle); 44 | 45 | // Reads data from the buffer. Returns the number of elements that were read. 46 | // The |data_ptr| will point to the address where the read data is located. 47 | // If no data can be read, |data_ptr| is set to |NULL|. If all data can be read 48 | // without buffer wrap around then |data_ptr| will point to the location in the 49 | // buffer. Otherwise, the data will be copied to |data| (memory allocation done 50 | // by the user) and |data_ptr| points to the address of |data|. |data_ptr| is 51 | // only guaranteed to be valid until the next call to WebRtc_WriteBuffer(). 52 | // 53 | // To force a copying to |data|, pass a null |data_ptr|. 54 | // 55 | // Returns number of elements read. 56 | size_t WebRtc_ReadBuffer(RingBuffer *handle, 57 | void **data_ptr, 58 | void *data, 59 | size_t element_count); 60 | 61 | // Writes |data| to buffer and returns the number of elements written. 62 | size_t WebRtc_WriteBuffer(RingBuffer *handle, 63 | const void *data, 64 | size_t element_count); 65 | 66 | // Moves the buffer read position and returns the number of elements moved. 67 | // Positive |element_count| moves the read position towards the write position, 68 | // that is, flushing the buffer. Negative |element_count| moves the read 69 | // position away from the the write position, that is, stuffing the buffer. 70 | // Returns number of elements moved. 71 | int WebRtc_MoveReadPtr(RingBuffer *handle, int element_count); 72 | 73 | // Returns number of available elements to read. 74 | size_t WebRtc_available_read(const RingBuffer *handle); 75 | 76 | // Returns number of available elements for write. 77 | size_t WebRtc_available_write(const RingBuffer *handle); 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | 83 | #endif // COMMON_AUDIO_RING_BUFFER_H_ 84 | -------------------------------------------------------------------------------- /aecm/signal_processing_library.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #include "signal_processing_library.h" 11 | 12 | // TODO(bugs.webrtc.org/9553): These function pointers are useless. Refactor 13 | // things so that we simply have a bunch of regular functions with different 14 | // implementations for different platforms. 15 | 16 | #if defined(WEBRTC_HAS_NEON) 17 | 18 | const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16Neon; 19 | const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32Neon; 20 | const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16Neon; 21 | const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32Neon; 22 | const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16Neon; 23 | const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32Neon; 24 | 25 | 26 | #elif defined(MIPS32_LE) 27 | 28 | const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16_mips; 29 | const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = 30 | #ifdef MIPS_DSP_R1_LE 31 | WebRtcSpl_MaxAbsValueW32_mips; 32 | #else 33 | WebRtcSpl_MaxAbsValueW32C; 34 | #endif 35 | const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16_mips; 36 | const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32_mips; 37 | const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16_mips; 38 | const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32_mips; 39 | 40 | 41 | #else 42 | 43 | const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16C; 44 | const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C; 45 | const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16C; 46 | const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32C; 47 | const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16C; 48 | const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32C; 49 | 50 | #endif 51 | 52 | // Table used by WebRtcSpl_CountLeadingZeros32_NotBuiltin. For each uint32_t n 53 | // that's a sequence of 0 bits followed by a sequence of 1 bits, the entry at 54 | // index (n * 0x8c0b2891) >> 26 in this table gives the number of zero bits in 55 | // n. 56 | const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64] = { 57 | 32, 8, 17, -1, -1, 14, -1, -1, -1, 20, -1, -1, -1, 28, -1, 18, 58 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 26, 25, 24, 59 | 4, 11, 23, 31, 3, 7, 10, 16, 22, 30, -1, -1, 2, 6, 13, 9, 60 | -1, 15, -1, 21, -1, 29, 19, -1, -1, -1, -1, -1, 1, 27, 5, 12, 61 | }; 62 | /* 63 | * Algorithm: 64 | * Successive approximation of the equation (root + delta) ^ 2 = N 65 | * until delta < 1. If delta < 1 we have the integer part of SQRT (N). 66 | * Use delta = 2^i for i = 15 .. 0. 67 | * 68 | * Output precision is 16 bits. Note for large input values (close to 69 | * 0x7FFFFFFF), bit 15 (the highest bit of the low 16-bit half word) 70 | * contains the MSB information (a non-sign value). Do with caution 71 | * if you need to cast the output to int16_t type. 72 | * 73 | * If the input value is negative, it returns 0. 74 | */ 75 | 76 | #define WEBRTC_SPL_SQRT_ITER(N) \ 77 | try1 = root + (1 << (N)); \ 78 | if (value >= try1 << (N)) \ 79 | { \ 80 | value -= try1 << (N); \ 81 | root |= 2 << (N); \ 82 | } 83 | 84 | int32_t WebRtcSpl_SqrtFloor(int32_t value) { 85 | int32_t root = 0, try1; 86 | 87 | WEBRTC_SPL_SQRT_ITER (15); 88 | WEBRTC_SPL_SQRT_ITER (14); 89 | WEBRTC_SPL_SQRT_ITER (13); 90 | WEBRTC_SPL_SQRT_ITER (12); 91 | WEBRTC_SPL_SQRT_ITER (11); 92 | WEBRTC_SPL_SQRT_ITER (10); 93 | WEBRTC_SPL_SQRT_ITER (9); 94 | WEBRTC_SPL_SQRT_ITER (8); 95 | WEBRTC_SPL_SQRT_ITER (7); 96 | WEBRTC_SPL_SQRT_ITER (6); 97 | WEBRTC_SPL_SQRT_ITER (5); 98 | WEBRTC_SPL_SQRT_ITER (4); 99 | WEBRTC_SPL_SQRT_ITER (3); 100 | WEBRTC_SPL_SQRT_ITER (2); 101 | WEBRTC_SPL_SQRT_ITER (1); 102 | WEBRTC_SPL_SQRT_ITER (0); 103 | 104 | return root >> 1; 105 | } 106 | 107 | uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den) { 108 | // Guard against division with 0 109 | if (den != 0) { 110 | return (uint32_t) (num / den); 111 | } else { 112 | return (uint32_t) 0xFFFFFFFF; 113 | } 114 | } 115 | 116 | int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den) { 117 | // Guard against division with 0 118 | if (den != 0) { 119 | return (int32_t) (num / den); 120 | } else { 121 | return (int32_t) 0x7FFFFFFF; 122 | } 123 | } 124 | 125 | 126 | static const uint32_t kMaxSeedUsed = 0x80000000; 127 | 128 | 129 | static uint32_t IncreaseSeed(uint32_t *seed) { 130 | seed[0] = (seed[0] * ((int32_t) 69069) + 1) & (kMaxSeedUsed - 1); 131 | return seed[0]; 132 | } 133 | 134 | int16_t WebRtcSpl_RandU(uint32_t *seed) { 135 | return (int16_t) (IncreaseSeed(seed) >> 16); 136 | } 137 | 138 | // Creates an array of uniformly distributed variables. 139 | int16_t WebRtcSpl_RandUArray(int16_t *vector, 140 | int16_t vector_length, 141 | uint32_t *seed) { 142 | int i; 143 | for (i = 0; i < vector_length; i++) { 144 | vector[i] = WebRtcSpl_RandU(seed); 145 | } 146 | return vector_length; 147 | } 148 | 149 | // TODO(bjorn/kma): Consolidate function pairs (e.g. combine 150 | // WebRtcSpl_MaxAbsValueW16C and WebRtcSpl_MaxAbsIndexW16 into a single one.) 151 | // TODO(kma): Move the next six functions into min_max_operations_c.c. 152 | 153 | // Maximum absolute value of word16 vector. C version for generic platforms. 154 | int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t *vector, size_t length) { 155 | size_t i = 0; 156 | int absolute = 0, maximum = 0; 157 | 158 | RTC_DCHECK_GT(length, 0); 159 | 160 | for (i = 0; i < length; i++) { 161 | absolute = abs((int) vector[i]); 162 | 163 | if (absolute > maximum) { 164 | maximum = absolute; 165 | } 166 | } 167 | 168 | // Guard the case for abs(-32768). 169 | if (maximum > WEBRTC_SPL_WORD16_MAX) { 170 | maximum = WEBRTC_SPL_WORD16_MAX; 171 | } 172 | 173 | return (int16_t) maximum; 174 | } 175 | 176 | // Maximum absolute value of word32 vector. C version for generic platforms. 177 | int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t *vector, size_t length) { 178 | // Use uint32_t for the local variables, to accommodate the return value 179 | // of abs(0x80000000), which is 0x80000000. 180 | 181 | uint32_t absolute = 0, maximum = 0; 182 | size_t i = 0; 183 | 184 | RTC_DCHECK_GT(length, 0); 185 | 186 | for (i = 0; i < length; i++) { 187 | absolute = abs((int) vector[i]); 188 | if (absolute > maximum) { 189 | maximum = absolute; 190 | } 191 | } 192 | 193 | maximum = WEBRTC_SPL_MIN(maximum, WEBRTC_SPL_WORD32_MAX); 194 | 195 | return (int32_t) maximum; 196 | } 197 | 198 | // Maximum value of word16 vector. C version for generic platforms. 199 | int16_t WebRtcSpl_MaxValueW16C(const int16_t *vector, size_t length) { 200 | int16_t maximum = WEBRTC_SPL_WORD16_MIN; 201 | size_t i = 0; 202 | 203 | RTC_DCHECK_GT(length, 0); 204 | 205 | for (i = 0; i < length; i++) { 206 | if (vector[i] > maximum) 207 | maximum = vector[i]; 208 | } 209 | return maximum; 210 | } 211 | 212 | // Maximum value of word32 vector. C version for generic platforms. 213 | int32_t WebRtcSpl_MaxValueW32C(const int32_t *vector, size_t length) { 214 | int32_t maximum = WEBRTC_SPL_WORD32_MIN; 215 | size_t i = 0; 216 | 217 | RTC_DCHECK_GT(length, 0); 218 | 219 | for (i = 0; i < length; i++) { 220 | if (vector[i] > maximum) 221 | maximum = vector[i]; 222 | } 223 | return maximum; 224 | } 225 | 226 | // Minimum value of word16 vector. C version for generic platforms. 227 | int16_t WebRtcSpl_MinValueW16C(const int16_t *vector, size_t length) { 228 | int16_t minimum = WEBRTC_SPL_WORD16_MAX; 229 | size_t i = 0; 230 | 231 | RTC_DCHECK_GT(length, 0); 232 | 233 | for (i = 0; i < length; i++) { 234 | if (vector[i] < minimum) 235 | minimum = vector[i]; 236 | } 237 | return minimum; 238 | } 239 | 240 | // Minimum value of word32 vector. C version for generic platforms. 241 | int32_t WebRtcSpl_MinValueW32C(const int32_t *vector, size_t length) { 242 | int32_t minimum = WEBRTC_SPL_WORD32_MAX; 243 | size_t i = 0; 244 | 245 | RTC_DCHECK_GT(length, 0); 246 | 247 | for (i = 0; i < length; i++) { 248 | if (vector[i] < minimum) 249 | minimum = vector[i]; 250 | } 251 | return minimum; 252 | } 253 | -------------------------------------------------------------------------------- /aecm/signal_processing_library.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | /* 12 | * This header file includes all of the fix point signal processing library 13 | * (SPL) function descriptions and declarations. For specific function calls, 14 | * see bottom of file. 15 | */ 16 | 17 | #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_ 18 | #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | // If you for some reson need to know if DCHECKs are on, test the value of 27 | // RTC_DCHECK_IS_ON. (Test its value, not if it's defined; it'll always be 28 | // defined, to either a true or a false value.) 29 | #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) 30 | #define RTC_DCHECK_IS_ON 1 31 | #else 32 | #define RTC_DCHECK_IS_ON 0 33 | #endif 34 | 35 | 36 | #define RTC_DCHECK(condition) \ 37 | do { \ 38 | if (RTC_DCHECK_IS_ON) { \ 39 | assert(condition); \ 40 | } \ 41 | } while (0) 42 | 43 | #define RTC_DCHECK_EQ(a, b) RTC_DCHECK((a) == (b)) 44 | #define RTC_DCHECK_NE(a, b) RTC_DCHECK((a) != (b)) 45 | #define RTC_DCHECK_LE(a, b) RTC_DCHECK((a) <= (b)) 46 | #define RTC_DCHECK_LT(a, b) RTC_DCHECK((a) < (b)) 47 | #define RTC_DCHECK_GE(a, b) RTC_DCHECK((a) >= (b)) 48 | #define RTC_DCHECK_GT(a, b) RTC_DCHECK((a) > (b)) 49 | 50 | // Processor architecture detection. For more info on what's defined, see: 51 | // http://msdn.microsoft.com/en-us/library/b0084kay.aspx 52 | // http://www.agner.org/optimize/calling_conventions.pdf 53 | // or with gcc, run: "echo | gcc -E -dM -" 54 | #if defined(_M_X64) || defined(__x86_64__) 55 | #define WEBRTC_ARCH_X86_FAMILY 56 | #define WEBRTC_ARCH_X86_64 57 | #define WEBRTC_ARCH_64_BITS 58 | #define WEBRTC_ARCH_LITTLE_ENDIAN 59 | #elif defined(_M_ARM64) || defined(__aarch64__) 60 | #define WEBRTC_ARCH_ARM_FAMILY 61 | #define WEBRTC_ARCH_64_BITS 62 | #define WEBRTC_ARCH_LITTLE_ENDIAN 63 | #elif defined(_M_IX86) || defined(__i386__) 64 | #define WEBRTC_ARCH_X86_FAMILY 65 | #define WEBRTC_ARCH_X86 66 | #define WEBRTC_ARCH_32_BITS 67 | #define WEBRTC_ARCH_LITTLE_ENDIAN 68 | #elif defined(__ARMEL__) 69 | #define WEBRTC_ARCH_ARM_FAMILY 70 | #define WEBRTC_ARCH_32_BITS 71 | #define WEBRTC_ARCH_LITTLE_ENDIAN 72 | #elif defined(__MIPSEL__) 73 | #define WEBRTC_ARCH_MIPS_FAMILY 74 | #if defined(__LP64__) 75 | #define WEBRTC_ARCH_64_BITS 76 | #else 77 | #define WEBRTC_ARCH_32_BITS 78 | #endif 79 | #define WEBRTC_ARCH_LITTLE_ENDIAN 80 | #elif defined(__pnacl__) 81 | #define WEBRTC_ARCH_32_BITS 82 | #define WEBRTC_ARCH_LITTLE_ENDIAN 83 | #elif defined(__EMSCRIPTEN__) 84 | #define WEBRTC_ARCH_32_BITS 85 | #define WEBRTC_ARCH_LITTLE_ENDIAN 86 | #else 87 | #error Please add support for your architecture in rtc_base/system/arch.h 88 | #endif 89 | 90 | #if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN)) 91 | #error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN 92 | #endif 93 | // Macros specific for the fixed point implementation 94 | #define WEBRTC_SPL_WORD16_MAX 32767 95 | #define WEBRTC_SPL_WORD16_MIN -32768 96 | #define WEBRTC_SPL_WORD32_MAX (int32_t)0x7fffffff 97 | #define WEBRTC_SPL_WORD32_MIN (int32_t)0x80000000 98 | #define WEBRTC_SPL_MIN(A, B) (A < B ? A : B) // Get min value 99 | #define WEBRTC_SPL_MAX(A, B) (A > B ? A : B) // Get max value 100 | // TODO(kma/bjorn): For the next two macros, investigate how to correct the code 101 | // for inputs of a = WEBRTC_SPL_WORD16_MIN or WEBRTC_SPL_WORD32_MIN. 102 | #define WEBRTC_SPL_ABS_W16(a) (((int16_t)a >= 0) ? ((int16_t)a) : -((int16_t)a)) 103 | #define WEBRTC_SPL_ABS_W32(a) (((int32_t)a >= 0) ? ((int32_t)a) : -((int32_t)a)) 104 | 105 | #define WEBRTC_SPL_UMUL_32_16(a, b) ((uint32_t)((uint32_t)(a) * (uint16_t)(b))) 106 | #define WEBRTC_SPL_MUL_16_U16(a, b) ((int32_t)(int16_t)(a) * (uint16_t)(b)) 107 | 108 | // clang-format off 109 | // clang-format would choose some identation 110 | // leading to presubmit error (cpplint.py) 111 | #ifndef WEBRTC_ARCH_ARM_V7 112 | // For ARMv7 platforms, these are inline functions in spl_inl_armv7.h 113 | #ifndef MIPS32_LE 114 | // For MIPS platforms, these are inline functions in spl_inl_mips.h 115 | #define WEBRTC_SPL_MUL_16_16(a, b) ((int32_t)(((int16_t)(a)) * ((int16_t)(b)))) 116 | #endif 117 | #endif 118 | 119 | // clang-format on 120 | 121 | #define WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, c) \ 122 | ((WEBRTC_SPL_MUL_16_16(a, b) + ((int32_t)(((int32_t)1) << ((c)-1)))) >> (c)) 123 | 124 | // C + the 32 most significant bits of A * B 125 | 126 | #define WEBRTC_SPL_SAT(a, b, c) (b > a ? a : b < c ? c : b) 127 | 128 | // Shifting with negative numbers allowed 129 | // Positive means left shift 130 | #define WEBRTC_SPL_SHIFT_W32(x, c) ((c) >= 0 ? (x) * (1 << (c)) : (x) >> -(c)) 131 | 132 | // Shifting with negative numbers not allowed 133 | // We cannot do casting here due to signed/unsigned problem 134 | #define WEBRTC_SPL_LSHIFT_W32(x, c) ((x) << (c)) 135 | 136 | #ifdef __cplusplus 137 | extern "C" { 138 | #endif 139 | 140 | // inline functions: 141 | #include "spl_inl.h" 142 | 143 | 144 | // 145 | // WebRtcSpl_SqrtFloor(...) 146 | // 147 | // Returns the square root of the input value |value|. The precision of this 148 | // function is rounding down integer precision, i.e., sqrt(8) gives 2 as answer. 149 | // If |value| is a negative number then 0 is returned. 150 | // 151 | // Algorithm: 152 | // 153 | // An iterative 4 cylce/bit routine 154 | // 155 | // Input: 156 | // - value : Value to calculate sqrt of 157 | // 158 | // Return value : Result of the sqrt calculation 159 | // 160 | int32_t WebRtcSpl_SqrtFloor(int32_t value); 161 | 162 | 163 | 164 | // Minimum and maximum operation functions and their pointers. 165 | // Implementation in min_max_operations.c. 166 | 167 | // Returns the largest absolute value in a signed 16-bit vector. 168 | // 169 | // Input: 170 | // - vector : 16-bit input vector. 171 | // - length : Number of samples in vector. 172 | // 173 | // Return value : Maximum absolute value in vector. 174 | typedef int16_t (*MaxAbsValueW16)(const int16_t *vector, size_t length); 175 | extern const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16; 176 | int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t *vector, size_t length); 177 | #if defined(WEBRTC_HAS_NEON) 178 | int16_t WebRtcSpl_MaxAbsValueW16Neon(const int16_t* vector, size_t length); 179 | #endif 180 | #if defined(MIPS32_LE) 181 | int16_t WebRtcSpl_MaxAbsValueW16_mips(const int16_t* vector, size_t length); 182 | #endif 183 | 184 | // Returns the largest absolute value in a signed 32-bit vector. 185 | // 186 | // Input: 187 | // - vector : 32-bit input vector. 188 | // - length : Number of samples in vector. 189 | // 190 | // Return value : Maximum absolute value in vector. 191 | typedef int32_t (*MaxAbsValueW32)(const int32_t *vector, size_t length); 192 | extern const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32; 193 | int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t *vector, size_t length); 194 | #if defined(WEBRTC_HAS_NEON) 195 | int32_t WebRtcSpl_MaxAbsValueW32Neon(const int32_t* vector, size_t length); 196 | #endif 197 | #if defined(MIPS_DSP_R1_LE) 198 | int32_t WebRtcSpl_MaxAbsValueW32_mips(const int32_t* vector, size_t length); 199 | #endif 200 | 201 | // Returns the maximum value of a 16-bit vector. 202 | // 203 | // Input: 204 | // - vector : 16-bit input vector. 205 | // - length : Number of samples in vector. 206 | // 207 | // Return value : Maximum sample value in |vector|. 208 | typedef int16_t (*MaxValueW16)(const int16_t *vector, size_t length); 209 | extern const MaxValueW16 WebRtcSpl_MaxValueW16; 210 | int16_t WebRtcSpl_MaxValueW16C(const int16_t *vector, size_t length); 211 | #if defined(WEBRTC_HAS_NEON) 212 | int16_t WebRtcSpl_MaxValueW16Neon(const int16_t* vector, size_t length); 213 | #endif 214 | #if defined(MIPS32_LE) 215 | int16_t WebRtcSpl_MaxValueW16_mips(const int16_t* vector, size_t length); 216 | #endif 217 | 218 | // Returns the maximum value of a 32-bit vector. 219 | // 220 | // Input: 221 | // - vector : 32-bit input vector. 222 | // - length : Number of samples in vector. 223 | // 224 | // Return value : Maximum sample value in |vector|. 225 | typedef int32_t (*MaxValueW32)(const int32_t *vector, size_t length); 226 | extern const MaxValueW32 WebRtcSpl_MaxValueW32; 227 | int32_t WebRtcSpl_MaxValueW32C(const int32_t *vector, size_t length); 228 | #if defined(WEBRTC_HAS_NEON) 229 | int32_t WebRtcSpl_MaxValueW32Neon(const int32_t* vector, size_t length); 230 | #endif 231 | #if defined(MIPS32_LE) 232 | int32_t WebRtcSpl_MaxValueW32_mips(const int32_t* vector, size_t length); 233 | #endif 234 | 235 | // Returns the minimum value of a 16-bit vector. 236 | // 237 | // Input: 238 | // - vector : 16-bit input vector. 239 | // - length : Number of samples in vector. 240 | // 241 | // Return value : Minimum sample value in |vector|. 242 | typedef int16_t (*MinValueW16)(const int16_t *vector, size_t length); 243 | extern const MinValueW16 WebRtcSpl_MinValueW16; 244 | int16_t WebRtcSpl_MinValueW16C(const int16_t *vector, size_t length); 245 | #if defined(WEBRTC_HAS_NEON) 246 | int16_t WebRtcSpl_MinValueW16Neon(const int16_t* vector, size_t length); 247 | #endif 248 | #if defined(MIPS32_LE) 249 | int16_t WebRtcSpl_MinValueW16_mips(const int16_t* vector, size_t length); 250 | #endif 251 | 252 | // Returns the minimum value of a 32-bit vector. 253 | // 254 | // Input: 255 | // - vector : 32-bit input vector. 256 | // - length : Number of samples in vector. 257 | // 258 | // Return value : Minimum sample value in |vector|. 259 | typedef int32_t (*MinValueW32)(const int32_t *vector, size_t length); 260 | extern const MinValueW32 WebRtcSpl_MinValueW32; 261 | int32_t WebRtcSpl_MinValueW32C(const int32_t *vector, size_t length); 262 | #if defined(WEBRTC_HAS_NEON) 263 | int32_t WebRtcSpl_MinValueW32Neon(const int32_t* vector, size_t length); 264 | #endif 265 | #if defined(MIPS32_LE) 266 | int32_t WebRtcSpl_MinValueW32_mips(const int32_t* vector, size_t length); 267 | #endif 268 | 269 | // Signal processing operations. 270 | 271 | 272 | // End: Signal processing operations. 273 | 274 | // Randomization functions. Implementations collected in 275 | // randomization_functions.c and descriptions at bottom of this file. 276 | int16_t WebRtcSpl_RandU(uint32_t *seed); 277 | int16_t WebRtcSpl_RandUArray(int16_t *vector, 278 | int16_t vector_length, 279 | uint32_t *seed); 280 | // End: Randomization functions. 281 | 282 | 283 | // Divisions. Implementations collected in division_operations.c and 284 | // descriptions at bottom of this file. 285 | uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den); 286 | int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den); 287 | // End: Divisions. 288 | 289 | 290 | // FFT operations 291 | 292 | int WebRtcSpl_ComplexFFT(int16_t vector[], int stages, int mode); 293 | int WebRtcSpl_ComplexIFFT(int16_t vector[], int stages, int mode); 294 | 295 | // Treat a 16-bit complex data buffer |complex_data| as an array of 32-bit 296 | // values, and swap elements whose indexes are bit-reverses of each other. 297 | // 298 | // Input: 299 | // - complex_data : Complex data buffer containing 2^|stages| real 300 | // elements interleaved with 2^|stages| imaginary 301 | // elements: [Re Im Re Im Re Im....] 302 | // - stages : Number of FFT stages. Must be at least 3 and at most 303 | // 10, since the table WebRtcSpl_kSinTable1024[] is 1024 304 | // elements long. 305 | // 306 | // Output: 307 | // - complex_data : The complex data buffer. 308 | 309 | void WebRtcSpl_ComplexBitReverse(int16_t *__restrict complex_data, int stages); 310 | 311 | // End: FFT operations 312 | 313 | 314 | #ifdef __cplusplus 315 | } 316 | #endif // __cplusplus 317 | #endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_ -------------------------------------------------------------------------------- /aecm/spl_inl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | // This header file includes the inline functions in 12 | // the fix point signal processing library. 13 | 14 | #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ 15 | #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ 16 | 17 | #include "signal_processing_library.h" 18 | 19 | extern const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64]; 20 | 21 | // Don't call this directly except in tests! 22 | static __inline int WebRtcSpl_CountLeadingZeros32_NotBuiltin(uint32_t n) { 23 | // Normalize n by rounding up to the nearest number that is a sequence of 0 24 | // bits followed by a sequence of 1 bits. This number has the same number of 25 | // leading zeros as the original n. There are exactly 33 such values. 26 | n |= n >> 1; 27 | n |= n >> 2; 28 | n |= n >> 4; 29 | n |= n >> 8; 30 | n |= n >> 16; 31 | 32 | // Multiply the modified n with a constant selected (by exhaustive search) 33 | // such that each of the 33 possible values of n give a product whose 6 most 34 | // significant bits are unique. Then look up the answer in the table. 35 | return kWebRtcSpl_CountLeadingZeros32_Table[(n * 0x8c0b2891) >> 26]; 36 | } 37 | 38 | 39 | // Returns the number of leading zero bits in the argument. 40 | static __inline int WebRtcSpl_CountLeadingZeros32(uint32_t n) { 41 | #ifdef __GNUC__ 42 | assert(sizeof(unsigned int) == sizeof(uint32_t)); 43 | return n == 0 ? 32 : __builtin_clz(n); 44 | #else 45 | return WebRtcSpl_CountLeadingZeros32_NotBuiltin(n); 46 | #endif 47 | } 48 | 49 | #ifdef WEBRTC_ARCH_ARM_V7 50 | #include "spl_inl_armv7.h" 51 | #else 52 | 53 | #if defined(MIPS32_LE) 54 | #include "spl_inl_mips.h" 55 | #endif 56 | 57 | #if !defined(MIPS_DSP_R1_LE) 58 | 59 | static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { 60 | int16_t out16 = (int16_t) value32; 61 | 62 | if (value32 > 32767) 63 | out16 = 32767; 64 | else if (value32 < -32768) 65 | out16 = -32768; 66 | 67 | return out16; 68 | } 69 | 70 | static __inline int32_t WebRtcSpl_AddSatW32(int32_t a, int32_t b) { 71 | // Do the addition in unsigned numbers, since signed overflow is undefined 72 | // behavior. 73 | const int32_t sum = (int32_t) ((uint32_t) a + (uint32_t) b); 74 | 75 | // a + b can't overflow if a and b have different signs. If they have the 76 | // same sign, a + b also has the same sign iff it didn't overflow. 77 | if ((a < 0) == (b < 0) && (a < 0) != (sum < 0)) { 78 | // The direction of the overflow is obvious from the sign of a + b. 79 | return sum < 0 ? INT32_MAX : INT32_MIN; 80 | } 81 | return sum; 82 | } 83 | 84 | static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { 85 | return WebRtcSpl_SatW32ToW16((int32_t) a + (int32_t) b); 86 | } 87 | 88 | 89 | #endif // #if !defined(MIPS_DSP_R1_LE) 90 | 91 | #if !defined(MIPS32_LE) 92 | 93 | 94 | // Return the number of steps a can be left-shifted without overflow, 95 | // or 0 if a == 0. 96 | static __inline int16_t WebRtcSpl_NormW32(int32_t a) { 97 | return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a : a) - 1; 98 | } 99 | 100 | // Return the number of steps a can be left-shifted without overflow, 101 | // or 0 if a == 0. 102 | static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { 103 | return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a); 104 | } 105 | 106 | // Return the number of steps a can be left-shifted without overflow, 107 | // or 0 if a == 0. 108 | static __inline int16_t WebRtcSpl_NormW16(int16_t a) { 109 | const int32_t a32 = a; 110 | return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a32 : a32) - 17; 111 | } 112 | 113 | #endif // #if !defined(MIPS32_LE) 114 | 115 | #endif // WEBRTC_ARCH_ARM_V7 116 | 117 | #endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ 118 | -------------------------------------------------------------------------------- /aecm/spl_inl_armv7.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | /* This header file includes the inline functions for ARM processors in 12 | * the fix point signal processing library. 13 | */ 14 | 15 | #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_ 16 | #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_ 17 | 18 | /* TODO(kma): Replace some assembly code with GCC intrinsics 19 | * (e.g. __builtin_clz). 20 | */ 21 | 22 | /* This function produces result that is not bit exact with that by the generic 23 | * C version in some cases, although the former is at least as accurate as the 24 | * later. 25 | */ 26 | static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) { 27 | int32_t tmp = 0; 28 | __asm __volatile("smulwb %0, %1, %2" : "=r"(tmp) : "r"(b), "r"(a)); 29 | return tmp; 30 | } 31 | 32 | static __inline int32_t WEBRTC_SPL_MUL_16_16(int16_t a, int16_t b) { 33 | int32_t tmp = 0; 34 | __asm __volatile("smulbb %0, %1, %2" : "=r"(tmp) : "r"(a), "r"(b)); 35 | return tmp; 36 | } 37 | 38 | // TODO(kma): add unit test. 39 | static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { 40 | int32_t tmp = 0; 41 | __asm __volatile("smlabb %0, %1, %2, %3" 42 | : "=r"(tmp) 43 | : "r"(a), "r"(b), "r"(c)); 44 | return tmp; 45 | } 46 | 47 | static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { 48 | int32_t s_sum = 0; 49 | 50 | __asm __volatile("qadd16 %0, %1, %2" : "=r"(s_sum) : "r"(a), "r"(b)); 51 | 52 | return (int16_t) s_sum; 53 | } 54 | 55 | static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { 56 | int32_t l_sum = 0; 57 | 58 | __asm __volatile("qadd %0, %1, %2" : "=r"(l_sum) : "r"(l_var1), "r"(l_var2)); 59 | 60 | return l_sum; 61 | } 62 | 63 | static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) { 64 | int32_t l_sub = 0; 65 | 66 | __asm __volatile("qsub %0, %1, %2" : "=r"(l_sub) : "r"(l_var1), "r"(l_var2)); 67 | 68 | return l_sub; 69 | } 70 | 71 | static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { 72 | int32_t s_sub = 0; 73 | 74 | __asm __volatile("qsub16 %0, %1, %2" : "=r"(s_sub) : "r"(var1), "r"(var2)); 75 | 76 | return (int16_t) s_sub; 77 | } 78 | 79 | static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { 80 | int32_t tmp = 0; 81 | 82 | __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(n)); 83 | 84 | return (int16_t)(32 - tmp); 85 | } 86 | 87 | static __inline int16_t WebRtcSpl_NormW32(int32_t a) { 88 | int32_t tmp = 0; 89 | 90 | if (a == 0) { 91 | return 0; 92 | } else if (a < 0) { 93 | a ^= 0xFFFFFFFF; 94 | } 95 | 96 | __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a)); 97 | 98 | return (int16_t)(tmp - 1); 99 | } 100 | 101 | static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { 102 | int tmp = 0; 103 | 104 | if (a == 0) 105 | return 0; 106 | 107 | __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a)); 108 | 109 | return (int16_t) tmp; 110 | } 111 | 112 | static __inline int16_t WebRtcSpl_NormW16(int16_t a) { 113 | int32_t tmp = 0; 114 | int32_t a_32 = a; 115 | 116 | if (a_32 == 0) { 117 | return 0; 118 | } else if (a_32 < 0) { 119 | a_32 ^= 0xFFFFFFFF; 120 | } 121 | 122 | __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a_32)); 123 | 124 | return (int16_t)(tmp - 17); 125 | } 126 | 127 | // TODO(kma): add unit test. 128 | static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { 129 | int32_t out = 0; 130 | 131 | __asm __volatile("ssat %0, #16, %1" : "=r"(out) : "r"(value32)); 132 | 133 | return (int16_t) out; 134 | } 135 | 136 | #endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_ 137 | -------------------------------------------------------------------------------- /aecm/spl_inl_mips.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | // This header file includes the inline functions in 12 | // the fix point signal processing library. 13 | 14 | #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ 15 | #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ 16 | 17 | static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a, int32_t b) { 18 | int32_t value32 = 0; 19 | int32_t a1 = 0, b1 = 0; 20 | 21 | __asm __volatile( 22 | #if defined(MIPS32_R2_LE) 23 | "seh %[a1], %[a] \n\t" 24 | "seh %[b1], %[b] \n\t" 25 | #else 26 | "sll %[a1], %[a], 16 \n\t" 27 | "sll %[b1], %[b], 16 \n\t" 28 | "sra %[a1], %[a1], 16 \n\t" 29 | "sra %[b1], %[b1], 16 \n\t" 30 | #endif 31 | "mul %[value32], %[a1], %[b1] \n\t" 32 | : [value32] "=r"(value32), [a1] "=&r"(a1), [b1] "=&r"(b1) 33 | : [a] "r"(a), [b] "r"(b) 34 | : "hi", "lo"); 35 | return value32; 36 | } 37 | 38 | static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) { 39 | int32_t value32 = 0, b1 = 0, b2 = 0; 40 | int32_t a1 = 0; 41 | 42 | __asm __volatile( 43 | #if defined(MIPS32_R2_LE) 44 | "seh %[a1], %[a] \n\t" 45 | #else 46 | "sll %[a1], %[a], 16 \n\t" 47 | "sra %[a1], %[a1], 16 \n\t" 48 | #endif 49 | "andi %[b2], %[b], 0xFFFF \n\t" 50 | "sra %[b1], %[b], 16 \n\t" 51 | "sra %[b2], %[b2], 1 \n\t" 52 | "mul %[value32], %[a1], %[b1] \n\t" 53 | "mul %[b2], %[a1], %[b2] \n\t" 54 | "addiu %[b2], %[b2], 0x4000 \n\t" 55 | "sra %[b2], %[b2], 15 \n\t" 56 | "addu %[value32], %[value32], %[b2] \n\t" 57 | : [value32] "=&r"(value32), [b1] "=&r"(b1), [b2] "=&r"(b2), [a1] "=&r"(a1) 58 | : [a] "r"(a), [b] "r"(b) 59 | : "hi", "lo"); 60 | return value32; 61 | } 62 | 63 | #if defined(MIPS_DSP_R1_LE) 64 | static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { 65 | __asm __volatile( 66 | "shll_s.w %[value32], %[value32], 16 \n\t" 67 | "sra %[value32], %[value32], 16 \n\t" 68 | : [value32] "+r"(value32) 69 | :); 70 | int16_t out16 = (int16_t)value32; 71 | return out16; 72 | } 73 | 74 | static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { 75 | int32_t value32 = 0; 76 | 77 | __asm __volatile("addq_s.ph %[value32], %[a], %[b] \n\t" 78 | : [value32] "=r"(value32) 79 | : [a] "r"(a), [b] "r"(b)); 80 | return (int16_t)value32; 81 | } 82 | 83 | static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { 84 | int32_t l_sum; 85 | 86 | __asm __volatile( 87 | "addq_s.w %[l_sum], %[l_var1], %[l_var2] \n\t" 88 | : [l_sum] "=r"(l_sum) 89 | : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2)); 90 | 91 | return l_sum; 92 | } 93 | 94 | static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { 95 | int32_t value32; 96 | 97 | __asm __volatile("subq_s.ph %[value32], %[var1], %[var2] \n\t" 98 | : [value32] "=r"(value32) 99 | : [var1] "r"(var1), [var2] "r"(var2)); 100 | 101 | return (int16_t)value32; 102 | } 103 | 104 | static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) { 105 | int32_t l_diff; 106 | 107 | __asm __volatile( 108 | "subq_s.w %[l_diff], %[l_var1], %[l_var2] \n\t" 109 | : [l_diff] "=r"(l_diff) 110 | : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2)); 111 | 112 | return l_diff; 113 | } 114 | #endif 115 | 116 | static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { 117 | int bits = 0; 118 | int i32 = 32; 119 | 120 | __asm __volatile( 121 | "clz %[bits], %[n] \n\t" 122 | "subu %[bits], %[i32], %[bits] \n\t" 123 | : [bits] "=&r"(bits) 124 | : [n] "r"(n), [i32] "r"(i32)); 125 | 126 | return (int16_t) bits; 127 | } 128 | 129 | static __inline int16_t WebRtcSpl_NormW32(int32_t a) { 130 | int zeros = 0; 131 | 132 | __asm __volatile( 133 | ".set push \n\t" 134 | ".set noreorder \n\t" 135 | "bnez %[a], 1f \n\t" 136 | " sra %[zeros], %[a], 31 \n\t" 137 | "b 2f \n\t" 138 | " move %[zeros], $zero \n\t" 139 | "1: \n\t" 140 | "xor %[zeros], %[a], %[zeros] \n\t" 141 | "clz %[zeros], %[zeros] \n\t" 142 | "addiu %[zeros], %[zeros], -1 \n\t" 143 | "2: \n\t" 144 | ".set pop \n\t" 145 | : [zeros] "=&r"(zeros) 146 | : [a] "r"(a)); 147 | 148 | return (int16_t) zeros; 149 | } 150 | 151 | static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { 152 | int zeros = 0; 153 | 154 | __asm __volatile("clz %[zeros], %[a] \n\t" 155 | : [zeros] "=r"(zeros) 156 | : [a] "r"(a)); 157 | 158 | return (int16_t)(zeros & 0x1f); 159 | } 160 | 161 | static __inline int16_t WebRtcSpl_NormW16(int16_t a) { 162 | int zeros = 0; 163 | int a0 = a << 16; 164 | 165 | __asm __volatile( 166 | ".set push \n\t" 167 | ".set noreorder \n\t" 168 | "bnez %[a0], 1f \n\t" 169 | " sra %[zeros], %[a0], 31 \n\t" 170 | "b 2f \n\t" 171 | " move %[zeros], $zero \n\t" 172 | "1: \n\t" 173 | "xor %[zeros], %[a0], %[zeros] \n\t" 174 | "clz %[zeros], %[zeros] \n\t" 175 | "addiu %[zeros], %[zeros], -1 \n\t" 176 | "2: \n\t" 177 | ".set pop \n\t" 178 | : [zeros] "=&r"(zeros) 179 | : [a0] "r"(a0)); 180 | 181 | return (int16_t) zeros; 182 | } 183 | 184 | static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { 185 | int32_t res = 0, c1 = 0; 186 | __asm __volatile( 187 | #if defined(MIPS32_R2_LE) 188 | "seh %[a], %[a] \n\t" 189 | "seh %[b], %[b] \n\t" 190 | #else 191 | "sll %[a], %[a], 16 \n\t" 192 | "sll %[b], %[b], 16 \n\t" 193 | "sra %[a], %[a], 16 \n\t" 194 | "sra %[b], %[b], 16 \n\t" 195 | #endif 196 | "mul %[res], %[a], %[b] \n\t" 197 | "addu %[c1], %[c], %[res] \n\t" 198 | : [c1] "=r"(c1), [res] "=&r"(res) 199 | : [a] "r"(a), [b] "r"(b), [c] "r"(c) 200 | : "hi", "lo"); 201 | return (c1); 202 | } 203 | 204 | #endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ 205 | -------------------------------------------------------------------------------- /main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define DR_WAV_IMPLEMENTATION 6 | 7 | #include "dr_wav.h" 8 | #include "timing.h" 9 | 10 | #ifndef nullptr 11 | #define nullptr 0 12 | #endif 13 | 14 | #ifndef MIN 15 | #define MIN(A, B) ((A) < (B) ? (A) : (B)) 16 | #endif 17 | 18 | #include "aecm/echo_control_mobile.h" 19 | 20 | 21 | //写wav文件 22 | void wavWrite_int16(char *filename, int16_t *buffer, size_t sampleRate, size_t totalSampleCount) { 23 | drwav wav; 24 | drwav_data_format format = {}; 25 | format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64. 26 | format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes. 27 | format.channels = 1; 28 | format.sampleRate = sampleRate; 29 | format.bitsPerSample = 16; 30 | drwav_init_file_write(&wav, filename, &format, NULL); 31 | drwav_uint64 framesWritten = drwav_write_pcm_frames(&wav, totalSampleCount, buffer); 32 | drwav_uninit(&wav); 33 | if (framesWritten != totalSampleCount) { 34 | fprintf(stderr, "ERROR\n"); 35 | exit(1); 36 | } 37 | } 38 | 39 | //读取wav文件 40 | int16_t *wavRead_int16(char *filename, uint32_t *sampleRate, uint64_t *totalSampleCount) { 41 | unsigned int channels; 42 | int16_t *buffer = drwav_open_file_and_read_pcm_frames_s16(filename, &channels, sampleRate, totalSampleCount, NULL); 43 | if (buffer == nullptr) { 44 | printf("读取wav文件失败."); 45 | } 46 | //仅仅处理单通道音频 47 | if (channels != 1) { 48 | drwav_free(buffer, NULL); 49 | buffer = nullptr; 50 | *sampleRate = 0; 51 | *totalSampleCount = 0; 52 | } 53 | return buffer; 54 | } 55 | 56 | //分割路径函数 57 | void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) { 58 | const char *end; 59 | const char *p; 60 | const char *s; 61 | if (path[0] && path[1] == ':') { 62 | if (drv) { 63 | *drv++ = *path++; 64 | *drv++ = *path++; 65 | *drv = '\0'; 66 | } 67 | } else if (drv) 68 | *drv = '\0'; 69 | for (end = path; *end && *end != ':';) 70 | end++; 71 | for (p = end; p > path && *--p != '\\' && *p != '/';) 72 | if (*p == '.') { 73 | end = p; 74 | break; 75 | } 76 | if (ext) 77 | for (s = end; (*ext = *s++);) 78 | ext++; 79 | for (p = end; p > path;) 80 | if (*--p == '\\' || *p == '/') { 81 | p++; 82 | break; 83 | } 84 | if (name) { 85 | for (s = p; s < end;) 86 | *name++ = *s++; 87 | *name = '\0'; 88 | } 89 | if (dir) { 90 | for (s = path; s < p;) 91 | *dir++ = *s++; 92 | *dir = '\0'; 93 | } 94 | } 95 | 96 | 97 | int aecProcess(int16_t *far_frame, int16_t *near_frame, uint32_t sampleRate, size_t samplesCount, int16_t nMode, 98 | int16_t msInSndCardBuf) { 99 | if (near_frame == nullptr) return -1; 100 | if (far_frame == nullptr) return -1; 101 | if (samplesCount == 0) return -1; 102 | AecmConfig config; 103 | config.cngMode = AecmTrue; 104 | config.echoMode = nMode;// 0, 1, 2, 3 (default), 4 105 | size_t samples = MIN(160, sampleRate / 100); 106 | if (samples == 0) 107 | return -1; 108 | const int maxSamples = 160; 109 | int16_t *near_input = near_frame; 110 | int16_t *far_input = far_frame; 111 | size_t nCount = (samplesCount / samples); 112 | void *aecmInst = WebRtcAecm_Create(); 113 | if (aecmInst == NULL) return -1; 114 | int status = WebRtcAecm_Init(aecmInst, sampleRate);//8000 or 16000 Sample rate 115 | if (status != 0) { 116 | printf("WebRtcAecm_Init fail\n"); 117 | WebRtcAecm_Free(aecmInst); 118 | return -1; 119 | } 120 | status = WebRtcAecm_set_config(aecmInst, config); 121 | if (status != 0) { 122 | printf("WebRtcAecm_set_config fail\n"); 123 | WebRtcAecm_Free(aecmInst); 124 | return -1; 125 | } 126 | 127 | int16_t out_buffer[maxSamples]; 128 | for (size_t i = 0; i < nCount; i++) { 129 | if (WebRtcAecm_BufferFarend(aecmInst, far_input, samples) != 0) { 130 | printf("WebRtcAecm_BufferFarend() failed."); 131 | WebRtcAecm_Free(aecmInst); 132 | return -1; 133 | } 134 | int nRet = WebRtcAecm_Process(aecmInst, near_input, NULL, out_buffer, samples, msInSndCardBuf); 135 | 136 | if (nRet != 0) { 137 | printf("failed in WebRtcAecm_Process\n"); 138 | WebRtcAecm_Free(aecmInst); 139 | return -1; 140 | } 141 | memcpy(near_input, out_buffer, samples * sizeof(int16_t)); 142 | near_input += samples; 143 | far_input += samples; 144 | } 145 | WebRtcAecm_Free(aecmInst); 146 | return 1; 147 | } 148 | 149 | void AECM(char *near_file, char *far_file, char *out_file) { 150 | //音频采样率 151 | uint32_t sampleRate = 0; 152 | uint64_t inSampleCount = 0; 153 | uint32_t ref_sampleRate = 0; 154 | uint64_t ref_inSampleCount = 0; 155 | int16_t *near_frame = wavRead_int16(near_file, &sampleRate, &inSampleCount); 156 | int16_t *far_frame = wavRead_int16(far_file, &ref_sampleRate, &ref_inSampleCount); 157 | if ((near_frame == nullptr || far_frame == nullptr)) { 158 | if (near_frame) free(near_frame); 159 | if (far_frame) free(far_frame); 160 | return; 161 | } 162 | //如果加载成功 163 | int16_t echoMode = 1;// 0, 1, 2, 3 (default), 4 164 | int16_t msInSndCardBuf = 40; 165 | double startTime = now(); 166 | aecProcess(far_frame, near_frame, sampleRate, inSampleCount, echoMode, msInSndCardBuf); 167 | double elapsed_time = calcElapsed(startTime, now()); 168 | printf("time interval: %d ms\n ", (int) (elapsed_time * 1000)); 169 | wavWrite_int16(out_file, near_frame, sampleRate, inSampleCount); 170 | free(near_frame); 171 | free(far_frame); 172 | } 173 | 174 | int main(int argc, char *argv[]) { 175 | printf("WebRTC Acoustic Echo Canceller for Mobile\n"); 176 | printf("blog:http://cpuimage.cnblogs.com/\n"); 177 | printf("usage : aecm far_file.wav near_file.wav\n"); 178 | if (argc < 3) 179 | return -1; 180 | // echo file 181 | char *far_file = argv[1]; 182 | // mixed file 183 | char *near_file = argv[2]; 184 | char drive[3]; 185 | char dir[256]; 186 | char fname[256]; 187 | char ext[256]; 188 | char out_file[1024]; 189 | splitpath(near_file, drive, dir, fname, ext); 190 | snprintf(out_file, sizeof(out_file), "%s%s%s_out%s", drive, dir, fname, ext); 191 | AECM(near_file, far_file, out_file); 192 | printf("press any key to exit. \n"); 193 | getchar(); 194 | return 0; 195 | } 196 | -------------------------------------------------------------------------------- /timing.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #if defined(__APPLE__) 5 | # include 6 | #elif defined(_WIN32) 7 | # define WIN32_LEAN_AND_MEAN 8 | 9 | # include 10 | 11 | #else // __linux 12 | 13 | # include 14 | 15 | # ifndef CLOCK_MONOTONIC //_RAW 16 | # define CLOCK_MONOTONIC CLOCK_REALTIME 17 | # endif 18 | #endif 19 | 20 | static 21 | uint64_t nanotimer() { 22 | static int ever = 0; 23 | #if defined(__APPLE__) 24 | return clock_gettime_nsec_np(CLOCK_MONOTONIC); 25 | #elif defined(_WIN32) 26 | static LARGE_INTEGER frequency; 27 | if (!ever) { 28 | QueryPerformanceFrequency(&frequency); 29 | ever = 1; 30 | } 31 | LARGE_INTEGER t; 32 | QueryPerformanceCounter(&t); 33 | return (t.QuadPart * (uint64_t) 1e9) / frequency.QuadPart; 34 | #else // __linux 35 | struct timespec t; 36 | if (!ever) { 37 | if (clock_gettime(CLOCK_MONOTONIC, &t) != 0) { 38 | return 0; 39 | } 40 | ever = 1; 41 | } 42 | clock_gettime(CLOCK_MONOTONIC, &t); 43 | return (t.tv_sec * (uint64_t) 1e9) + t.tv_nsec; 44 | #endif 45 | } 46 | 47 | 48 | static double now() { 49 | static uint64_t epoch = 0; 50 | if (!epoch) { 51 | epoch = nanotimer(); 52 | } 53 | return (nanotimer() - epoch) / 1e9; 54 | } 55 | 56 | double calcElapsed(double start, double end) { 57 | double took = -start; 58 | return took + end; 59 | } --------------------------------------------------------------------------------