/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Performs echo control (suppression) with fft routines in fixed-point. /* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * This header file includes all of the fix point signal processing library (SPL) function * descriptions and declarations. * For specific function calls, see bottom of file. */ /*****************************************************************************/ /* string.h v4.2.0 */ /* Copyright (c) 1993-2008 Texas Instruments Incorporated */ /*****************************************************************************/ typedef unsigned size_t; /*****************************************************************************/ /* linkage.h v4.2.0 */ /* Copyright (c) 1998-2008 Texas Instruments Incorporated */ /*****************************************************************************/ /* No modifiers are needed to access code or data */ /*--------------------------------------------------------------------------*/ /* Define _IDECL ==> how inline functions are declared */ /*--------------------------------------------------------------------------*/ static __inline size_t strlen(const char *_string); static __inline char *strcpy(char *_dest, const char *_src); static __inline char *strncpy(char *_to, const char *_from, size_t _n); static __inline char *strcat(char *_string1, const char *_string2); static __inline char *strncat(char *_to, const char *_from, size_t _n); static __inline char *strchr(const char *_string, int _c); static __inline char *strrchr(const char *_string, int _c); static __inline int strcmp(const char *_string1, const char *_string2); static __inline int strncmp(const char *_string1, const char *_string2, size_t _n); int strcoll(const char *_string1, const char *_string2); size_t strxfrm(char *_to, const char *_from, size_t _n); char *strpbrk(const char *_string, const char *_chs); size_t strspn(const char *_string, const char *_chs); size_t strcspn(const char *_string, const char *_chs); char *strstr(const char *_string1, const char *_string2); char *strtok(char *_str1, const char *_str2); char *strerror(int _errno); void *memmove(void *_s1, const void *_s2, size_t _n); void *memcpy(void *_s1, const void *_s2, size_t _n); static __inline int memcmp(const void *_cs, const void *_ct, size_t _n); static __inline void *memchr(const void *_cs, int _c, size_t _n); static __inline void *memset(void *_mem, int _ch, size_t _n); static __inline size_t strlen(const char *string) { size_t n = (size_t)-1; const char *s = string; do n++; while (*s++); return n; } static __inline char *strcpy(register char *dest, register const char *src) { register char *d = dest; register const char *s = src; while (*d++ = *s++); return dest; } static __inline char *strncpy(register char *dest, register const char *src, register size_t n) { if (n) { register char *d = dest; register const char *s = src; while ((*d++ = *s++) && --n); /* COPY STRING */ if (n-- > 1) do *d++ = '\0'; while (--n); /* TERMINATION PADDING */ } return dest; } static __inline char *strcat(char *string1, const char *string2) { char *s1 = string1; const char *s2 = string2; while (*s1) s1++; /* FIND END OF STRING */ while (*s1++ = *s2++); /* APPEND SECOND STRING */ return string1; } static __inline char *strncat(char *dest, const char *src, register size_t n) { if (n) { char *d = dest; const char *s = src; while (*d) d++; /* FIND END OF STRING */ while (n--) if (!(*d++ = *s++)) return dest; /* APPEND SECOND STRING */ *d = 0; } return dest; } static __inline char *strchr(const char *string, int c) { char tch, ch = c; const char *s = string; for (;;) { if ((tch = *s) == ch) return (char *) s; if (!tch) return (char *) 0; s++; } } static __inline char *strrchr(const char *string, int c) { char tch, ch = c; char *result = 0; const char *s = string; for (;;) { if ((tch = *s) == ch) result = (char *) s; if (!tch) break; s++; } return result; } static __inline int strcmp(register const char *string1, register const char *string2) { register int c1, res; for (;;) { c1 = (unsigned char)*string1++; res = c1 - (unsigned char)*string2++; if (c1 == 0 || res != 0) break; } return res; } static __inline int strncmp(const char *string1, const char *string2, size_t n) { if (n) { const char *s1 = string1; const char *s2 = string2; unsigned char cp; int result; do if (result = (unsigned char)*s1++ - (cp = (unsigned char)*s2++)) return result; while (cp && --n); } return 0; } static __inline int memcmp(const void *cs, const void *ct, size_t n) { if (n) { const unsigned char *mem1 = (unsigned char *)cs; const unsigned char *mem2 = (unsigned char *)ct; int cp1, cp2; while ((cp1 = *mem1++) == (cp2 = *mem2++) && --n); return cp1 - cp2; } return 0; } static __inline void *memchr(const void *cs, int c, size_t n) { if (n) { const unsigned char *mem = (unsigned char *)cs; unsigned char ch = c; do if ( *mem == ch ) return (void *)mem; else mem++; while (--n); } return 0; } static __inline void *memset(void *mem, register int ch, register size_t length) { register char *m = (char *)mem; while (length--) *m++ = ch; return mem; } /* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This file contains platform-specific typedefs and defines. // Much of it is derived from Chromium's build/build_config.h. // For access to standard POSIXish features, use WEBRTC_POSIX instead of a // more specific macro. // Processor architecture detection. For more info on what's defined, see: // http://msdn.microsoft.com/en-us/library/b0084kay.aspx // http://www.agner.org/optimize/calling_conventions.pdf // or with gcc, run: "echo | gcc -E -dM -" // TODO(andrew): replace WEBRTC_LITTLE_ENDIAN with WEBRTC_ARCH_LITTLE_ENDIAN. /*****************************************************************************/ /* STDINT.H v4.2.0 */ /* Copyright (c) 2002-2008 Texas Instruments Incorporated */ /*****************************************************************************/ /* 7.18.1.1 Exact-width integer types */ typedef int int16_t; typedef unsigned int uint16_t; typedef long int32_t; typedef unsigned long uint32_t; /* 7.18.1.2 Minimum-width integer types */ typedef int16_t int_least8_t; typedef uint16_t uint_least8_t; typedef int16_t int_least16_t; typedef uint16_t uint_least16_t; typedef int32_t int_least32_t; typedef uint32_t uint_least32_t; /* sorry, int_least64_t not implemented for C54x, C55x, MSP430 */ /* 7.18.1.3 Fastest minimum-width integer types */ typedef int16_t int_fast8_t; typedef uint16_t uint_fast8_t; typedef int16_t int_fast16_t; typedef uint16_t uint_fast16_t; typedef int32_t int_fast32_t; typedef uint32_t uint_fast32_t; /* 7.18.1.4 Integer types capable of holding object pointers */ typedef long intptr_t; typedef unsigned long uintptr_t; /* 7.18.1.5 Greatest-width integer types */ typedef long intmax_t; typedef unsigned long uintmax_t; /* According to footnotes in the 1999 C standard, "C++ implementations should define these macros only when __STDC_LIMIT_MACROS is defined before is included." */ /* 7.18.2 Limits of specified width integer types */ /* 7.18.3 Limits of other integer types */ /* 7.18.4.1 Macros for minimum-width integer constants */ /* There is a defect report filed against the C99 standard concerning how the (U)INTN_C macros should be implemented. Please refer to -- http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_209.htm for more information. These macros are implemented according to the suggestion given at this web site. */ /* 7.18.4.2 Macros for greatest-width integer constants */ // Borrowed from Chromium's base/compiler_specific.h. // Annotate a virtual method indicating it must be overriding a virtual // method in the parent class. // Use like: // virtual void foo() OVERRIDE; // Macros specific for the fixed point implementation // TODO(kma/bjorn): For the next two macros, investigate how to correct the code // for inputs of a = WEBRTC_SPL_WORD16_MIN or WEBRTC_SPL_WORD32_MIN. // For ARMv7 platforms, these are inline functions in spl_inl_armv7.h // For MIPS platforms, these are inline functions in spl_inl_mips.h // C + the 32 most significant bits of A * B // We cannot do casting here due to signed/unsigned problem // Shifting with negative numbers allowed // Positive means left shift // Shifting with negative numbers not allowed // We cannot do casting here due to signed/unsigned problem // inline functions: /* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // This header file includes the inline functions in // the fix point signal processing library. static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { int16_t out16 = (int16_t) value32; if (value32 > 32767) out16 = 32767; else if (value32 < -32768) out16 = -32768; return out16; } static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { return WebRtcSpl_SatW32ToW16((int32_t) a + (int32_t) b); } static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { return WebRtcSpl_SatW32ToW16((int32_t) var1 - (int32_t) var2); } static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { int bits; if (0xFFFF0000 & n) { bits = 16; } else { bits = 0; } if (0x0000FF00 & (n >> bits)) bits += 8; if (0x000000F0 & (n >> bits)) bits += 4; if (0x0000000C & (n >> bits)) bits += 2; if (0x00000002 & (n >> bits)) bits += 1; if (0x00000001 & (n >> bits)) bits += 1; return bits; } static __inline int WebRtcSpl_NormW32(int32_t a) { int zeros; if (a == 0) { return 0; } else if (a < 0) { a = ~a; } if (!(0xFFFF8000 & a)) { zeros = 16; } else { zeros = 0; } if (!(0xFF800000 & (a << zeros))) zeros += 8; if (!(0xF8000000 & (a << zeros))) zeros += 4; if (!(0xE0000000 & (a << zeros))) zeros += 2; if (!(0xC0000000 & (a << zeros))) zeros += 1; return zeros; } static __inline int WebRtcSpl_NormU32(uint32_t a) { int zeros; if (a == 0) return 0; if (!(0xFFFF0000 & a)) { zeros = 16; } else { zeros = 0; } if (!(0xFF000000 & (a << zeros))) zeros += 8; if (!(0xF0000000 & (a << zeros))) zeros += 4; if (!(0xC0000000 & (a << zeros))) zeros += 2; if (!(0x80000000 & (a << zeros))) zeros += 1; return zeros; } static __inline int WebRtcSpl_NormW16(int16_t a) { int zeros; if (a == 0) { return 0; } else if (a < 0) { a = ~a; } if (!(0xFF80 & a)) { zeros = 8; } else { zeros = 0; } if (!(0xF800 & (a << zeros))) zeros += 4; if (!(0xE000 & (a << zeros))) zeros += 2; if (!(0xC000 & (a << zeros))) zeros += 1; return zeros; } static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { return (a * b + c); } // The following functions have no optimized versions. // TODO(kma): Consider saturating add/sub instructions in X86 platform. static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { int32_t l_sum; // Perform long addition l_sum = l_var1 + l_var2; if (l_var1 < 0) { // Check for underflow. if ((l_var2 < 0) && (l_sum >= 0)) { l_sum = (int32_t)0x80000000; } } else { // Check for overflow. if ((l_var2 > 0) && (l_sum < 0)) { l_sum = (int32_t)0x7FFFFFFF; } } return l_sum; } static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) { int32_t l_diff; // Perform subtraction. l_diff = l_var1 - l_var2; if (l_var1 < 0) { // Check for underflow. if ((l_var2 > 0) && (l_diff > 0)) { l_diff = (int32_t)0x80000000; } } else { // Check for overflow. if ((l_var2 < 0) && (l_diff < 0)) { l_diff = (int32_t)0x7FFFFFFF; } } return l_diff; } // Initialize SPL. Currently it contains only function pointer initialization. // If the underlying platform is known to be ARM-Neon (WEBRTC_ARCH_ARM_NEON // defined), the pointers will be assigned to code optimized for Neon; otherwise // if run-time Neon detection (WEBRTC_DETECT_ARM_NEON) is enabled, the pointers // will be assigned to either Neon code or generic C code; otherwise, generic C // code will be assigned. // Note that this function MUST be called in any application that uses SPL // functions. void WebRtcSpl_Init(); // Get SPL Version int16_t WebRtcSpl_get_version(char* version, int16_t length_in_bytes); int WebRtcSpl_GetScalingSquare(int16_t* in_vector, int in_vector_length, int times); // Copy and set operations. Implementation in copy_set_operations.c. // Descriptions at bottom of file. void WebRtcSpl_MemSetW16(int16_t* vector, int16_t set_value, int vector_length); void WebRtcSpl_MemSetW32(int32_t* vector, int32_t set_value, int vector_length); void WebRtcSpl_MemCpyReversedOrder(int16_t* out_vector, int16_t* in_vector, int vector_length); int16_t WebRtcSpl_CopyFromEndW16(const int16_t* in_vector, int16_t in_vector_length, int16_t samples, int16_t* out_vector); int16_t WebRtcSpl_ZerosArrayW16(int16_t* vector, int16_t vector_length); int16_t WebRtcSpl_ZerosArrayW32(int32_t* vector, int16_t vector_length); int16_t WebRtcSpl_OnesArrayW16(int16_t* vector, int16_t vector_length); int16_t WebRtcSpl_OnesArrayW32(int32_t* vector, int16_t vector_length); // End: Copy and set operations. // Minimum and maximum operation functions and their pointers. // Implementation in min_max_operations.c. // Returns the largest absolute value in a signed 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Maximum absolute value in vector; // or -1, if (vector == NULL || length <= 0). typedef int16_t (*MaxAbsValueW16)(const int16_t* vector, int length); extern MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16; int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, int length); // Returns the largest absolute value in a signed 32-bit vector. // // Input: // - vector : 32-bit input vector. // - length : Number of samples in vector. // // Return value : Maximum absolute value in vector; // or -1, if (vector == NULL || length <= 0). typedef int32_t (*MaxAbsValueW32)(const int32_t* vector, int length); extern MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32; int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, int length); // Returns the maximum value of a 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Maximum sample value in |vector|. // If (vector == NULL || length <= 0) WEBRTC_SPL_WORD16_MIN // is returned. Note that WEBRTC_SPL_WORD16_MIN is a feasible // value and we can't catch errors purely based on it. typedef int16_t (*MaxValueW16)(const int16_t* vector, int length); extern MaxValueW16 WebRtcSpl_MaxValueW16; int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, int length); // Returns the maximum value of a 32-bit vector. // // Input: // - vector : 32-bit input vector. // - length : Number of samples in vector. // // Return value : Maximum sample value in |vector|. // If (vector == NULL || length <= 0) WEBRTC_SPL_WORD32_MIN // is returned. Note that WEBRTC_SPL_WORD32_MIN is a feasible // value and we can't catch errors purely based on it. typedef int32_t (*MaxValueW32)(const int32_t* vector, int length); extern MaxValueW32 WebRtcSpl_MaxValueW32; int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, int length); // Returns the minimum value of a 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Minimum sample value in |vector|. // If (vector == NULL || length <= 0) WEBRTC_SPL_WORD16_MAX // is returned. Note that WEBRTC_SPL_WORD16_MAX is a feasible // value and we can't catch errors purely based on it. typedef int16_t (*MinValueW16)(const int16_t* vector, int length); extern MinValueW16 WebRtcSpl_MinValueW16; int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, int length); // Returns the minimum value of a 32-bit vector. // // Input: // - vector : 32-bit input vector. // - length : Number of samples in vector. // // Return value : Minimum sample value in |vector|. // If (vector == NULL || length <= 0) WEBRTC_SPL_WORD32_MAX // is returned. Note that WEBRTC_SPL_WORD32_MAX is a feasible // value and we can't catch errors purely based on it. typedef int32_t (*MinValueW32)(const int32_t* vector, int length); extern MinValueW32 WebRtcSpl_MinValueW32; int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, int length); // Returns the vector index to the largest absolute value of a 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Index to the maximum absolute value in vector, or -1, // if (vector == NULL || length <= 0). // If there are multiple equal maxima, return the index of the // first. -32768 will always have precedence over 32767 (despite // -32768 presenting an int16 absolute value of 32767); int WebRtcSpl_MaxAbsIndexW16(const int16_t* vector, int length); // Returns the vector index to the maximum sample value of a 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Index to the maximum value in vector (if multiple // indexes have the maximum, return the first); // or -1, if (vector == NULL || length <= 0). int WebRtcSpl_MaxIndexW16(const int16_t* vector, int length); // Returns the vector index to the maximum sample value of a 32-bit vector. // // Input: // - vector : 32-bit input vector. // - length : Number of samples in vector. // // Return value : Index to the maximum value in vector (if multiple // indexes have the maximum, return the first); // or -1, if (vector == NULL || length <= 0). int WebRtcSpl_MaxIndexW32(const int32_t* vector, int length); // Returns the vector index to the minimum sample value of a 16-bit vector. // // Input: // - vector : 16-bit input vector. // - length : Number of samples in vector. // // Return value : Index to the mimimum value in vector (if multiple // indexes have the minimum, return the first); // or -1, if (vector == NULL || length <= 0). int WebRtcSpl_MinIndexW16(const int16_t* vector, int length); // Returns the vector index to the minimum sample value of a 32-bit vector. // // Input: // - vector : 32-bit input vector. // - length : Number of samples in vector. // // Return value : Index to the mimimum value in vector (if multiple // indexes have the minimum, return the first); // or -1, if (vector == NULL || length <= 0). int WebRtcSpl_MinIndexW32(const int32_t* vector, int length); // End: Minimum and maximum operations. // Vector scaling operations. Implementation in vector_scaling_operations.c. // Description at bottom of file. void WebRtcSpl_VectorBitShiftW16(int16_t* out_vector, int16_t vector_length, const int16_t* in_vector, int16_t right_shifts); void WebRtcSpl_VectorBitShiftW32(int32_t* out_vector, int16_t vector_length, const int32_t* in_vector, int16_t right_shifts); void WebRtcSpl_VectorBitShiftW32ToW16(int16_t* out_vector, int vector_length, const int32_t* in_vector, int right_shifts); void WebRtcSpl_ScaleVector(const int16_t* in_vector, int16_t* out_vector, int16_t gain, int16_t vector_length, int16_t right_shifts); void WebRtcSpl_ScaleVectorWithSat(const int16_t* in_vector, int16_t* out_vector, int16_t gain, int16_t vector_length, int16_t right_shifts); void WebRtcSpl_ScaleAndAddVectors(const int16_t* in_vector1, int16_t gain1, int right_shifts1, const int16_t* in_vector2, int16_t gain2, int right_shifts2, int16_t* out_vector, int vector_length); // The functions (with related pointer) perform the vector operation: // out_vector[k] = ((scale1 * in_vector1[k]) + (scale2 * in_vector2[k]) // + round_value) >> right_shifts, // where round_value = (1 << right_shifts) >> 1. // // Input: // - in_vector1 : Input vector 1 // - in_vector1_scale : Gain to be used for vector 1 // - in_vector2 : Input vector 2 // - in_vector2_scale : Gain to be used for vector 2 // - right_shifts : Number of right bit shifts to be applied // - length : Number of elements in the input vectors // // Output: // - out_vector : Output vector // Return value : 0 if OK, -1 if (in_vector1 == NULL // || in_vector2 == NULL || out_vector == NULL // || length <= 0 || right_shift < 0). typedef int (*ScaleAndAddVectorsWithRound)(const int16_t* in_vector1, int16_t in_vector1_scale, const int16_t* in_vector2, int16_t in_vector2_scale, int right_shifts, int16_t* out_vector, int length); extern ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound; int WebRtcSpl_ScaleAndAddVectorsWithRoundC(const int16_t* in_vector1, int16_t in_vector1_scale, const int16_t* in_vector2, int16_t in_vector2_scale, int right_shifts, int16_t* out_vector, int length); // End: Vector scaling operations. // iLBC specific functions. Implementations in ilbc_specific_functions.c. // Description at bottom of file. void WebRtcSpl_ReverseOrderMultArrayElements(int16_t* out_vector, const int16_t* in_vector, const int16_t* window, int16_t vector_length, int16_t right_shifts); void WebRtcSpl_ElementwiseVectorMult(int16_t* out_vector, const int16_t* in_vector, const int16_t* window, int16_t vector_length, int16_t right_shifts); void WebRtcSpl_AddVectorsAndShift(int16_t* out_vector, const int16_t* in_vector1, const int16_t* in_vector2, int16_t vector_length, int16_t right_shifts); void WebRtcSpl_AddAffineVectorToVector(int16_t* out_vector, int16_t* in_vector, int16_t gain, int32_t add_constant, int16_t right_shifts, int vector_length); void WebRtcSpl_AffineTransformVector(int16_t* out_vector, int16_t* in_vector, int16_t gain, int32_t add_constant, int16_t right_shifts, int vector_length); // End: iLBC specific functions. // Signal processing operations. // A 32-bit fix-point implementation of auto-correlation computation // // Input: // - in_vector : Vector to calculate autocorrelation upon // - in_vector_length : Length (in samples) of |vector| // - order : The order up to which the autocorrelation should be // calculated // // Output: // - result : auto-correlation values (values should be seen // relative to each other since the absolute values // might have been down shifted to avoid overflow) // // - scale : The number of left shifts required to obtain the // auto-correlation in Q0 // // Return value : // - -1, if |order| > |in_vector_length|; // - Number of samples in |result|, i.e. (order+1), otherwise. int WebRtcSpl_AutoCorrelation(const int16_t* in_vector, int in_vector_length, int order, int32_t* result, int* scale); // A 32-bit fix-point implementation of the Levinson-Durbin algorithm that // does NOT use the 64 bit class // // Input: // - auto_corr : Vector with autocorrelation values of length >= // |use_order|+1 // - use_order : The LPC filter order (support up to order 20) // // Output: // - lpc_coef : lpc_coef[0..use_order] LPC coefficients in Q12 // - refl_coef : refl_coef[0...use_order-1]| Reflection coefficients in // Q15 // // Return value : 1 for stable 0 for unstable int16_t WebRtcSpl_LevinsonDurbin(int32_t* auto_corr, int16_t* lpc_coef, int16_t* refl_coef, int16_t order); // Converts reflection coefficients |refl_coef| to LPC coefficients |lpc_coef|. // This version is a 16 bit operation. // // NOTE: The 16 bit refl_coef -> lpc_coef conversion might result in a // "slightly unstable" filter (i.e., a pole just outside the unit circle) in // "rare" cases even if the reflection coefficients are stable. // // Input: // - refl_coef : Reflection coefficients in Q15 that should be converted // to LPC coefficients // - use_order : Number of coefficients in |refl_coef| // // Output: // - lpc_coef : LPC coefficients in Q12 void WebRtcSpl_ReflCoefToLpc(const int16_t* refl_coef, int use_order, int16_t* lpc_coef); // Converts LPC coefficients |lpc_coef| to reflection coefficients |refl_coef|. // This version is a 16 bit operation. // The conversion is implemented by the step-down algorithm. // // Input: // - lpc_coef : LPC coefficients in Q12, that should be converted to // reflection coefficients // - use_order : Number of coefficients in |lpc_coef| // // Output: // - refl_coef : Reflection coefficients in Q15. void WebRtcSpl_LpcToReflCoef(int16_t* lpc_coef, int use_order, int16_t* refl_coef); // Calculates reflection coefficients (16 bit) from auto-correlation values // // Input: // - auto_corr : Auto-correlation values // - use_order : Number of coefficients wanted be calculated // // Output: // - refl_coef : Reflection coefficients in Q15. void WebRtcSpl_AutoCorrToReflCoef(const int32_t* auto_corr, int use_order, int16_t* refl_coef); // The functions (with related pointer) calculate the cross-correlation between // two sequences |seq1| and |seq2|. // |seq1| is fixed and |seq2| slides as the pointer is increased with the // amount |step_seq2|. Note the arguments should obey the relationship: // |dim_seq| - 1 + |step_seq2| * (|dim_cross_correlation| - 1) < // buffer size of |seq2| // // Input: // - seq1 : First sequence (fixed throughout the correlation) // - seq2 : Second sequence (slides |step_vector2| for each // new correlation) // - dim_seq : Number of samples to use in the cross-correlation // - dim_cross_correlation : Number of cross-correlations to calculate (the // start position for |vector2| is updated for each // new one) // - right_shifts : Number of right bit shifts to use. This will // become the output Q-domain. // - step_seq2 : How many (positive or negative) steps the // |vector2| pointer should be updated for each new // cross-correlation value. // // Output: // - cross_correlation : The cross-correlation in Q(-right_shifts) typedef void (*CrossCorrelation)(int32_t* cross_correlation, const int16_t* seq1, const int16_t* seq2, int16_t dim_seq, int16_t dim_cross_correlation, int16_t right_shifts, int16_t step_seq2); extern CrossCorrelation WebRtcSpl_CrossCorrelation; void WebRtcSpl_CrossCorrelationC(int32_t* cross_correlation, const int16_t* seq1, const int16_t* seq2, int16_t dim_seq, int16_t dim_cross_correlation, int16_t right_shifts, int16_t step_seq2); // Creates (the first half of) a Hanning window. Size must be at least 1 and // at most 512. // // Input: // - size : Length of the requested Hanning window (1 to 512) // // Output: // - window : Hanning vector in Q14. void WebRtcSpl_GetHanningWindow(int16_t* window, int16_t size); // Calculates y[k] = sqrt(1 - x[k]^2) for each element of the input vector // |in_vector|. Input and output values are in Q15. // // Inputs: // - in_vector : Values to calculate sqrt(1 - x^2) of // - vector_length : Length of vector |in_vector| // // Output: // - out_vector : Output values in Q15 void WebRtcSpl_SqrtOfOneMinusXSquared(int16_t* in_vector, int vector_length, int16_t* out_vector); // End: Signal processing operations. // Randomization functions. Implementations collected in // randomization_functions.c and descriptions at bottom of this file. uint32_t WebRtcSpl_IncreaseSeed(uint32_t* seed); int16_t WebRtcSpl_RandU(uint32_t* seed); int16_t WebRtcSpl_RandN(uint32_t* seed); int16_t WebRtcSpl_RandUArray(int16_t* vector, int16_t vector_length, uint32_t* seed); // End: Randomization functions. // Math functions int32_t WebRtcSpl_Sqrt(int32_t value); int32_t WebRtcSpl_SqrtFloor(int32_t value); // Divisions. Implementations collected in division_operations.c and // descriptions at bottom of this file. uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den); int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den); int16_t WebRtcSpl_DivW32W16ResW16(int32_t num, int16_t den); int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den); int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low); // End: Divisions. int32_t WebRtcSpl_Energy(int16_t* vector, int vector_length, int* scale_factor); // Calculates the dot product between two (int16_t) vectors. // // Input: // - vector1 : Vector 1 // - vector2 : Vector 2 // - vector_length : Number of samples used in the dot product // - scaling : The number of right bit shifts to apply on each term // during calculation to avoid overflow, i.e., the // output will be in Q(-|scaling|) // // Return value : The dot product in Q(-scaling) int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1, const int16_t* vector2, int length, int scaling); // Filter operations. int WebRtcSpl_FilterAR(const int16_t* ar_coef, int ar_coef_length, const int16_t* in_vector, int in_vector_length, int16_t* filter_state, int filter_state_length, int16_t* filter_state_low, int filter_state_low_length, int16_t* out_vector, int16_t* out_vector_low, int out_vector_low_length); void WebRtcSpl_FilterMAFastQ12(int16_t* in_vector, int16_t* out_vector, int16_t* ma_coef, int16_t ma_coef_length, int16_t vector_length); // Performs a AR filtering on a vector in Q12 // Input: // - data_in : Input samples // - data_out : State information in positions // data_out[-order] .. data_out[-1] // - coefficients : Filter coefficients (in Q12) // - coefficients_length: Number of coefficients (order+1) // - data_length : Number of samples to be filtered // Output: // - data_out : Filtered samples void WebRtcSpl_FilterARFastQ12(const int16_t* data_in, int16_t* data_out, const int16_t* coefficients, int coefficients_length, int data_length); // The functions (with related pointer) perform a MA down sampling filter // on a vector. // Input: // - data_in : Input samples (state in positions // data_in[-order] .. data_in[-1]) // - data_in_length : Number of samples in |data_in| to be filtered. // This must be at least // |delay| + |factor|*(|out_vector_length|-1) + 1) // - data_out_length : Number of down sampled samples desired // - coefficients : Filter coefficients (in Q12) // - coefficients_length: Number of coefficients (order+1) // - factor : Decimation factor // - delay : Delay of filter (compensated for in out_vector) // Output: // - data_out : Filtered samples // Return value : 0 if OK, -1 if |in_vector| is too short typedef int (*DownsampleFast)(const int16_t* data_in, int data_in_length, int16_t* data_out, int data_out_length, // const int16_t* coefficients, int coefficients_length, int factor, int delay); extern DownsampleFast WebRtcSpl_DownsampleFast; int WebRtcSpl_DownsampleFastC(const int16_t* data_in, int data_in_length, int16_t* data_out, int data_out_length, const int16_t* coefficients, int coefficients_length, int factor, int delay); // End: Filter operations. // FFT operations int WebRtcSpl_ComplexFFT(int16_t vector[], int stages, int mode); int WebRtcSpl_ComplexIFFT(int16_t vector[], int stages, int mode); // Treat a 16-bit complex data buffer |complex_data| as an array of 32-bit // values, and swap elements whose indexes are bit-reverses of each other. // // Input: // - complex_data : Complex data buffer containing 2^|stages| real // elements interleaved with 2^|stages| imaginary // elements: [Re Im Re Im Re Im....] // - stages : Number of FFT stages. Must be at least 3 and at most // 10, since the table WebRtcSpl_kSinTable1024[] is 1024 // elements long. // // Output: // - complex_data : The complex data buffer. void WebRtcSpl_ComplexBitReverse(int16_t* complex_data, int stages); // End: FFT operations /************************************************************ * * RESAMPLING FUNCTIONS AND THEIR STRUCTS ARE DEFINED BELOW * ************************************************************/ /******************************************************************* * resample.c * * Includes the following resampling combinations * 22 kHz -> 16 kHz * 16 kHz -> 22 kHz * 22 kHz -> 8 kHz * 8 kHz -> 22 kHz * ******************************************************************/ // state structure for 22 -> 16 resampler typedef struct { int32_t S_22_44[8]; int32_t S_44_32[8]; int32_t S_32_16[8]; } WebRtcSpl_State22khzTo16khz; void WebRtcSpl_Resample22khzTo16khz(const int16_t* in, int16_t* out, WebRtcSpl_State22khzTo16khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample22khzTo16khz(WebRtcSpl_State22khzTo16khz* state); // state structure for 16 -> 22 resampler typedef struct { int32_t S_16_32[8]; int32_t S_32_22[8]; } WebRtcSpl_State16khzTo22khz; void WebRtcSpl_Resample16khzTo22khz(const int16_t* in, int16_t* out, WebRtcSpl_State16khzTo22khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample16khzTo22khz(WebRtcSpl_State16khzTo22khz* state); // state structure for 22 -> 8 resampler typedef struct { int32_t S_22_22[16]; int32_t S_22_16[8]; int32_t S_16_8[8]; } WebRtcSpl_State22khzTo8khz; void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, int16_t* out, WebRtcSpl_State22khzTo8khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample22khzTo8khz(WebRtcSpl_State22khzTo8khz* state); // state structure for 8 -> 22 resampler typedef struct { int32_t S_8_16[8]; int32_t S_16_11[8]; int32_t S_11_22[8]; } WebRtcSpl_State8khzTo22khz; void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, int16_t* out, WebRtcSpl_State8khzTo22khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample8khzTo22khz(WebRtcSpl_State8khzTo22khz* state); /******************************************************************* * resample_fractional.c * Functions for internal use in the other resample functions * * Includes the following resampling combinations * 48 kHz -> 32 kHz * 32 kHz -> 24 kHz * 44 kHz -> 32 kHz * ******************************************************************/ void WebRtcSpl_Resample48khzTo32khz(const int32_t* In, int32_t* Out, int32_t K); void WebRtcSpl_Resample32khzTo24khz(const int32_t* In, int32_t* Out, int32_t K); void WebRtcSpl_Resample44khzTo32khz(const int32_t* In, int32_t* Out, int32_t K); /******************************************************************* * resample_48khz.c * * Includes the following resampling combinations * 48 kHz -> 16 kHz * 16 kHz -> 48 kHz * 48 kHz -> 8 kHz * 8 kHz -> 48 kHz * ******************************************************************/ typedef struct { int32_t S_48_48[16]; int32_t S_48_32[8]; int32_t S_32_16[8]; } WebRtcSpl_State48khzTo16khz; void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, int16_t* out, WebRtcSpl_State48khzTo16khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample48khzTo16khz(WebRtcSpl_State48khzTo16khz* state); typedef struct { int32_t S_16_32[8]; int32_t S_32_24[8]; int32_t S_24_48[8]; } WebRtcSpl_State16khzTo48khz; void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, int16_t* out, WebRtcSpl_State16khzTo48khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample16khzTo48khz(WebRtcSpl_State16khzTo48khz* state); typedef struct { int32_t S_48_24[8]; int32_t S_24_24[16]; int32_t S_24_16[8]; int32_t S_16_8[8]; } WebRtcSpl_State48khzTo8khz; void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, int16_t* out, WebRtcSpl_State48khzTo8khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample48khzTo8khz(WebRtcSpl_State48khzTo8khz* state); typedef struct { int32_t S_8_16[8]; int32_t S_16_12[8]; int32_t S_12_24[8]; int32_t S_24_48[8]; } WebRtcSpl_State8khzTo48khz; void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, int16_t* out, WebRtcSpl_State8khzTo48khz* state, int32_t* tmpmem); void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state); /******************************************************************* * resample_by_2.c * * Includes down and up sampling by a factor of two. * ******************************************************************/ void WebRtcSpl_DownsampleBy2(const int16_t* in, int16_t len, int16_t* out, int32_t* filtState); void WebRtcSpl_UpsampleBy2(const int16_t* in, int16_t len, int16_t* out, int32_t* filtState); /************************************************************ * END OF RESAMPLING FUNCTIONS ************************************************************/ void WebRtcSpl_AnalysisQMF(const int16_t* in_data, int16_t* low_band, int16_t* high_band, int32_t* filter_state1, int32_t* filter_state2); void WebRtcSpl_SynthesisQMF(const int16_t* low_band, const int16_t* high_band, int16_t* out_data, int32_t* filter_state1, int32_t* filter_state2); // // WebRtcSpl_AddSatW16(...) // WebRtcSpl_AddSatW32(...) // // Returns the result of a saturated 16-bit, respectively 32-bit, addition of // the numbers specified by the |var1| and |var2| parameters. // // Input: // - var1 : Input variable 1 // - var2 : Input variable 2 // // Return value : Added and saturated value // // // WebRtcSpl_SubSatW16(...) // WebRtcSpl_SubSatW32(...) // // Returns the result of a saturated 16-bit, respectively 32-bit, subtraction // of the numbers specified by the |var1| and |var2| parameters. // // Input: // - var1 : Input variable 1 // - var2 : Input variable 2 // // Returned value : Subtracted and saturated value // // // WebRtcSpl_GetSizeInBits(...) // // Returns the # of bits that are needed at the most to represent the number // specified by the |value| parameter. // // Input: // - value : Input value // // Return value : Number of bits needed to represent |value| // // // WebRtcSpl_NormW32(...) // // Norm returns the # of left shifts required to 32-bit normalize the 32-bit // signed number specified by the |value| parameter. // // Input: // - value : Input value // // Return value : Number of bit shifts needed to 32-bit normalize |value| // // // WebRtcSpl_NormW16(...) // // Norm returns the # of left shifts required to 16-bit normalize the 16-bit // signed number specified by the |value| parameter. // // Input: // - value : Input value // // Return value : Number of bit shifts needed to 32-bit normalize |value| // // // WebRtcSpl_NormU32(...) // // Norm returns the # of left shifts required to 32-bit normalize the unsigned // 32-bit number specified by the |value| parameter. // // Input: // - value : Input value // // Return value : Number of bit shifts needed to 32-bit normalize |value| // // // WebRtcSpl_GetScalingSquare(...) // // Returns the # of bits required to scale the samples specified in the // |in_vector| parameter so that, if the squares of the samples are added the // # of times specified by the |times| parameter, the 32-bit addition will not // overflow (result in int32_t). // // Input: // - in_vector : Input vector to check scaling on // - in_vector_length : Samples in |in_vector| // - times : Number of additions to be performed // // Return value : Number of right bit shifts needed to avoid // overflow in the addition calculation // // // WebRtcSpl_MemSetW16(...) // // Sets all the values in the int16_t vector |vector| of length // |vector_length| to the specified value |set_value| // // Input: // - vector : Pointer to the int16_t vector // - set_value : Value specified // - vector_length : Length of vector // // // WebRtcSpl_MemSetW32(...) // // Sets all the values in the int32_t vector |vector| of length // |vector_length| to the specified value |set_value| // // Input: // - vector : Pointer to the int16_t vector // - set_value : Value specified // - vector_length : Length of vector // // // WebRtcSpl_MemCpyReversedOrder(...) // // Copies all the values from the source int16_t vector |in_vector| to a // destination int16_t vector |out_vector|. It is done in reversed order, // meaning that the first sample of |in_vector| is copied to the last sample of // the |out_vector|. The procedure continues until the last sample of // |in_vector| has been copied to the first sample of |out_vector|. This // creates a reversed vector. Used in e.g. prediction in iLBC. // // Input: // - in_vector : Pointer to the first sample in a int16_t vector // of length |length| // - vector_length : Number of elements to copy // // Output: // - out_vector : Pointer to the last sample in a int16_t vector // of length |length| // // // WebRtcSpl_CopyFromEndW16(...) // // Copies the rightmost |samples| of |in_vector| (of length |in_vector_length|) // to the vector |out_vector|. // // Input: // - in_vector : Input vector // - in_vector_length : Number of samples in |in_vector| // - samples : Number of samples to extract (from right side) // from |in_vector| // // Output: // - out_vector : Vector with the requested samples // // Return value : Number of copied samples in |out_vector| // // // WebRtcSpl_ZerosArrayW16(...) // WebRtcSpl_ZerosArrayW32(...) // // Inserts the value "zero" in all positions of a w16 and a w32 vector // respectively. // // Input: // - vector_length : Number of samples in vector // // Output: // - vector : Vector containing all zeros // // Return value : Number of samples in vector // // // WebRtcSpl_OnesArrayW16(...) // WebRtcSpl_OnesArrayW32(...) // // Inserts the value "one" in all positions of a w16 and a w32 vector // respectively. // // Input: // - vector_length : Number of samples in vector // // Output: // - vector : Vector containing all ones // // Return value : Number of samples in vector // // // WebRtcSpl_VectorBitShiftW16(...) // WebRtcSpl_VectorBitShiftW32(...) // // Bit shifts all the values in a vector up or downwards. Different calls for // int16_t and int32_t vectors respectively. // // Input: // - vector_length : Length of vector // - in_vector : Pointer to the vector that should be bit shifted // - right_shifts : Number of right bit shifts (negative value gives left // shifts) // // Output: // - out_vector : Pointer to the result vector (can be the same as // |in_vector|) // // // WebRtcSpl_VectorBitShiftW32ToW16(...) // // Bit shifts all the values in a int32_t vector up or downwards and // stores the result as an int16_t vector. The function will saturate the // signal if needed, before storing in the output vector. // // Input: // - vector_length : Length of vector // - in_vector : Pointer to the vector that should be bit shifted // - right_shifts : Number of right bit shifts (negative value gives left // shifts) // // Output: // - out_vector : Pointer to the result vector (can be the same as // |in_vector|) // // // WebRtcSpl_ScaleVector(...) // // Performs the vector operation: // out_vector[k] = (gain*in_vector[k])>>right_shifts // // Input: // - in_vector : Input vector // - gain : Scaling gain // - vector_length : Elements in the |in_vector| // - right_shifts : Number of right bit shifts applied // // Output: // - out_vector : Output vector (can be the same as |in_vector|) // // // WebRtcSpl_ScaleVectorWithSat(...) // // Performs the vector operation: // out_vector[k] = SATURATE( (gain*in_vector[k])>>right_shifts ) // // Input: // - in_vector : Input vector // - gain : Scaling gain // - vector_length : Elements in the |in_vector| // - right_shifts : Number of right bit shifts applied // // Output: // - out_vector : Output vector (can be the same as |in_vector|) // // // WebRtcSpl_ScaleAndAddVectors(...) // // Performs the vector operation: // out_vector[k] = (gain1*in_vector1[k])>>right_shifts1 // + (gain2*in_vector2[k])>>right_shifts2 // // Input: // - in_vector1 : Input vector 1 // - gain1 : Gain to be used for vector 1 // - right_shifts1 : Right bit shift to be used for vector 1 // - in_vector2 : Input vector 2 // - gain2 : Gain to be used for vector 2 // - right_shifts2 : Right bit shift to be used for vector 2 // - vector_length : Elements in the input vectors // // Output: // - out_vector : Output vector // // // WebRtcSpl_ReverseOrderMultArrayElements(...) // // Performs the vector operation: // out_vector[n] = (in_vector[n]*window[-n])>>right_shifts // // Input: // - in_vector : Input vector // - window : Window vector (should be reversed). The pointer // should be set to the last value in the vector // - right_shifts : Number of right bit shift to be applied after the // multiplication // - vector_length : Number of elements in |in_vector| // // Output: // - out_vector : Output vector (can be same as |in_vector|) // // // WebRtcSpl_ElementwiseVectorMult(...) // // Performs the vector operation: // out_vector[n] = (in_vector[n]*window[n])>>right_shifts // // Input: // - in_vector : Input vector // - window : Window vector. // - right_shifts : Number of right bit shift to be applied after the // multiplication // - vector_length : Number of elements in |in_vector| // // Output: // - out_vector : Output vector (can be same as |in_vector|) // // // WebRtcSpl_AddVectorsAndShift(...) // // Performs the vector operation: // out_vector[k] = (in_vector1[k] + in_vector2[k])>>right_shifts // // Input: // - in_vector1 : Input vector 1 // - in_vector2 : Input vector 2 // - right_shifts : Number of right bit shift to be applied after the // multiplication // - vector_length : Number of elements in |in_vector1| and |in_vector2| // // Output: // - out_vector : Output vector (can be same as |in_vector1|) // // // WebRtcSpl_AddAffineVectorToVector(...) // // Adds an affine transformed vector to another vector |out_vector|, i.e, // performs // out_vector[k] += (in_vector[k]*gain+add_constant)>>right_shifts // // Input: // - in_vector : Input vector // - gain : Gain value, used to multiply the in vector with // - add_constant : Constant value to add (usually 1<<(right_shifts-1), // but others can be used as well // - right_shifts : Number of right bit shifts (0-16) // - vector_length : Number of samples in |in_vector| and |out_vector| // // Output: // - out_vector : Vector with the output // // // WebRtcSpl_AffineTransformVector(...) // // Affine transforms a vector, i.e, performs // out_vector[k] = (in_vector[k]*gain+add_constant)>>right_shifts // // Input: // - in_vector : Input vector // - gain : Gain value, used to multiply the in vector with // - add_constant : Constant value to add (usually 1<<(right_shifts-1), // but others can be used as well // - right_shifts : Number of right bit shifts (0-16) // - vector_length : Number of samples in |in_vector| and |out_vector| // // Output: // - out_vector : Vector with the output // // // WebRtcSpl_IncreaseSeed(...) // // Increases the seed (and returns the new value) // // Input: // - seed : Seed for random calculation // // Output: // - seed : Updated seed value // // Return value : The new seed value // // // WebRtcSpl_RandU(...) // // Produces a uniformly distributed value in the int16_t range // // Input: // - seed : Seed for random calculation // // Output: // - seed : Updated seed value // // Return value : Uniformly distributed value in the range // [Word16_MIN...Word16_MAX] // // // WebRtcSpl_RandN(...) // // Produces a normal distributed value in the int16_t range // // Input: // - seed : Seed for random calculation // // Output: // - seed : Updated seed value // // Return value : N(0,1) value in the Q13 domain // // // WebRtcSpl_RandUArray(...) // // Produces a uniformly distributed vector with elements in the int16_t // range // // Input: // - vector_length : Samples wanted in the vector // - seed : Seed for random calculation // // Output: // - vector : Vector with the uniform values // - seed : Updated seed value // // Return value : Number of samples in vector, i.e., |vector_length| // // // WebRtcSpl_Sqrt(...) // // Returns the square root of the input value |value|. The precision of this // function is integer precision, i.e., sqrt(8) gives 2 as answer. // If |value| is a negative number then 0 is returned. // // Algorithm: // // A sixth order Taylor Series expansion is used here to compute the square // root of a number y^0.5 = (1+x)^0.5 // where // x = y-1 // = 1+(x/2)-0.5*((x/2)^2+0.5*((x/2)^3-0.625*((x/2)^4+0.875*((x/2)^5) // 0.5 <= x < 1 // // Input: // - value : Value to calculate sqrt of // // Return value : Result of the sqrt calculation // // // WebRtcSpl_SqrtFloor(...) // // Returns the square root of the input value |value|. The precision of this // function is rounding down integer precision, i.e., sqrt(8) gives 2 as answer. // If |value| is a negative number then 0 is returned. // // Algorithm: // // An iterative 4 cylce/bit routine // // Input: // - value : Value to calculate sqrt of // // Return value : Result of the sqrt calculation // // // WebRtcSpl_DivU32U16(...) // // Divides a uint32_t |num| by a uint16_t |den|. // // If |den|==0, (uint32_t)0xFFFFFFFF is returned. // // Input: // - num : Numerator // - den : Denominator // // Return value : Result of the division (as a uint32_t), i.e., the // integer part of num/den. // // // WebRtcSpl_DivW32W16(...) // // Divides a int32_t |num| by a int16_t |den|. // // If |den|==0, (int32_t)0x7FFFFFFF is returned. // // Input: // - num : Numerator // - den : Denominator // // Return value : Result of the division (as a int32_t), i.e., the // integer part of num/den. // // // WebRtcSpl_DivW32W16ResW16(...) // // Divides a int32_t |num| by a int16_t |den|, assuming that the // result is less than 32768, otherwise an unpredictable result will occur. // // If |den|==0, (int16_t)0x7FFF is returned. // // Input: // - num : Numerator // - den : Denominator // // Return value : Result of the division (as a int16_t), i.e., the // integer part of num/den. // // // WebRtcSpl_DivResultInQ31(...) // // Divides a int32_t |num| by a int16_t |den|, assuming that the // absolute value of the denominator is larger than the numerator, otherwise // an unpredictable result will occur. // // Input: // - num : Numerator // - den : Denominator // // Return value : Result of the division in Q31. // // // WebRtcSpl_DivW32HiLow(...) // // Divides a int32_t |num| by a denominator in hi, low format. The // absolute value of the denominator has to be larger (or equal to) the // numerator. // // Input: // - num : Numerator // - den_hi : High part of denominator // - den_low : Low part of denominator // // Return value : Divided value in Q31 // // // WebRtcSpl_Energy(...) // // Calculates the energy of a vector // // Input: // - vector : Vector which the energy should be calculated on // - vector_length : Number of samples in vector // // Output: // - scale_factor : Number of left bit shifts needed to get the physical // energy value, i.e, to get the Q0 value // // Return value : Energy value in Q(-|scale_factor|) // // // WebRtcSpl_FilterAR(...) // // Performs a 32-bit AR filtering on a vector in Q12 // // Input: // - ar_coef : AR-coefficient vector (values in Q12), // ar_coef[0] must be 4096. // - ar_coef_length : Number of coefficients in |ar_coef|. // - in_vector : Vector to be filtered. // - in_vector_length : Number of samples in |in_vector|. // - filter_state : Current state (higher part) of the filter. // - filter_state_length : Length (in samples) of |filter_state|. // - filter_state_low : Current state (lower part) of the filter. // - filter_state_low_length : Length (in samples) of |filter_state_low|. // - out_vector_low_length : Maximum length (in samples) of // |out_vector_low|. // // Output: // - filter_state : Updated state (upper part) vector. // - filter_state_low : Updated state (lower part) vector. // - out_vector : Vector containing the upper part of the // filtered values. // - out_vector_low : Vector containing the lower part of the // filtered values. // // Return value : Number of samples in the |out_vector|. // // // WebRtcSpl_FilterMAFastQ12(...) // // Performs a MA filtering on a vector in Q12 // // Input: // - in_vector : Input samples (state in positions // in_vector[-order] .. in_vector[-1]) // - ma_coef : Filter coefficients (in Q12) // - ma_coef_length : Number of B coefficients (order+1) // - vector_length : Number of samples to be filtered // // Output: // - out_vector : Filtered samples // // // WebRtcSpl_ComplexIFFT(...) // // Complex Inverse FFT // // Computes an inverse complex 2^|stages|-point FFT on the input vector, which // is in bit-reversed order. The original content of the vector is destroyed in // the process, since the input is overwritten by the output, normal-ordered, // FFT vector. With X as the input complex vector, y as the output complex // vector and with M = 2^|stages|, the following is computed: // // M-1 // y(k) = sum[X(i)*[cos(2*pi*i*k/M) + j*sin(2*pi*i*k/M)]] // i=0 // // The implementations are optimized for speed, not for code size. It uses the // decimation-in-time algorithm with radix-2 butterfly technique. // // Input: // - vector : In pointer to complex vector containing 2^|stages| // real elements interleaved with 2^|stages| imaginary // elements. // [ReImReImReIm....] // The elements are in Q(-scale) domain, see more on Return // Value below. // // - stages : Number of FFT stages. Must be at least 3 and at most 10, // since the table WebRtcSpl_kSinTable1024[] is 1024 // elements long. // // - mode : This parameter gives the user to choose how the FFT // should work. // mode==0: Low-complexity and Low-accuracy mode // mode==1: High-complexity and High-accuracy mode // // Output: // - vector : Out pointer to the FFT vector (the same as input). // // Return Value : The scale value that tells the number of left bit shifts // that the elements in the |vector| should be shifted with // in order to get Q0 values, i.e. the physically correct // values. The scale parameter is always 0 or positive, // except if N>1024 (|stages|>10), which returns a scale // value of -1, indicating error. // // // WebRtcSpl_ComplexFFT(...) // // Complex FFT // // Computes a complex 2^|stages|-point FFT on the input vector, which is in // bit-reversed order. The original content of the vector is destroyed in // the process, since the input is overwritten by the output, normal-ordered, // FFT vector. With x as the input complex vector, Y as the output complex // vector and with M = 2^|stages|, the following is computed: // // M-1 // Y(k) = 1/M * sum[x(i)*[cos(2*pi*i*k/M) + j*sin(2*pi*i*k/M)]] // i=0 // // The implementations are optimized for speed, not for code size. It uses the // decimation-in-time algorithm with radix-2 butterfly technique. // // This routine prevents overflow by scaling by 2 before each FFT stage. This is // a fixed scaling, for proper normalization - there will be log2(n) passes, so // this results in an overall factor of 1/n, distributed to maximize arithmetic // accuracy. // // Input: // - vector : In pointer to complex vector containing 2^|stages| real // elements interleaved with 2^|stages| imaginary elements. // [ReImReImReIm....] // The output is in the Q0 domain. // // - stages : Number of FFT stages. Must be at least 3 and at most 10, // since the table WebRtcSpl_kSinTable1024[] is 1024 // elements long. // // - mode : This parameter gives the user to choose how the FFT // should work. // mode==0: Low-complexity and Low-accuracy mode // mode==1: High-complexity and High-accuracy mode // // Output: // - vector : The output FFT vector is in the Q0 domain. // // Return value : The scale parameter is always 0, except if N>1024, // which returns a scale value of -1, indicating error. // // // WebRtcSpl_AnalysisQMF(...) // // Splits a 0-2*F Hz signal into two sub bands: 0-F Hz and F-2*F Hz. The // current version has F = 8000, therefore, a super-wideband audio signal is // split to lower-band 0-8 kHz and upper-band 8-16 kHz. // // Input: // - in_data : Wide band speech signal, 320 samples (10 ms) // // Input & Output: // - filter_state1 : Filter state for first All-pass filter // - filter_state2 : Filter state for second All-pass filter // // Output: // - low_band : Lower-band signal 0-8 kHz band, 160 samples (10 ms) // - high_band : Upper-band signal 8-16 kHz band (flipped in frequency // domain), 160 samples (10 ms) // // // WebRtcSpl_SynthesisQMF(...) // // Combines the two sub bands (0-F and F-2*F Hz) into a signal of 0-2*F // Hz, (current version has F = 8000 Hz). So the filter combines lower-band // (0-8 kHz) and upper-band (8-16 kHz) channels to obtain super-wideband 0-16 // kHz audio. // // Input: // - low_band : The signal with the 0-8 kHz band, 160 samples (10 ms) // - high_band : The signal with the 8-16 kHz band, 160 samples (10 ms) // // Input & Output: // - filter_state1 : Filter state for first All-pass filter // - filter_state2 : Filter state for second All-pass filter // // Output: // - out_data : Super-wideband speech signal, 0-16 kHz // // int16_t WebRtcSpl_SatW32ToW16(...) // // This function saturates a 32-bit word into a 16-bit word. // // Input: // - value32 : The value of a 32-bit word. // // Output: // - out16 : the saturated 16-bit word. // // int32_t WebRtc_MulAccumW16(...) // // This function multiply a 16-bit word by a 16-bit word, and accumulate this // value to a 32-bit integer. // // Input: // - a : The value of the first 16-bit word. // - b : The value of the second 16-bit word. // - c : The value of an 32-bit integer. // // Return Value: The value of a * b + c. // // int16_t WebRtcSpl_get_version(...) // // This function gives the version string of the Signal Processing Library. // // Input: // - length_in_bytes : The size of Allocated space (in Bytes) where // the version number is written to (in string format). // // Output: // - version : Pointer to a buffer where the version number is // written to. // /* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* Algorithm parameters */ /* Counter parameters */ /* Energy parameters */ /* in energy. */ /* and min. */ /* Stepsize parameters */ /* dependent). */ /* dependent). */ /* Channel parameters */ /* far end energy to compare channel estimates. */ /* accept a new storage (0.8 in Q-MSE_RESOLUTION). */ /* to update channel. */ /* Suppression gain parameters: SUPGAIN parameters in Q-(RESOLUTION_SUPGAIN). */ /* (Maximum gain) (8 in Q8). */ /* (Gain before going down). */ /* (Should be the same as Default) (1 in Q8). */ /* Defines for "check delay estimation" */ /* Note that CORR_WIDTH + 2*CORR_MAX <= MAX_BUF_LEN. */ /* NLP defines */ /* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // A ring buffer to hold arbitrary data. Provides no thread safety. Unless // otherwise specified, functions return 0 on success and -1 on error. /*****************************************************************************/ /* stddef.h v4.2.0 */ /* Copyright (c) 1993-2008 Texas Instruments Incorporated */ /*****************************************************************************/ typedef int ptrdiff_t; typedef unsigned int wchar_t; typedef struct RingBuffer RingBuffer; // Returns NULL on failure. RingBuffer* WebRtc_CreateBuffer(size_t element_count, size_t element_size); int WebRtc_InitBuffer(RingBuffer* handle); void WebRtc_FreeBuffer(void* handle); // Reads data from the buffer. The |data_ptr| will point to the address where // it is located. If all |element_count| data are feasible to read without // buffer wrap around |data_ptr| will point to the location in the buffer. // Otherwise, the data will be copied to |data| (memory allocation done by the // user) and |data_ptr| points to the address of |data|. |data_ptr| is only // guaranteed to be valid until the next call to WebRtc_WriteBuffer(). // // To force a copying to |data|, pass a NULL |data_ptr|. // // Returns number of elements read. size_t WebRtc_ReadBuffer(RingBuffer* handle, void** data_ptr, void* data, size_t element_count); // Writes |data| to buffer and returns the number of elements written. size_t WebRtc_WriteBuffer(RingBuffer* handle, const void* data, size_t element_count); // Moves the buffer read position and returns the number of elements moved. // Positive |element_count| moves the read position towards the write position, // that is, flushing the buffer. Negative |element_count| moves the read // position away from the the write position, that is, stuffing the buffer. // Returns number of elements moved. int WebRtc_MoveReadPtr(RingBuffer* handle, int element_count); // Returns number of available elements to read. size_t WebRtc_available_read(const RingBuffer* handle); // Returns number of available elements for write. size_t WebRtc_available_write(const RingBuffer* handle); typedef struct { int16_t real; int16_t imag; } complex16_t; typedef struct { int farBufWritePos; int farBufReadPos; int knownDelay; int lastKnownDelay; int firstVAD; // Parameter to control poorly initialized channels RingBuffer* farFrameBuf; RingBuffer* nearNoisyFrameBuf; RingBuffer* nearCleanFrameBuf; RingBuffer* outFrameBuf; int16_t farBuf[(64 << 2)]; int16_t mult; uint32_t seed; // Delay estimation variables void* delay_estimator_farend; void* delay_estimator; uint16_t currentDelay; // Far end history variables // TODO(bjornv): Replace |far_history| with ring_buffer. uint16_t far_history[(64 + 1) * 100]; int far_history_pos; int far_q_domains[100]; int16_t nlpFlag; int16_t fixedDelay; uint32_t totCount; int16_t dfaCleanQDomain; int16_t dfaCleanQDomainOld; int16_t dfaNoisyQDomain; int16_t dfaNoisyQDomainOld; int16_t nearLogEnergy[64]; int16_t farLogEnergy; int16_t echoAdaptLogEnergy[64]; int16_t echoStoredLogEnergy[64]; // The extra 16 or 32 bytes in the following buffers are for alignment based // Neon code. // It's designed this way since the current GCC compiler can't align a // buffer in 16 or 32 byte boundaries properly. int16_t channelStored_buf[(64 + 1) + 8]; int16_t channelAdapt16_buf[(64 + 1) + 8]; int32_t channelAdapt32_buf[(64 + 1) + 8]; int16_t xBuf_buf[(64 << 1) + 16]; // farend int16_t dBufClean_buf[(64 << 1) + 16]; // nearend int16_t dBufNoisy_buf[(64 << 1) + 16]; // nearend int16_t outBuf_buf[64 + 8]; // Pointers to the above buffers int16_t *channelStored; int16_t *channelAdapt16; int32_t *channelAdapt32; int16_t *xBuf; int16_t *dBufClean; int16_t *dBufNoisy; int16_t *outBuf; int32_t echoFilt[(64 + 1)]; int16_t nearFilt[(64 + 1)]; int32_t noiseEst[(64 + 1)]; int noiseEstTooLowCtr[(64 + 1)]; int noiseEstTooHighCtr[(64 + 1)]; int16_t noiseEstCtr; int16_t cngMode; int32_t mseAdaptOld; int32_t mseStoredOld; int32_t mseThreshold; int16_t farEnergyMin; int16_t farEnergyMax; int16_t farEnergyMaxMin; int16_t farEnergyVAD; int16_t farEnergyMSE; int currentVADValue; int16_t vadUpdateCount; int16_t startupState; int16_t mseChannelCount; int16_t supGain; int16_t supGainOld; int16_t supGainErrParamA; int16_t supGainErrParamD; int16_t supGainErrParamDiffAB; int16_t supGainErrParamDiffBD; struct RealFFT* real_fft; } AecmCore_t; //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_CreateCore(...) // // Allocates the memory needed by the AECM. The memory needs to be // initialized separately using the WebRtcAecm_InitCore() function. // // Input: // - aecm : Instance that should be created // // Output: // - aecm : Created instance // // Return value : 0 - Ok // -1 - Error // int WebRtcAecm_CreateCore(AecmCore_t **aecm); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_InitCore(...) // // This function initializes the AECM instant created with // WebRtcAecm_CreateCore(...) // Input: // - aecm : Pointer to the AECM instance // - samplingFreq : Sampling Frequency // // Output: // - aecm : Initialized instance // // Return value : 0 - Ok // -1 - Error // int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_FreeCore(...) // // This function releases the memory allocated by WebRtcAecm_CreateCore() // Input: // - aecm : Pointer to the AECM instance // // Return value : 0 - Ok // -1 - Error // 11001-11016: Error // int WebRtcAecm_FreeCore(AecmCore_t *aecm); int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_InitEchoPathCore(...) // // This function resets the echo channel adaptation with the specified channel. // Input: // - aecm : Pointer to the AECM instance // - echo_path : Pointer to the data that should initialize the echo // path // // Output: // - aecm : Initialized instance // void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const int16_t* echo_path); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_ProcessFrame(...) // // This function processes frames and sends blocks to // WebRtcAecm_ProcessBlock(...) // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one frame of echo signal // - nearendNoisy : In buffer containing one frame of nearend+echo signal // without NS // - nearendClean : In buffer containing one frame of nearend+echo signal // with NS // // Output: // - out : Out buffer, one frame of nearend signal : // // int WebRtcAecm_ProcessFrame(AecmCore_t * aecm, const int16_t * farend, const int16_t * nearendNoisy, const int16_t * nearendClean, int16_t * out); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_ProcessBlock(...) // // This function is called for every block within one frame // This function is called by WebRtcAecm_ProcessFrame(...) // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one block of echo signal // - nearendNoisy : In buffer containing one frame of nearend+echo signal // without NS // - nearendClean : In buffer containing one frame of nearend+echo signal // with NS // // Output: // - out : Out buffer, one block of nearend signal : // // int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, const int16_t * farend, const int16_t * nearendNoisy, const int16_t * noisyClean, int16_t * out); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_BufferFarFrame() // // Inserts a frame of data into farend buffer. // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one frame of farend signal // - farLen : Length of frame // void WebRtcAecm_BufferFarFrame(AecmCore_t * const aecm, const int16_t * const farend, const int farLen); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_FetchFarFrame() // // Read the farend buffer to account for known delay // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one frame of farend signal // - farLen : Length of frame // - knownDelay : known delay // void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, int16_t * const farend, const int farLen, const int knownDelay); /////////////////////////////////////////////////////////////////////////////// // Some function pointers, for internal functions shared by ARM NEON and // generic C code. // typedef void (*CalcLinearEnergies)( AecmCore_t* aecm, const uint16_t* far_spectrum, int32_t* echoEst, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored);//__attribute__((far)); extern CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;//__attribute__((far)); typedef void (*StoreAdaptiveChannel)( AecmCore_t* aecm, const uint16_t* far_spectrum, int32_t* echo_est); extern StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; typedef void (*ResetAdaptiveChannel)(AecmCore_t* aecm); extern ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; // For the above function pointers, functions for generic platforms are declared // and defined as static in file aecm_core.c, while those for ARM Neon platforms // are declared below and defined in file aecm_core_neon.s. /*****************************************************************************/ /* assert.h v4.2.0 */ /* Copyright (c) 1993-2008 Texas Instruments Incorporated */ /*****************************************************************************/ /* this #ifndef can go away when C2000 uses extern C builtins */ extern void _nassert(int); extern void _assert(int, const char *); extern void _abort_msg(const char *); /*****************************************************************************/ /* stddef.h v4.2.0 */ /* Copyright (c) 1993-2008 Texas Instruments Incorporated */ /*****************************************************************************/ /*****************************************************************************/ /* stdlib.h v4.2.0 */ /* Copyright (c) 1993-2008 Texas Instruments Incorporated */ /*****************************************************************************/ typedef struct { int quot, rem; } div_t; typedef struct { long quot, rem; } ldiv_t; /*---------------------------------------------------------------*/ /* NOTE - Normally, abs, labs, and fabs are expanded inline, so */ /* no formal definition is really required. However, ANSI */ /* requires that they exist as separate functions, so */ /* they are supplied in the library. The prototype is */ /* here mainly for documentation. */ /*---------------------------------------------------------------*/ int abs(int _val); long labs(long _val); int atoi(const char *_st); long atol(const char *_st); int ltoa(long val, char *buffer); static __inline double atof(const char *_st); long strtol(const char *_st, char **_endptr, int _base); unsigned long strtoul(const char *_st, char **_endptr, int _base); double strtod(const char *_st, char **_endptr); long double strtold(const char *_st, char **_endptr); int rand(void); void srand(unsigned _seed); void *calloc(size_t _num, size_t _size); void *malloc(size_t _size); void *realloc(void *_ptr, size_t _size); void free(void *_ptr); void *memalign(size_t _aln, size_t _size); void abort(void); int atexit(void (*_func)(void)); void *bsearch(const void *_key, const void *_base, size_t _nmemb, size_t _size, int (*compar)(const void *,const void *)); void qsort(void *_base, size_t _nmemb, size_t _size, int (*_compar)(const void *, const void *)); void exit(int _status); div_t div(int _numer, int _denom); ldiv_t ldiv(long _numer, long _denom); char *getenv(const char *_string); int system(const char *_name); int mblen(const char *, size_t); size_t mbstowcs(wchar_t *, const char *, size_t); int mbtowc(wchar_t *, const char *, size_t); size_t wcstombs(char *, const wchar_t *, size_t); int wctomb(char *, wchar_t); static __inline double atof(const char *_st) { return strtod(_st, (char **)0); } /* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // For ComplexFFT(), the maximum fft order is 10; // for OpenMax FFT in ARM, it is 12; // WebRTC APM uses orders of only 7 and 8. enum {kMaxFFTOrder = 10}; struct RealFFT; typedef struct RealFFT* (*CreateRealFFT)(int order); typedef void (*FreeRealFFT)(struct RealFFT* self); typedef int (*RealForwardFFT)(struct RealFFT* self, const int16_t* real_data_in, int16_t* complex_data_out); typedef int (*RealInverseFFT)(struct RealFFT* self, const int16_t* complex_data_in, int16_t* real_data_out); extern CreateRealFFT WebRtcSpl_CreateRealFFT; extern FreeRealFFT WebRtcSpl_FreeRealFFT; extern RealForwardFFT WebRtcSpl_RealForwardFFT; extern RealInverseFFT WebRtcSpl_RealInverseFFT; struct RealFFT* WebRtcSpl_CreateRealFFTC(int order); void WebRtcSpl_FreeRealFFTC(struct RealFFT* self); // Compute an FFT for a real-valued signal of length of 2^order, // where 1 < order <= MAX_FFT_ORDER. Transform length is determined by the // specification structure, which must be initialized prior to calling the FFT // function with WebRtcSpl_CreateRealFFT(). // The relationship between the input and output sequences can // be expressed in terms of the DFT, i.e.: // x[n] = (2^(-scalefactor)/N) . SUM[k=0,...,N-1] X[k].e^(jnk.2.pi/N) // n=0,1,2,...N-1 // N=2^order. // The conjugate-symmetric output sequence is represented using a CCS vector, // which is of length N+2, and is organized as follows: // Index: 0 1 2 3 4 5 . . . N-2 N-1 N N+1 // Component: R0 0 R1 I1 R2 I2 . . . R[N/2-1] I[N/2-1] R[N/2] 0 // where R[n] and I[n], respectively, denote the real and imaginary components // for FFT bin 'n'. Bins are numbered from 0 to N/2, where N is the FFT length. // Bin index 0 corresponds to the DC component, and bin index N/2 corresponds to // the foldover frequency. // // Input Arguments: // self - pointer to preallocated and initialized FFT specification structure. // real_data_in - the input signal. For an ARM Neon platform, it must be // aligned on a 32-byte boundary. // // Output Arguments: // complex_data_out - the output complex signal with (2^order + 2) 16-bit // elements. For an ARM Neon platform, it must be different // from real_data_in, and aligned on a 32-byte boundary. // // Return Value: // 0 - FFT calculation is successful. // -1 - Error with bad arguments (NULL pointers). int WebRtcSpl_RealForwardFFTC(struct RealFFT* self, const int16_t* real_data_in, int16_t* complex_data_out); // Compute the inverse FFT for a conjugate-symmetric input sequence of length of // 2^order, where 1 < order <= MAX_FFT_ORDER. Transform length is determined by // the specification structure, which must be initialized prior to calling the // FFT function with WebRtcSpl_CreateRealFFT(). // For a transform of length M, the input sequence is represented using a packed // CCS vector of length M+2, which is explained in the comments for // WebRtcSpl_RealForwardFFTC above. // // Input Arguments: // self - pointer to preallocated and initialized FFT specification structure. // complex_data_in - the input complex signal with (2^order + 2) 16-bit // elements. For an ARM Neon platform, it must be aligned on // a 32-byte boundary. // // Output Arguments: // real_data_out - the output real signal. For an ARM Neon platform, it must // be different to complex_data_in, and aligned on a 32-byte // boundary. // // Return Value: // 0 or a positive number - a value that the elements in the |real_data_out| // should be shifted left with in order to get // correct physical values. // -1 - Error with bad arguments (NULL pointers). int WebRtcSpl_RealInverseFFTC(struct RealFFT* self, const int16_t* complex_data_in, int16_t* real_data_out); /* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /*****************************************************************************/ /* stdlib.h v4.2.0 */ /* Copyright (c) 1993-2008 Texas Instruments Incorporated */ /*****************************************************************************/ enum { AecmFalse = 0, AecmTrue }; // Errors // Warnings typedef struct { int16_t cngMode; // AECM_FALSE, AECM_TRUE (default) int16_t echoMode; // 0, 1, 2, 3 (default), 4 } AecmConfig; /* * Allocates the memory needed by the AECM. The memory needs to be * initialized separately using the WebRtcAecm_Init() function. * * Inputs Description * ------------------------------------------------------------------- * void **aecmInst Pointer to the AECM instance to be * created and initialized * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * -1: error */ int32_t WebRtcAecm_Create(void **aecmInst); /* * This function releases the memory allocated by WebRtcAecm_Create() * * Inputs Description * ------------------------------------------------------------------- * void *aecmInst Pointer to the AECM instance * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * -1: error */ int32_t WebRtcAecm_Free(void *aecmInst); /* * Initializes an AECM instance. * * Inputs Description * ------------------------------------------------------------------- * void *aecmInst Pointer to the AECM instance * int32_t sampFreq Sampling frequency of data * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * -1: error */ int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq); /* * Inserts an 80 or 160 sample block of data into the farend buffer. * * Inputs Description * ------------------------------------------------------------------- * void *aecmInst Pointer to the AECM instance * int16_t *farend In buffer containing one frame of * farend signal * int16_t nrOfSamples Number of samples in farend buffer * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * -1: error */ int32_t WebRtcAecm_BufferFarend(void* aecmInst, const int16_t* farend, int16_t nrOfSamples); /* * Runs the AECM on an 80 or 160 sample blocks of data. * * Inputs Description * ------------------------------------------------------------------- * void *aecmInst Pointer to the AECM instance * int16_t *nearendNoisy In buffer containing one frame of * reference nearend+echo signal. If * noise reduction is active, provide * the noisy signal here. * int16_t *nearendClean In buffer containing one frame of * nearend+echo signal. If noise * reduction is active, provide the * clean signal here. Otherwise pass a * NULL pointer. * int16_t nrOfSamples Number of samples in nearend buffer * int16_t msInSndCardBuf Delay estimate for sound card and * system buffers * * Outputs Description * ------------------------------------------------------------------- * int16_t *out Out buffer, one frame of processed nearend * int32_t return 0: OK * -1: error */ int32_t WebRtcAecm_Process(void* aecmInst, const int16_t* nearendNoisy, const int16_t* nearendClean, int16_t* out, int16_t nrOfSamples, int16_t msInSndCardBuf); /* * This function enables the user to set certain parameters on-the-fly * * Inputs Description * ------------------------------------------------------------------- * void *aecmInst Pointer to the AECM instance * AecmConfig config Config instance that contains all * properties to be set * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * -1: error */ int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config); /* * This function enables the user to set certain parameters on-the-fly * * Inputs Description * ------------------------------------------------------------------- * void *aecmInst Pointer to the AECM instance * * Outputs Description * ------------------------------------------------------------------- * AecmConfig *config Pointer to the config instance that * all properties will be written to * int32_t return 0: OK * -1: error */ int32_t WebRtcAecm_get_config(void *aecmInst, AecmConfig *config); /* * This function enables the user to set the echo path on-the-fly. * * Inputs Description * ------------------------------------------------------------------- * void* aecmInst Pointer to the AECM instance * void* echo_path Pointer to the echo path to be set * size_t size_bytes Size in bytes of the echo path * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * -1: error */ int32_t WebRtcAecm_InitEchoPath(void* aecmInst, const void* echo_path, size_t size_bytes); /* * This function enables the user to get the currently used echo path * on-the-fly * * Inputs Description * ------------------------------------------------------------------- * void* aecmInst Pointer to the AECM instance * void* echo_path Pointer to echo path * size_t size_bytes Size in bytes of the echo path * * Outputs Description * ------------------------------------------------------------------- * int32_t return 0: OK * -1: error */ int32_t WebRtcAecm_GetEchoPath(void* aecmInst, void* echo_path, size_t size_bytes); /* * This function enables the user to get the echo path size in bytes * * Outputs Description * ------------------------------------------------------------------- * size_t return : size in bytes */ size_t WebRtcAecm_echo_path_size_bytes(); /* * Gets the last error code. * * Inputs Description * ------------------------------------------------------------------- * void *aecmInst Pointer to the AECM instance * * Outputs Description * ------------------------------------------------------------------- * int32_t return 11000-11100: error code */ int32_t WebRtcAecm_get_error_code(void *aecmInst); /* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Performs delay estimation on block by block basis. // The return value is 0 - OK and -1 - Error, unless otherwise stated. // Releases the memory allocated by WebRtc_CreateDelayEstimatorFarend(...) // Input: // - handle : Pointer to the delay estimation far-end instance. // void WebRtc_FreeDelayEstimatorFarend(void* handle); // Allocates the memory needed by the far-end part of the delay estimation. The // memory needs to be initialized separately through // WebRtc_InitDelayEstimatorFarend(...). // // Inputs: // - spectrum_size : Size of the spectrum used both in far-end and // near-end. Used to allocate memory for spectrum // specific buffers. // - history_size : The far-end history buffer size. Note that the maximum // delay which can be estimated is controlled together // with |lookahead| through // WebRtc_CreateDelayEstimator(). // // Return value: // - void* : Created |handle|. If the memory can't be allocated or // if any of the input parameters are invalid NULL is // returned. // void* WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size); // Initializes the far-end part of the delay estimation instance returned by // WebRtc_CreateDelayEstimatorFarend(...) // Input: // - handle : Pointer to the delay estimation far-end instance. // // Output: // - handle : Initialized instance. // int WebRtc_InitDelayEstimatorFarend(void* handle); // Adds the far-end spectrum to the far-end history buffer. This spectrum is // used as reference when calculating the delay using // WebRtc_ProcessSpectrum(). // // Inputs: // - handle : Pointer to the delay estimation far-end instance. // - far_spectrum : Far-end spectrum. // - spectrum_size : The size of the data arrays (same for both far- and // near-end). // - far_q : The Q-domain of the far-end data. // // Output: // - handle : Updated far-end instance. // int WebRtc_AddFarSpectrumFix(void* handle, uint16_t* far_spectrum, int spectrum_size, int far_q); // See WebRtc_AddFarSpectrumFix() for description. int WebRtc_AddFarSpectrumFloat(void* handle, float* far_spectrum, int spectrum_size); // Releases the memory allocated by WebRtc_CreateDelayEstimator(...) // Input: // - handle : Pointer to the delay estimation instance. // void WebRtc_FreeDelayEstimator(void* handle); // Allocates the memory needed by the delay estimation. The memory needs to be // initialized separately through WebRtc_InitDelayEstimator(...). // // Inputs: // - farend_handle : Pointer to the far-end part of the delay estimation // instance created prior to this call using // WebRtc_CreateDelayEstimatorFarend(). // // Note that WebRtc_CreateDelayEstimator does not take // ownership of |farend_handle|, which has to be torn // down properly after this instance. // // - lookahead : Amount of non-causal lookahead to use. This can // detect cases in which a near-end signal occurs before // the corresponding far-end signal. It will delay the // estimate for the current block by an equal amount, // and the returned values will be offset by it. // // A value of zero is the typical no-lookahead case. // This also represents the minimum delay which can be // estimated. // // Note that the effective range of delay estimates is // [-|lookahead|,... ,|history_size|-|lookahead|) // where |history_size| was set upon creating the far-end // history buffer size. // // Return value: // - void* : Created |handle|. If the memory can't be allocated or // if any of the input parameters are invalid NULL is // returned. // void* WebRtc_CreateDelayEstimator(void* farend_handle, int lookahead); // Initializes the delay estimation instance returned by // WebRtc_CreateDelayEstimator(...) // Input: // - handle : Pointer to the delay estimation instance. // // Output: // - handle : Initialized instance. // int WebRtc_InitDelayEstimator(void* handle); // Estimates and returns the delay between the far-end and near-end blocks. The // value will be offset by the lookahead (i.e. the lookahead should be // subtracted from the returned value). // Inputs: // - handle : Pointer to the delay estimation instance. // - near_spectrum : Pointer to the near-end spectrum data of the current // block. // - spectrum_size : The size of the data arrays (same for both far- and // near-end). // - near_q : The Q-domain of the near-end data. // // Output: // - handle : Updated instance. // // Return value: // - delay : >= 0 - Calculated delay value. // -1 - Error. // -2 - Insufficient data for estimation. // int WebRtc_DelayEstimatorProcessFix(void* handle, uint16_t* near_spectrum, int spectrum_size, int near_q); // See WebRtc_DelayEstimatorProcessFix() for description. int WebRtc_DelayEstimatorProcessFloat(void* handle, float* near_spectrum, int spectrum_size); // Returns the last calculated delay updated by the function // WebRtc_DelayEstimatorProcess(...). // // Input: // - handle : Pointer to the delay estimation instance. // // Return value: // - delay : >= 0 - Last calculated delay value. // -1 - Error. // -2 - Insufficient data for estimation. // int WebRtc_last_delay(void* handle); // Returns the estimation quality/probability of the last calculated delay // updated by the function WebRtc_DelayEstimatorProcess(...). The estimation // quality is a value in the interval [0, 1] in Q9. The higher the value, the // better quality. // // Input: // - handle : Pointer to the delay estimation instance. // // Return value: // - delay_quality : >= 0 - Estimation quality (in Q9) of last calculated // delay value. // -1 - Error. // -2 - Insufficient data for estimation. // int WebRtc_last_delay_quality(void* handle); /* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* Use this macro to verify at compile time that certain restrictions are met. * The argument is the boolean expression to evaluate. * Example: * COMPILE_ASSERT(sizeof(foo) < 128); */ /* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ typedef unsigned long uint64_t; //#include // List of features in x86. typedef enum { kSSE2, kSSE3 } CPUFeature; // List of features in ARM. enum { kCPUFeatureARMv7 = (1 << 0), kCPUFeatureVFPv3 = (1 << 1), kCPUFeatureNEON = (1 << 2), kCPUFeatureLDREXSTREX = (1 << 3) }; typedef int (*WebRtc_CPUInfo)(CPUFeature feature); // Returns true if the CPU supports the feature. extern WebRtc_CPUInfo WebRtc_GetCPUInfo; // No CPU feature is available => straight C path. extern WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM; // Return the features in an ARM device. // It detects the features in the hardware platform, and returns supported // values in the above enum definition as a bitmask. extern uint64_t WebRtc_GetCPUFeaturesARM(void); // Square root of Hanning window in Q14. static const int16_t WebRtcAecm_kSqrtHanning[] = { 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172, 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514, 11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079, 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034, 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384}; //Q15 alpha = 0.99439986968132 const Factor for magnitude approximation static const uint16_t kAlpha1 = 32584; //Q15 beta = 0.12967166976970 const Factor for magnitude approximation static const uint16_t kBeta1 = 4249; //Q15 alpha = 0.94234827210087 const Factor for magnitude approximation static const uint16_t kAlpha2 = 30879; //Q15 beta = 0.33787806009150 const Factor for magnitude approximation static const uint16_t kBeta2 = 11072; //Q15 alpha = 0.82247698684306 const Factor for magnitude approximation static const uint16_t kAlpha3 = 26951; //Q15 beta = 0.57762063060713 const Factor for magnitude approximation static const uint16_t kBeta3 = 18927; // Initialization table for echo channel in 8 kHz static const int16_t kChannelStored8kHz[(64 + 1)] = { 2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418, 1451, 1506, 1562, 1644, 1726, 1804, 1882, 1918, 1953, 1982, 2010, 2025, 2040, 2034, 2027, 2021, 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683, 1635, 1604, 1572, 1545, 1517, 1481, 1444, 1405, 1367, 1331, 1294, 1270, 1245, 1239, 1233, 1247, 1260, 1282, 1303, 1338, 1373, 1407, 1441, 1470, 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649, 1676 }; // Initialization table for echo channel in 16 kHz static const int16_t kChannelStored16kHz[(64 + 1)] = { 2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882, 1953, 2010, 2040, 2027, 2014, 1980, 1869, 1732, 1635, 1572, 1517, 1444, 1367, 1294, 1245, 1233, 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621, 1676, 1741, 1802, 1861, 1921, 1983, 2040, 2102, 2170, 2265, 2375, 2515, 2651, 2781, 2922, 3075, 3253, 3471, 3738, 3976, 4151, 4258, 4308, 4288, 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484, 3153 }; static const int16_t kCosTable[] = { 8192, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112, 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647, 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, 7094, 7021, 6947, 6870, 6791, 6710, 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991, 5892, 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, 3719, 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667, 2531, 2395, 2258, 2120, 1981, 1842, 1703, 1563, 1422, 1281, 1140, 998, 856, 713, 571, 428, 285, 142, 0, -142, -285, -428, -571, -713, -856, -998, -1140, -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698, -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233, -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112, -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834, -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362, -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710, -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845, -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667, -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281, -1140, -998, -856, -713, -571, -428, -285, -142, 0, 142, 285, 428, 571, 713, 856, 998, 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120, 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698, 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542, 6627, 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745, 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190 }; static const int16_t kSinTable[] = { 0, 142, 285, 428, 571, 713, 856, 998, 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120, 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698, 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542, 6627, 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745, 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190, 8191, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112, 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647, 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, 7094, 7021, 6947, 6870, 6791, 6710, 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991, 5892, 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, 3719, 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667, 2531, 2395, 2258, 2120, 1981, 1842, 1703, 1563, 1422, 1281, 1140, 998, 856, 713, 571, 428, 285, 142, 0, -142, -285, -428, -571, -713, -856, -998, -1140, -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698, -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233, -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112, -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834, -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362, -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710, -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845, -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667, -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281, -1140, -998, -856, -713, -571, -428, -285, -142 }; static const int16_t kNoiseEstQDomain = 15; static const int16_t kNoiseEstIncCount = 5; static void ComfortNoise(AecmCore_t* aecm, const uint16_t* dfa, complex16_t* out, const int16_t* lambda); static int16_t CalcSuppressionGain(AecmCore_t * const aecm); // Moves the pointer to the next entry and inserts |far_spectrum| and // corresponding Q-domain in its buffer. // // Inputs: // - self : Pointer to the delay estimation instance // - far_spectrum : Pointer to the far end spectrum // - far_q : Q-domain of far end spectrum // static void UpdateFarHistory(AecmCore_t* self, uint16_t* far_spectrum, int far_q) { // Get new buffer position self->far_history_pos++; if (self->far_history_pos >= 100) { self->far_history_pos = 0; } // Update Q-domain buffer self->far_q_domains[self->far_history_pos] = far_q; // Update far end spectrum buffer memcpy(&(self->far_history[self->far_history_pos * (64 + 1)]), far_spectrum, sizeof(uint16_t) * (64 + 1)); } // Returns a pointer to the far end spectrum aligned to current near end // spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been // called before AlignedFarend(...). Otherwise, you get the pointer to the // previous frame. The memory is only valid until the next call of // WebRtc_DelayEstimatorProcessFix(...). // // Inputs: // - self : Pointer to the AECM instance. // - delay : Current delay estimate. // // Output: // - far_q : The Q-domain of the aligned far end spectrum // // Return value: // - far_spectrum : Pointer to the aligned far end spectrum // NULL - Error // static const uint16_t* AlignedFarend(AecmCore_t* self, int* far_q, int delay) { int buffer_position = 0; _assert((self != 0) != 0, "Assertion failed, (" "self != 0" "), file " "D:/ti/myprojects/vcs/dtmf_aec/webrtc/modules/audio_processing/aecm/aecm_core.c" ", line " "230" "\n"); buffer_position = self->far_history_pos - delay; // Check buffer position if (buffer_position < 0) { buffer_position += 100; } // Get Q-domain *far_q = self->far_q_domains[buffer_position]; // Return far end spectrum return &(self->far_history[buffer_position * (64 + 1)]); } // Declare function pointers. CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;//__attribute__((far)); StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; int WebRtcAecm_CreateCore(AecmCore_t **aecmInst) { AecmCore_t *aecm = malloc(sizeof(AecmCore_t)); *aecmInst = aecm; if (aecm == 0) { return -1; } aecm->farFrameBuf = WebRtc_CreateBuffer(80 + 64, sizeof(int16_t)); if (!aecm->farFrameBuf) { WebRtcAecm_FreeCore(aecm); aecm = 0; return -1; } aecm->nearNoisyFrameBuf = WebRtc_CreateBuffer(80 + 64, sizeof(int16_t)); if (!aecm->nearNoisyFrameBuf) { WebRtcAecm_FreeCore(aecm); aecm = 0; return -1; } aecm->nearCleanFrameBuf = WebRtc_CreateBuffer(80 + 64, sizeof(int16_t)); if (!aecm->nearCleanFrameBuf) { WebRtcAecm_FreeCore(aecm); aecm = 0; return -1; } aecm->outFrameBuf = WebRtc_CreateBuffer(80 + 64, sizeof(int16_t)); if (!aecm->outFrameBuf) { WebRtcAecm_FreeCore(aecm); aecm = 0; return -1; } aecm->delay_estimator_farend = WebRtc_CreateDelayEstimatorFarend((64 + 1), 100); if (aecm->delay_estimator_farend == 0) { WebRtcAecm_FreeCore(aecm); aecm = 0; return -1; } aecm->delay_estimator = WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0); if (aecm->delay_estimator == 0) { WebRtcAecm_FreeCore(aecm); aecm = 0; return -1; } // aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT); //modified by DDC aecm->real_fft = WebRtcSpl_CreateRealFFTC(7); if (aecm->real_fft == 0) { WebRtcAecm_FreeCore(aecm); aecm = 0; return -1; } // Init some aecm pointers. 16 and 32 byte alignment is only necessary // for Neon code currently. aecm->xBuf = (int16_t*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31); aecm->dBufClean = (int16_t*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31); aecm->dBufNoisy = (int16_t*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31); aecm->outBuf = (int16_t*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15); aecm->channelStored = (int16_t*) (((uintptr_t) aecm->channelStored_buf + 15) & ~ 15); aecm->channelAdapt16 = (int16_t*) (((uintptr_t) aecm->channelAdapt16_buf + 15) & ~ 15); aecm->channelAdapt32 = (int32_t*) (((uintptr_t) aecm->channelAdapt32_buf + 31) & ~ 31); return 0; } void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const int16_t* echo_path) { int i = 0; // Reset the stored channel memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * (64 + 1)); // Reset the adapted channels memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * (64 + 1)); for (i = 0; i < (64 + 1); i++) { aecm->channelAdapt32[i] = (((int32_t)(aecm->channelAdapt16[i])) << (16)); } // Reset channel storing variables aecm->mseAdaptOld = 1000; aecm->mseStoredOld = 1000; aecm->mseThreshold = (int32_t)0x7fffffff; aecm->mseChannelCount = 0; } static void WindowAndFFT(AecmCore_t* aecm, int16_t* fft, const int16_t* time_signal, complex16_t* freq_signal, int time_signal_scaling) { int i = 0; // FFT of signal for (i = 0; i < 64; i++) { // Window time domain signal and insert into real part of // transformation array |fft| fft[i] = (int16_t)(((int32_t) (((int16_t)((time_signal[i] << time_signal_scaling))) * ((int16_t)(WebRtcAecm_kSqrtHanning[i])))) >> (14)); fft[64 + i] = (int16_t)(((int32_t) (((int16_t)((time_signal[i + 64] << time_signal_scaling))) * ((int16_t)(WebRtcAecm_kSqrtHanning[64 - i])))) >> (14)); } // Do forward FFT, then take only the first PART_LEN complex samples, // and change signs of the imaginary parts. // WebRtcSpl_RealForwardFFT(aecm->real_fft, fft, (int16_t*)freq_signal); WebRtcSpl_RealForwardFFTC(aecm->real_fft, fft, (int16_t*)freq_signal); //modified by DDC for (i = 0; i < 64; i++) { freq_signal[i].imag = -freq_signal[i].imag; } } static void InverseFFTAndWindow(AecmCore_t* aecm, int16_t* fft, complex16_t* efw, int16_t* output, const int16_t* nearendClean) { int i, j, outCFFT; int32_t tmp32no1; // Reuse |efw| for the inverse FFT output after transferring // the contents to |fft|. int16_t* ifft_out = (int16_t*)efw; // Synthesis for (i = 1, j = 2; i < 64; i += 1, j += 2) { fft[j] = efw[i].real; fft[j + 1] = -efw[i].imag; } fft[0] = efw[0].real; fft[1] = -efw[0].imag; fft[(64 << 1)] = efw[64].real; fft[(64 << 1) + 1] = -efw[64].imag; // Inverse FFT. Keep outCFFT to scale the samples in the next block. // outCFFT = WebRtcSpl_RealInverseFFT(aecm->real_fft, fft, ifft_out); outCFFT = WebRtcSpl_RealInverseFFTC(aecm->real_fft, fft, ifft_out); //modified by DDC for (i = 0; i < 64; i++) { ifft_out[i] = (int16_t)((((int32_t) (((int16_t)(ifft_out[i])) * ((int16_t)(WebRtcAecm_kSqrtHanning[i])))) + ((int32_t) (((int32_t)1) << ((14) - 1)))) >> (14)); tmp32no1 = (((outCFFT - aecm->dfaCleanQDomain) >= 0) ? (((int32_t)ifft_out[i]) << (outCFFT - aecm->dfaCleanQDomain)) : (((int32_t)ifft_out[i]) >> (-(outCFFT - aecm->dfaCleanQDomain)))); output[i] = (int16_t)(tmp32no1 + aecm->outBuf[i] > 32767 ? 32767 : tmp32no1 + aecm->outBuf[i] < -32768 ? -32768 : tmp32no1 + aecm->outBuf[i]); tmp32no1 = (((int32_t) (((int16_t)(ifft_out[64 + i])) * ((int16_t)(WebRtcAecm_kSqrtHanning[64 - i])))) >> (14)); tmp32no1 = (((outCFFT - aecm->dfaCleanQDomain) >= 0) ? ((tmp32no1) << (outCFFT - aecm->dfaCleanQDomain)) : ((tmp32no1) >> (-(outCFFT - aecm->dfaCleanQDomain)))); aecm->outBuf[i] = (int16_t)(tmp32no1 > 32767 ? 32767 : tmp32no1 < -32768 ? -32768 : tmp32no1); } // Copy the current block to the old position (aecm->outBuf is shifted elsewhere) memcpy(aecm->xBuf, aecm->xBuf + 64, sizeof(int16_t) * 64); memcpy(aecm->dBufNoisy, aecm->dBufNoisy + 64, sizeof(int16_t) * 64); if (nearendClean != 0) { memcpy(aecm->dBufClean, aecm->dBufClean + 64, sizeof(int16_t) * 64); } } static void CalcLinearEnergiesC(AecmCore_t* aecm, const uint16_t* far_spectrum, int32_t* echo_est, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored) { int i; //return; // Get energy for the delayed far end signal and estimated // echo using both stored and adapted channels. for (i = 0; i < (64 + 1); i++) { echo_est[i] = ((int32_t)(int16_t)(aecm->channelStored[i]) * (uint16_t)(far_spectrum[i])); (*far_energy) += (uint32_t)(far_spectrum[i]); (*echo_energy_adapt) += ((uint32_t) (uint16_t)(aecm->channelAdapt16[i]) * (uint16_t)(far_spectrum[i])); (*echo_energy_stored) += (uint32_t)echo_est[i]; } } static void StoreAdaptiveChannelC(AecmCore_t* aecm, const uint16_t* far_spectrum, int32_t* echo_est) { int i; // During startup we store the channel every block. memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(int16_t) * (64 + 1)); // Recalculate echo estimate for (i = 0; i < 64; i += 4) { echo_est[i] = ((int32_t)(int16_t)(aecm->channelStored[i]) * (uint16_t)(far_spectrum[i])); echo_est[i + 1] = ((int32_t)(int16_t)(aecm->channelStored[i + 1]) * (uint16_t)(far_spectrum[i + 1])); echo_est[i + 2] = ((int32_t)(int16_t)(aecm->channelStored[i + 2]) * (uint16_t)(far_spectrum[i + 2])); echo_est[i + 3] = ((int32_t)(int16_t)(aecm->channelStored[i + 3]) * (uint16_t)(far_spectrum[i + 3])); } echo_est[i] = ((int32_t)(int16_t)(aecm->channelStored[i]) * (uint16_t)(far_spectrum[i])); } static void ResetAdaptiveChannelC(AecmCore_t* aecm) { int i; // The stored channel has a significantly lower MSE than the adaptive one for // two consecutive calculations. Reset the adaptive channel. memcpy(aecm->channelAdapt16, aecm->channelStored, sizeof(int16_t) * (64 + 1)); // Restore the W32 channel for (i = 0; i < 64; i += 4) { aecm->channelAdapt32[i] = (((int32_t)aecm->channelStored[i]) << (16)); aecm->channelAdapt32[i + 1] = (((int32_t)aecm->channelStored[i + 1]) << (16)); aecm->channelAdapt32[i + 2] = (((int32_t)aecm->channelStored[i + 2]) << (16)); aecm->channelAdapt32[i + 3] = (((int32_t)aecm->channelStored[i + 3]) << (16)); } aecm->channelAdapt32[i] = (((int32_t)aecm->channelStored[i]) << (16)); } // Initialize function pointers for ARM Neon platform. // WebRtcAecm_InitCore(...) // // This function initializes the AECM instant created with WebRtcAecm_CreateCore(...) // Input: // - aecm : Pointer to the Echo Suppression instance // - samplingFreq : Sampling Frequency // // Output: // - aecm : Initialized instance // // Return value : 0 - Ok // -1 - Error // int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq) { int i = 0; int32_t tmp32 = (64 + 1) * (64 + 1); int16_t tmp16 = (64 + 1); if (samplingFreq != 8000 && samplingFreq != 16000) { samplingFreq = 8000; return -1; } // sanity check of sampling frequency aecm->mult = (int16_t)samplingFreq / 8000; aecm->farBufWritePos = 0; aecm->farBufReadPos = 0; aecm->knownDelay = 0; aecm->lastKnownDelay = 0; WebRtc_InitBuffer(aecm->farFrameBuf); WebRtc_InitBuffer(aecm->nearNoisyFrameBuf); WebRtc_InitBuffer(aecm->nearCleanFrameBuf); WebRtc_InitBuffer(aecm->outFrameBuf); memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf)); memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf)); memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf)); memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf)); aecm->seed = 666; aecm->totCount = 0; if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) { return -1; } if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) { return -1; } // Set far end histories to zero memset(aecm->far_history, 0, sizeof(uint16_t) * (64 + 1) * 100); memset(aecm->far_q_domains, 0, sizeof(int) * 100); aecm->far_history_pos = 100; aecm->nlpFlag = 1; aecm->fixedDelay = -1; aecm->dfaCleanQDomain = 0; aecm->dfaCleanQDomainOld = 0; aecm->dfaNoisyQDomain = 0; aecm->dfaNoisyQDomainOld = 0; memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy)); aecm->farLogEnergy = 0; memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy)); memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy)); // Initialize the echo channels with a stored shape. if (samplingFreq == 8000) { WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz); } else { WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz); } memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt)); memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt)); aecm->noiseEstCtr = 0; aecm->cngMode = AecmTrue; memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr)); memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr)); // Shape the initial noise level to an approximate pink noise. for (i = 0; i < ((64 + 1) >> 1) - 1; i++) { aecm->noiseEst[i] = (tmp32 << 8); tmp16--; tmp32 -= (int32_t)((tmp16 << 1) + 1); } for (; i < (64 + 1); i++) { aecm->noiseEst[i] = (tmp32 << 8); } aecm->farEnergyMin = 32767; aecm->farEnergyMax = -32768; aecm->farEnergyMaxMin = 0; aecm->farEnergyVAD = 1025; // This prevents false speech detection at the // beginning. aecm->farEnergyMSE = 0; aecm->currentVADValue = 0; aecm->vadUpdateCount = 0; aecm->firstVAD = 1; aecm->startupState = 0; aecm->supGain = (1 << 8); aecm->supGainOld = (1 << 8); aecm->supGainErrParamA = 3072; aecm->supGainErrParamD = (1 << 8); aecm->supGainErrParamDiffAB = 3072 - 1536; aecm->supGainErrParamDiffBD = 1536 - (1 << 8); // Assert a preprocessor definition at compile-time. It's an assumption // used in assembly code, so check the assembly files before any change. switch(0){case 0: case 64 % 16 == 0:;}; // Initialize function pointers. WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC; WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC; WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC; return 0; } // DO(bjornv): This function is currently not used. Add support for these // parameters from a higher level int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag) { aecm->nlpFlag = nlpFlag; aecm->fixedDelay = delay; return 0; } int WebRtcAecm_FreeCore(AecmCore_t *aecm) { if (aecm == 0) { return -1; } WebRtc_FreeBuffer(aecm->farFrameBuf); WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf); WebRtc_FreeBuffer(aecm->nearCleanFrameBuf); WebRtc_FreeBuffer(aecm->outFrameBuf); WebRtc_FreeDelayEstimator(aecm->delay_estimator); WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend); // WebRtcSpl_FreeRealFFT(aecm->real_fft); //modified by DDC WebRtcSpl_FreeRealFFTC(aecm->real_fft); free(aecm); return 0; } int WebRtcAecm_ProcessFrame(AecmCore_t * aecm, const int16_t * farend, const int16_t * nearendNoisy, const int16_t * nearendClean, int16_t * out) { int16_t outBlock_buf[64 + 8]; // Align buffer to 8-byte boundary. int16_t* outBlock = (int16_t*) (((uintptr_t) outBlock_buf + 15) & ~ 15); int16_t farFrame[80]; const int16_t* out_ptr = 0; int size = 0; // Buffer the current frame. // Fetch an older one corresponding to the delay. WebRtcAecm_BufferFarFrame(aecm, farend, 80); WebRtcAecm_FetchFarFrame(aecm, farFrame, 80, aecm->knownDelay); // Buffer the synchronized far and near frames, // to pass the smaller blocks individually. WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, 80); WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, 80); if (nearendClean != 0) { WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, 80); } // Process as many blocks as possible. while (WebRtc_available_read(aecm->farFrameBuf) >= 64) { int16_t far_block[64]; const int16_t* far_block_ptr = 0; int16_t near_noisy_block[64]; const int16_t* near_noisy_block_ptr = 0; WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block, 64); WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf, (void**) &near_noisy_block_ptr, near_noisy_block, 64); if (nearendClean != 0) { int16_t near_clean_block[64]; const int16_t* near_clean_block_ptr = 0; WebRtc_ReadBuffer(aecm->nearCleanFrameBuf, (void**) &near_clean_block_ptr, near_clean_block, 64); if (WebRtcAecm_ProcessBlock(aecm, far_block_ptr, near_noisy_block_ptr, near_clean_block_ptr, outBlock) == -1) { return -1; } } else { if (WebRtcAecm_ProcessBlock(aecm, far_block_ptr, near_noisy_block_ptr, 0, outBlock) == -1) { return -1; } } WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, 64); } // Stuff the out buffer if we have less than a frame to output. // This should only happen for the first frame. size = (int) WebRtc_available_read(aecm->outFrameBuf); if (size < 80) { WebRtc_MoveReadPtr(aecm->outFrameBuf, size - 80); } // Obtain an output frame. WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, 80); if (out_ptr != out) { // ReadBuffer() hasn't copied to |out| in this case. memcpy(out, out_ptr, 80 * sizeof(int16_t)); } return 0; } // WebRtcAecm_AsymFilt(...) // // Performs asymmetric filtering. // // Inputs: // - filtOld : Previous filtered value. // - inVal : New input value. // - stepSizePos : Step size when we have a positive contribution. // - stepSizeNeg : Step size when we have a negative contribution. // // Output: // // Return: - Filtered value. // int16_t WebRtcAecm_AsymFilt(const int16_t filtOld, const int16_t inVal, const int16_t stepSizePos, const int16_t stepSizeNeg) { int16_t retVal; if ((filtOld == 32767) | (filtOld == -32768)) { return inVal; } retVal = filtOld; if (filtOld > inVal) { retVal -= ((filtOld - inVal) >> (stepSizeNeg)); } else { retVal += ((inVal - filtOld) >> (stepSizePos)); } return retVal; } // WebRtcAecm_CalcEnergies(...) // // This function calculates the log of energies for nearend, farend and estimated // echoes. There is also an update of energy decision levels, i.e. internal VAD. // // // @param aecm [i/o] Handle of the AECM instance. // @param far_spectrum [in] Pointer to farend spectrum. // @param far_q [in] Q-domain of farend spectrum. // @param nearEner [in] Near end energy for current block in // Q(aecm->dfaQDomain). // @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16). // void WebRtcAecm_CalcEnergies(AecmCore_t * aecm, const uint16_t* far_spectrum, const int16_t far_q, const uint32_t nearEner, int32_t * echoEst) { // Local variables uint32_t tmpAdapt = 0; uint32_t tmpStored = 0; uint32_t tmpFar = 0; int i; int16_t zeros, frac; int16_t tmp16; int16_t increase_max_shifts = 4; int16_t decrease_max_shifts = 11; int16_t increase_min_shifts = 11; int16_t decrease_min_shifts = 3; int16_t kLogLowValue = ((7) << (7)); // Get log of near end energy and store in buffer // Shift buffer memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy, sizeof(int16_t) * (64 - 1)); // Logarithm of integrated magnitude spectrum (nearEner) tmp16 = kLogLowValue; if (nearEner) { zeros = WebRtcSpl_NormU32(nearEner); frac = (int16_t)((uint32_t)((((uint32_t)(nearEner) << (zeros)) & 0x7FFFFFFF)) >> (23)); // log2 in Q8 tmp16 += (((31 - zeros)) << (8)) + frac; tmp16 -= ((aecm->dfaNoisyQDomain) << (8)); } // return; aecm->nearLogEnergy[0] = tmp16; // END: Get log of near end energy // return; // WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored); CalcLinearEnergiesC(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored);// modified by DDC // Shift buffers memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy, sizeof(int16_t) * (64 - 1)); memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy, sizeof(int16_t) * (64 - 1)); // Logarithm of delayed far end energy tmp16 = kLogLowValue; if (tmpFar) { zeros = WebRtcSpl_NormU32(tmpFar); frac = (int16_t)((uint32_t)((((uint32_t)(tmpFar) << (zeros)) & 0x7FFFFFFF)) >> (23)); // log2 in Q8 tmp16 += (((31 - zeros)) << (8)) + frac; tmp16 -= ((far_q) << (8)); } aecm->farLogEnergy = tmp16; // Logarithm of estimated echo energy through adapted channel tmp16 = kLogLowValue; if (tmpAdapt) { zeros = WebRtcSpl_NormU32(tmpAdapt); frac = (int16_t)((uint32_t)((((uint32_t)(tmpAdapt) << (zeros)) & 0x7FFFFFFF)) >> (23)); //log2 in Q8 tmp16 += (((31 - zeros)) << (8)) + frac; tmp16 -= ((12 + far_q) << (8)); } aecm->echoAdaptLogEnergy[0] = tmp16; // Logarithm of estimated echo energy through stored channel tmp16 = kLogLowValue; if (tmpStored) { zeros = WebRtcSpl_NormU32(tmpStored); frac = (int16_t)((uint32_t)((((uint32_t)(tmpStored) << (zeros)) & 0x7FFFFFFF)) >> (23)); //log2 in Q8 tmp16 += (((31 - zeros)) << (8)) + frac; tmp16 -= ((12 + far_q) << (8)); } aecm->echoStoredLogEnergy[0] = tmp16; // Update farend energy levels (min, max, vad, mse) if (aecm->farLogEnergy > 1025) { if (aecm->startupState == 0) { increase_max_shifts = 2; decrease_min_shifts = 2; increase_min_shifts = 8; } aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy, increase_min_shifts, decrease_min_shifts); aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy, increase_max_shifts, decrease_max_shifts); aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin); // Dynamic VAD region size tmp16 = 2560 - aecm->farEnergyMin; if (tmp16 > 0) { tmp16 = (int16_t)(((int32_t) (((int16_t)(tmp16)) * ((int16_t)(230)))) >> (9)); } else { tmp16 = 0; } tmp16 += 230; if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024)) { // In startup phase or VAD update halted aecm->farEnergyVAD = aecm->farEnergyMin + tmp16; } else { if (aecm->farEnergyVAD > aecm->farLogEnergy) { aecm->farEnergyVAD += ((aecm->farLogEnergy + tmp16 - aecm->farEnergyVAD) >> (6)); aecm->vadUpdateCount = 0; } else { aecm->vadUpdateCount++; } } // Put MSE threshold higher than VAD aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8); } // Update VAD variables if (aecm->farLogEnergy > aecm->farEnergyVAD) { if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > 929)) { // We are in startup or have significant dynamics in input speech level aecm->currentVADValue = 1; } } else { aecm->currentVADValue = 0; } if ((aecm->currentVADValue) && (aecm->firstVAD)) { aecm->firstVAD = 0; if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0]) { // The estimated echo has higher energy than the near end signal. // This means that the initialization was too aggressive. Scale // down by a factor 8 for (i = 0; i < (64 + 1); i++) { aecm->channelAdapt16[i] >>= 3; } // Compensate the adapted echo energy level accordingly. aecm->echoAdaptLogEnergy[0] -= (3 << 8); aecm->firstVAD = 1; } } } // WebRtcAecm_CalcStepSize(...) // // This function calculates the step size used in channel estimation // // // @param aecm [in] Handle of the AECM instance. // @param mu [out] (Return value) Stepsize in log2(), i.e. number of shifts. // // int16_t WebRtcAecm_CalcStepSize(AecmCore_t * const aecm) { int32_t tmp32; int16_t tmp16; int16_t mu = 1; // Here we calculate the step size mu used in the // following NLMS based Channel estimation algorithm if (!aecm->currentVADValue) { // Far end energy level too low, no channel update mu = 0; } else if (aecm->startupState > 0) { if (aecm->farEnergyMin >= aecm->farEnergyMax) { mu = 10; } else { tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin); tmp32 = ((int32_t) (((int16_t)(tmp16)) * ((int16_t)(9)))); tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin); mu = 10 - 1 - (int16_t)(tmp32); // The -1 is an alternative to rounding. This way we get a larger // stepsize, so we in some sense compensate for truncation in NLMS } if (mu < 1) { mu = 1; // Equivalent with maximum step size of 2^-MU_MAX } } return mu; } // WebRtcAecm_UpdateChannel(...) // // This function performs channel estimation. NLMS and decision on channel storage. // // // @param aecm [i/o] Handle of the AECM instance. // @param far_spectrum [in] Absolute value of the farend signal in Q(far_q) // @param far_q [in] Q-domain of the farend signal // @param dfa [in] Absolute value of the nearend signal (Q[aecm->dfaQDomain]) // @param mu [in] NLMS step size. // @param echoEst [i/o] Estimated echo in Q(far_q+RESOLUTION_CHANNEL16). // void WebRtcAecm_UpdateChannel(AecmCore_t * aecm, const uint16_t* far_spectrum, const int16_t far_q, const uint16_t * const dfa, const int16_t mu, int32_t * echoEst) { uint32_t tmpU32no1, tmpU32no2; int32_t tmp32no1, tmp32no2; int32_t mseStored; int32_t mseAdapt; int i; int16_t zerosFar, zerosNum, zerosCh, zerosDfa; int16_t shiftChFar, shiftNum, shift2ResChan; int16_t tmp16no1; int16_t xfaQ, dfaQ; // return; // This is the channel estimation algorithm. It is base on NLMS but has a variable step // length, which was calculated above. if (mu) { for (i = 0; i < (64 + 1); i++) { // Determine norm of channel and farend to make sure we don't get overflow in // multiplication zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]); zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]); if (zerosCh + zerosFar > 31) { // Multiplication is safe tmpU32no1 = ((uint32_t) ((uint32_t)(aecm->channelAdapt32[i]) * (uint16_t)(far_spectrum[i]))); shiftChFar = 0; } else { // We need to shift down before multiplication shiftChFar = 32 - zerosCh - zerosFar; tmpU32no1 = ((uint32_t) ((uint32_t)(((aecm->channelAdapt32[i]) >> (shiftChFar))) * (uint16_t)(far_spectrum[i]))); } // Determine Q-domain of numerator zerosNum = WebRtcSpl_NormU32(tmpU32no1); if (dfa[i]) { zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]); } else { zerosDfa = 32; } tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain - 28 - far_q + shiftChFar; if (zerosNum > tmp16no1 + 1) { xfaQ = tmp16no1; dfaQ = zerosDfa - 2; } else { xfaQ = zerosNum - 2; dfaQ = 28 + far_q - aecm->dfaNoisyQDomain - shiftChFar + xfaQ; } // Add in the same Q-domain tmpU32no1 = (((xfaQ) >= 0) ? ((tmpU32no1) << (xfaQ)) : ((tmpU32no1) >> (-(xfaQ)))); tmpU32no2 = (((dfaQ) >= 0) ? (((uint32_t)dfa[i]) << (dfaQ)) : (((uint32_t)dfa[i]) >> (-(dfaQ)))); tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1; zerosNum = WebRtcSpl_NormW32(tmp32no1); if ((tmp32no1) && (far_spectrum[i] > (16 << far_q))) { // // Update is needed // // This is what we would like to compute // // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i]) // tmp32norm = (i + 1) // aecm->channelAdapt[i] += (2^mu) * tmp32no1 // / (tmp32norm * far_spectrum[i]) // // Make sure we don't get overflow in multiplication. if (zerosNum + zerosFar > 31) { if (tmp32no1 > 0) { tmp32no2 = (int32_t)((uint32_t) ((uint32_t)(tmp32no1) * (uint16_t)(far_spectrum[i]))); } else { tmp32no2 = -(int32_t)((uint32_t) ((uint32_t)(-tmp32no1) * (uint16_t)(far_spectrum[i]))); } shiftNum = 0; } else { shiftNum = 32 - (zerosNum + zerosFar); if (tmp32no1 > 0) { tmp32no2 = (int32_t)((uint32_t) ((uint32_t)(((tmp32no1) >> (shiftNum))) * (uint16_t)(far_spectrum[i]))); } else { tmp32no2 = -(int32_t)((uint32_t) ((uint32_t)(((-tmp32no1) >> (shiftNum))) * (uint16_t)(far_spectrum[i]))); } } // Normalize with respect to frequency bin tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1); // Make sure we are in the right Q-domain shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1); if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan) { tmp32no2 = (int32_t)0x7fffffff; } else { tmp32no2 = (((shift2ResChan) >= 0) ? ((tmp32no2) << (shift2ResChan)) : ((tmp32no2) >> (-(shift2ResChan)))); } aecm->channelAdapt32[i] = WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2); if (aecm->channelAdapt32[i] < 0) { // We can never have negative channel gain aecm->channelAdapt32[i] = 0; } aecm->channelAdapt16[i] = (int16_t)((aecm->channelAdapt32[i]) >> (16)); } } } // END: Adaptive channel update //return; // Determine if we should store or restore the channel if ((aecm->startupState == 0) & (aecm->currentVADValue)) { // During startup we store the channel every block, // and we recalculate echo estimate // WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst); StoreAdaptiveChannelC(aecm, far_spectrum, echoEst); //modified by DDC } else { if (aecm->farLogEnergy < aecm->farEnergyMSE) { aecm->mseChannelCount = 0; } else { aecm->mseChannelCount++; } // Enough data for validation. Store channel if we can. if (aecm->mseChannelCount >= (20 + 10)) { // We have enough data. // Calculate MSE of "Adapt" and "Stored" versions. // It is actually not MSE, but average absolute error. mseStored = 0; mseAdapt = 0; // return; for (i = 0; i < 20; i++) { tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i] - (int32_t)aecm->nearLogEnergy[i]); tmp32no2 = (((int32_t)tmp32no1 >= 0) ? ((int32_t)tmp32no1) : -((int32_t)tmp32no1)); mseStored += tmp32no2; tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i] - (int32_t)aecm->nearLogEnergy[i]); tmp32no2 = (((int32_t)tmp32no1 >= 0) ? ((int32_t)tmp32no1) : -((int32_t)tmp32no1)); mseAdapt += tmp32no2; } // return; if (((mseStored << 5) < (29 * mseAdapt)) & ((aecm->mseStoredOld << 5) < (29 * aecm->mseAdaptOld))) { // The stored channel has a significantly lower MSE than the adaptive one for // two consecutive calculations. Reset the adaptive channel. // WebRtcAecm_ResetAdaptiveChannel(aecm); ResetAdaptiveChannelC(aecm); //modified by DDC } else if (((29 * mseStored) > (mseAdapt << 5)) & (mseAdapt < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold)) { // The adaptive channel has a significantly lower MSE than the stored one. // The MSE for the adaptive channel has also been low for two consecutive // calculations. Store the adaptive channel. // WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst); // StoreAdaptiveChannelC(aecm, far_spectrum, echoEst); //modified by DDC // Update threshold if (aecm->mseThreshold == (int32_t)0x7fffffff) { aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld); } else { aecm->mseThreshold += (((int32_t) (((int16_t)(mseAdapt - (((int32_t) (((int16_t)(aecm->mseThreshold)) * ((int16_t)(5)))) >> (3)))) * ((int16_t)(205)))) >> (8)); } } // Reset counter aecm->mseChannelCount = 0; // Store the MSE values. aecm->mseStoredOld = mseStored; aecm->mseAdaptOld = mseAdapt; } } // END: Determine if we should store or reset channel estimate. } // CalcSuppressionGain(...) // // This function calculates the suppression gain that is used in the Wiener filter. // // // @param aecm [i/n] Handle of the AECM instance. // @param supGain [out] (Return value) Suppression gain with which to scale the noise // level (Q14). // // static int16_t CalcSuppressionGain(AecmCore_t * const aecm) { int32_t tmp32no1; int16_t supGain = (1 << 8); int16_t tmp16no1; int16_t dE = 0; // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far // end energy and echo estimation error. // Adjust for the far end signal level. A low signal level indicates no far end signal, // hence we set the suppression gain to 0 if (!aecm->currentVADValue) { supGain = 0; } else { // Adjust for possible double talk. If we have large variations in estimation error we // likely have double talk (or poor channel). tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - 0); dE = (((int16_t)tmp16no1 >= 0) ? ((int16_t)tmp16no1) : -((int16_t)tmp16no1)); if (dE < 400) { // Likely no double talk. The better estimation, the more we can suppress signal. // Update counters if (dE < 200) { tmp32no1 = ((int32_t) (((int16_t)(aecm->supGainErrParamDiffAB)) * ((int16_t)(dE)))); tmp32no1 += (200 >> 1); tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, 200); supGain = aecm->supGainErrParamA - tmp16no1; } else { tmp32no1 = ((int32_t) (((int16_t)(aecm->supGainErrParamDiffBD)) * ((int16_t)((400 - dE))))); tmp32no1 += ((400 - 200) >> 1); tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, (400 - 200)); supGain = aecm->supGainErrParamD + tmp16no1; } } else { // Likely in double talk. Use default value supGain = aecm->supGainErrParamD; } } if (supGain > aecm->supGainOld) { tmp16no1 = supGain; } else { tmp16no1 = aecm->supGainOld; } aecm->supGainOld = supGain; if (tmp16no1 < aecm->supGain) { aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4); } else { aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4); } // END: Update suppression gain return aecm->supGain; } // Transforms a time domain signal into the frequency domain, outputting the // complex valued signal, absolute value and sum of absolute values. // // time_signal [in] Pointer to time domain signal // freq_signal_real [out] Pointer to real part of frequency domain array // freq_signal_imag [out] Pointer to imaginary part of frequency domain // array // freq_signal_abs [out] Pointer to absolute value of frequency domain // array // freq_signal_sum_abs [out] Pointer to the sum of all absolute values in // the frequency domain array // return value The Q-domain of current frequency values // static int TimeToFrequencyDomain(AecmCore_t* aecm, const int16_t* time_signal, complex16_t* freq_signal, uint16_t* freq_signal_abs, uint32_t* freq_signal_sum_abs) { int i = 0; int time_signal_scaling = 0; int32_t tmp32no1 = 0; int32_t tmp32no2 = 0; // In fft_buf, +16 for 32-byte alignment. int16_t fft_buf[(64 << 2) + 16]; int16_t *fft = (int16_t *) (((uintptr_t) fft_buf + 31) & ~31); int16_t tmp16no1; int16_t tmp16no2; // tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2); tmp16no1 = WebRtcSpl_MaxAbsValueW16C(time_signal, (64 << 1)); //modified by DDC time_signal_scaling = WebRtcSpl_NormW16(tmp16no1); // WindowAndFFT(aecm, fft, time_signal, freq_signal, time_signal_scaling); // Extract imaginary and real part, calculate the magnitude for all frequency bins /* freq_signal[0].imag = 0; freq_signal[PART_LEN].imag = 0; freq_signal_abs[0] = (uint16_t)WEBRTC_SPL_ABS_W16( freq_signal[0].real); freq_signal_abs[PART_LEN] = (uint16_t)WEBRTC_SPL_ABS_W16( freq_signal[PART_LEN].real); (*freq_signal_sum_abs) = (uint32_t)(freq_signal_abs[0]) + (uint32_t)(freq_signal_abs[PART_LEN]); */ for (i = 1; i < 64; i++) { if (freq_signal[i].real == 0) { freq_signal_abs[i] = (uint16_t)(((int16_t)freq_signal[i]. imag >= 0) ? ((int16_t)freq_signal[i]. imag) : -((int16_t)freq_signal[i]. imag)); } else if (freq_signal[i].imag == 0) { freq_signal_abs[i] = (uint16_t)(((int16_t)freq_signal[i]. real >= 0) ? ((int16_t)freq_signal[i]. real) : -((int16_t)freq_signal[i]. real)); } else { // Approximation for magnitude of complex fft output // magn = sqrt(real^2 + imag^2) // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|) // // The parameters alpha and beta are stored in Q15 tmp16no1 = (((int16_t)freq_signal[i]. real >= 0) ? ((int16_t)freq_signal[i]. real) : -((int16_t)freq_signal[i]. real)); tmp16no2 = (((int16_t)freq_signal[i]. imag >= 0) ? ((int16_t)freq_signal[i]. imag) : -((int16_t)freq_signal[i]. imag)); tmp32no1 = ((int32_t) (((int16_t)(tmp16no1)) * ((int16_t)(tmp16no1)))); tmp32no2 = ((int32_t) (((int16_t)(tmp16no2)) * ((int16_t)(tmp16no2)))); tmp32no2 = WebRtcSpl_AddSatW32(tmp32no1, tmp32no2); tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2); freq_signal_abs[i] = (uint16_t)tmp32no1; } (*freq_signal_sum_abs) += (uint32_t)freq_signal_abs[i]; } return time_signal_scaling; } int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, const int16_t * farend, const int16_t * nearendNoisy, const int16_t * nearendClean, int16_t * output) { int i; uint32_t xfaSum; uint32_t dfaNoisySum; uint32_t dfaCleanSum; uint32_t echoEst32Gained; uint32_t tmpU32; int32_t tmp32no1; uint16_t xfa[(64 + 1)]; uint16_t dfaNoisy[(64 + 1)]; uint16_t dfaClean[(64 + 1)]; uint16_t* ptrDfaClean = dfaClean; const uint16_t* far_spectrum_ptr = 0; // 32 byte aligned buffers (with +8 or +16). // TO (kma): define fft with complex16_t. int16_t fft_buf[(64 << 2) + 2 + 16]; // +2 to make a loop safe. int32_t echoEst32_buf[(64 + 1) + 8]; int32_t dfw_buf[(64 << 1) + 8]; int32_t efw_buf[(64 << 1) + 8]; int16_t* fft = (int16_t*) (((uintptr_t) fft_buf + 31) & ~ 31); int32_t* echoEst32 = (int32_t*) (((uintptr_t) echoEst32_buf + 31) & ~ 31); complex16_t* dfw = (complex16_t*) (((uintptr_t) dfw_buf + 31) & ~ 31); complex16_t* efw = (complex16_t*) (((uintptr_t) efw_buf + 31) & ~ 31); int16_t hnl[(64 + 1)]; int16_t numPosCoef = 0; int16_t nlpGain = (1 << 14); int delay; int16_t tmp16no1; int16_t tmp16no2; int16_t mu; int16_t supGain; int16_t zeros32, zeros16; int16_t zerosDBufNoisy, zerosDBufClean, zerosXBuf; int far_q; int16_t resolutionDiff, qDomainDiff; const int kMinPrefBand = 4; const int kMaxPrefBand = 24; int32_t avgHnl32 = 0; // Determine startup state. There are three states: // (0) the first CONV_LEN blocks // (1) another CONV_LEN blocks // (2) the rest if (aecm->startupState < 2) { aecm->startupState = (aecm->totCount >= 512) + (aecm->totCount >= (512 << 1)); } // END: Determine startup state // Buffer near and far end signals memcpy(aecm->xBuf + 64, farend, sizeof(int16_t) * 64); memcpy(aecm->dBufNoisy + 64, nearendNoisy, sizeof(int16_t) * 64); if (nearendClean != 0) { memcpy(aecm->dBufClean + 64, nearendClean, sizeof(int16_t) * 64); } // Transform far end signal from time domain to frequency domain. far_q = TimeToFrequencyDomain(aecm, aecm->xBuf, dfw, xfa, &xfaSum); // Transform noisy near end signal from time domain to frequency domain. zerosDBufNoisy = TimeToFrequencyDomain(aecm, aecm->dBufNoisy, dfw, dfaNoisy, &dfaNoisySum); aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain; aecm->dfaNoisyQDomain = (int16_t)zerosDBufNoisy; if (nearendClean == 0) { ptrDfaClean = dfaNoisy; aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld; aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain; dfaCleanSum = dfaNoisySum; } else { // Transform clean near end signal from time domain to frequency domain. zerosDBufClean = TimeToFrequencyDomain(aecm, aecm->dBufClean, dfw, dfaClean, &dfaCleanSum); aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain; aecm->dfaCleanQDomain = (int16_t)zerosDBufClean; } // Get the delay // Save far-end history and estimate delay UpdateFarHistory(aecm, xfa, far_q); // if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend, xfa, PART_LEN1, // far_q) == -1) { // return -1; // } /* delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator, dfaNoisy, PART_LEN1, zerosDBufNoisy); if (delay == -1) { return -1; } else if (delay == -2) */ { // If the delay is unknown, we assume zero. // NOTE: this will have to be adjusted if we ever add lookahead. delay = 0; } if (aecm->fixedDelay >= 0) { // Use fixed delay delay = aecm->fixedDelay; } // Get aligned far end spectrum far_spectrum_ptr = AlignedFarend(aecm, &far_q, delay); zerosXBuf = (int16_t) far_q; if (far_spectrum_ptr == 0) { return -1; } // Calculate log(energy) and update energy threshold levels WebRtcAecm_CalcEnergies(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisySum, echoEst32); // Calculate stepsize mu = WebRtcAecm_CalcStepSize(aecm); // Update counters aecm->totCount++; // This is the channel estimation algorithm. // It is base on NLMS but has a variable step length, which was calculated above. WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu, echoEst32); supGain = CalcSuppressionGain(aecm); // Calculate Wiener filter hnl[] for (i = 0; i < (64 + 1); i++) { // Far end signal through channel estimate in Q8 // How much can we shift right to preserve resolution tmp32no1 = echoEst32[i] - aecm->echoFilt[i]; aecm->echoFilt[i] += ((((tmp32no1) * (50))) >> (8)); zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1; zeros16 = WebRtcSpl_NormW16(supGain) + 1; if (zeros32 + zeros16 > 16) { // Multiplication is safe // Result in Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+aecm->xfaQDomainBuf[diff]) echoEst32Gained = ((uint32_t) ((uint32_t)((uint32_t)aecm->echoFilt[i]) * (uint16_t)((uint16_t)supGain))); resolutionDiff = 14 - 12 - 8; resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); } else { tmp16no1 = 17 - zeros32 - zeros16; resolutionDiff = 14 + tmp16no1 - 12 - 8; resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); if (zeros32 > tmp16no1) { echoEst32Gained = ((uint32_t) ((uint32_t)((uint32_t)aecm->echoFilt[i]) * (uint16_t)((uint16_t)((supGain) >> (tmp16no1))))); // Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16) } else { // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16) echoEst32Gained = ((uint32_t) ((uint32_t)((uint32_t)((aecm->echoFilt[i]) >> (tmp16no1))) * (uint16_t)((uint16_t)supGain))); } } zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]); if ((zeros16 < (aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld)) & (aecm->nearFilt[i])) { tmp16no1 = (((zeros16) >= 0) ? ((aecm->nearFilt[i]) << (zeros16)) : ((aecm->nearFilt[i]) >> (-(zeros16)))); qDomainDiff = zeros16 - aecm->dfaCleanQDomain + aecm->dfaCleanQDomainOld; } else { tmp16no1 = (((aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld) >= 0) ? ((aecm->nearFilt[i]) << (aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld)) : ((aecm->nearFilt[i]) >> (-(aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld)))); qDomainDiff = 0; } tmp16no2 = (((qDomainDiff) >= 0) ? ((ptrDfaClean[i]) << (qDomainDiff)) : ((ptrDfaClean[i]) >> (-(qDomainDiff)))); tmp32no1 = (int32_t)(tmp16no2 - tmp16no1); tmp16no2 = (int16_t)((tmp32no1) >> (4)); tmp16no2 += tmp16no1; zeros16 = WebRtcSpl_NormW16(tmp16no2); if ((tmp16no2) & (-qDomainDiff > zeros16)) { aecm->nearFilt[i] = 32767; } else { aecm->nearFilt[i] = (((-qDomainDiff) >= 0) ? ((tmp16no2) << (-qDomainDiff)) : ((tmp16no2) >> (-(-qDomainDiff)))); } // Wiener filter coefficients, resulting hnl in Q14 if (echoEst32Gained == 0) { hnl[i] = (1 << 14); } else if (aecm->nearFilt[i] == 0) { hnl[i] = 0; } else { // Multiply the suppression gain // Rounding echoEst32Gained += (uint32_t)(aecm->nearFilt[i] >> 1); tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained, (uint16_t)aecm->nearFilt[i]); // Current resolution is // Q-(RESOLUTION_CHANNEL + RESOLUTION_SUPGAIN - max(0, 17 - zeros16 - zeros32)) // Make sure we are in Q14 tmp32no1 = (int32_t)(((resolutionDiff) >= 0) ? ((tmpU32) << (resolutionDiff)) : ((tmpU32) >> (-(resolutionDiff)))); if (tmp32no1 > (1 << 14)) { hnl[i] = 0; } else if (tmp32no1 < 0) { hnl[i] = (1 << 14); } else { // 1-echoEst/dfa hnl[i] = (1 << 14) - (int16_t)tmp32no1; if (hnl[i] < 0) { hnl[i] = 0; } } } if (hnl[i]) { numPosCoef++; } } // Only in wideband. Prevent the gain in upper band from being larger than // in lower band. if (aecm->mult == 2) { // DO(bjornv): Investigate if the scaling of hnl[i] below can cause // speech distortion in double-talk. for (i = 0; i < (64 + 1); i++) { hnl[i] = (int16_t)(((int32_t) (((int16_t)(hnl[i])) * ((int16_t)(hnl[i])))) >> (14)); } for (i = kMinPrefBand; i <= kMaxPrefBand; i++) { avgHnl32 += (int32_t)hnl[i]; } _assert((kMaxPrefBand - kMinPrefBand + 1 > 0) != 0, "Assertion failed, (" "kMaxPrefBand - kMinPrefBand + 1 > 0" "), file " "D:/ti/myprojects/vcs/dtmf_aec/webrtc/modules/audio_processing/aecm/aecm_core.c" ", line " "1763" "\n"); avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1); for (i = kMaxPrefBand; i < (64 + 1); i++) { if (hnl[i] > (int16_t)avgHnl32) { hnl[i] = (int16_t)avgHnl32; } } } // Calculate NLP gain, result is in Q14 if (aecm->nlpFlag) { for (i = 0; i < (64 + 1); i++) { // Truncate values close to zero and one. if (hnl[i] > (1 << 14)) { hnl[i] = (1 << 14); } else if (hnl[i] < 3277) { hnl[i] = 0; } // Remove outliers if (numPosCoef < 3) { nlpGain = 0; } else { nlpGain = (1 << 14); } // NLP if ((hnl[i] == (1 << 14)) && (nlpGain == (1 << 14))) { hnl[i] = (1 << 14); } else { hnl[i] = (int16_t)(((int32_t) (((int16_t)(hnl[i])) * ((int16_t)(nlpGain)))) >> (14)); } // multiply with Wiener coefficients efw[i].real = (int16_t)(((((int32_t) (((int16_t)(dfw[i]. real)) * ((int16_t)(hnl[i])))) + ((int32_t) (((int32_t)1) << ((14) - 1)))) >> (14))); efw[i].imag = (int16_t)(((((int32_t) (((int16_t)(dfw[i]. imag)) * ((int16_t)(hnl[i])))) + ((int32_t) (((int32_t)1) << ((14) - 1)))) >> (14))); } } else { // multiply with Wiener coefficients for (i = 0; i < (64 + 1); i++) { efw[i].real = (int16_t)(((((int32_t) (((int16_t)(dfw[i]. real)) * ((int16_t)(hnl[i])))) + ((int32_t) (((int32_t)1) << ((14) - 1)))) >> (14))); efw[i].imag = (int16_t)(((((int32_t) (((int16_t)(dfw[i]. imag)) * ((int16_t)(hnl[i])))) + ((int32_t) (((int32_t)1) << ((14) - 1)))) >> (14))); } } if (aecm->cngMode == AecmTrue) { ComfortNoise(aecm, ptrDfaClean, efw, hnl); } // InverseFFTAndWindow(aecm, fft, efw, output, nearendClean); return 0; } // Generate comfort noise and add to output signal. // // \param[in] aecm Handle of the AECM instance. // \param[in] dfa Absolute value of the nearend signal (Q[aecm->dfaQDomain]). // \param[in,out] outReal Real part of the output signal (Q[aecm->dfaQDomain]). // \param[in,out] outImag Imaginary part of the output signal (Q[aecm->dfaQDomain]). // \param[in] lambda Suppression gain with which to scale the noise level (Q14). // static void ComfortNoise(AecmCore_t* aecm, const uint16_t* dfa, complex16_t* out, const int16_t* lambda) { int16_t i; int16_t tmp16; int32_t tmp32; int16_t randW16[64]; int16_t uReal[(64 + 1)]; int16_t uImag[(64 + 1)]; int32_t outLShift32; int16_t noiseRShift16[(64 + 1)]; int16_t shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain; int16_t minTrackShift; // assert(shiftFromNearToNoise >= 0); // assert(shiftFromNearToNoise < 16); //modified by DDC return; if (aecm->noiseEstCtr < 100) { // Track the minimum more quickly initially. aecm->noiseEstCtr++; minTrackShift = 6; } else { minTrackShift = 9; } // Estimate noise power. for (i = 0; i < (64 + 1); i++) { // Shift to the noise domain. tmp32 = (int32_t)dfa[i]; outLShift32 = ((tmp32) << (shiftFromNearToNoise)); if (outLShift32 < aecm->noiseEst[i]) { // Reset "too low" counter aecm->noiseEstTooLowCtr[i] = 0; // Track the minimum. if (aecm->noiseEst[i] < (1 << minTrackShift)) { // For small values, decrease noiseEst[i] every // |kNoiseEstIncCount| block. The regular approach below can not // go further down due to truncation. aecm->noiseEstTooHighCtr[i]++; if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount) { aecm->noiseEst[i]--; aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter } } else { aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32) >> minTrackShift); } } else { // Reset "too high" counter aecm->noiseEstTooHighCtr[i] = 0; // Ramp slowly upwards until we hit the minimum again. if ((aecm->noiseEst[i] >> 19) > 0) { // Avoid overflow. // Multiplication with 2049 will cause wrap around. Scale // down first and then multiply aecm->noiseEst[i] >>= 11; aecm->noiseEst[i] *= 2049; } else if ((aecm->noiseEst[i] >> 11) > 0) { // Large enough for relative increase aecm->noiseEst[i] *= 2049; aecm->noiseEst[i] >>= 11; } else { // Make incremental increases based on size every // |kNoiseEstIncCount| block aecm->noiseEstTooLowCtr[i]++; if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) { aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1; aecm->noiseEstTooLowCtr[i] = 0; // Reset counter } } } } for (i = 0; i < (64 + 1); i++) { tmp32 = ((aecm->noiseEst[i]) >> (shiftFromNearToNoise)); if (tmp32 > 32767) { tmp32 = 32767; aecm->noiseEst[i] = ((tmp32) << (shiftFromNearToNoise)); } noiseRShift16[i] = (int16_t)tmp32; tmp16 = (1 << 14) - lambda[i]; noiseRShift16[i] = (int16_t)(((int32_t) (((int16_t)(tmp16)) * ((int16_t)(noiseRShift16[i])))) >> (14)); } // Generate a uniform random array on [0 2^15-1]. WebRtcSpl_RandUArray(randW16, 64, &aecm->seed); // Generate noise according to estimated energy. uReal[0] = 0; // Reject LF noise. uImag[0] = 0; for (i = 1; i < (64 + 1); i++) { // Get a random index for the cos and sin tables over [0 359]. tmp16 = (int16_t)(((int32_t) (((int16_t)(359)) * ((int16_t)(randW16[i - 1])))) >> (15)); // Tables are in Q13. uReal[i] = (int16_t)(((int32_t) (((int16_t)(noiseRShift16[i])) * ((int16_t)(kCosTable[tmp16])))) >> (13)); uImag[i] = (int16_t)(((int32_t) (((int16_t)(-noiseRShift16[i])) * ((int16_t)(kSinTable[tmp16])))) >> (13)); } uImag[64] = 0; for (i = 0; i < (64 + 1); i++) { out[i].real = WebRtcSpl_AddSatW16(out[i]. real, uReal[i]); out[i].imag = WebRtcSpl_AddSatW16(out[i]. imag, uImag[i]); } } void WebRtcAecm_BufferFarFrame(AecmCore_t* const aecm, const int16_t* const farend, const int farLen) { int writeLen = farLen, writePos = 0; // Check if the write position must be wrapped while (aecm->farBufWritePos + writeLen > (64 << 2)) { // Write to remaining buffer space before wrapping writeLen = (64 << 2) - aecm->farBufWritePos; memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos, sizeof(int16_t) * writeLen); aecm->farBufWritePos = 0; writePos = writeLen; writeLen = farLen - writeLen; } memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos, sizeof(int16_t) * writeLen); aecm->farBufWritePos += writeLen; } void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, int16_t * const farend, const int farLen, const int knownDelay) { int readLen = farLen; int readPos = 0; int delayChange = knownDelay - aecm->lastKnownDelay; aecm->farBufReadPos -= delayChange; // Check if delay forces a read position wrap while (aecm->farBufReadPos < 0) { aecm->farBufReadPos += (64 << 2); } while (aecm->farBufReadPos > (64 << 2) - 1) { aecm->farBufReadPos -= (64 << 2); } aecm->lastKnownDelay = knownDelay; // Check if read position must be wrapped while (aecm->farBufReadPos + readLen > (64 << 2)) { // Read from remaining buffer space before wrapping readLen = (64 << 2) - aecm->farBufReadPos; memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos, sizeof(int16_t) * readLen); aecm->farBufReadPos = 0; readPos = readLen; readLen = farLen - readLen; } memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos, sizeof(int16_t) * readLen); aecm->farBufReadPos += readLen; }