diff options
79 files changed, 6376 insertions, 8737 deletions
diff --git a/configure.ac b/configure.ac index 0b1d17b..952657a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ # Revision changelog (version - date, svn rev. from upstream that was merged) -# 0.1 - 15 Sep 2011, r597 +# 0.1 - 19 Oct 2011, r766 AC_INIT([webrtc-audio-processing], [0.1]) AM_INIT_AUTOMAKE([tar-ustar]) diff --git a/src/common_audio/signal_processing_library/OWNERS b/src/common_audio/signal_processing_library/OWNERS deleted file mode 100644 index 97d0283..0000000 --- a/src/common_audio/signal_processing_library/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -bjornv@webrtc.org -tina.legrand@webrtc.org -jan.skoglund@webrtc.org diff --git a/src/common_audio/signal_processing_library/main/interface/signal_processing_library.h b/src/common_audio/signal_processing_library/main/interface/signal_processing_library.h index 1cdea71..81c55b6 100644 --- a/src/common_audio/signal_processing_library/main/interface/signal_processing_library.h +++ b/src/common_audio/signal_processing_library/main/interface/signal_processing_library.h @@ -1659,6 +1659,30 @@ void WebRtcSpl_SynthesisQMF(const WebRtc_Word16* low_band, // - out_data : Super-wideband speech signal, 0-16 kHz // +// WebRtc_Word16 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. +// + // WebRtc_Word16 WebRtcSpl_get_version(...) // // This function gives the version string of the Signal Processing Library. diff --git a/src/common_audio/signal_processing_library/main/interface/spl_inl.h b/src/common_audio/signal_processing_library/main/interface/spl_inl.h index e9edd87..23b3209 100644 --- a/src/common_audio/signal_processing_library/main/interface/spl_inl.h +++ b/src/common_audio/signal_processing_library/main/interface/spl_inl.h @@ -19,16 +19,20 @@ #include "spl_inl_armv7.h" #else -static __inline WebRtc_Word16 WebRtcSpl_AddSatW16(WebRtc_Word16 a, - WebRtc_Word16 b) { - WebRtc_Word32 s_sum = (WebRtc_Word32) a + (WebRtc_Word32) b; +static __inline WebRtc_Word16 WebRtcSpl_SatW32ToW16(WebRtc_Word32 value32) { + WebRtc_Word16 out16 = (WebRtc_Word16) value32; - if (s_sum > WEBRTC_SPL_WORD16_MAX) - s_sum = WEBRTC_SPL_WORD16_MAX; - else if (s_sum < WEBRTC_SPL_WORD16_MIN) - s_sum = WEBRTC_SPL_WORD16_MIN; + if (value32 > 32767) + out16 = 32767; + else if (value32 < -32768) + out16 = -32768; - return (WebRtc_Word16)s_sum; + return out16; +} + +static __inline WebRtc_Word16 WebRtcSpl_AddSatW16(WebRtc_Word16 a, + WebRtc_Word16 b) { + return WebRtcSpl_SatW32ToW16((WebRtc_Word32) a + (WebRtc_Word32) b); } static __inline WebRtc_Word32 WebRtcSpl_AddSatW32(WebRtc_Word32 l_var1, @@ -54,24 +58,7 @@ static __inline WebRtc_Word32 WebRtcSpl_AddSatW32(WebRtc_Word32 l_var1, static __inline WebRtc_Word16 WebRtcSpl_SubSatW16(WebRtc_Word16 var1, WebRtc_Word16 var2) { - WebRtc_Word32 l_diff; - WebRtc_Word16 s_diff; - - // perform subtraction - l_diff = (WebRtc_Word32)var1 - (WebRtc_Word32)var2; - - // default setting - s_diff = (WebRtc_Word16) l_diff; - - // check for overflow - if (l_diff > (WebRtc_Word32)32767) - s_diff = (WebRtc_Word16)32767; - - // check for underflow - if (l_diff < (WebRtc_Word32)-32768) - s_diff = (WebRtc_Word16)-32768; - - return s_diff; + return WebRtcSpl_SatW32ToW16((WebRtc_Word32) var1 - (WebRtc_Word32) var2); } static __inline WebRtc_Word32 WebRtcSpl_SubSatW32(WebRtc_Word32 l_var1, @@ -161,6 +148,12 @@ static __inline int WebRtcSpl_NormW16(WebRtc_Word16 a) { return zeros; } +static __inline int32_t WebRtc_MulAccumW16(int16_t a, + int16_t b, + int32_t c) { + return (a * b + c); +} + #endif // WEBRTC_ARCH_ARM_V7A #endif // WEBRTC_SPL_SPL_INL_H_ diff --git a/src/common_audio/signal_processing_library/main/interface/spl_inl_armv7.h b/src/common_audio/signal_processing_library/main/interface/spl_inl_armv7.h index 5d94936..689c2ba 100644 --- a/src/common_audio/signal_processing_library/main/interface/spl_inl_armv7.h +++ b/src/common_audio/signal_processing_library/main/interface/spl_inl_armv7.h @@ -45,6 +45,14 @@ static __inline WebRtc_Word32 WEBRTC_SPL_MUL_16_16(WebRtc_Word16 a, return tmp; } +static __inline int32_t WebRtc_MulAccumW16(int16_t a, + int16_t b, + int32_t c) { + int32_t tmp = 0; + __asm__("smlabb %0, %1, %2, %3":"=r"(tmp):"r"(a), "r"(b), "r"(c)); + return tmp; +} + static __inline WebRtc_Word16 WebRtcSpl_AddSatW16(WebRtc_Word16 a, WebRtc_Word16 b) { WebRtc_Word32 s_sum; @@ -119,4 +127,11 @@ static __inline int WebRtcSpl_NormW16(WebRtc_Word16 a) { return tmp - 17; } +static __inline WebRtc_Word16 WebRtcSpl_SatW32ToW16(WebRtc_Word32 value32) { + WebRtc_Word16 out16; + + __asm__("ssat %r0, #16, %r1" : "=r"(out16) : "r"(value32)); + + return out16; +} #endif // WEBRTC_SPL_SPL_INL_ARMV7_H_ diff --git a/src/common_audio/signal_processing_library/main/source/downsample_fast.c b/src/common_audio/signal_processing_library/main/source/downsample_fast.c index 9338275..cce463c 100644 --- a/src/common_audio/signal_processing_library/main/source/downsample_fast.c +++ b/src/common_audio/signal_processing_library/main/source/downsample_fast.c @@ -52,7 +52,7 @@ int WebRtcSpl_DownsampleFast(WebRtc_Word16 *in_ptr, WebRtc_Word16 in_length, // If output is higher than 32768, saturate it. Same with negative side - *downsampled_ptr++ = (WebRtc_Word16)WEBRTC_SPL_SAT(32767, o, -32768); + *downsampled_ptr++ = WebRtcSpl_SatW32ToW16(o); } return 0; diff --git a/src/common_audio/signal_processing_library/main/source/resample_by_2.c b/src/common_audio/signal_processing_library/main/source/resample_by_2.c index 6c296ba..e239db7 100644 --- a/src/common_audio/signal_processing_library/main/source/resample_by_2.c +++ b/src/common_audio/signal_processing_library/main/source/resample_by_2.c @@ -17,154 +17,165 @@ #include "signal_processing_library.h" +#ifdef WEBRTC_ARCH_ARM_V7A + +// allpass filter coefficients. +static const WebRtc_UWord32 kResampleAllpass1[3] = {3284, 24441, 49528 << 15}; +static const WebRtc_UWord32 kResampleAllpass2[3] = + {12199, 37471 << 15, 60255 << 15}; + +// Multiply two 32-bit values and accumulate to another input value. +// Return: state + ((diff * tbl_value) >> 16) + +static __inline WebRtc_Word32 MUL_ACCUM_1(WebRtc_Word32 tbl_value, + WebRtc_Word32 diff, + WebRtc_Word32 state) { + WebRtc_Word32 result; + __asm__("smlawb %r0, %r1, %r2, %r3": "=r"(result): "r"(diff), + "r"(tbl_value), "r"(state)); + return result; +} + +// Multiply two 32-bit values and accumulate to another input value. +// Return: Return: state + (((diff << 1) * tbl_value) >> 32) +// +// The reason to introduce this function is that, in case we can't use smlawb +// instruction (in MUL_ACCUM_1) due to input value range, we can still use +// smmla to save some cycles. + +static __inline WebRtc_Word32 MUL_ACCUM_2(WebRtc_Word32 tbl_value, + WebRtc_Word32 diff, + WebRtc_Word32 state) { + WebRtc_Word32 result; + __asm__("smmla %r0, %r1, %r2, %r3": "=r"(result): "r"(diff << 1), + "r"(tbl_value), "r"(state)); + return result; +} + +#else + // allpass filter coefficients. static const WebRtc_UWord16 kResampleAllpass1[3] = {3284, 24441, 49528}; static const WebRtc_UWord16 kResampleAllpass2[3] = {12199, 37471, 60255}; +// Multiply a 32-bit value with a 16-bit value and accumulate to another input: +#define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) +#define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) + +#endif // WEBRTC_ARCH_ARM_V7A + + // decimator void WebRtcSpl_DownsampleBy2(const WebRtc_Word16* in, const WebRtc_Word16 len, - WebRtc_Word16* out, WebRtc_Word32* filtState) -{ - WebRtc_Word32 tmp1, tmp2, diff, in32, out32; - WebRtc_Word16 i; - - register WebRtc_Word32 state0 = filtState[0]; - register WebRtc_Word32 state1 = filtState[1]; - register WebRtc_Word32 state2 = filtState[2]; - register WebRtc_Word32 state3 = filtState[3]; - register WebRtc_Word32 state4 = filtState[4]; - register WebRtc_Word32 state5 = filtState[5]; - register WebRtc_Word32 state6 = filtState[6]; - register WebRtc_Word32 state7 = filtState[7]; - - for (i = (len >> 1); i > 0; i--) - { - // lower allpass filter - in32 = (WebRtc_Word32)(*in++) << 10; - diff = in32 - state1; - tmp1 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass2[0], diff, state0); - state0 = in32; - diff = tmp1 - state2; - tmp2 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass2[1], diff, state1); - state1 = tmp1; - diff = tmp2 - state3; - state3 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass2[2], diff, state2); - state2 = tmp2; - - // upper allpass filter - in32 = (WebRtc_Word32)(*in++) << 10; - diff = in32 - state5; - tmp1 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass1[0], diff, state4); - state4 = in32; - diff = tmp1 - state6; - tmp2 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass1[1], diff, state5); - state5 = tmp1; - diff = tmp2 - state7; - state7 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass1[2], diff, state6); - state6 = tmp2; - - // add two allpass outputs, divide by two and round - out32 = (state3 + state7 + 1024) >> 11; - - // limit amplitude to prevent wrap-around, and write to output array -#ifdef WEBRTC_ARCH_ARM_V7A - __asm__("ssat %r0, #16, %r1" : "=r"(*out) : "r"(out32)); - out++; -#else - if (out32 > 32767) - *out++ = 32767; - else if (out32 < -32768) - *out++ = -32768; - else - *out++ = (WebRtc_Word16)out32; -#endif - } - - filtState[0] = state0; - filtState[1] = state1; - filtState[2] = state2; - filtState[3] = state3; - filtState[4] = state4; - filtState[5] = state5; - filtState[6] = state6; - filtState[7] = state7; + WebRtc_Word16* out, WebRtc_Word32* filtState) { + WebRtc_Word32 tmp1, tmp2, diff, in32, out32; + WebRtc_Word16 i; + + register WebRtc_Word32 state0 = filtState[0]; + register WebRtc_Word32 state1 = filtState[1]; + register WebRtc_Word32 state2 = filtState[2]; + register WebRtc_Word32 state3 = filtState[3]; + register WebRtc_Word32 state4 = filtState[4]; + register WebRtc_Word32 state5 = filtState[5]; + register WebRtc_Word32 state6 = filtState[6]; + register WebRtc_Word32 state7 = filtState[7]; + + for (i = (len >> 1); i > 0; i--) { + // lower allpass filter + in32 = (WebRtc_Word32)(*in++) << 10; + diff = in32 - state1; + tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); + state0 = in32; + diff = tmp1 - state2; + tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); + state1 = tmp1; + diff = tmp2 - state3; + state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); + state2 = tmp2; + + // upper allpass filter + in32 = (WebRtc_Word32)(*in++) << 10; + diff = in32 - state5; + tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); + state4 = in32; + diff = tmp1 - state6; + tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); + state5 = tmp1; + diff = tmp2 - state7; + state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); + state6 = tmp2; + + // add two allpass outputs, divide by two and round + out32 = (state3 + state7 + 1024) >> 11; + + // limit amplitude to prevent wrap-around, and write to output array + *out++ = WebRtcSpl_SatW32ToW16(out32); + } + + filtState[0] = state0; + filtState[1] = state1; + filtState[2] = state2; + filtState[3] = state3; + filtState[4] = state4; + filtState[5] = state5; + filtState[6] = state6; + filtState[7] = state7; } -void WebRtcSpl_UpsampleBy2(const WebRtc_Word16* in, WebRtc_Word16 len, WebRtc_Word16* out, - WebRtc_Word32* filtState) -{ - WebRtc_Word32 tmp1, tmp2, diff, in32, out32; - WebRtc_Word16 i; - - register WebRtc_Word32 state0 = filtState[0]; - register WebRtc_Word32 state1 = filtState[1]; - register WebRtc_Word32 state2 = filtState[2]; - register WebRtc_Word32 state3 = filtState[3]; - register WebRtc_Word32 state4 = filtState[4]; - register WebRtc_Word32 state5 = filtState[5]; - register WebRtc_Word32 state6 = filtState[6]; - register WebRtc_Word32 state7 = filtState[7]; - - for (i = len; i > 0; i--) - { - // lower allpass filter - in32 = (WebRtc_Word32)(*in++) << 10; - diff = in32 - state1; - tmp1 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass1[0], diff, state0); - state0 = in32; - diff = tmp1 - state2; - tmp2 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass1[1], diff, state1); - state1 = tmp1; - diff = tmp2 - state3; - state3 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass1[2], diff, state2); - state2 = tmp2; - - // round; limit amplitude to prevent wrap-around; write to output array - out32 = (state3 + 512) >> 10; -#ifdef WEBRTC_ARCH_ARM_V7A - __asm__("ssat %r0, #16, %r1":"=r"(*out): "r"(out32)); - out++; -#else - if (out32 > 32767) - *out++ = 32767; - else if (out32 < -32768) - *out++ = -32768; - else - *out++ = (WebRtc_Word16)out32; -#endif - - // upper allpass filter - diff = in32 - state5; - tmp1 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass2[0], diff, state4); - state4 = in32; - diff = tmp1 - state6; - tmp2 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass2[1], diff, state5); - state5 = tmp1; - diff = tmp2 - state7; - state7 = WEBRTC_SPL_SCALEDIFF32(kResampleAllpass2[2], diff, state6); - state6 = tmp2; - - // round; limit amplitude to prevent wrap-around; write to output array - out32 = (state7 + 512) >> 10; -#ifdef WEBRTC_ARCH_ARM_V7A - __asm__("ssat %r0, #16, %r1":"=r"(*out): "r"(out32)); - out++; -#else - if (out32 > 32767) - *out++ = 32767; - else if (out32 < -32768) - *out++ = -32768; - else - *out++ = (WebRtc_Word16)out32; -#endif - } - - filtState[0] = state0; - filtState[1] = state1; - filtState[2] = state2; - filtState[3] = state3; - filtState[4] = state4; - filtState[5] = state5; - filtState[6] = state6; - filtState[7] = state7; + +void WebRtcSpl_UpsampleBy2(const WebRtc_Word16* in, WebRtc_Word16 len, + WebRtc_Word16* out, WebRtc_Word32* filtState) { + WebRtc_Word32 tmp1, tmp2, diff, in32, out32; + WebRtc_Word16 i; + + register WebRtc_Word32 state0 = filtState[0]; + register WebRtc_Word32 state1 = filtState[1]; + register WebRtc_Word32 state2 = filtState[2]; + register WebRtc_Word32 state3 = filtState[3]; + register WebRtc_Word32 state4 = filtState[4]; + register WebRtc_Word32 state5 = filtState[5]; + register WebRtc_Word32 state6 = filtState[6]; + register WebRtc_Word32 state7 = filtState[7]; + + for (i = len; i > 0; i--) { + // lower allpass filter + in32 = (WebRtc_Word32)(*in++) << 10; + diff = in32 - state1; + tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0); + state0 = in32; + diff = tmp1 - state2; + tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1); + state1 = tmp1; + diff = tmp2 - state3; + state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2); + state2 = tmp2; + + // round; limit amplitude to prevent wrap-around; write to output array + out32 = (state3 + 512) >> 10; + *out++ = WebRtcSpl_SatW32ToW16(out32); + + // upper allpass filter + diff = in32 - state5; + tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4); + state4 = in32; + diff = tmp1 - state6; + tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5); + state5 = tmp1; + diff = tmp2 - state7; + state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6); + state6 = tmp2; + + // round; limit amplitude to prevent wrap-around; write to output array + out32 = (state7 + 512) >> 10; + *out++ = WebRtcSpl_SatW32ToW16(out32); + } + + filtState[0] = state0; + filtState[1] = state1; + filtState[2] = state2; + filtState[3] = state3; + filtState[4] = state4; + filtState[5] = state5; + filtState[6] = state6; + filtState[7] = state7; } diff --git a/src/common_audio/signal_processing_library/main/source/splitting_filter.c b/src/common_audio/signal_processing_library/main/source/splitting_filter.c index 98442f4..f1acf67 100644 --- a/src/common_audio/signal_processing_library/main/source/splitting_filter.c +++ b/src/common_audio/signal_processing_library/main/source/splitting_filter.c @@ -147,13 +147,11 @@ void WebRtcSpl_AnalysisQMF(const WebRtc_Word16* in_data, WebRtc_Word16* low_band { tmp = filter1[i] + filter2[i] + 1024; tmp = WEBRTC_SPL_RSHIFT_W32(tmp, 11); - low_band[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, - tmp, WEBRTC_SPL_WORD16_MIN); + low_band[i] = WebRtcSpl_SatW32ToW16(tmp); tmp = filter1[i] - filter2[i] + 1024; tmp = WEBRTC_SPL_RSHIFT_W32(tmp, 11); - high_band[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, - tmp, WEBRTC_SPL_WORD16_MIN); + high_band[i] = WebRtcSpl_SatW32ToW16(tmp); } } @@ -191,10 +189,10 @@ void WebRtcSpl_SynthesisQMF(const WebRtc_Word16* low_band, const WebRtc_Word16* for (i = 0, k = 0; i < kBandFrameLength; i++) { tmp = WEBRTC_SPL_RSHIFT_W32(filter2[i] + 512, 10); - out_data[k++] = (WebRtc_Word16)WEBRTC_SPL_SAT(32767, tmp, -32768); + out_data[k++] = WebRtcSpl_SatW32ToW16(tmp); tmp = WEBRTC_SPL_RSHIFT_W32(filter1[i] + 512, 10); - out_data[k++] = (WebRtc_Word16)WEBRTC_SPL_SAT(32767, tmp, -32768); + out_data[k++] = WebRtcSpl_SatW32ToW16(tmp); } } diff --git a/src/common_audio/signal_processing_library/main/source/vector_scaling_operations.c b/src/common_audio/signal_processing_library/main/source/vector_scaling_operations.c index 47362ee..20d239c 100644 --- a/src/common_audio/signal_processing_library/main/source/vector_scaling_operations.c +++ b/src/common_audio/signal_processing_library/main/source/vector_scaling_operations.c @@ -125,7 +125,7 @@ void WebRtcSpl_ScaleVectorWithSat(G_CONST WebRtc_Word16 *in_vector, WebRtc_Word1 for (i = 0; i < in_vector_length; i++) { tmpW32 = WEBRTC_SPL_MUL_16_16_RSFT(*inptr++, gain, right_shifts); - ( *outptr++) = (WebRtc_Word16)WEBRTC_SPL_SAT(32767, tmpW32, -32768); + (*outptr++) = WebRtcSpl_SatW32ToW16(tmpW32); } } diff --git a/src/common_audio/vad/Makefile.am b/src/common_audio/vad/Makefile.am index aa00fc0..deab054 100644 --- a/src/common_audio/vad/Makefile.am +++ b/src/common_audio/vad/Makefile.am @@ -2,11 +2,9 @@ noinst_LTLIBRARIES = libvad.la libvad_la_SOURCES = main/interface/webrtc_vad.h \ main/source/webrtc_vad.c \ - main/source/vad_const.c \ - main/source/vad_const.h \ - main/source/vad_defines.h \ main/source/vad_core.c \ main/source/vad_core.h \ + main/source/vad_defines.h \ main/source/vad_filterbank.c \ main/source/vad_filterbank.h \ main/source/vad_gmm.c \ diff --git a/src/common_audio/vad/OWNERS b/src/common_audio/vad/OWNERS deleted file mode 100644 index d0e9870..0000000 --- a/src/common_audio/vad/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -bjornv@webrtc.org -jan.skoglund@webrtc.org diff --git a/src/common_audio/vad/main/source/vad.gypi b/src/common_audio/vad/main/source/vad.gypi index 7b23ae8..442d8a9 100644 --- a/src/common_audio/vad/main/source/vad.gypi +++ b/src/common_audio/vad/main/source/vad.gypi @@ -25,11 +25,9 @@ 'sources': [ '../interface/webrtc_vad.h', 'webrtc_vad.c', - 'vad_const.c', - 'vad_const.h', - 'vad_defines.h', 'vad_core.c', 'vad_core.h', + 'vad_defines.h', 'vad_filterbank.c', 'vad_filterbank.h', 'vad_gmm.c', diff --git a/src/common_audio/vad/main/source/vad_const.c b/src/common_audio/vad/main/source/vad_const.c deleted file mode 100644 index 47b6a4b..0000000 --- a/src/common_audio/vad/main/source/vad_const.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -/* - * This file includes the constant values used internally in VAD. - */ - -#include "vad_const.h" - -// Spectrum Weighting -const WebRtc_Word16 kSpectrumWeight[6] = {6, 8, 10, 12, 14, 16}; - -const WebRtc_Word16 kCompVar = 22005; - -// Constant 160*log10(2) in Q9 -const WebRtc_Word16 kLogConst = 24660; - -// Constant log2(exp(1)) in Q12 -const WebRtc_Word16 kLog10Const = 5909; - -// Q15 -const WebRtc_Word16 kNoiseUpdateConst = 655; -const WebRtc_Word16 kSpeechUpdateConst = 6554; - -// Q8 -const WebRtc_Word16 kBackEta = 154; - -// Coefficients used by WebRtcVad_HpOutput, Q14 -const WebRtc_Word16 kHpZeroCoefs[3] = {6631, -13262, 6631}; -const WebRtc_Word16 kHpPoleCoefs[3] = {16384, -7756, 5620}; - -// Allpass filter coefficients, upper and lower, in Q15 -// Upper: 0.64, Lower: 0.17 -const WebRtc_Word16 kAllPassCoefsQ15[2] = {20972, 5571}; -const WebRtc_Word16 kAllPassCoefsQ13[2] = {5243, 1392}; // Q13 - -// Minimum difference between the two models, Q5 -const WebRtc_Word16 kMinimumDifference[6] = {544, 544, 576, 576, 576, 576}; - -// Upper limit of mean value for speech model, Q7 -const WebRtc_Word16 kMaximumSpeech[6] = {11392, 11392, 11520, 11520, 11520, 11520}; - -// Minimum value for mean value -const WebRtc_Word16 kMinimumMean[2] = {640, 768}; - -// Upper limit of mean value for noise model, Q7 -const WebRtc_Word16 kMaximumNoise[6] = {9216, 9088, 8960, 8832, 8704, 8576}; - -// Adjustment for division with two in WebRtcVad_SplitFilter -const WebRtc_Word16 kOffsetVector[6] = {368, 368, 272, 176, 176, 176}; - -// Start values for the Gaussian models, Q7 -// Weights for the two Gaussians for the six channels (noise) -const WebRtc_Word16 kNoiseDataWeights[12] = {34, 62, 72, 66, 53, 25, 94, 66, 56, 62, 75, 103}; - -// Weights for the two Gaussians for the six channels (speech) -const WebRtc_Word16 kSpeechDataWeights[12] = {48, 82, 45, 87, 50, 47, 80, 46, 83, 41, 78, 81}; - -// Means for the two Gaussians for the six channels (noise) -const WebRtc_Word16 kNoiseDataMeans[12] = {6738, 4892, 7065, 6715, 6771, 3369, 7646, 3863, - 7820, 7266, 5020, 4362}; - -// Means for the two Gaussians for the six channels (speech) -const WebRtc_Word16 kSpeechDataMeans[12] = {8306, 10085, 10078, 11823, 11843, 6309, 9473, - 9571, 10879, 7581, 8180, 7483}; - -// Stds for the two Gaussians for the six channels (noise) -const WebRtc_Word16 kNoiseDataStds[12] = {378, 1064, 493, 582, 688, 593, 474, 697, 475, 688, - 421, 455}; - -// Stds for the two Gaussians for the six channels (speech) -const WebRtc_Word16 kSpeechDataStds[12] = {555, 505, 567, 524, 585, 1231, 509, 828, 492, 1540, - 1079, 850}; diff --git a/src/common_audio/vad/main/source/vad_const.h b/src/common_audio/vad/main/source/vad_const.h deleted file mode 100644 index 8980437..0000000 --- a/src/common_audio/vad/main/source/vad_const.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - - -/* - * This header file includes the declarations of the internally used constants. - */ - -#ifndef WEBRTC_VAD_CONST_H_ -#define WEBRTC_VAD_CONST_H_ - -#include "typedefs.h" - -// TODO(ajm): give these internal-linkage by moving to the appropriate file -// where possible, and otherwise tag with WebRtcVad_. - -// Spectrum Weighting -extern const WebRtc_Word16 kSpectrumWeight[]; -extern const WebRtc_Word16 kCompVar; -// Logarithm constant -extern const WebRtc_Word16 kLogConst; -extern const WebRtc_Word16 kLog10Const; -// Q15 -extern const WebRtc_Word16 kNoiseUpdateConst; -extern const WebRtc_Word16 kSpeechUpdateConst; -// Q8 -extern const WebRtc_Word16 kBackEta; -// Coefficients used by WebRtcVad_HpOutput, Q14 -extern const WebRtc_Word16 kHpZeroCoefs[]; -extern const WebRtc_Word16 kHpPoleCoefs[]; -// Allpass filter coefficients, upper and lower, in Q15 resp. Q13 -extern const WebRtc_Word16 kAllPassCoefsQ15[]; -extern const WebRtc_Word16 kAllPassCoefsQ13[]; -// Minimum difference between the two models, Q5 -extern const WebRtc_Word16 kMinimumDifference[]; -// Maximum value when updating the speech model, Q7 -extern const WebRtc_Word16 kMaximumSpeech[]; -// Minimum value for mean value -extern const WebRtc_Word16 kMinimumMean[]; -// Upper limit of mean value for noise model, Q7 -extern const WebRtc_Word16 kMaximumNoise[]; -// Adjustment for division with two in WebRtcVad_SplitFilter -extern const WebRtc_Word16 kOffsetVector[]; -// Start values for the Gaussian models, Q7 -extern const WebRtc_Word16 kNoiseDataWeights[]; -extern const WebRtc_Word16 kSpeechDataWeights[]; -extern const WebRtc_Word16 kNoiseDataMeans[]; -extern const WebRtc_Word16 kSpeechDataMeans[]; -extern const WebRtc_Word16 kNoiseDataStds[]; -extern const WebRtc_Word16 kSpeechDataStds[]; - -#endif // WEBRTC_VAD_CONST_H_ diff --git a/src/common_audio/vad/main/source/vad_core.c b/src/common_audio/vad/main/source/vad_core.c index 85864e1..e05c296 100644 --- a/src/common_audio/vad/main/source/vad_core.c +++ b/src/common_audio/vad/main/source/vad_core.c @@ -15,12 +15,50 @@ */ #include "vad_core.h" -#include "vad_const.h" + +#include "signal_processing_library.h" +#include "typedefs.h" #include "vad_defines.h" #include "vad_filterbank.h" #include "vad_gmm.h" #include "vad_sp.h" -#include "signal_processing_library.h" + +// Spectrum Weighting +static const WebRtc_Word16 kSpectrumWeight[6] = { 6, 8, 10, 12, 14, 16 }; +static const WebRtc_Word16 kNoiseUpdateConst = 655; // Q15 +static const WebRtc_Word16 kSpeechUpdateConst = 6554; // Q15 +static const WebRtc_Word16 kBackEta = 154; // Q8 +// Minimum difference between the two models, Q5 +static const WebRtc_Word16 kMinimumDifference[6] = { + 544, 544, 576, 576, 576, 576 }; +// Upper limit of mean value for speech model, Q7 +static const WebRtc_Word16 kMaximumSpeech[6] = { + 11392, 11392, 11520, 11520, 11520, 11520 }; +// Minimum value for mean value +static const WebRtc_Word16 kMinimumMean[2] = { 640, 768 }; +// Upper limit of mean value for noise model, Q7 +static const WebRtc_Word16 kMaximumNoise[6] = { + 9216, 9088, 8960, 8832, 8704, 8576 }; +// Start values for the Gaussian models, Q7 +// Weights for the two Gaussians for the six channels (noise) +static const WebRtc_Word16 kNoiseDataWeights[12] = { + 34, 62, 72, 66, 53, 25, 94, 66, 56, 62, 75, 103 }; +// Weights for the two Gaussians for the six channels (speech) +static const WebRtc_Word16 kSpeechDataWeights[12] = { + 48, 82, 45, 87, 50, 47, 80, 46, 83, 41, 78, 81 }; +// Means for the two Gaussians for the six channels (noise) +static const WebRtc_Word16 kNoiseDataMeans[12] = { + 6738, 4892, 7065, 6715, 6771, 3369, 7646, 3863, 7820, 7266, 5020, 4362 }; +// Means for the two Gaussians for the six channels (speech) +static const WebRtc_Word16 kSpeechDataMeans[12] = { + 8306, 10085, 10078, 11823, 11843, 6309, 9473, 9571, 10879, 7581, 8180, 7483 +}; +// Stds for the two Gaussians for the six channels (noise) +static const WebRtc_Word16 kNoiseDataStds[12] = { + 378, 1064, 493, 582, 688, 593, 474, 697, 475, 688, 421, 455 }; +// Stds for the two Gaussians for the six channels (speech) +static const WebRtc_Word16 kSpeechDataStds[12] = { + 555, 505, 567, 524, 585, 1231, 509, 828, 492, 1540, 1079, 850 }; static const int kInitCheck = 42; diff --git a/src/common_audio/vad/main/source/vad_filterbank.c b/src/common_audio/vad/main/source/vad_filterbank.c index 11392c9..9bd4443 100644 --- a/src/common_audio/vad/main/source/vad_filterbank.c +++ b/src/common_audio/vad/main/source/vad_filterbank.c @@ -15,9 +15,21 @@ */ #include "vad_filterbank.h" -#include "vad_defines.h" -#include "vad_const.h" + #include "signal_processing_library.h" +#include "typedefs.h" +#include "vad_defines.h" + +// Constant 160*log10(2) in Q9 +static const WebRtc_Word16 kLogConst = 24660; +// Coefficients used by WebRtcVad_HpOutput, Q14 +static const WebRtc_Word16 kHpZeroCoefs[3] = {6631, -13262, 6631}; +static const WebRtc_Word16 kHpPoleCoefs[3] = {16384, -7756, 5620}; +// Allpass filter coefficients, upper and lower, in Q15 +// Upper: 0.64, Lower: 0.17 +static const WebRtc_Word16 kAllPassCoefsQ15[2] = {20972, 5571}; +// Adjustment for division with two in WebRtcVad_SplitFilter +static const WebRtc_Word16 kOffsetVector[6] = {368, 368, 272, 176, 176, 176}; void WebRtcVad_HpOutput(WebRtc_Word16 *in_vector, WebRtc_Word16 in_vector_length, diff --git a/src/common_audio/vad/main/source/vad_gmm.c b/src/common_audio/vad/main/source/vad_gmm.c index 23d12fb..0865261 100644 --- a/src/common_audio/vad/main/source/vad_gmm.c +++ b/src/common_audio/vad/main/source/vad_gmm.c @@ -15,8 +15,13 @@ */ #include "vad_gmm.h" + #include "signal_processing_library.h" -#include "vad_const.h" +#include "typedefs.h" + +static const WebRtc_Word32 kCompVar = 22005; +// Constant log2(exp(1)) in Q12 +static const WebRtc_Word16 kLog10Const = 5909; WebRtc_Word32 WebRtcVad_GaussianProbability(WebRtc_Word16 in_sample, WebRtc_Word16 mean, diff --git a/src/common_audio/vad/main/source/vad_sp.c b/src/common_audio/vad/main/source/vad_sp.c index f347ab5..620ab97 100644 --- a/src/common_audio/vad/main/source/vad_sp.c +++ b/src/common_audio/vad/main/source/vad_sp.c @@ -10,15 +10,20 @@ /* - * This file includes the implementation of the VAD internal calls for Downsampling and - * FindMinimum. + * This file includes the implementation of the VAD internal calls for + * Downsampling and FindMinimum. * For function call descriptions; See vad_sp.h. */ #include "vad_sp.h" -#include "vad_defines.h" -#include "vad_const.h" + #include "signal_processing_library.h" +#include "typedefs.h" +#include "vad_defines.h" + +// Allpass filter coefficients, upper and lower, in Q13 +// Upper: 0.64, Lower: 0.17 +static const WebRtc_Word16 kAllPassCoefsQ13[2] = {5243, 1392}; // Q13 // Downsampling filter based on the splitting filter and the allpass functions // in vad_filterbank.c diff --git a/src/common_types.h b/src/common_types.h index 8b0b8a5..a3c12d9 100644 --- a/src/common_types.h +++ b/src/common_types.h @@ -485,6 +485,7 @@ enum RawVideoType // Video codec enum { kConfigParameterSize = 128}; enum { kPayloadNameSize = 32}; +enum { kMaxSimulcastStreams = 4}; // H.263 specific struct VideoCodecH263 @@ -530,9 +531,10 @@ struct VideoCodecH264 // VP8 specific struct VideoCodecVP8 { - bool pictureLossIndicationOn; - bool feedbackModeOn; - VideoCodecComplexity complexity; + bool pictureLossIndicationOn; + bool feedbackModeOn; + VideoCodecComplexity complexity; + unsigned char numberOfTemporalLayers; }; // MPEG-4 specific @@ -570,6 +572,19 @@ union VideoCodecUnion VideoCodecGeneric Generic; }; +/* +* Simulcast is when the same stream is encoded multiple times with different +* settings such as resolution. +*/ +struct SimulcastStream +{ + unsigned short width; + unsigned short height; + unsigned char numberOfTemporalLayers; + unsigned int maxBitrate; + unsigned int qpMax; // minimum quality +}; + // Common video codec properties struct VideoCodec { @@ -588,8 +603,8 @@ struct VideoCodec VideoCodecUnion codecSpecific; unsigned int qpMax; + unsigned char numberOfSimulcastStreams; + SimulcastStream simulcastStream[kMaxSimulcastStreams]; }; - } // namespace webrtc - #endif // WEBRTC_COMMON_TYPES_H diff --git a/src/modules/audio_processing/aec/main/interface/echo_cancellation.h b/src/modules/audio_processing/aec/main/interface/echo_cancellation.h index 883357d..4da6e73 100644 --- a/src/modules/audio_processing/aec/main/interface/echo_cancellation.h +++ b/src/modules/audio_processing/aec/main/interface/echo_cancellation.h @@ -38,6 +38,7 @@ typedef struct { WebRtc_Word16 nlpMode; // default kAecNlpModerate WebRtc_Word16 skewMode; // default kAecFalse WebRtc_Word16 metricsMode; // default kAecFalse + int delay_logging; // default kAecFalse //float realSkew; } AecConfig; @@ -66,7 +67,7 @@ extern "C" { * Inputs Description * ------------------------------------------------------------------- * void **aecInst Pointer to the AEC instance to be created - * and initilized + * and initialized * * Outputs Description * ------------------------------------------------------------------- @@ -226,6 +227,23 @@ WebRtc_Word32 WebRtcAec_get_echo_status(void *aecInst, WebRtc_Word16 *status); WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics); /* + * Gets the current delay metrics for the session. + * + * Inputs Description + * ------------------------------------------------------------------- + * void* handle Pointer to the AEC instance + * + * Outputs Description + * ------------------------------------------------------------------- + * int* median Delay median value. + * int* std Delay standard deviation. + * + * int return 0: OK + * -1: error + */ +int WebRtcAec_GetDelayMetrics(void* handle, int* median, int* std); + +/* * Gets the last error code. * * Inputs Description diff --git a/src/modules/audio_processing/aec/main/matlab/fullaec.m b/src/modules/audio_processing/aec/main/matlab/fullaec.m deleted file mode 100644 index 0f86a8c..0000000 --- a/src/modules/audio_processing/aec/main/matlab/fullaec.m +++ /dev/null @@ -1,953 +0,0 @@ -% Partitioned block frequency domain adaptive filtering NLMS and -% standard time-domain sample-based NLMS -%fid=fopen('aecFar-samsung.pcm', 'rb'); % Load far end -fid=fopen('aecFar.pcm', 'rb'); % Load far end -%fid=fopen(farFile, 'rb'); % Load far end -rrin=fread(fid,inf,'int16'); -fclose(fid); -%rrin=loadsl('data/far_me2.pcm'); % Load far end -%fid=fopen('aecNear-samsung.pcm', 'rb'); % Load near end -fid=fopen('aecNear.pcm', 'rb'); % Load near end -%fid=fopen(nearFile, 'rb'); % Load near end -ssin=fread(fid,inf,'int16'); -%ssin = [zeros(1024,1) ; ssin(1:end-1024)]; - -fclose(fid); -rand('state',13); -fs=16000; -mult=fs/8000; -%rrin=rrin(fs*0+1:round(fs*120)); -%ssin=ssin(fs*0+1:round(fs*120)); -if fs == 8000 - cohRange = 2:3; -elseif fs==16000 - cohRange = 2; -end - -% Flags -NLPon=1; % NLP -CNon=1; % Comfort noise -PLTon=1; % Plotting - -M = 16; % Number of partitions -N = 64; % Partition length -L = M*N; % Filter length -if fs == 8000 - mufb = 0.6; -else - mufb = 0.5; -end -%mufb=1; -VADtd=48; -alp = 0.1; % Power estimation factor alc = 0.1; % Coherence estimation factor -beta = 0.9; % Plotting factor -%% Changed a little %% -step = 0.3;%0.1875; % Downward step size -%% -if fs == 8000 - threshold=2e-6; % DTrob threshold -else - %threshold=0.7e-6; - threshold=1.5e-6; end - -if fs == 8000 - echoBandRange = ceil(300*2/fs*N):floor(1800*2/fs*N); - %echoBandRange = ceil(1500*2/fs*N):floor(2500*2/fs*N); -else - echoBandRange = ceil(300*2/fs*N):floor(1800*2/fs*N); - %echoBandRange = ceil(300*2/fs*N):floor(1800*2/fs*N); -end -%echoBandRange = ceil(1600*2/fs*N):floor(1900*2/fs*N); -%echoBandRange = ceil(2000*2/fs*N):floor(4000*2/fs*N); -suppState = 1; -transCtr = 0; - -Nt=1; -vt=1; - -ramp = 1.0003; % Upward ramp -rampd = 0.999; % Downward ramp -cvt = 20; % Subband VAD threshold; -nnthres = 20; % Noise threshold - -shh=logspace(-1.3,-2.2,N+1)'; -sh=[shh;flipud(shh(2:end-1))]; % Suppression profile - -len=length(ssin); -w=zeros(L,1); % Sample-based TD NLMS -WFb=zeros(N+1,M); % Block-based FD NLMS -WFbOld=zeros(N+1,M); % Block-based FD NLMS -YFb=zeros(N+1,M); -erfb=zeros(len,1); -erfb3=zeros(len,1); - -ercn=zeros(len,1); -zm=zeros(N,1); -XFm=zeros(N+1,M); -YFm=zeros(N+1,M); -pn0=10*ones(N+1,1); -pn=zeros(N+1,1); -NN=len; -Nb=floor(NN/N)-M; -erifb=zeros(Nb+1,1)+0.1; -erifb3=zeros(Nb+1,1)+0.1; -ericn=zeros(Nb+1,1)+0.1; -dri=zeros(Nb+1,1)+0.1; -start=1; -xo=zeros(N,1); -do=xo; -eo=xo; - -echoBands=zeros(Nb+1,1); -cohxdAvg=zeros(Nb+1,1); -cohxdSlow=zeros(Nb+1,N+1); -cohedSlow=zeros(Nb+1,N+1); -%overdriveM=zeros(Nb+1,N+1); -cohxdFastAvg=zeros(Nb+1,1); -cohxdAvgBad=zeros(Nb+1,1); -cohedAvg=zeros(Nb+1,1); -cohedFastAvg=zeros(Nb+1,1); -hnledAvg=zeros(Nb+1,1); -hnlxdAvg=zeros(Nb+1,1); -ovrdV=zeros(Nb+1,1); -dIdxV=zeros(Nb+1,1); -SLxV=zeros(Nb+1,1); -hnlSortQV=zeros(Nb+1,1); -hnlPrefAvgV=zeros(Nb+1,1); -mutInfAvg=zeros(Nb+1,1); -%overdrive=zeros(Nb+1,1); -hnled = zeros(N+1, 1); -weight=zeros(N+1,1); -hnlMax = zeros(N+1, 1); -hnl = zeros(N+1, 1); -overdrive = ones(1, N+1); -xfwm=zeros(N+1,M); -dfm=zeros(N+1,M); -WFbD=ones(N+1,1); - -fbSupp = 0; -hnlLocalMin = 1; -cohxdLocalMin = 1; -hnlLocalMinV=zeros(Nb+1,1); -cohxdLocalMinV=zeros(Nb+1,1); -hnlMinV=zeros(Nb+1,1); -dkEnV=zeros(Nb+1,1); -ekEnV=zeros(Nb+1,1); -ovrd = 2; -ovrdPos = floor((N+1)/4); -ovrdSm = 2; -hnlMin = 1; -minCtr = 0; -SeMin = 0; -SdMin = 0; -SeLocalAvg = 0; -SeMinSm = 0; -divergeFact = 1; -dIdx = 1; -hnlMinCtr = 0; -hnlNewMin = 0; -divergeState = 0; - -Sy=ones(N+1,1); -Sym=1e7*ones(N+1,1); - -wins=[0;sqrt(hanning(2*N-1))]; -ubufn=zeros(2*N,1); -ebuf=zeros(2*N,1); -ebuf2=zeros(2*N,1); -ebuf4=zeros(2*N,1); -mbuf=zeros(2*N,1); - -cohedFast = zeros(N+1,1); -cohxdFast = zeros(N+1,1); -cohxd = zeros(N+1,1); -Se = zeros(N+1,1); -Sd = zeros(N+1,1); -Sx = zeros(N+1,1); -SxBad = zeros(N+1,1); -Sed = zeros(N+1,1); -Sxd = zeros(N+1,1); -SxdBad = zeros(N+1,1); -hnledp=[]; - -cohxdMax = 0; - -%hh=waitbar(0,'Please wait...'); -progressbar(0); - -%spaces = ' '; -%spaces = repmat(spaces, 50, 1); -%spaces = ['[' ; spaces ; ']']; -%fprintf(1, spaces); -%fprintf(1, '\n'); - -for kk=1:Nb - pos = N * (kk-1) + start; - - % FD block method - % ---------------------- Organize data - xk = rrin(pos:pos+N-1); - dk = ssin(pos:pos+N-1); - - xx = [xo;xk]; - xo = xk; - tmp = fft(xx); - XX = tmp(1:N+1); - - dd = [do;dk]; % Overlap - do = dk; - tmp = fft(dd); % Frequency domain - DD = tmp(1:N+1); - - % ------------------------ Power estimation - pn0 = (1 - alp) * pn0 + alp * real(XX.* conj(XX)); - pn = pn0; - %pn = (1 - alp) * pn + alp * M * pn0; - if (CNon) - Yp = real(conj(DD).*DD); % Instantaneous power - Sy = (1 - alp) * Sy + alp * Yp; % Averaged power - - mm = min(Sy,Sym); - diff = Sym - mm; - if (kk>50) - Sym = (mm + step*diff) * ramp; % Estimated background noise power - end - end - - % ---------------------- Filtering - XFm(:,1) = XX; - for mm=0:(M-1) - m=mm+1; - YFb(:,m) = XFm(:,m) .* WFb(:,m); - end - yfk = sum(YFb,2); - tmp = [yfk ; flipud(conj(yfk(2:N)))]; - ykt = real(ifft(tmp)); - ykfb = ykt(end-N+1:end); - - % ---------------------- Error estimation - ekfb = dk - ykfb; - %if sum(abs(ekfb)) < sum(abs(dk)) - %ekfb = dk - ykfb; - % erfb(pos:pos+N-1) = ekfb; - %else - %ekfb = dk; - % erfb(pos:pos+N-1) = dk; - %end - %(kk-1)*(N*2)+1 - erfb(pos:pos+N-1) = ekfb; - tmp = fft([zm;ekfb]); % FD version for cancelling part (overlap-save) - Ek = tmp(1:N+1); - - % ------------------------ Adaptation - Ek2 = Ek ./(M*pn + 0.001); % Normalized error - %Ek2 = Ek ./(pn + 0.001); % Normalized error - %Ek2 = Ek ./(100*pn + 0.001); % Normalized error - - absEf = max(abs(Ek2), threshold); - absEf = ones(N+1,1)*threshold./absEf; - Ek2 = Ek2.*absEf; - - mEk = mufb.*Ek2; - PP = conj(XFm).*(ones(M,1) * mEk')'; - tmp = [PP ; flipud(conj(PP(2:N,:)))]; - IFPP = real(ifft(tmp)); - PH = IFPP(1:N,:); - tmp = fft([PH;zeros(N,M)]); - FPH = tmp(1:N+1,:); - WFb = WFb + FPH; - - if mod(kk, 10*mult) == 0 - WFbEn = sum(real(WFb.*conj(WFb))); - %WFbEn = sum(abs(WFb)); - [tmp, dIdx] = max(WFbEn); - - WFbD = sum(abs(WFb(:, dIdx)),2); - %WFbD = WFbD / (mean(WFbD) + 1e-10); - WFbD = min(max(WFbD, 0.5), 4); - end - dIdxV(kk) = dIdx; - - % NLP - if (NLPon) - - ee = [eo;ekfb]; - eo = ekfb; - window = wins; - if fs == 8000 - %gamma = 0.88; - gamma = 0.9; - else - %gamma = 0.92; - gamma = 0.93; - end - %gamma = 0.9; - - tmp = fft(xx.*window); - xf = tmp(1:N+1); - tmp = fft(dd.*window); - df = tmp(1:N+1); - tmp = fft(ee.*window); - ef = tmp(1:N+1); - - xfwm(:,1) = xf; - xf = xfwm(:,dIdx); - %fprintf(1,'%d: %f\n', kk, xf(4)); - dfm(:,1) = df; - - SxOld = Sx; - - Se = gamma*Se + (1-gamma)*real(ef.*conj(ef)); - Sd = gamma*Sd + (1-gamma)*real(df.*conj(df)); - Sx = gamma*Sx + (1 - gamma)*real(xf.*conj(xf)); - - %xRatio = real(xfwm(:,1).*conj(xfwm(:,1))) ./ ... - % (real(xfwm(:,2).*conj(xfwm(:,2))) + 1e-10); - %xRatio = Sx ./ (SxOld + 1e-10); - %SLx = log(1/(N+1)*sum(xRatio)) - 1/(N+1)*sum(log(xRatio)); - %SLxV(kk) = SLx; - - %freqSm = 0.9; - %Sx = filter(freqSm, [1 -(1-freqSm)], Sx); - %Sx(end:1) = filter(freqSm, [1 -(1-freqSm)], Sx(end:1)); - %Se = filter(freqSm, [1 -(1-freqSm)], Se); - %Se(end:1) = filter(freqSm, [1 -(1-freqSm)], Se(end:1)); - %Sd = filter(freqSm, [1 -(1-freqSm)], Sd); - %Sd(end:1) = filter(freqSm, [1 -(1-freqSm)], Sd(end:1)); - - %SeFast = ef.*conj(ef); - %SdFast = df.*conj(df); - %SxFast = xf.*conj(xf); - %cohedFast = 0.9*cohedFast + 0.1*SeFast ./ (SdFast + 1e-10); - %cohedFast(find(cohedFast > 1)) = 1; - %cohedFast(find(cohedFast > 1)) = 1 ./ cohedFast(find(cohedFast>1)); - %cohedFastAvg(kk) = mean(cohedFast(echoBandRange)); - %cohedFastAvg(kk) = min(cohedFast); - - %cohxdFast = 0.8*cohxdFast + 0.2*log(SdFast ./ (SxFast + 1e-10)); - %cohxdFastAvg(kk) = mean(cohxdFast(echoBandRange)); - - % coherence - Sxd = gamma*Sxd + (1 - gamma)*xf.*conj(df); - Sed = gamma*Sed + (1-gamma)*ef.*conj(df); - - %Sxd = filter(freqSm, [1 -(1-freqSm)], Sxd); - %Sxd(end:1) = filter(freqSm, [1 -(1-freqSm)], Sxd(end:1)); - %Sed = filter(freqSm, [1 -(1-freqSm)], Sed); - %Sed(end:1) = filter(freqSm, [1 -(1-freqSm)], Sed(end:1)); - - cohed = real(Sed.*conj(Sed))./(Se.*Sd + 1e-10); - %cohedAvg(kk) = mean(cohed(echoBandRange)); - %cohedAvg(kk) = cohed(6); - %cohedAvg(kk) = min(cohed); - - cohxd = real(Sxd.*conj(Sxd))./(Sx.*Sd + 1e-10); - %freqSm = 0.5; - %cohxd(3:end) = filter(freqSm, [1 -(1-freqSm)], cohxd(3:end)); - %cohxd(end:3) = filter(freqSm, [1 -(1-freqSm)], cohxd(end:3)); - %cohxdAvg(kk) = mean(cohxd(echoBandRange)); - %cohxdAvg(kk) = (cohxd(32)); - %cohxdAvg(kk) = max(cohxd); - - %xf = xfm(:,dIdx); - %SxBad = gamma*SxBad + (1 - gamma)*real(xf.*conj(xf)); - %SxdBad = gamma*SxdBad + (1 - gamma)*xf.*conj(df); - %cohxdBad = real(SxdBad.*conj(SxdBad))./(SxBad.*Sd + 0.01); - %cohxdAvgBad(kk) = mean(cohxdBad); - - %for j=1:N+1 - % mutInf(j) = 0.9*mutInf(j) + 0.1*information(abs(xfm(j,:)), abs(dfm(j,:))); - %end - %mutInfAvg(kk) = mean(mutInf); - - %hnled = cohedFast; - %xIdx = find(cohxd > 1 - cohed); - %hnled(xIdx) = 1 - cohxd(xIdx); - %hnled = 1 - max(cohxd, 1-cohedFast); - hnled = min(1 - cohxd, cohed); - %hnled = 1 - cohxd; - %hnled = max(1 - (cohxd + (1-cohedFast)), 0); - %hnled = 1 - max(cohxd, 1-cohed); - - if kk > 1 - cohxdSlow(kk,:) = 0.99*cohxdSlow(kk-1,:) + 0.01*cohxd'; - cohedSlow(kk,:) = 0.99*cohedSlow(kk-1,:) + 0.01*(1-cohed)'; - end - - - if 0 - %if kk > 50 - %idx = find(hnled > 0.3); - hnlMax = hnlMax*0.9999; - %hnlMax(idx) = max(hnlMax(idx), hnled(idx)); - hnlMax = max(hnlMax, hnled); - %overdrive(idx) = max(log(hnlMax(idx))/log(0.99), 1); - avgHnl = mean(hnlMax(echoBandRange)); - if avgHnl > 0.3 - overdrive = max(log(avgHnl)/log(0.99), 1); - end - weight(4:end) = max(hnlMax) - hnlMax(4:end); - end - - - - %[hg, gidx] = max(hnled); - %fnrg = Sx(gidx) / (Sd(gidx) + 1e-10); - - %[tmp, bidx] = find((Sx / Sd + 1e-10) > fnrg); - %hnled(bidx) = hg; - - - %cohed1 = mean(cohed(cohRange)); % range depends on bandwidth - %cohed1 = cohed1^2; - %echoBands(kk) = length(find(cohed(echoBandRange) < 0.25))/length(echoBandRange); - - %if (fbSupp == 0) - % if (echoBands(kk) > 0.8) - % fbSupp = 1; - % end - %else - % if (echoBands(kk) < 0.6) - % fbSupp = 0; - % end - %end - %overdrive(kk) = 7.5*echoBands(kk) + 0.5; - - % Factor by which to weight other bands - %if (cohed1 < 0.1) - % w = 0.8 - cohed1*10*0.4; - %else - % w = 0.4; - %end - - % Weight coherence subbands - %hnled = w*cohed1 + (1 - w)*cohed; - %hnled = (hnled).^2; - %cohed(floor(N/2):end) = cohed(floor(N/2):end).^2; - %if fbSupp == 1 - % cohed = zeros(size(cohed)); - %end - %cohed = cohed.^overdrive(kk); - - %hnled = gamma*hnled + (1 - gamma)*cohed; - % Additional hf suppression - %hnledp = [hnledp ; mean(hnled)]; - %hnled(floor(N/2):end) = hnled(floor(N/2):end).^2; - %ef = ef.*((weight*(min(1 - hnled)).^2 + (1 - weight).*(1 - hnled)).^2); - - cohedMean = mean(cohed(echoBandRange)); - %aggrFact = 4*(1-mean(hnled(echoBandRange))) + 1; - %[hnlSort, hnlSortIdx] = sort(hnled(echoBandRange)); - [hnlSort, hnlSortIdx] = sort(1-cohxd(echoBandRange)); - [xSort, xSortIdx] = sort(Sx); - %aggrFact = (1-mean(hnled(echoBandRange))); - %hnlSortQ = hnlSort(qIdx); - hnlSortQ = mean(1 - cohxd(echoBandRange)); - %hnlSortQ = mean(1 - cohxd); - - [hnlSort2, hnlSortIdx2] = sort(hnled(echoBandRange)); - %[hnlSort2, hnlSortIdx2] = sort(hnled); - hnlQuant = 0.75; - hnlQuantLow = 0.5; - qIdx = floor(hnlQuant*length(hnlSort2)); - qIdxLow = floor(hnlQuantLow*length(hnlSort2)); - hnlPrefAvg = hnlSort2(qIdx); - hnlPrefAvgLow = hnlSort2(qIdxLow); - %hnlPrefAvgLow = mean(hnled); - %hnlPrefAvg = max(hnlSort2); - %hnlPrefAvgLow = min(hnlSort2); - - %hnlPref = hnled(echoBandRange); - %hnlPrefAvg = mean(hnlPref(xSortIdx((0.5*length(xSortIdx)):end))); - - %hnlPrefAvg = min(hnlPrefAvg, hnlSortQ); - - %hnlSortQIdx = hnlSortIdx(qIdx); - %SeQ = Se(qIdx + echoBandRange(1) - 1); - %SdQ = Sd(qIdx + echoBandRange(1) - 1); - %SeQ = Se(qIdxLow + echoBandRange(1) - 1); - %SdQ = Sd(qIdxLow + echoBandRange(1) - 1); - %propLow = length(find(hnlSort < 0.1))/length(hnlSort); - %aggrFact = min((1 - hnlSortQ)/2, 0.5); - %aggrTerm = 1/aggrFact; - - %hnlg = mean(hnled(echoBandRange)); - %hnlg = hnlSortQ; - %if suppState == 0 - % if hnlg < 0.05 - % suppState = 2; - % transCtr = 0; - % elseif hnlg < 0.75 - % suppState = 1; - % transCtr = 0; - % end - %elseif suppState == 1 - % if hnlg > 0.8 - % suppState = 0; - % transCtr = 0; - % elseif hnlg < 0.05 - % suppState = 2; - % transCtr = 0; - % end - %else - % if hnlg > 0.8 - % suppState = 0; - % transCtr = 0; - % elseif hnlg > 0.25 - % suppState = 1; - % transCtr = 0; - % end - %end - %if kk > 50 - - if cohedMean > 0.98 & hnlSortQ > 0.9 - %if suppState == 1 - % hnled = 0.5*hnled + 0.5*cohed; - % %hnlSortQ = 0.5*hnlSortQ + 0.5*cohedMean; - % hnlPrefAvg = 0.5*hnlPrefAvg + 0.5*cohedMean; - %else - % hnled = cohed; - % %hnlSortQ = cohedMean; - % hnlPrefAvg = cohedMean; - %end - suppState = 0; - elseif cohedMean < 0.95 | hnlSortQ < 0.8 - %if suppState == 0 - % hnled = 0.5*hnled + 0.5*cohed; - % %hnlSortQ = 0.5*hnlSortQ + 0.5*cohedMean; - % hnlPrefAvg = 0.5*hnlPrefAvg + 0.5*cohedMean; - %end - suppState = 1; - end - - if hnlSortQ < cohxdLocalMin & hnlSortQ < 0.75 - cohxdLocalMin = hnlSortQ; - end - - if cohxdLocalMin == 1 - ovrd = 3; - hnled = 1-cohxd; - hnlPrefAvg = hnlSortQ; - hnlPrefAvgLow = hnlSortQ; - end - - if suppState == 0 - hnled = cohed; - hnlPrefAvg = cohedMean; - hnlPrefAvgLow = cohedMean; - end - - %if hnlPrefAvg < hnlLocalMin & hnlPrefAvg < 0.6 - if hnlPrefAvgLow < hnlLocalMin & hnlPrefAvgLow < 0.6 - %hnlLocalMin = hnlPrefAvg; - %hnlMin = hnlPrefAvg; - hnlLocalMin = hnlPrefAvgLow; - hnlMin = hnlPrefAvgLow; - hnlNewMin = 1; - hnlMinCtr = 0; - %if hnlMinCtr == 0 - % hnlMinCtr = hnlMinCtr + 1; - %else - % hnlMinCtr = 0; - % hnlMin = hnlLocalMin; - %SeLocalMin = SeQ; - %SdLocalMin = SdQ; - %SeLocalAvg = 0; - %minCtr = 0; - % ovrd = max(log(0.0001)/log(hnlMin), 2); - %divergeFact = hnlLocalMin; - end - - if hnlNewMin == 1 - hnlMinCtr = hnlMinCtr + 1; - end - if hnlMinCtr == 2 - hnlNewMin = 0; - hnlMinCtr = 0; - %ovrd = max(log(0.0001)/log(hnlMin), 2); - ovrd = max(log(0.00001)/(log(hnlMin + 1e-10) + 1e-10), 3); - %ovrd = max(log(0.00000001)/(log(hnlMin + 1e-10) + 1e-10), 5); - %ovrd = max(log(0.0001)/log(hnlPrefAvg), 2); - %ovrd = max(log(0.001)/log(hnlMin), 2); - end - hnlLocalMin = min(hnlLocalMin + 0.0008/mult, 1); - cohxdLocalMin = min(cohxdLocalMin + 0.0004/mult, 1); - %divergeFact = hnlSortQ; - - - %if minCtr > 0 & hnlLocalMin < 1 - % hnlMin = hnlLocalMin; - % %SeMin = 0.9*SeMin + 0.1*sqrt(SeLocalMin); - % SdMin = sqrt(SdLocalMin); - % %SeMin = sqrt(SeLocalMin)*hnlSortQ; - % SeMin = sqrt(SeLocalMin); - % %ovrd = log(100/SeMin)/log(hnlSortQ); - % %ovrd = log(100/SeMin)/log(hnlSortQ); - % ovrd = log(0.01)/log(hnlMin); - % ovrd = max(ovrd, 2); - % ovrdPos = hnlSortQIdx; - % %ovrd = max(ovrd, 1); - % %SeMin = sqrt(SeLocalAvg/5); - % minCtr = 0; - %else - % %SeLocalMin = 0.9*SeLocalMin +0.1*SeQ; - % SeLocalAvg = SeLocalAvg + SeQ; - % minCtr = minCtr + 1; - %end - - if ovrd < ovrdSm - ovrdSm = 0.99*ovrdSm + 0.01*ovrd; - else - ovrdSm = 0.9*ovrdSm + 0.1*ovrd; - end - %end - - %ekEn = sum(real(ekfb.^2)); - %dkEn = sum(real(dk.^2)); - ekEn = sum(Se); - dkEn = sum(Sd); - - if divergeState == 0 - if ekEn > dkEn - ef = df; - divergeState = 1; - %hnlPrefAvg = hnlSortQ; - %hnled = (1 - cohxd); - end - else - %if ekEn*1.1 < dkEn - %if ekEn*1.26 < dkEn - if ekEn*1.05 < dkEn - divergeState = 0; - else - ef = df; - end - end - - if ekEn > dkEn*19.95 - WFb=zeros(N+1,M); % Block-based FD NLMS - end - - ekEnV(kk) = ekEn; - dkEnV(kk) = dkEn; - - hnlLocalMinV(kk) = hnlLocalMin; - cohxdLocalMinV(kk) = cohxdLocalMin; - hnlMinV(kk) = hnlMin; - %cohxdMaxLocal = max(cohxdSlow(kk,:)); - %if kk > 50 - %cohxdMaxLocal = 1-hnlSortQ; - %if cohxdMaxLocal > 0.5 - % %if cohxdMaxLocal > cohxdMax - % odScale = max(log(cohxdMaxLocal)/log(0.95), 1); - % %overdrive(7:end) = max(log(cohxdSlow(kk,7:end))/log(0.9), 1); - % cohxdMax = cohxdMaxLocal; - % end - %end - %end - %cohxdMax = cohxdMax*0.999; - - %overdriveM(kk,:) = max(overdrive, 1); - %aggrFact = 0.25; - aggrFact = 0.3; - %aggrFact = 0.5*propLow; - %if fs == 8000 - % wCurve = [0 ; 0 ; aggrFact*sqrt(linspace(0,1,N-1))' + 0.1]; - %else - % wCurve = [0; 0; 0; aggrFact*sqrt(linspace(0,1,N-2))' + 0.1]; - %end - wCurve = [0; aggrFact*sqrt(linspace(0,1,N))' + 0.1]; - % For sync with C - %if fs == 8000 - % wCurve = wCurve(2:end); - %else - % wCurve = wCurve(1:end-1); - %end - %weight = aggrFact*(sqrt(linspace(0,1,N+1)')); - %weight = aggrFact*wCurve; - weight = wCurve; - %weight = aggrFact*ones(N+1,1); - %weight = zeros(N+1,1); - %hnled = weight.*min(hnled) + (1 - weight).*hnled; - %hnled = weight.*min(mean(hnled(echoBandRange)), hnled) + (1 - weight).*hnled; - %hnled = weight.*min(hnlSortQ, hnled) + (1 - weight).*hnled; - - %hnlSortQV(kk) = mean(hnled); - %hnlPrefAvgV(kk) = mean(hnled(echoBandRange)); - - hnled = weight.*min(hnlPrefAvg, hnled) + (1 - weight).*hnled; - - %od = aggrFact*(sqrt(linspace(0,1,N+1)') + aggrTerm); - %od = 4*(sqrt(linspace(0,1,N+1)') + 1/4); - - %ovrdFact = (ovrdSm - 1) / sqrt(ovrdPos/(N+1)); - %ovrdFact = ovrdSm / sqrt(echoBandRange(floor(length(echoBandRange)/2))/(N+1)); - %od = ovrdFact*sqrt(linspace(0,1,N+1))' + 1; - %od = ovrdSm*ones(N+1,1).*abs(WFb(:,dIdx))/(max(abs(WFb(:,dIdx)))+1e-10); - - %od = ovrdSm*ones(N+1,1); - %od = ovrdSm*WFbD.*(sqrt(linspace(0,1,N+1))' + 1); - - od = ovrdSm*(sqrt(linspace(0,1,N+1))' + 1); - %od = 4*(sqrt(linspace(0,1,N+1))' + 1); - - %od = 2*ones(N+1,1); - %od = 2*ones(N+1,1); - %sshift = ((1-hnled)*2-1).^3+1; - sshift = ones(N+1,1); - - hnled = hnled.^(od.*sshift); - - %if hnlg > 0.75 - %if (suppState ~= 0) - % transCtr = 0; - %end - % suppState = 0; - %elseif hnlg < 0.6 & hnlg > 0.2 - % suppState = 1; - %elseif hnlg < 0.1 - %hnled = zeros(N+1, 1); - %if (suppState ~= 2) - % transCtr = 0; - %end - % suppState = 2; - %else - % if (suppState ~= 2) - % transCtr = 0; - % end - % suppState = 2; - %end - %if suppState == 0 - % hnled = ones(N+1, 1); - %elseif suppState == 2 - % hnled = zeros(N+1, 1); - %end - %hnled(find(hnled < 0.1)) = 0; - %hnled = hnled.^2; - %if transCtr < 5 - %hnl = 0.75*hnl + 0.25*hnled; - % transCtr = transCtr + 1; - %else - hnl = hnled; - %end - %hnled(find(hnled < 0.05)) = 0; - ef = ef.*(hnl); - - %ef = ef.*(min(1 - cohxd, cohed).^2); - %ef = ef.*((1-cohxd).^2); - - ovrdV(kk) = ovrdSm; - %ovrdV(kk) = dIdx; - %ovrdV(kk) = divergeFact; - %hnledAvg(kk) = 1-mean(1-cohedFast(echoBandRange)); - hnledAvg(kk) = 1-mean(1-cohed(echoBandRange)); - hnlxdAvg(kk) = 1-mean(cohxd(echoBandRange)); - %hnlxdAvg(kk) = cohxd(5); - %hnlSortQV(kk) = mean(hnled); - hnlSortQV(kk) = hnlPrefAvgLow; - hnlPrefAvgV(kk) = hnlPrefAvg; - %hnlAvg(kk) = propLow; - %ef(N/2:end) = 0; - %ner = (sum(Sd) ./ (sum(Se.*(hnl.^2)) + 1e-10)); - - % Comfort noise - if (CNon) - snn=sqrt(Sym); - snn(1)=0; % Reject LF noise - Un=snn.*exp(j*2*pi.*[0;rand(N-1,1);0]); - - % Weight comfort noise by suppression - Un = sqrt(1-hnled.^2).*Un; - Fmix = ef + Un; - else - Fmix = ef; - end - - % Overlap and add in time domain for smoothness - tmp = [Fmix ; flipud(conj(Fmix(2:N)))]; - mixw = wins.*real(ifft(tmp)); - mola = mbuf(end-N+1:end) + mixw(1:N); - mbuf = mixw; - ercn(pos:pos+N-1) = mola; - end % NLPon - - % Filter update - %Ek2 = Ek ./(12*pn + 0.001); % Normalized error - %Ek2 = Ek2 * divergeFact; - %Ek2 = Ek ./(pn + 0.001); % Normalized error - %Ek2 = Ek ./(100*pn + 0.001); % Normalized error - - %divergeIdx = find(abs(Ek) > abs(DD)); - %divergeIdx = find(Se > Sd); - %threshMod = threshold*ones(N+1,1); - %if length(divergeIdx) > 0 - %if sum(abs(Ek)) > sum(abs(DD)) - %WFb(divergeIdx,:) = WFb(divergeIdx,:) .* repmat(sqrt(Sd(divergeIdx)./(Se(divergeIdx)+1e-10))),1,M); - %Ek2(divergeIdx) = Ek2(divergeIdx) .* sqrt(Sd(divergeIdx)./(Se(divergeIdx)+1e-10)); - %Ek2(divergeIdx) = Ek2(divergeIdx) .* abs(DD(divergeIdx))./(abs(Ek(divergeIdx))+1e-10); - %WFb(divergeIdx,:) = WFbOld(divergeIdx,:); - %WFb = WFbOld; - %threshMod(divergeIdx) = threshMod(divergeIdx) .* abs(DD(divergeIdx))./(abs(Ek(divergeIdx))+1e-10); - % threshMod(divergeIdx) = threshMod(divergeIdx) .* sqrt(Sd(divergeIdx)./(Se(divergeIdx)+1e-10)); - %end - - %absEf = max(abs(Ek2), threshold); - %absEf = ones(N+1,1)*threshold./absEf; - %absEf = max(abs(Ek2), threshMod); - %absEf = threshMod./absEf; - %Ek2 = Ek2.*absEf; - - %if sum(Se) <= sum(Sd) - - % mEk = mufb.*Ek2; - % PP = conj(XFm).*(ones(M,1) * mEk')'; - % tmp = [PP ; flipud(conj(PP(2:N,:)))]; - % IFPP = real(ifft(tmp)); - % PH = IFPP(1:N,:); - % tmp = fft([PH;zeros(N,M)]); - % FPH = tmp(1:N+1,:); - % %WFbOld = WFb; - % WFb = WFb + FPH; - - %else - % WF = WFbOld; - %end - - % Shift old FFTs - %for m=M:-1:2 - % XFm(:,m) = XFm(:,m-1); - % YFm(:,m) = YFm(:,m-1); - %end - XFm(:,2:end) = XFm(:,1:end-1); - YFm(:,2:end) = YFm(:,1:end-1); - xfwm(:,2:end) = xfwm(:,1:end-1); - dfm(:,2:end) = dfm(:,1:end-1); - - %if mod(kk, floor(Nb/50)) == 0 - % fprintf(1, '.'); - %end - - if mod(kk, floor(Nb/100)) == 0 - %if mod(kk, floor(Nb/500)) == 0 - progressbar(kk/Nb); - %figure(5) - %plot(abs(WFb)); - %legend('1','2','3','4','5','6','7','8','9','10','11','12'); - %title(kk*N/fs); - %figure(6) - %plot(WFbD); - %figure(6) - %plot(threshMod) - %if length(divergeIdx) > 0 - % plot(abs(DD)) - % hold on - % plot(abs(Ek), 'r') - % hold off - %plot(min(sqrt(Sd./(Se+1e-10)),1)) - %axis([0 N 0 1]); - %end - %figure(6) - %plot(cohedFast); - %axis([1 N+1 0 1]); - %plot(WFbEn); - - %figure(7) - %plot(weight); - %plot([cohxd 1-cohed]); - %plot([cohxd 1-cohed 1-cohedFast hnled]); - %plot([cohxd cohxdFast/max(cohxdFast)]); - %legend('cohxd', '1-cohed', '1-cohedFast'); - %axis([1 65 0 1]); - %pause(0.5); - %overdrive - end -end -progressbar(1); - -%figure(2); -%plot([feat(:,1) feat(:,2)+1 feat(:,3)+2 mfeat+3]); -%plot([feat(:,1) mfeat+1]); - -%figure(3); -%plot(10*log10([dri erifb erifb3 ericn])); -%legend('Near-end','Error','Post NLP','Final',4); -% Compensate for delay -%ercn=[ercn(N+1:end);zeros(N,1)]; -%ercn_=[ercn_(N+1:end);zeros(N,1)]; - -%figure(11); -%plot(cohxdSlow); - -%figure(12); -%surf(cohxdSlow); -%shading interp; - -%figure(13); -%plot(overdriveM); - -%figure(14); -%surf(overdriveM); -%shading interp; - -figure(10); -t = (0:Nb)*N/fs; -rrinSubSamp = rrin(N*(1:(Nb+1))); -plot(t, rrinSubSamp/max(abs(rrinSubSamp)),'b'); -hold on -plot(t, hnledAvg, 'r'); -plot(t, hnlxdAvg, 'g'); -plot(t, hnlSortQV, 'y'); -plot(t, hnlLocalMinV, 'k'); -plot(t, cohxdLocalMinV, 'c'); -plot(t, hnlPrefAvgV, 'm'); -%plot(t, cohxdAvg, 'r'); -%plot(cohxdFastAvg, 'r'); -%plot(cohxdAvgBad, 'k'); -%plot(t, cohedAvg, 'k'); -%plot(t, 1-cohedFastAvg, 'k'); -%plot(ssin(N*(1:floor(length(ssin)/N)))/max(abs(ssin))); -%plot(echoBands,'r'); -%plot(overdrive, 'g'); -%plot(erfb(N*(1:floor(length(erfb)/N)))/max(abs(erfb))); -hold off -tightx; - -figure(11) -plot(t, ovrdV); -tightx; -%plot(mfeat,'r'); -%plot(1-cohxyp_,'r'); -%plot(Hnlxydp,'y'); -%plot(hnledp,'k'); -%plot(Hnlxydp, 'c'); -%plot(ccohpd_,'k'); -%plot(supplot_, 'g'); -%plot(ones(length(mfeat),1)*rr1_, 'k'); -%plot(ones(length(mfeat),1)*rr2_, 'k'); -%plot(N*(1:length(feat)), feat); -%plot(Sep_,'r'); -%axis([1 floor(length(erfb)/N) -1 1]) -%hold off -%plot(10*log10([Se_, Sx_, Seu_, real(sf_.*conj(sf_))])); -%legend('Se','Sx','Seu','S'); -%figure(5) -%plot([ercn ercn_]); - -figure(12) -plot(t, dIdxV); -%plot(t, SLxV); -tightx; - -%figure(13) -%plot(t, [ekEnV dkEnV]); -%plot(t, dkEnV./(ekEnV+1e-10)); -%tightx; - -%close(hh); -%spclab(fs,ssin,erfb,ercn,'outxd.pcm'); -%spclab(fs,rrin,ssin,erfb,1.78*ercn,'vqeOut-1.pcm'); -%spclab(fs,erfb,'aecOutLp.pcm'); -%spclab(fs,rrin,ssin,erfb,1.78*ercn,'aecOut25.pcm','vqeOut-1.pcm'); -%spclab(fs,rrin,ssin,erfb,ercn,'aecOut-mba.pcm'); -%spclab(fs,rrin,ssin,erfb,ercn,'aecOut.pcm'); -%spclab(fs, ssin, erfb, ercn, 'out0.pcm'); diff --git a/src/modules/audio_processing/aec/main/source/aec_core.c b/src/modules/audio_processing/aec/main/source/aec_core.c index 8782242..e01728f 100644 --- a/src/modules/audio_processing/aec/main/source/aec_core.c +++ b/src/modules/audio_processing/aec/main/source/aec_core.c @@ -12,12 +12,14 @@ * The core AEC algorithm, which is presented with time-aligned signals. */ +#include "aec_core.h" + #include <math.h> #include <stdlib.h> #include <string.h> -#include "aec_core.h" #include "aec_rdft.h" +#include "delay_estimator_float.h" #include "ring_buffer.h" #include "system_wrappers/interface/cpu_features_wrapper.h" @@ -34,26 +36,9 @@ static const float cnScaleHband = (float)0.4; // scale for comfort noise in H ba // Initial bin for averaging nlp gain in low band static const int freqAvgIc = PART_LEN / 2; -/* Matlab code to produce table: -win = sqrt(hanning(63)); win = [0 ; win(1:32)]; -fprintf(1, '\t%.14f, %.14f, %.14f,\n', win); -*/ -/* -static const float sqrtHanning[33] = { - 0.00000000000000, 0.04906767432742, 0.09801714032956, - 0.14673047445536, 0.19509032201613, 0.24298017990326, - 0.29028467725446, 0.33688985339222, 0.38268343236509, - 0.42755509343028, 0.47139673682600, 0.51410274419322, - 0.55557023301960, 0.59569930449243, 0.63439328416365, - 0.67155895484702, 0.70710678118655, 0.74095112535496, - 0.77301045336274, 0.80320753148064, 0.83146961230255, - 0.85772861000027, 0.88192126434835, 0.90398929312344, - 0.92387953251129, 0.94154406518302, 0.95694033573221, - 0.97003125319454, 0.98078528040323, 0.98917650996478, - 0.99518472667220, 0.99879545620517, 1.00000000000000 -}; -*/ - +// Matlab code to produce table: +// win = sqrt(hanning(63)); win = [0 ; win(1:32)]; +// fprintf(1, '\t%.14f, %.14f, %.14f,\n', win); static const float sqrtHanning[65] = { 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f, 0.09801714032956f, 0.12241067519922f, @@ -79,10 +64,9 @@ static const float sqrtHanning[65] = { 0.99969881869620f, 1.00000000000000f }; -/* Matlab code to produce table: -weightCurve = [0 ; 0.3 * sqrt(linspace(0,1,64))' + 0.1]; -fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', weightCurve); -*/ +// Matlab code to produce table: +// weightCurve = [0 ; 0.3 * sqrt(linspace(0,1,64))' + 0.1]; +// fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', weightCurve); const float WebRtcAec_weightCurve[65] = { 0.0000f, 0.1000f, 0.1378f, 0.1535f, 0.1655f, 0.1756f, 0.1845f, 0.1926f, 0.2000f, 0.2069f, 0.2134f, 0.2195f, @@ -97,10 +81,9 @@ const float WebRtcAec_weightCurve[65] = { 0.3903f, 0.3928f, 0.3952f, 0.3976f, 0.4000f }; -/* Matlab code to produce table: -overDriveCurve = [sqrt(linspace(0,1,65))' + 1]; -fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', overDriveCurve); -*/ +// Matlab code to produce table: +// overDriveCurve = [sqrt(linspace(0,1,65))' + 1]; +// fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', overDriveCurve); const float WebRtcAec_overDriveCurve[65] = { 1.0000f, 1.1250f, 1.1768f, 1.2165f, 1.2500f, 1.2795f, 1.3062f, 1.3307f, 1.3536f, 1.3750f, 1.3953f, 1.4146f, @@ -193,6 +176,15 @@ int WebRtcAec_CreateAec(aec_t **aecInst) return -1; } + if (WebRtc_CreateDelayEstimatorFloat(&aec->delay_estimator, + PART_LEN1, + kMaxDelay, + 0) == -1) { + WebRtcAec_FreeAec(aec); + aec = NULL; + return -1; + } + return 0; } @@ -209,6 +201,8 @@ int WebRtcAec_FreeAec(aec_t *aec) WebRtcApm_FreeBuffer(aec->nearFrBufH); WebRtcApm_FreeBuffer(aec->outFrBufH); + WebRtc_FreeDelayEstimatorFloat(aec->delay_estimator); + free(aec); return 0; } @@ -255,6 +249,32 @@ static void ScaleErrorSignal(aec_t *aec, float ef[2][PART_LEN1]) } } +// Time-unconstrined filter adaptation. +// TODO(andrew): consider for a low-complexity mode. +//static void FilterAdaptationUnconstrained(aec_t *aec, float *fft, +// float ef[2][PART_LEN1]) { +// int i, j; +// for (i = 0; i < NR_PART; i++) { +// int xPos = (i + aec->xfBufBlockPos)*(PART_LEN1); +// int pos; +// // Check for wrap +// if (i + aec->xfBufBlockPos >= NR_PART) { +// xPos -= NR_PART * PART_LEN1; +// } +// +// pos = i * PART_LEN1; +// +// for (j = 0; j < PART_LEN1; j++) { +// aec->wfBuf[pos + j][0] += MulRe(aec->xfBuf[xPos + j][0], +// -aec->xfBuf[xPos + j][1], +// ef[j][0], ef[j][1]); +// aec->wfBuf[pos + j][1] += MulIm(aec->xfBuf[xPos + j][0], +// -aec->xfBuf[xPos + j][1], +// ef[j][0], ef[j][1]); +// } +// } +//} + static void FilterAdaptation(aec_t *aec, float *fft, float ef[2][PART_LEN1]) { int i, j; for (i = 0; i < NR_PART; i++) { @@ -267,16 +287,6 @@ static void FilterAdaptation(aec_t *aec, float *fft, float ef[2][PART_LEN1]) { pos = i * PART_LEN1; -#ifdef UNCONSTR - for (j = 0; j < PART_LEN1; j++) { - aec->wfBuf[pos + j][0] += MulRe(aec->xfBuf[xPos + j][0], - -aec->xfBuf[xPos + j][1], - ef[j][0], ef[j][1]); - aec->wfBuf[pos + j][1] += MulIm(aec->xfBuf[xPos + j][0], - -aec->xfBuf[xPos + j][1], - ef[j][0], ef[j][1]); - } -#else for (j = 0; j < PART_LEN; j++) { fft[2 * j] = MulRe(aec->xfBuf[0][xPos + j], @@ -309,7 +319,6 @@ static void FilterAdaptation(aec_t *aec, float *fft, float ef[2][PART_LEN1]) { aec->wfBuf[0][pos + j] += fft[2 * j]; aec->wfBuf[1][pos + j] += fft[2 * j + 1]; } -#endif // UNCONSTR } } @@ -375,6 +384,12 @@ int WebRtcAec_InitAec(aec_t *aec, int sampFreq) return -1; } + if (WebRtc_InitDelayEstimatorFloat(aec->delay_estimator) != 0) { + return -1; + } + aec->delay_logging_enabled = 0; + memset(aec->delay_histogram, 0, sizeof(aec->delay_histogram)); + // Default target suppression level aec->targetSupp = -11.5; aec->minOverDrive = 2.0; @@ -565,6 +580,10 @@ static void ProcessBlock(aec_t *aec, const short *farend, float fft[PART_LEN2]; float xf[2][PART_LEN1], yf[2][PART_LEN1], ef[2][PART_LEN1]; complex_t df[PART_LEN1]; + float far_spectrum = 0.0f; + float near_spectrum = 0.0f; + float abs_far_spectrum[PART_LEN1]; + float abs_near_spectrum[PART_LEN1]; const float gPow[2] = {0.9f, 0.1f}; @@ -629,10 +648,15 @@ static void ProcessBlock(aec_t *aec, const short *farend, // Power smoothing for (i = 0; i < PART_LEN1; i++) { - aec->xPow[i] = gPow[0] * aec->xPow[i] + gPow[1] * NR_PART * - (xf[0][i] * xf[0][i] + xf[1][i] * xf[1][i]); - aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * - (df[i][0] * df[i][0] + df[i][1] * df[i][1]); + far_spectrum = xf[0][i] * xf[0][i] + xf[1][i] * xf[1][i]; + aec->xPow[i] = gPow[0] * aec->xPow[i] + gPow[1] * NR_PART * far_spectrum; + // Calculate absolute spectra + abs_far_spectrum[i] = sqrtf(far_spectrum); + + near_spectrum = df[i][0] * df[i][0] + df[i][1] * df[i][1]; + aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum; + // Calculate absolute spectra + abs_near_spectrum[i] = sqrtf(near_spectrum); } // Estimate noise power. Wait until dPow is more stable. @@ -667,6 +691,20 @@ static void ProcessBlock(aec_t *aec, const short *farend, aec->noisePow = aec->dMinPow; } + // Block wise delay estimation used for logging + if (aec->delay_logging_enabled) { + int delay_estimate = 0; + // Estimate the delay + delay_estimate = WebRtc_DelayEstimatorProcessFloat(aec->delay_estimator, + abs_far_spectrum, + abs_near_spectrum, + PART_LEN1, + aec->echoState); + if (delay_estimate >= 0) { + // Update delay estimate buffer + aec->delay_histogram[delay_estimate]++; + } + } // Update the xfBuf block position. aec->xfBufBlockPos--; @@ -720,9 +758,7 @@ static void ProcessBlock(aec_t *aec, const short *farend, // Scale error signal inversely with far power. WebRtcAec_ScaleErrorSignal(aec, ef); - // Filter adaptation WebRtcAec_FilterAdaptation(aec, fft, ef); - NonLinearProcessing(aec, output, outputH); #ifdef AEC_DEBUG diff --git a/src/modules/audio_processing/aec/main/source/aec_core.h b/src/modules/audio_processing/aec/main/source/aec_core.h index 8726bd5..e693425 100644 --- a/src/modules/audio_processing/aec/main/source/aec_core.h +++ b/src/modules/audio_processing/aec/main/source/aec_core.h @@ -20,7 +20,6 @@ #include "signal_processing_library.h" #include "typedefs.h" -//#define UNCONSTR // time-unconstrained filter //#define AEC_DEBUG // for recording files #define FRAME_LEN 80 @@ -34,6 +33,8 @@ #define PREF_BAND_SIZE 24 #define BLOCKL_MAX FRAME_LEN +// Maximum delay in fixed point delay estimator, used for logging +enum {kMaxDelay = 100}; typedef float complex_t[2]; // For performance reasons, some arrays of complex numbers are replaced by twice @@ -142,6 +143,10 @@ typedef struct { int flag_Hband_cn; //for comfort noise float cn_scale_Hband; //scale for comfort noise in H band + int delay_histogram[kMaxDelay]; + int delay_logging_enabled; + void* delay_estimator; + #ifdef AEC_DEBUG FILE *farFile; FILE *nearFile; diff --git a/src/modules/audio_processing/aec/main/source/aec_core_sse2.c b/src/modules/audio_processing/aec/main/source/aec_core_sse2.c index 0f732e0..8894f28 100644 --- a/src/modules/audio_processing/aec/main/source/aec_core_sse2.c +++ b/src/modules/audio_processing/aec/main/source/aec_core_sse2.c @@ -138,16 +138,6 @@ static void FilterAdaptationSSE2(aec_t *aec, float *fft, float ef[2][PART_LEN1]) xPos -= NR_PART * PART_LEN1; } -#ifdef UNCONSTR - for (j = 0; j < PART_LEN1; j++) { - aec->wfBuf[pos + j][0] += MulRe(aec->xfBuf[xPos + j][0], - -aec->xfBuf[xPos + j][1], - ef[j][0], ef[j][1]); - aec->wfBuf[pos + j][1] += MulIm(aec->xfBuf[xPos + j][0], - -aec->xfBuf[xPos + j][1], - ef[j][0], ef[j][1]); - } -#else // Process the whole array... for (j = 0; j < PART_LEN; j+= 4) { // Load xfBuf and ef. @@ -208,7 +198,6 @@ static void FilterAdaptationSSE2(aec_t *aec, float *fft, float ef[2][PART_LEN1]) } aec->wfBuf[1][pos] = wt1; } -#endif // UNCONSTR } } @@ -246,10 +235,9 @@ static __m128 mm_pow_ps(__m128 a, __m128 b) {0x43BF8000, 0x43BF8000, 0x43BF8000, 0x43BF8000}; static const int shift_exponent_into_top_mantissa = 8; const __m128 two_n = _mm_and_ps(a, *((__m128 *)float_exponent_mask)); - const __m128 n_1 = (__m128)_mm_srli_epi32((__m128i)two_n, - shift_exponent_into_top_mantissa); - const __m128 n_0 = _mm_or_ps( - (__m128)n_1, *((__m128 *)eight_biased_exponent)); + const __m128 n_1 = _mm_castsi128_ps(_mm_srli_epi32(_mm_castps_si128(two_n), + shift_exponent_into_top_mantissa)); + const __m128 n_0 = _mm_or_ps(n_1, *((__m128 *)eight_biased_exponent)); const __m128 n = _mm_sub_ps(n_0, *((__m128 *)implicit_leading_one)); // Compute y. @@ -328,8 +316,8 @@ static __m128 mm_pow_ps(__m128 a, __m128 b) static const int float_exponent_shift = 23; const __m128i two_n_exponent = _mm_add_epi32( x_minus_half_floor, *((__m128i *)float_exponent_bias)); - const __m128 two_n = (__m128)_mm_slli_epi32( - two_n_exponent, float_exponent_shift); + const __m128 two_n = _mm_castsi128_ps(_mm_slli_epi32( + two_n_exponent, float_exponent_shift)); // Compute y. const __m128 y = _mm_sub_ps(x_max, _mm_cvtepi32_ps(x_minus_half_floor)); // Approximate 2^y ~= C2 * y^2 + C1 * y + C0. diff --git a/src/modules/audio_processing/aec/main/source/aec_rdft.h b/src/modules/audio_processing/aec/main/source/aec_rdft.h index 5f4085b..91bedc9 100644 --- a/src/modules/audio_processing/aec/main/source/aec_rdft.h +++ b/src/modules/audio_processing/aec/main/source/aec_rdft.h @@ -11,6 +11,14 @@ #ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_ #define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_ +// These intrinsics were unavailable before VS 2008. +// TODO(andrew): move to a common file. +#if defined(_MSC_VER) && _MSC_VER < 1500 +#include <emmintrin.h> +static __inline __m128 _mm_castsi128_ps(__m128i a) { return *(__m128*)&a; } +static __inline __m128i _mm_castps_si128(__m128 a) { return *(__m128i*)&a; } +#endif + #ifdef _MSC_VER /* visual c++ */ # define ALIGN16_BEG __declspec(align(16)) # define ALIGN16_END diff --git a/src/modules/audio_processing/aec/main/source/aec_rdft_sse2.c b/src/modules/audio_processing/aec/main/source/aec_rdft_sse2.c index 89aea87..f936e2a 100644 --- a/src/modules/audio_processing/aec/main/source/aec_rdft_sse2.c +++ b/src/modules/audio_processing/aec/main/source/aec_rdft_sse2.c @@ -42,27 +42,33 @@ static void cft1st_128_SSE2(float *a) { const __m128 x1v = _mm_sub_ps(a01v, a23v); const __m128 x2v = _mm_add_ps(a45v, a67v); const __m128 x3v = _mm_sub_ps(a45v, a67v); + __m128 x0w; a01v = _mm_add_ps(x0v, x2v); x0v = _mm_sub_ps(x0v, x2v); - __m128 x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1)); - - const __m128 a45_0v = _mm_mul_ps(wk2rv, x0v); - const __m128 a45_1v = _mm_mul_ps(wk2iv, x0w); - a45v = _mm_add_ps(a45_0v, a45_1v); - - const __m128 x3w = _mm_shuffle_ps(x3v, x3v, _MM_SHUFFLE(2, 3, 0 ,1)); - const __m128 x3s = _mm_mul_ps(mm_swap_sign, x3w); - x0v = _mm_add_ps(x1v, x3s); - x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1)); - const __m128 a23_0v = _mm_mul_ps(wk1rv, x0v); - const __m128 a23_1v = _mm_mul_ps(wk1iv, x0w); - a23v = _mm_add_ps(a23_0v, a23_1v); - - x0v = _mm_sub_ps(x1v, x3s); x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1)); - const __m128 a67_0v = _mm_mul_ps(wk3rv, x0v); - const __m128 a67_1v = _mm_mul_ps(wk3iv, x0w); - a67v = _mm_add_ps(a67_0v, a67_1v); + { + const __m128 a45_0v = _mm_mul_ps(wk2rv, x0v); + const __m128 a45_1v = _mm_mul_ps(wk2iv, x0w); + a45v = _mm_add_ps(a45_0v, a45_1v); + } + { + __m128 a23_0v, a23_1v; + const __m128 x3w = _mm_shuffle_ps(x3v, x3v, _MM_SHUFFLE(2, 3, 0 ,1)); + const __m128 x3s = _mm_mul_ps(mm_swap_sign, x3w); + x0v = _mm_add_ps(x1v, x3s); + x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1)); + a23_0v = _mm_mul_ps(wk1rv, x0v); + a23_1v = _mm_mul_ps(wk1iv, x0w); + a23v = _mm_add_ps(a23_0v, a23_1v); + + x0v = _mm_sub_ps(x1v, x3s); + x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1)); + } + { + const __m128 a67_0v = _mm_mul_ps(wk3rv, x0v); + const __m128 a67_1v = _mm_mul_ps(wk3iv, x0w); + a67v = _mm_add_ps(a67_0v, a67_1v); + } a00v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(1, 0, 1 ,0)); a04v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(1, 0, 1 ,0)); @@ -78,7 +84,7 @@ static void cft1st_128_SSE2(float *a) { static void cftmdl_128_SSE2(float *a) { const int l = 8; const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign); - int j0, k, k1, k2; + int j0; __m128 wk1rv = _mm_load_ps(cftmdl_wk1r); for (j0 = 0; j0 < l; j0 += 2) { @@ -86,9 +92,11 @@ static void cftmdl_128_SSE2(float *a) { const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]); const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]); const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]); - const __m128 a_00_32 = _mm_shuffle_ps((__m128)a_00, (__m128)a_32, + const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00), + _mm_castsi128_ps(a_32), _MM_SHUFFLE(1, 0, 1 ,0)); - const __m128 a_08_40 = _mm_shuffle_ps((__m128)a_08, (__m128)a_40, + const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08), + _mm_castsi128_ps(a_40), _MM_SHUFFLE(1, 0, 1 ,0)); __m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40); const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40); @@ -97,30 +105,24 @@ static void cftmdl_128_SSE2(float *a) { const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]); const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]); const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]); - const __m128 a_16_48 = _mm_shuffle_ps((__m128)a_16, (__m128)a_48, + const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16), + _mm_castsi128_ps(a_48), _MM_SHUFFLE(1, 0, 1 ,0)); - const __m128 a_24_56 = _mm_shuffle_ps((__m128)a_24, (__m128)a_56, + const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24), + _mm_castsi128_ps(a_56), _MM_SHUFFLE(1, 0, 1 ,0)); const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56); const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56); const __m128 xx0 = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); - _mm_storel_epi64((__m128i*)&a[j0 + 0], (__m128i)xx0); - _mm_storel_epi64((__m128i*)&a[j0 + 32], - _mm_shuffle_epi32((__m128i)xx0, _MM_SHUFFLE(3, 2, 3, 2))); const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); - _mm_storel_epi64((__m128i*)&a[j0 + 16], (__m128i)xx1); - _mm_storel_epi64((__m128i*)&a[j0 + 48], - _mm_shuffle_epi32((__m128i)xx1, _MM_SHUFFLE(2, 3, 2, 3))); - a[j0 + 48] = -a[j0 + 48]; - const __m128 x3i0_3r0_3i1_x3r1 = (__m128) - _mm_shuffle_epi32((__m128i)x3r0_3i0_3r1_x3i1, _MM_SHUFFLE(2, 3, 0, 1)); + const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps( + _mm_shuffle_epi32(_mm_castps_si128(x3r0_3i0_3r1_x3i1), + _MM_SHUFFLE(2, 3, 0, 1))); const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1); const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped); const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped); - _mm_storel_epi64((__m128i*)&a[j0 + 8], (__m128i)x1_x3_add); - _mm_storel_epi64((__m128i*)&a[j0 + 24], (__m128i)x1_x3_sub); const __m128 yy0 = _mm_shuffle_ps(x1_x3_add, x1_x3_sub, _MM_SHUFFLE(2, 2, 2 ,2)); @@ -129,79 +131,111 @@ static void cftmdl_128_SSE2(float *a) { const __m128 yy2 = _mm_mul_ps(mm_swap_sign, yy1); const __m128 yy3 = _mm_add_ps(yy0, yy2); const __m128 yy4 = _mm_mul_ps(wk1rv, yy3); - _mm_storel_epi64((__m128i*)&a[j0 + 40], (__m128i)yy4); - _mm_storel_epi64((__m128i*)&a[j0 + 56], - _mm_shuffle_epi32((__m128i)yy4, _MM_SHUFFLE(2, 3, 2, 3))); - } - k1 = 0; - k = 64; - k1 += 2; - k2 = 2 * k1; - const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2+0]); - const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2+0]); - wk1rv = _mm_load_ps(&rdft_wk1r[k2+0]); - const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2+0]); - const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2+0]); - const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2+0]); - for (j0 = k; j0 < l + k; j0 += 2) { - const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]); - const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]); - const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]); - const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]); - const __m128 a_00_32 = _mm_shuffle_ps((__m128)a_00, (__m128)a_32, - _MM_SHUFFLE(1, 0, 1 ,0)); - const __m128 a_08_40 = _mm_shuffle_ps((__m128)a_08, (__m128)a_40, - _MM_SHUFFLE(1, 0, 1 ,0)); - __m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40); - const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40); - - const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]); - const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]); - const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]); - const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]); - const __m128 a_16_48 = _mm_shuffle_ps((__m128)a_16, (__m128)a_48, - _MM_SHUFFLE(1, 0, 1 ,0)); - const __m128 a_24_56 = _mm_shuffle_ps((__m128)a_24, (__m128)a_56, - _MM_SHUFFLE(1, 0, 1 ,0)); - const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56); - const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56); - - const __m128 xx = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); - _mm_storel_epi64((__m128i*)&a[j0 + 0], (__m128i)xx); + _mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx0)); _mm_storel_epi64((__m128i*)&a[j0 + 32], - _mm_shuffle_epi32((__m128i)xx, _MM_SHUFFLE(3, 2, 3, 2))); - - const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); - const __m128 xx2 = _mm_mul_ps(xx1 , wk2rv); - const __m128 xx3 = _mm_mul_ps(wk2iv, - (__m128)_mm_shuffle_epi32((__m128i)xx1, _MM_SHUFFLE(2, 3, 0, 1))); - const __m128 xx4 = _mm_add_ps(xx2, xx3); - _mm_storel_epi64((__m128i*)&a[j0 + 16], (__m128i)xx4); + _mm_shuffle_epi32(_mm_castps_si128(xx0), + _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx1)); _mm_storel_epi64((__m128i*)&a[j0 + 48], - _mm_shuffle_epi32((__m128i)xx4, _MM_SHUFFLE(3, 2, 3, 2))); + _mm_shuffle_epi32(_mm_castps_si128(xx1), + _MM_SHUFFLE(2, 3, 2, 3))); + a[j0 + 48] = -a[j0 + 48]; - const __m128 x3i0_3r0_3i1_x3r1 = (__m128) - _mm_shuffle_epi32((__m128i)x3r0_3i0_3r1_x3i1, _MM_SHUFFLE(2, 3, 0, 1)); - const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1); - const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped); - const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + _mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(x1_x3_add)); + _mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(x1_x3_sub)); - const __m128 xx10 = _mm_mul_ps(x1_x3_add, wk1rv); - const __m128 xx11 = _mm_mul_ps(wk1iv, - (__m128)_mm_shuffle_epi32((__m128i)x1_x3_add, _MM_SHUFFLE(2, 3, 0, 1))); - const __m128 xx12 = _mm_add_ps(xx10, xx11); - _mm_storel_epi64((__m128i*)&a[j0 + 8], (__m128i)xx12); - _mm_storel_epi64((__m128i*)&a[j0 + 40], - _mm_shuffle_epi32((__m128i)xx12, _MM_SHUFFLE(3, 2, 3, 2))); - - const __m128 xx20 = _mm_mul_ps(x1_x3_sub, wk3rv); - const __m128 xx21 = _mm_mul_ps(wk3iv, - (__m128)_mm_shuffle_epi32((__m128i)x1_x3_sub, _MM_SHUFFLE(2, 3, 0, 1))); - const __m128 xx22 = _mm_add_ps(xx20, xx21); - _mm_storel_epi64((__m128i*)&a[j0 + 24], (__m128i)xx22); + _mm_storel_epi64((__m128i*)&a[j0 + 40], _mm_castps_si128(yy4)); _mm_storel_epi64((__m128i*)&a[j0 + 56], - _mm_shuffle_epi32((__m128i)xx22, _MM_SHUFFLE(3, 2, 3, 2))); + _mm_shuffle_epi32(_mm_castps_si128(yy4), + _MM_SHUFFLE(2, 3, 2, 3))); + } + + { + int k = 64; + int k1 = 2; + int k2 = 2 * k1; + const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2+0]); + const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2+0]); + const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2+0]); + const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2+0]); + const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2+0]); + wk1rv = _mm_load_ps(&rdft_wk1r[k2+0]); + for (j0 = k; j0 < l + k; j0 += 2) { + const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]); + const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]); + const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]); + const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]); + const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00), + _mm_castsi128_ps(a_32), + _MM_SHUFFLE(1, 0, 1 ,0)); + const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08), + _mm_castsi128_ps(a_40), + _MM_SHUFFLE(1, 0, 1 ,0)); + __m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40); + const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40); + + const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]); + const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]); + const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]); + const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]); + const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16), + _mm_castsi128_ps(a_48), + _MM_SHUFFLE(1, 0, 1 ,0)); + const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24), + _mm_castsi128_ps(a_56), + _MM_SHUFFLE(1, 0, 1 ,0)); + const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56); + const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56); + + const __m128 xx = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const __m128 xx2 = _mm_mul_ps(xx1 , wk2rv); + const __m128 xx3 = _mm_mul_ps(wk2iv, + _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xx1), + _MM_SHUFFLE(2, 3, 0, 1)))); + const __m128 xx4 = _mm_add_ps(xx2, xx3); + + const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps( + _mm_shuffle_epi32(_mm_castps_si128(x3r0_3i0_3r1_x3i1), + _MM_SHUFFLE(2, 3, 0, 1))); + const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1); + const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + + const __m128 xx10 = _mm_mul_ps(x1_x3_add, wk1rv); + const __m128 xx11 = _mm_mul_ps(wk1iv, + _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_add), + _MM_SHUFFLE(2, 3, 0, 1)))); + const __m128 xx12 = _mm_add_ps(xx10, xx11); + + const __m128 xx20 = _mm_mul_ps(x1_x3_sub, wk3rv); + const __m128 xx21 = _mm_mul_ps(wk3iv, + _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_sub), + _MM_SHUFFLE(2, 3, 0, 1)))); + const __m128 xx22 = _mm_add_ps(xx20, xx21); + + _mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx)); + _mm_storel_epi64((__m128i*)&a[j0 + 32], + _mm_shuffle_epi32(_mm_castps_si128(xx), + _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx4)); + _mm_storel_epi64((__m128i*)&a[j0 + 48], + _mm_shuffle_epi32(_mm_castps_si128(xx4), + _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(xx12)); + _mm_storel_epi64((__m128i*)&a[j0 + 40], + _mm_shuffle_epi32(_mm_castps_si128(xx12), + _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(xx22)); + _mm_storel_epi64((__m128i*)&a[j0 + 56], + _mm_shuffle_epi32(_mm_castps_si128(xx22), + _MM_SHUFFLE(3, 2, 3, 2))); + } } } diff --git a/src/modules/audio_processing/aec/main/source/echo_cancellation.c b/src/modules/audio_processing/aec/main/source/echo_cancellation.c index f6a2538..36738f7 100644 --- a/src/modules/audio_processing/aec/main/source/echo_cancellation.c +++ b/src/modules/audio_processing/aec/main/source/echo_cancellation.c @@ -11,16 +11,18 @@ /* * Contains the API functions for the AEC. */ +#include "echo_cancellation.h" + +#include <math.h> +#ifdef AEC_DEBUG +#include <stdio.h> +#endif #include <stdlib.h> #include <string.h> -#include "echo_cancellation.h" #include "aec_core.h" -#include "ring_buffer.h" #include "resampler.h" -#ifdef AEC_DEBUG - #include <stdio.h> -#endif +#include "ring_buffer.h" #define BUF_SIZE_FRAMES 50 // buffer size (frames) // Maximum length of resampled signal. Must be an integer multiple of frames @@ -215,7 +217,7 @@ WebRtc_Word32 WebRtcAec_Init(void *aecInst, WebRtc_Word32 sampFreq, WebRtc_Word3 return -1; } - aecpc->initFlag = initCheck; // indicates that initilisation has been done + aecpc->initFlag = initCheck; // indicates that initialization has been done if (aecpc->sampFreq == 32000) { aecpc->splitSampFreq = 16000; @@ -254,6 +256,7 @@ WebRtc_Word32 WebRtcAec_Init(void *aecInst, WebRtc_Word32 sampFreq, WebRtc_Word3 aecConfig.nlpMode = kAecNlpModerate; aecConfig.skewMode = kAecFalse; aecConfig.metricsMode = kAecFalse; + aecConfig.delay_logging = kAecFalse; if (WebRtcAec_set_config(aecpc, aecConfig) == -1) { aecpc->lastError = AEC_UNSPECIFIED_ERROR; @@ -566,6 +569,15 @@ WebRtc_Word32 WebRtcAec_set_config(void *aecInst, AecConfig config) WebRtcAec_InitMetrics(aecpc->aec); } + if (config.delay_logging != kAecFalse && config.delay_logging != kAecTrue) { + aecpc->lastError = AEC_BAD_PARAMETER_ERROR; + return -1; + } + aecpc->aec->delay_logging_enabled = config.delay_logging; + if (aecpc->aec->delay_logging_enabled == kAecTrue) { + memset(aecpc->aec->delay_histogram, 0, sizeof(aecpc->aec->delay_histogram)); + } + return 0; } @@ -590,6 +602,7 @@ WebRtc_Word32 WebRtcAec_get_config(void *aecInst, AecConfig *config) config->nlpMode = aecpc->nlpMode; config->skewMode = aecpc->skewMode; config->metricsMode = aecpc->aec->metricsMode; + config->delay_logging = aecpc->aec->delay_logging_enabled; return 0; } @@ -717,6 +730,69 @@ WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics) return 0; } +int WebRtcAec_GetDelayMetrics(void* handle, int* median, int* std) { + aecpc_t* self = handle; + int i = 0; + int delay_values = 0; + int num_delay_values = 0; + int my_median = 0; + float l1_norm = 0; + + if (self == NULL) { + return -1; + } + if (median == NULL) { + self->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + if (std == NULL) { + self->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + if (self->initFlag != initCheck) { + self->lastError = AEC_UNINITIALIZED_ERROR; + return -1; + } + if (self->aec->delay_logging_enabled == 0) { + // Logging disabled + self->lastError = AEC_UNSUPPORTED_FUNCTION_ERROR; + return -1; + } + + // Get number of delay values since last update + for (i = 0; i < kMaxDelay; i++) { + num_delay_values += self->aec->delay_histogram[i]; + } + if (num_delay_values == 0) { + // We have no new delay value data + *median = -1; + *std = -1; + return 0; + } + + delay_values = num_delay_values >> 1; // Start value for median count down + // Get median of delay values since last update + for (i = 0; i < kMaxDelay; i++) { + delay_values -= self->aec->delay_histogram[i]; + if (delay_values < 0) { + my_median = i; + break; + } + } + *median = my_median; + + // Calculate the L1 norm, with median value as central moment + for (i = 0; i < kMaxDelay; i++) { + l1_norm += (float) (fabs(i - my_median) * self->aec->delay_histogram[i]); + } + *std = (int) (l1_norm / (float) num_delay_values + 0.5f); + + // Reset histogram + memset(self->aec->delay_histogram, 0, sizeof(self->aec->delay_histogram)); + + return 0; +} + WebRtc_Word32 WebRtcAec_get_version(WebRtc_Word8 *versionStr, WebRtc_Word16 len) { const char version[] = "AEC 2.5.0"; diff --git a/src/modules/audio_processing/aecm/Makefile.am b/src/modules/audio_processing/aecm/Makefile.am index c36bb40..b25fd09 100644 --- a/src/modules/audio_processing/aecm/Makefile.am +++ b/src/modules/audio_processing/aecm/Makefile.am @@ -3,9 +3,7 @@ noinst_LTLIBRARIES = libaecm.la libaecm_la_SOURCES = main/interface/echo_control_mobile.h \ main/source/echo_control_mobile.c \ main/source/aecm_core.c \ - main/source/aecm_core.h \ - main/source/aecm_delay_estimator.c \ - main/source/aecm_delay_estimator.h + main/source/aecm_core.h libaecm_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS) \ -I$(top_srcdir)/src/common_audio/signal_processing_library/main/interface \ -I$(top_srcdir)/src/modules/audio_processing/utility diff --git a/src/modules/audio_processing/aecm/main/matlab/compsup.m b/src/modules/audio_processing/aecm/main/matlab/compsup.m deleted file mode 100644 index 9575ec4..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/compsup.m +++ /dev/null @@ -1,447 +0,0 @@ -function [emicrophone,aaa]=compsup(microphone,TheFarEnd,avtime,samplingfreq); -% microphone = microphone signal -% aaa = nonlinearity input variable -% TheFarEnd = far end signal -% avtime = interval to compute suppression from (seconds) -% samplingfreq = sampling frequency - -%if(nargin==6) -% fprintf(1,'suppress has received a delay sequence\n'); -%end - - -Ap500=[ 1.00, -4.95, 9.801, -9.70299, 4.80298005, -0.9509900499]; -Bp500=[ 0.662743088639636, -2.5841655608125, 3.77668102146288, -2.45182477425154, 0.596566274575251, 0.0]; - - -Ap200=[ 1.00, -4.875, 9.50625, -9.26859375, 4.518439453125, -0.881095693359375]; -Bp200=[ 0.862545460994275, -3.2832804496114, 4.67892032308828, -2.95798023879133, 0.699796870041299, 0.0]; - -maxDelay=0.4; %[s] -histLen=1; %[s] - - -% CONSTANTS THAT YOU CAN EXPERIMENT WITH -A_GAIN=10.0; % for the suppress case -oversampling = 2; % must be power of 2; minimum is 2; 4 works -% fine for support=64, but for support=128, -% 8 gives better results. -support=64; %512 % fft support (frequency resolution; at low -% settings you can hear more distortion -% (e.g. pitch that is left-over from far-end)) -% 128 works well, 64 is ok) - -lowlevel = mean(abs(microphone))*0.0001; - -G_ol = 0; % Use overlapping sets of estimates - -% ECHO SUPPRESSION SPECIFIC PARAMETERS -suppress_overdrive=1.0; % overdrive factor for suppression 1.4 is good -gamma_echo=1.0; % same as suppress_overdrive but at different place -de_echo_bound=0.0; -mLim=10; % rank of matrix G -%limBW = 1; % use bandwidth-limited response for G -if mLim > (support/2+1) - error('mLim in suppress.m too large\n'); -end - - -dynrange=1.0000e-004; - -% other, constants -hsupport = support/2; -hsupport1 = hsupport+1; -factor = 2 / oversampling; -updatel = support/oversampling; -win=sqrt(designwindow(0,support)); -estLen = round(avtime * samplingfreq/updatel) - -runningfmean =0.0; - -mLim = floor(hsupport1/2); -V = sqrt(2/hsupport1)*cos(pi/hsupport1*(repmat((0:hsupport1-1) + 0.5, mLim, 1).* ... - repmat((0:mLim-1)' + 0.5, 1, hsupport1))); - -fprintf(1,'updatel is %5.3f s\n', updatel/samplingfreq); - - - -bandfirst=8; bandlast=25; -dosmooth=0; % to get rid of wavy bin counts (can be worse or better) - -% compute some constants -blockLen = support/oversampling; -maxDelayb = floor(samplingfreq*maxDelay/updatel); % in blocks -histLenb = floor(samplingfreq*histLen/updatel); % in blocks - -x0=TheFarEnd; -y0=microphone; - - -%input -tlength=min([length(microphone),length(TheFarEnd)]); -updateno=floor(tlength/updatel); -tlength=updatel*updateno; -updateno = updateno - oversampling + 1; - -TheFarEnd =TheFarEnd(1:tlength); -microphone =microphone(1:tlength); - -TheFarEnd =[zeros(hsupport,1);TheFarEnd(1:tlength)]; -microphone =[zeros(hsupport,1);microphone(1:tlength)]; - - -% signal length -n = min([floor(length(x0)/support)*support,floor(length(y0)/support)*support]); -nb = n/blockLen - oversampling + 1; % in blocks - -% initialize space -win = sqrt([0 ; hanning(support-1)]); -sxAll2 = zeros(hsupport1,nb); -syAll2 = zeros(hsupport1,nb); - -z500=zeros(5,maxDelayb+1); -z200=zeros(5,hsupport1); - -bxspectrum=uint32(zeros(nb,1)); -bxhist=uint32(zeros(maxDelayb+1,1)); -byspectrum=uint32(zeros(nb,1)); -bcount=zeros(1+maxDelayb,nb); -fcount=zeros(1+maxDelayb,nb); -fout=zeros(1+maxDelayb,nb); -delay=zeros(nb,1); -tdelay=zeros(nb,1); -nlgains=zeros(nb,1); - -% create space (mainly for debugging) -emicrophone=zeros(tlength,1); -femicrophone=complex(zeros(hsupport1,updateno)); -thefilter=zeros(hsupport1,updateno); -thelimiter=ones(hsupport1,updateno); -fTheFarEnd=complex(zeros(hsupport1,updateno)); -afTheFarEnd=zeros(hsupport1,updateno); -fmicrophone=complex(zeros(hsupport1,updateno)); -afmicrophone=zeros(hsupport1,updateno); - -G = zeros(hsupport1, hsupport1); -zerovec = zeros(hsupport1,1); -zeromat = zeros(hsupport1); - -% Reset sums -mmxs_a = zerovec; -mmys_a = zerovec; -s2xs_a = zerovec; -s2ys_a = zerovec; -Rxxs_a = zeromat; -Ryxs_a = zeromat; -count_a = 1; - -mmxs_b = zerovec; -mmys_b = zerovec; -s2xs_b = zerovec; -s2ys_b = zerovec; -Rxxs_b = zeromat; -Ryxs_b = zeromat; -count_b = 1; - -nog=0; - -aaa=zeros(size(TheFarEnd)); - -% loop over signal blocks -fprintf(1,'.. Suppression; averaging G over %5.1f seconds; file length %5.1f seconds ..\n',avtime, length(microphone)/samplingfreq); -fprintf(1,'.. SUPPRESSING ONLY AFTER %5.1f SECONDS! ..\n',avtime); -fprintf(1,'.. 20 seconds is good ..\n'); -hh = waitbar_j(0,'Please wait...'); - - -for i=1:updateno - - sb = (i-1)*updatel + 1; - se=sb+support-1; - - % analysis FFTs - temp=fft(win .* TheFarEnd(sb:se)); - fTheFarEnd(:,i)=temp(1:hsupport1); - xf=fTheFarEnd(:,i); - afTheFarEnd(:,i)= abs(fTheFarEnd(:,i)); - - temp=win .* microphone(sb:se); - - temp=fft(win .* microphone(sb:se)); - fmicrophone(:,i)=temp(1:hsupport1); - yf=fmicrophone(:,i); - afmicrophone(:,i)= abs(fmicrophone(:,i)); - - - ener_orig = afmicrophone(:,i)'*afmicrophone(:,i); - if( ener_orig == 0) - afmicrophone(:,i)=lowlevel*ones(size(afmicrophone(:,i))); - end - - - % use log domain (showed improved performance) -xxf= sqrt(real(xf.*conj(xf))+1e-20); -yyf= sqrt(real(yf.*conj(yf))+1e-20); - sxAll2(:,i) = 20*log10(xxf); - syAll2(:,i) = 20*log10(yyf); - - mD=min(i-1,maxDelayb); - xthreshold = sum(sxAll2(:,i-mD:i),2)/(maxDelayb+1); - - [yout, z200] = filter(Bp200,Ap200,syAll2(:,i),z200,2); - yout=yout/(maxDelayb+1); - ythreshold = mean(syAll2(:,i-mD:i),2); - - - bxspectrum(i)=getBspectrum(sxAll2(:,i),xthreshold,bandfirst,bandlast); - byspectrum(i)=getBspectrum(syAll2(:,i),yout,bandfirst,bandlast); - - bxhist(end-mD:end)=bxspectrum(i-mD:i); - - bcount(:,i)=hisser2( ... - byspectrum(i),flipud(bxhist),bandfirst,bandlast); - - - [fout(:,i), z500] = filter(Bp500,Ap500,bcount(:,i),z500,2); - fcount(:,i)=sum(bcount(:,max(1,i-histLenb+1):i),2); % using the history range - fout(:,i)=round(fout(:,i)); - [value,delay(i)]=min(fout(:,i),[],1); - tdelay(i)=(delay(i)-1)*support/(samplingfreq*oversampling); - - % compensate - - idel = max(i - delay(i) + 1,1); - - - % echo suppression - - noisyspec = afmicrophone(:,i); - - % Estimate G using covariance matrices - - % Cumulative estimates - xx = afTheFarEnd(:,idel); - yy = afmicrophone(:,i); - - % Means - mmxs_a = mmxs_a + xx; - mmys_a = mmys_a + yy; - if (G_ol) - mmxs_b = mmxs_b + xx; - mmys_b = mmys_b + yy; - mmy = mean([mmys_a/count_a mmys_b/count_b],2); - mmx = mean([mmxs_a/count_a mmxs_b/count_b],2); - else - mmx = mmxs_a/count_a; - mmy = mmys_a/count_a; - end - count_a = count_a + 1; - count_b = count_b + 1; - - % Mean removal - xxm = xx - mmx; - yym = yy - mmy; - - % Variances - s2xs_a = s2xs_a + xxm .* xxm; - s2ys_a = s2ys_a + yym .* yym; - s2xs_b = s2xs_b + xxm .* xxm; - s2ys_b = s2ys_b + yym .* yym; - - % Correlation matrices - Rxxs_a = Rxxs_a + xxm * xxm'; - Ryxs_a = Ryxs_a + yym * xxm'; - Rxxs_b = Rxxs_b + xxm * xxm'; - Ryxs_b = Ryxs_b + yym * xxm'; - - - % Gain matrix A - - if mod(i, estLen) == 0 - - - % Cumulative based estimates - Rxxf = Rxxs_a / (estLen - 1); - Ryxf = Ryxs_a / (estLen - 1); - - % Variance normalization - s2x2 = s2xs_a / (estLen - 1); - s2x2 = sqrt(s2x2); - % Sx = diag(max(s2x2,dynrange*max(s2x2))); - Sx = diag(s2x2); - if (sum(s2x2) > 0) - iSx = inv(Sx); - else - iSx= Sx + 0.01; - end - - s2y2 = s2ys_a / (estLen - 1); - s2y2 = sqrt(s2y2); - % Sy = diag(max(s2y2,dynrange*max(s2y2))); - Sy = diag(s2y2); - iSy = inv(Sy); - rx = iSx * Rxxf * iSx; - ryx = iSy * Ryxf * iSx; - - - - dbd= 7; % Us less than the full matrix - - % k x m - % Bandlimited structure on G - LSEon = 0; % Default is using MMSE - if (LSEon) - ryx = ryx*rx; - rx = rx*rx; - end - p = dbd-1; - gaj = min(min(hsupport1,2*p+1),min([p+(1:hsupport1); hsupport1+p+1-(1:hsupport1)])); - cgaj = [0 cumsum(gaj)]; - - G3 = zeros(hsupport1); - for kk=1:hsupport1 - ki = max(0,kk-p-1); - if (sum(sum(rx(ki+1:ki+gaj(kk),ki+1:ki+gaj(kk))))>0) - G3(kk,ki+1:ki+gaj(kk)) = ryx(kk,ki+1:ki+gaj(kk))/rx(ki+1:ki+gaj(kk),ki+1:ki+gaj(kk)); - else - G3(kk,ki+1:ki+gaj(kk)) = ryx(kk,ki+1:ki+gaj(kk)); - end - end - % End Bandlimited structure - - G = G3; - G(abs(G)<0.01)=0; - G = suppress_overdrive * Sy * G * iSx; - - if 1 - figure(32); mi=2; - surf(max(min(G,mi),-mi)); view(2) - title('Unscaled Masked Limited-bandwidth G'); - end - pause(0.05); - - % Reset sums - mmxs_a = zerovec; - mmys_a = zerovec; - s2xs_a = zerovec; - s2ys_a = zerovec; - Rxxs_a = zeromat; - Ryxs_a = zeromat; - count_a = 1; - - end - - if (G_ol) - % Gain matrix B - - if ((mod((i-estLen/2), estLen) == 0) & i>estLen) - - - % Cumulative based estimates - Rxxf = Rxxs_b / (estLen - 1); - Ryxf = Ryxs_b / (estLen - 1); - - % Variance normalization - s2x2 = s2xs_b / (estLen - 1); - s2x2 = sqrt(s2x2); - Sx = diag(max(s2x2,dynrange*max(s2x2))); - iSx = inv(Sx); - s2y2 = s2ys_b / (estLen - 1); - s2y2 = sqrt(s2y2); - Sy = diag(max(s2y2,dynrange*max(s2y2))); - iSy = inv(Sy); - rx = iSx * Rxxf * iSx; - ryx = iSy * Ryxf * iSx; - - - % Bandlimited structure on G - LSEon = 0; % Default is using MMSE - if (LSEon) - ryx = ryx*rx; - rx = rx*rx; - end - p = dbd-1; - gaj = min(min(hsupport1,2*p+1),min([p+(1:hsupport1); hsupport1+p+1-(1:hsupport1)])); - cgaj = [0 cumsum(gaj)]; - - G3 = zeros(hsupport1); - for kk=1:hsupport1 - ki = max(0,kk-p-1); - G3(kk,ki+1:ki+gaj(kk)) = ryx(kk,ki+1:ki+gaj(kk))/rx(ki+1:ki+gaj(kk),ki+1:ki+gaj(kk)); - end - % End Bandlimited structure - - G = G3; - G(abs(G)<0.01)=0; - G = suppress_overdrive * Sy * G * iSx; - - if 1 - figure(32); mi=2; - surf(max(min(G,mi),-mi)); view(2) - title('Unscaled Masked Limited-bandwidth G'); - end - pause(0.05); - - - % Reset sums - mmxs_b = zerovec; - mmys_b = zerovec; - s2xs_b = zerovec; - s2ys_b = zerovec; - Rxxs_b = zeromat; - Ryxs_b = zeromat; - count_b = 1; - - end - - end - - FECestimate2 = G*afTheFarEnd(:,idel); - - % compute Wiener filter and suppressor function - thefilter(:,i) = (noisyspec - gamma_echo*FECestimate2) ./ noisyspec; - ix0 = find(thefilter(:,i)<de_echo_bound); % bounding trick 1 - thefilter(ix0,i) = de_echo_bound; % bounding trick 2 - ix0 = find(thefilter(:,i)>1); % bounding in reasonable range - thefilter(ix0,i) = 1; - - % NONLINEARITY - nl_alpha=0.8; % memory; seems not very critical - nlSeverity=0.3; % nonlinearity severity: 0 does nothing; 1 suppresses all - thefmean=mean(thefilter(8:16,i)); - if (thefmean<1) - disp(''); - end - runningfmean = nl_alpha*runningfmean + (1-nl_alpha)*thefmean; - aaa(sb+20+1:sb+20+updatel)=10000*runningfmean* ones(updatel,1); % debug - slope0=1.0/(1.0-nlSeverity); % - thegain = max(0.0,min(1.0,slope0*(runningfmean-nlSeverity))); - % END NONLINEARITY - thefilter(:,i) = thegain*thefilter(:,i); - - - % Wiener filtering - femicrophone(:,i) = fmicrophone(:,i) .* thefilter(:,i); - thelimiter(:,i) = (noisyspec - A_GAIN*FECestimate2) ./ noisyspec; - index = find(thelimiter(:,i)>1.0); - thelimiter(index,i) = 1.0; - index = find(thelimiter(:,i)<0.0); - thelimiter(index,i) = 0.0; - - if (rem(i,floor(updateno/20))==0) - fprintf(1,'.'); - end - if mod(i,50)==0 - waitbar_j(i/updateno,hh); - end - - - % reconstruction; first make spectrum odd - temp=[femicrophone(:,i);flipud(conj(femicrophone(2:hsupport,i)))]; - emicrophone(sb:se) = emicrophone(sb:se) + factor * win .* real(ifft(temp)); - -end -fprintf(1,'\n'); - -close(hh);
\ No newline at end of file diff --git a/src/modules/audio_processing/aecm/main/matlab/getBspectrum.m b/src/modules/audio_processing/aecm/main/matlab/getBspectrum.m deleted file mode 100644 index a4a533d..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/getBspectrum.m +++ /dev/null @@ -1,22 +0,0 @@ -function bspectrum=getBspectrum(ps,threshold,bandfirst,bandlast) -% function bspectrum=getBspectrum(ps,threshold,bandfirst,bandlast) -% compute binary spectrum using threshold spectrum as pivot -% bspectrum = binary spectrum (binary) -% ps=current power spectrum (float) -% threshold=threshold spectrum (float) -% bandfirst = first band considered -% bandlast = last band considered - -% initialization stuff - if( length(ps)<bandlast | bandlast>32 | length(ps)~=length(threshold)) - error('BinDelayEst:spectrum:invalid','Dimensionality error'); -end - -% get current binary spectrum -diff = ps - threshold; -bspectrum=uint32(0); -for(i=bandfirst:bandlast) - if( diff(i)>0 ) - bspectrum = bitset(bspectrum,i); - end -end diff --git a/src/modules/audio_processing/aecm/main/matlab/hisser2.m b/src/modules/audio_processing/aecm/main/matlab/hisser2.m deleted file mode 100644 index 5a414f9..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/hisser2.m +++ /dev/null @@ -1,21 +0,0 @@ -function bcount=hisser2(bs,bsr,bandfirst,bandlast) -% function bcount=hisser(bspectrum,bandfirst,bandlast) -% histogram for the binary spectra -% bcount= array of bit counts -% bs=binary spectrum (one int32 number each) -% bsr=reference binary spectra (one int32 number each) -% blockSize = histogram over blocksize blocks -% bandfirst = first band considered -% bandlast = last band considered - -% weight all delays equally -maxDelay = length(bsr); - -% compute counts (two methods; the first works better and is operational) -bcount=zeros(maxDelay,1); -for(i=1:maxDelay) - % the delay should have low count for low-near&high-far and high-near&low-far - bcount(i)= sum(bitget(bitxor(bs,bsr(i)),bandfirst:bandlast)); - % the delay should have low count for low-near&high-far (works less well) -% bcount(i)= sum(bitget(bitand(bsr(i),bitxor(bs,bsr(i))),bandfirst:bandlast)); -end diff --git a/src/modules/audio_processing/aecm/main/matlab/main2.m b/src/modules/audio_processing/aecm/main/matlab/main2.m deleted file mode 100644 index 7e24c69..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/main2.m +++ /dev/null @@ -1,19 +0,0 @@ - -fid=fopen('aecfar.pcm'); far=fread(fid,'short'); fclose(fid); -fid=fopen('aecnear.pcm'); mic=fread(fid,'short'); fclose(fid); - -%fid=fopen('QA1far.pcm'); far=fread(fid,'short'); fclose(fid); -%fid=fopen('QA1near.pcm'); mic=fread(fid,'short'); fclose(fid); - -start=0 * 8000+1; -stop= 30 * 8000; -microphone=mic(start:stop); -TheFarEnd=far(start:stop); -avtime=1; - -% 16000 to make it compatible with the C-version -[emicrophone,tdel]=compsup(microphone,TheFarEnd,avtime,16000); - -spclab(8000,TheFarEnd,microphone,emicrophone); - - diff --git a/src/modules/audio_processing/aecm/main/matlab/matlab/AECMobile.m b/src/modules/audio_processing/aecm/main/matlab/matlab/AECMobile.m deleted file mode 100644 index 2d3e686..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/matlab/AECMobile.m +++ /dev/null @@ -1,269 +0,0 @@ -function [femicrophone, aecmStructNew, enerNear, enerFar] = AECMobile(fmicrophone, afTheFarEnd, setupStruct, aecmStruct) -global NEARENDFFT; -global F; - -aecmStructNew = aecmStruct; - -% Magnitude spectrum of near end signal -afmicrophone = abs(fmicrophone); -%afmicrophone = NEARENDFFT(setupStruct.currentBlock,:)'/2^F(setupStruct.currentBlock,end); -% Near end energy level -ener_orig = afmicrophone'*afmicrophone; -if( ener_orig == 0) - lowlevel = 0.01; - afmicrophone = lowlevel*ones(size(afmicrophone)); -end -%adiff = max(abs(afmicrophone - afTheFarEnd)); -%if (adiff > 0) -% disp([setupStruct.currentBlock adiff]) -%end - -% Store the near end energy -%aecmStructNew.enerNear(setupStruct.currentBlock) = log(afmicrophone'*afmicrophone); -aecmStructNew.enerNear(setupStruct.currentBlock) = log(sum(afmicrophone)); -% Store the far end energy -%aecmStructNew.enerFar(setupStruct.currentBlock) = log(afTheFarEnd'*afTheFarEnd); -aecmStructNew.enerFar(setupStruct.currentBlock) = log(sum(afTheFarEnd)); - -% Update subbands (We currently use all frequency bins, hence .useSubBand is turned off) -if aecmStructNew.useSubBand - internalIndex = 1; - for kk=1:setupStruct.subBandLength+1 - ySubBand(kk) = mean(afmicrophone(internalIndex:internalIndex+setupStruct.numInBand(kk)-1).^aecmStructNew.bandFactor); - xSubBand(kk) = mean(afTheFarEnd(internalIndex:internalIndex+setupStruct.numInBand(kk)-1).^aecmStructNew.bandFactor); - internalIndex = internalIndex + setupStruct.numInBand(kk); - end -else - ySubBand = afmicrophone.^aecmStructNew.bandFactor; - xSubBand = afTheFarEnd.^aecmStructNew.bandFactor; -end - -% Estimated echo energy -if (aecmStructNew.bandFactor == 1) - %aecmStructNew.enerEcho(setupStruct.currentBlock) = log((aecmStructNew.H.*xSubBand)'*(aecmStructNew.H.*xSubBand)); - %aecmStructNew.enerEchoStored(setupStruct.currentBlock) = log((aecmStructNew.HStored.*xSubBand)'*(aecmStructNew.HStored.*xSubBand)); - aecmStructNew.enerEcho(setupStruct.currentBlock) = log(sum(aecmStructNew.H.*xSubBand)); - aecmStructNew.enerEchoStored(setupStruct.currentBlock) = log(sum(aecmStructNew.HStored.*xSubBand)); -elseif (aecmStructNew.bandFactor == 2) - aecmStructNew.enerEcho(setupStruct.currentBlock) = log(aecmStructNew.H'*xSubBand); - aecmStructNew.enerEchoStored(setupStruct.currentBlock) = log(aecmStructNew.HStored'*xSubBand); -end - -% Last 100 blocks of data, used for plotting -n100 = max(1,setupStruct.currentBlock-99):setupStruct.currentBlock; -enerError = aecmStructNew.enerNear(n100)-aecmStructNew.enerEcho(n100); -enerErrorStored = aecmStructNew.enerNear(n100)-aecmStructNew.enerEchoStored(n100); - -% Store the far end sub band. This is needed if we use LSE instead of NLMS -aecmStructNew.X = [xSubBand aecmStructNew.X(:,1:end-1)]; - -% Update energy levels, which control the VAD -if ((aecmStructNew.enerFar(setupStruct.currentBlock) < aecmStructNew.energyMin) & (aecmStructNew.enerFar(setupStruct.currentBlock) >= aecmStruct.FAR_ENERGY_MIN)) - aecmStructNew.energyMin = aecmStructNew.enerFar(setupStruct.currentBlock); - %aecmStructNew.energyMin = max(aecmStructNew.energyMin,12); - aecmStructNew.energyMin = max(aecmStructNew.energyMin,aecmStruct.FAR_ENERGY_MIN); - aecmStructNew.energyLevel = (aecmStructNew.energyMax-aecmStructNew.energyMin)*aecmStructNew.energyThres+aecmStructNew.energyMin; - aecmStructNew.energyLevelMSE = (aecmStructNew.energyMax-aecmStructNew.energyMin)*aecmStructNew.energyThresMSE+aecmStructNew.energyMin; -end -if (aecmStructNew.enerFar(setupStruct.currentBlock) > aecmStructNew.energyMax) - aecmStructNew.energyMax = aecmStructNew.enerFar(setupStruct.currentBlock); - aecmStructNew.energyLevel = (aecmStructNew.energyMax-aecmStructNew.energyMin)*aecmStructNew.energyThres+aecmStructNew.energyMin; - aecmStructNew.energyLevelMSE = (aecmStructNew.energyMax-aecmStructNew.energyMin)*aecmStructNew.energyThresMSE+aecmStructNew.energyMin; -end - -% Calculate current energy error in near end (estimated echo vs. near end) -dE = aecmStructNew.enerNear(setupStruct.currentBlock)-aecmStructNew.enerEcho(setupStruct.currentBlock); - -%%%%%%%% -% Calculate step size used in LMS algorithm, based on current far end energy and near end energy error (dE) -%%%%%%%% -if setupStruct.stepSize_flag - [mu, aecmStructNew] = calcStepSize(aecmStructNew.enerFar(setupStruct.currentBlock), dE, aecmStructNew, setupStruct.currentBlock, 1); -else - mu = 0.25; -end -aecmStructNew.muLog(setupStruct.currentBlock) = mu; % Store the step size - -% Estimate Echo Spectral Shape -[U, aecmStructNew.H] = fallerEstimator(ySubBand,aecmStructNew.X,aecmStructNew.H,mu); - -%%%%% -% Determine if we should store or restore the channel -%%%%% -if ((setupStruct.currentBlock <= aecmStructNew.convLength) | (~setupStruct.channelUpdate_flag)) - aecmStructNew.HStored = aecmStructNew.H; % Store what you have after startup -elseif ((setupStruct.currentBlock > aecmStructNew.convLength) & (setupStruct.channelUpdate_flag)) - if ((aecmStructNew.enerFar(setupStruct.currentBlock) < aecmStructNew.energyLevelMSE) & (aecmStructNew.enerFar(setupStruct.currentBlock-1) >= aecmStructNew.energyLevelMSE)) - xxx = aecmStructNew.countMseH; - if (xxx > 20) - mseStored = mean(abs(aecmStructNew.enerEchoStored(setupStruct.currentBlock-xxx:setupStruct.currentBlock-1)-aecmStructNew.enerNear(setupStruct.currentBlock-xxx:setupStruct.currentBlock-1))); - mseLatest = mean(abs(aecmStructNew.enerEcho(setupStruct.currentBlock-xxx:setupStruct.currentBlock-1)-aecmStructNew.enerNear(setupStruct.currentBlock-xxx:setupStruct.currentBlock-1))); - %fprintf('Stored: %4f Latest: %4f\n', mseStored, mseLatest) % Uncomment if you want to display the MSE values - if ((mseStored < 0.8*mseLatest) & (aecmStructNew.mseHStoredOld < 0.8*aecmStructNew.mseHLatestOld)) - aecmStructNew.H = aecmStructNew.HStored; - fprintf('Restored H at block %d\n',setupStruct.currentBlock) - elseif (((0.8*mseStored > mseLatest) & (mseLatest < aecmStructNew.mseHThreshold) & (aecmStructNew.mseHLatestOld < aecmStructNew.mseHThreshold)) | (mseStored == Inf)) - aecmStructNew.HStored = aecmStructNew.H; - fprintf('Stored new H at block %d\n',setupStruct.currentBlock) - end - aecmStructNew.mseHStoredOld = mseStored; - aecmStructNew.mseHLatestOld = mseLatest; - end - elseif ((aecmStructNew.enerFar(setupStruct.currentBlock) >= aecmStructNew.energyLevelMSE) & (aecmStructNew.enerFar(setupStruct.currentBlock-1) < aecmStructNew.energyLevelMSE)) - aecmStructNew.countMseH = 1; - elseif (aecmStructNew.enerFar(setupStruct.currentBlock) >= aecmStructNew.energyLevelMSE) - aecmStructNew.countMseH = aecmStructNew.countMseH + 1; - end -end - -%%%%% -% Check delay (calculate the delay offset (if we can)) -% The algorithm is not tuned and should be used with care. It runs separately from Bastiaan's algorithm. -%%%%% -yyy = 31; % Correlation buffer length (currently unfortunately hard coded) -dxxx = 25; % Maximum offset (currently unfortunately hard coded) -if (setupStruct.currentBlock > aecmStructNew.convLength) - if (aecmStructNew.enerFar(setupStruct.currentBlock-(yyy+2*dxxx-1):setupStruct.currentBlock) > aecmStructNew.energyLevelMSE) - for xxx = -dxxx:dxxx - aecmStructNew.delayLatestS(xxx+dxxx+1) = sum(sign(aecmStructNew.enerEcho(setupStruct.currentBlock-(yyy+dxxx-xxx)+1:setupStruct.currentBlock+xxx-dxxx)-mean(aecmStructNew.enerEcho(setupStruct.currentBlock-(yyy++dxxx-xxx)+1:setupStruct.currentBlock+xxx-dxxx))).*sign(aecmStructNew.enerNear(setupStruct.currentBlock-yyy-dxxx+1:setupStruct.currentBlock-dxxx)-mean(aecmStructNew.enerNear(setupStruct.currentBlock-yyy-dxxx+1:setupStruct.currentBlock-dxxx)))); - end - aecmStructNew.newDelayCurve = 1; - end -end -if ((setupStruct.currentBlock > 2*aecmStructNew.convLength) & ~rem(setupStruct.currentBlock,yyy*2) & aecmStructNew.newDelayCurve) - [maxV,maxP] = max(aecmStructNew.delayLatestS); - if ((maxP > 2) & (maxP < 2*dxxx)) - maxVLeft = aecmStructNew.delayLatestS(max(1,maxP-4)); - maxVRight = aecmStructNew.delayLatestS(min(2*dxxx+1,maxP+4)); - %fprintf('Max %d, Left %d, Right %d\n',maxV,maxVLeft,maxVRight) % Uncomment if you want to see max value - if ((maxV > 24) & (maxVLeft < maxV - 10) & (maxVRight < maxV - 10)) - aecmStructNew.feedbackDelay = maxP-dxxx-1; - aecmStructNew.newDelayCurve = 0; - aecmStructNew.feedbackDelayUpdate = 1; - fprintf('Feedback Update at block %d\n',setupStruct.currentBlock) - end - end -end -% End of "Check delay" -%%%%%%%% - -%%%%% -% Calculate suppression gain, based on far end energy and near end energy error (dE) -if (setupStruct.supGain_flag) - [gamma_echo, aecmStructNew.cntIn, aecmStructNew.cntOut] = calcFilterGain(aecmStructNew.enerFar(setupStruct.currentBlock), dE, aecmStructNew, setupStruct.currentBlock, aecmStructNew.convLength, aecmStructNew.cntIn, aecmStructNew.cntOut); -else - gamma_echo = 1; -end -aecmStructNew.gammaLog(setupStruct.currentBlock) = gamma_echo; % Store the gain -gamma_use = gamma_echo; - -% Use the stored channel -U = aecmStructNew.HStored.*xSubBand; - -% compute Wiener filter and suppressor function -Iy = find(ySubBand); -subBandFilter = zeros(size(ySubBand)); -if (aecmStructNew.bandFactor == 2) - subBandFilter(Iy) = (1 - gamma_use*sqrt(U(Iy)./ySubBand(Iy))); % For Faller -else - subBandFilter(Iy) = (1 - gamma_use*(U(Iy)./ySubBand(Iy))); % For COV -end -ix0 = find(subBandFilter < 0); % bounding trick 1 -subBandFilter(ix0) = 0; -ix0 = find(subBandFilter > 1); % bounding trick 1 -subBandFilter(ix0) = 1; - -% Interpolate back to normal frequency bins if we use sub bands -if aecmStructNew.useSubBand - thefilter = interp1(setupStruct.centerFreq,subBandFilter,linspace(0,setupStruct.samplingfreq/2,setupStruct.hsupport1)','nearest'); - testfilter = interp1(setupStruct.centerFreq,subBandFilter,linspace(0,setupStruct.samplingfreq/2,1000),'nearest'); - thefilter(end) = subBandFilter(end); - - internalIndex = 1; - for kk=1:setupStruct.subBandLength+1 - internalIndex:internalIndex+setupStruct.numInBand(kk)-1; - thefilter(internalIndex:internalIndex+setupStruct.numInBand(kk)-1) = subBandFilter(kk); - internalIndex = internalIndex + setupStruct.numInBand(kk); - end -else - thefilter = subBandFilter; - testfilter = subBandFilter; -end - -% Bound the filter -ix0 = find(thefilter < setupStruct.de_echo_bound); % bounding trick 1 -thefilter(ix0) = setupStruct.de_echo_bound; % bounding trick 2 -ix0 = find(thefilter > 1); % bounding in reasonable range -thefilter(ix0) = 1; - -%%%% -% NLP -%%%% -thefmean = mean(thefilter(8:16)); -if (thefmean < 1) - disp(''); -end -aecmStructNew.runningfmean = setupStruct.nl_alpha*aecmStructNew.runningfmean + (1-setupStruct.nl_alpha)*thefmean; -slope0 = 1.0/(1.0 - setupStruct.nlSeverity); % -thegain = max(0.0, min(1.0, slope0*(aecmStructNew.runningfmean - setupStruct.nlSeverity))); -if ~setupStruct.nlp_flag - thegain = 1; -end -% END NONLINEARITY -thefilter = thegain*thefilter; - -%%%% -% The suppression -%%%% -femicrophone = fmicrophone .* thefilter; -% Store the output energy (used for plotting) -%aecmStructNew.enerOut(setupStruct.currentBlock) = log(abs(femicrophone)'*abs(femicrophone)); -aecmStructNew.enerOut(setupStruct.currentBlock) = log(sum(abs(femicrophone))); - -if aecmStructNew.plotIt - figure(13) - subplot(311) - %plot(n100,enerFar(n100),'b-',n100,enerNear(n100),'k--',n100,enerEcho(n100),'r-',[n100(1) n100(end)],[1 1]*vadThNew,'b:',[n100(1) n100(end)],[1 1]*((energyMax-energyMin)/4+energyMin),'r-.',[n100(1) n100(end)],[1 1]*vadNearThNew,'g:',[n100(1) n100(end)],[1 1]*energyMax,'r-.',[n100(1) n100(end)],[1 1]*energyMin,'r-.','LineWidth',2) - plot(n100,aecmStructNew.enerFar(n100),'b-',n100,aecmStructNew.enerNear(n100),'k--',n100,aecmStructNew.enerOut(n100),'r-.',n100,aecmStructNew.enerEcho(n100),'r-',n100,aecmStructNew.enerEchoStored(n100),'c-',[n100(1) n100(end)],[1 1]*((aecmStructNew.energyMax-aecmStructNew.energyMin)/4+aecmStructNew.energyMin),'g-.',[n100(1) n100(end)],[1 1]*aecmStructNew.energyMax,'g-.',[n100(1) n100(end)],[1 1]*aecmStructNew.energyMin,'g-.','LineWidth',2) - %title(['Frame ',int2str(i),' av ',int2str(setupStruct.updateno),' State = ',int2str(speechState),' \mu = ',num2str(mu)]) - title(['\gamma = ',num2str(gamma_echo),' \mu = ',num2str(mu)]) - subplot(312) - %plot(n100,enerError,'b-',[n100(1) n100(end)],[1 1]*vadNearTh,'r:',[n100(1) n100(end)],[-1.5 -1.5]*vadNearTh,'r:','LineWidth',2) - %plot(n100,enerError,'b-',[n100(1) n100(end)],[1 1],'r:',[n100(1) n100(end)],[-2 -2],'r:','LineWidth',2) - plot(n100,enerError,'b-',n100,enerErrorStored,'c-',[n100(1) n100(end)],[1 1]*aecmStructNew.varMean,'k--',[n100(1) n100(end)],[1 1],'r:',[n100(1) n100(end)],[-2 -2],'r:','LineWidth',2) - % Plot mu - %plot(n100,log2(aecmStructNew.muLog(n100)),'b-','LineWidth',2) - %plot(n100,log2(aecmStructNew.HGain(n100)),'b-',[n100(1) n100(end)],[1 1]*log2(sum(aecmStructNew.HStored)),'r:','LineWidth',2) - title(['Block ',int2str(setupStruct.currentBlock),' av ',int2str(setupStruct.updateno)]) - subplot(313) - %plot(n100,enerVar(n100),'b-',[n100(1) n100(end)],[1 1],'r:',[n100(1) n100(end)],[-2 -2],'r:','LineWidth',2) - %plot(n100,enerVar(n100),'b-','LineWidth',2) - % Plot correlation curve - - %plot(-25:25,aecmStructNew.delayStored/max(aecmStructNew.delayStored),'c-',-25:25,aecmStructNew.delayLatest/max(aecmStructNew.delayLatest),'r-',-25:25,(max(aecmStructNew.delayStoredS)-aecmStructNew.delayStoredS)/(max(aecmStructNew.delayStoredS)-min(aecmStructNew.delayStoredS)),'c:',-25:25,(max(aecmStructNew.delayLatestS)-aecmStructNew.delayLatestS)/(max(aecmStructNew.delayLatestS)-min(aecmStructNew.delayLatestS)),'r:','LineWidth',2) - %plot(-25:25,aecmStructNew.delayStored,'c-',-25:25,aecmStructNew.delayLatest,'r-',-25:25,(max(aecmStructNew.delayStoredS)-aecmStructNew.delayStoredS)/(max(aecmStructNew.delayStoredS)-min(aecmStructNew.delayStoredS)),'c:',-25:25,(max(aecmStructNew.delayLatestS)-aecmStructNew.delayLatestS)/(max(aecmStructNew.delayLatestS)-min(aecmStructNew.delayLatestS)),'r:','LineWidth',2) - %plot(-25:25,aecmStructNew.delayLatest,'r-',-25:25,(50-aecmStructNew.delayLatestS)/100,'r:','LineWidth',2) - plot(-25:25,aecmStructNew.delayLatestS,'r:','LineWidth',2) - %plot(-25:25,aecmStructNew.delayStored,'c-',-25:25,aecmStructNew.delayLatest,'r-','LineWidth',2) - plot(0:32,aecmStruct.HStored,'bo-','LineWidth',2) - %title(['\gamma | In = ',int2str(aecmStructNew.muStruct.countInInterval),' | Out High = ',int2str(aecmStructNew.muStruct.countOutHighInterval),' | Out Low = ',int2str(aecmStructNew.muStruct.countOutLowInterval)]) - pause(1) - %if ((setupStruct.currentBlock == 860) | (setupStruct.currentBlock == 420) | (setupStruct.currentBlock == 960)) - if 0%(setupStruct.currentBlock == 960) - figure(60) - plot(n100,aecmStructNew.enerNear(n100),'k--',n100,aecmStructNew.enerEcho(n100),'k:','LineWidth',2) - legend('Near End','Estimated Echo') - title('Signal Energy witH offset compensation') - figure(61) - subplot(211) - stem(sign(aecmStructNew.enerNear(n100)-mean(aecmStructNew.enerNear(n100)))) - title('Near End Energy Pattern (around mean value)') - subplot(212) - stem(sign(aecmStructNew.enerEcho(n100)-mean(aecmStructNew.enerEcho(n100)))) - title('Estimated Echo Energy Pattern (around mean value)') - pause - end - drawnow%,pause -elseif ~rem(setupStruct.currentBlock,100) - fprintf('Block %d of %d\n',setupStruct.currentBlock,setupStruct.updateno) -end diff --git a/src/modules/audio_processing/aecm/main/matlab/matlab/align.m b/src/modules/audio_processing/aecm/main/matlab/matlab/align.m deleted file mode 100644 index 9b9c0ba..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/matlab/align.m +++ /dev/null @@ -1,98 +0,0 @@ -function [delayStructNew] = align(xf, yf, delayStruct, i, trueDelay); - -%%%%%%% -% Bastiaan's algorithm copied -%%%%%%% -Ap500 = [1.00, -4.95, 9.801, -9.70299, 4.80298005, -0.9509900499]; -Bp500 = [0.662743088639636, -2.5841655608125, 3.77668102146288, -2.45182477425154, 0.596566274575251, 0.0]; -Ap200 = [1.00, -4.875, 9.50625, -9.26859375, 4.518439453125, -0.881095693359375]; -Bp200 = [0.862545460994275, -3.2832804496114, 4.67892032308828, -2.95798023879133, 0.699796870041299, 0.0]; - -oldMethod = 1; % Turn on or off the old method. The new one is Bastiaan's August 2008 updates -THReSHoLD = 2.0; % ADJUSTABLE threshold factor; 4.0 seems good -%%%%%%%%%%%%%%%%%%% -% use log domain (showed improved performance) -xxf = sqrt(real(xf.*conj(xf))+1e-20); -yyf = sqrt(real(yf.*conj(yf))+1e-20); -delayStruct.sxAll2(:,i) = 20*log10(xxf); -delayStruct.syAll2(:,i) = 20*log10(yyf); - -mD = min(i-1,delayStruct.maxDelayb); -if oldMethod - factor = 1.0; - histLenb = 250; - xthreshold = factor*median(delayStruct.sxAll2(:,i-mD:i),2); - ythreshold = factor*median(delayStruct.syAll2(:,i-mD:i),2); -else - xthreshold = sum(delayStruct.sxAll2(:,i-mD:i),2)/(delayStruct.maxDelayb+1); - - [yout, delayStruct.z200] = filter(Bp200, Ap200, delayStruct.syAll2(:,i), delayStruct.z200, 2); - yout = yout/(delayStruct.maxDelayb+1); - ythreshold = mean(delayStruct.syAll2(:,i-mD:i),2); - ythreshold = yout; -end - -delayStruct.bxspectrum(i) = getBspectrum(delayStruct.sxAll2(:,i), xthreshold, delayStruct.bandfirst, delayStruct.bandlast); -delayStruct.byspectrum(i) = getBspectrum(delayStruct.syAll2(:,i), ythreshold, delayStruct.bandfirst, delayStruct.bandlast); - -delayStruct.bxhist(end-mD:end) = delayStruct.bxspectrum(i-mD:i); - -delayStruct.bcount(:,i) = hisser2(delayStruct.byspectrum(i), flipud(delayStruct.bxhist), delayStruct.bandfirst, delayStruct.bandlast); -[delayStruct.fout(:,i), delayStruct.z500] = filter(Bp500, Ap500, delayStruct.bcount(:,i), delayStruct.z500, 2); -if oldMethod - %delayStruct.new(:,i) = sum(delayStruct.bcount(:,max(1,i-histLenb+1):i),2); % using the history range - tmpVec = [delayStruct.fout(1,i)*ones(2,1); delayStruct.fout(:,i); delayStruct.fout(end,i)*ones(2,1)]; % using the history range - tmpVec = filter(ones(1,5), 1, tmpVec); - delayStruct.new(:,i) = tmpVec(5:end); - %delayStruct.new(:,i) = delayStruct.fout(:,i); % using the history range -else - [delayStruct.fout(:,i), delayStruct.z500] = filter(Bp500, Ap500, delayStruct.bcount(:,i), delayStruct.z500, 2); - % NEW CODE - delayStruct.new(:,i) = filter([-1,-2,1,4,1,-2,-1], 1, delayStruct.fout(:,i)); %remv smth component - delayStruct.new(1:end-3,i) = delayStruct.new(1+3:end,i); - delayStruct.new(1:6,i) = 0.0; - delayStruct.new(end-6:end,i) = 0.0; % ends are no good -end -[valuen, tempdelay] = min(delayStruct.new(:,i)); % find minimum -if oldMethod - threshold = valuen + (max(delayStruct.new(:,i)) - valuen)/4; - thIndex = find(delayStruct.new(:,i) <= threshold); - if (i > 1) - delayDiff = abs(delayStruct.delay(i-1)-tempdelay+1); - if (delayStruct.oneGoodEstimate & (max(diff(thIndex)) > 1) & (delayDiff < 10)) - % We consider this minimum to be significant, hence update the delay - delayStruct.delay(i) = tempdelay; - elseif (~delayStruct.oneGoodEstimate & (max(diff(thIndex)) > 1)) - delayStruct.delay(i) = tempdelay; - if (i > histLenb) - delayStruct.oneGoodEstimate = 1; - end - else - delayStruct.delay(i) = delayStruct.delay(i-1); - end - else - delayStruct.delay(i) = tempdelay; - end -else - threshold = THReSHoLD*std(delayStruct.new(:,i)); % set updata threshold - if ((-valuen > threshold) | (i < delayStruct.smlength)) % see if you want to update delay - delayStruct.delay(i) = tempdelay; - else - delayStruct.delay(i) = delayStruct.delay(i-1); - end - % END NEW CODE -end -delayStructNew = delayStruct; - -% administrative and plotting stuff -if( 0) - figure(10); - plot([1:length(delayStructNew.new(:,i))],delayStructNew.new(:,i),trueDelay*[1 1],[min(delayStructNew.new(:,i)),max(delayStructNew.new(:,i))],'r',[1 length(delayStructNew.new(:,i))],threshold*[1 1],'r:', 'LineWidth',2); - %plot([1:length(delayStructNew.bcount(:,i))],delayStructNew.bcount(:,i),trueDelay*[1 1],[min(delayStructNew.bcount(:,i)),max(delayStructNew.bcount(:,i))],'r','LineWidth',2); - %plot([thedelay,thedelay],[min(fcount(:,i)),max(fcount(:,i))],'r'); - %title(sprintf('bin count and known delay at time %5.1f s\n',(i-1)*(support/(fs*oversampling)))); - title(delayStructNew.oneGoodEstimate) - xlabel('delay in frames'); - %hold off; - drawnow -end diff --git a/src/modules/audio_processing/aecm/main/matlab/matlab/calcFilterGain.m b/src/modules/audio_processing/aecm/main/matlab/matlab/calcFilterGain.m deleted file mode 100644 index a09a7f2..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/matlab/calcFilterGain.m +++ /dev/null @@ -1,88 +0,0 @@ -function [gam, cntIn2, cntOut2] = calcFilterGain(energy, dE, aecmStruct, t, T, cntIn, cntOut) - -defaultLevel = 1.2; -cntIn2 = cntIn; -cntOut2 = cntOut; -if (t < T) - gam = 1; -else - dE1 = -5; - dE2 = 1; - gamMid = 0.2; - gam = max(0,min((energy - aecmStruct.energyMin)/(aecmStruct.energyLevel - aecmStruct.energyMin), 1-(1-gamMid)*(aecmStruct.energyMax-energy)/(aecmStruct.energyMax-aecmStruct.energyLevel))); - - dEOffset = -0.5; - dEWidth = 1.5; - %gam2 = max(1,2-((dE-dEOffset)/(dE2-dEOffset)).^2); - gam2 = 1+(abs(dE-dEOffset)<(dE2-dEOffset)); - - gam = gam*gam2; - - - if (energy < aecmStruct.energyLevel) - gam = 0; - else - gam = defaultLevel; - end - dEVec = aecmStruct.enerNear(t-63:t)-aecmStruct.enerEcho(t-63:t); - %dEVec = aecmStruct.enerNear(t-20:t)-aecmStruct.enerEcho(t-20:t); - numCross = 0; - currentState = 0; - for ii=1:64 - if (currentState == 0) - currentState = (dEVec(ii) > dE2) - (dEVec(ii) < -2); - elseif ((currentState == 1) & (dEVec(ii) < -2)) - numCross = numCross + 1; - currentState = -1; - elseif ((currentState == -1) & (dEVec(ii) > dE2)) - numCross = numCross + 1; - currentState = 1; - end - end - gam = max(0, gam - numCross/25); - gam = 1; - - ener_A = 1; - ener_B = 0.8; - ener_C = aecmStruct.energyLevel + (aecmStruct.energyMax-aecmStruct.energyLevel)/5; - dE_A = 4;%2; - dE_B = 3.6;%1.8; - dE_C = 0.9*dEWidth; - dE_D = 1; - timeFactorLength = 10; - ddE = abs(dE-dEOffset); - if (energy < aecmStruct.energyLevel) - gam = 0; - else - gam = 1; - gam2 = max(0, min(ener_B*(energy-aecmStruct.energyLevel)/(ener_C-aecmStruct.energyLevel), ener_B+(ener_A-ener_B)*(energy-ener_C)/(aecmStruct.energyMax-ener_C))); - if (ddE < dEWidth) - % Update counters - cntIn2 = cntIn2 + 1; - if (cntIn2 > 2) - cntOut2 = 0; - end - gam3 = max(dE_D, min(dE_A-(dE_A-dE_B)*(ddE/dE_C), dE_D+(dE_B-dE_D)*(dEWidth-ddE)/(dEWidth-dE_C))); - gam3 = dE_A; - else - % Update counters - cntOut2 = cntOut2 + 1; - if (cntOut2 > 2) - cntIn2 = 0; - end - %gam2 = 1; - gam3 = dE_D; - end - timeFactor = min(1, cntIn2/timeFactorLength); - gam = gam*(1-timeFactor) + timeFactor*gam2*gam3; - end - %gam = gam/floor(numCross/2+1); -end -if isempty(gam) - numCross - timeFactor - cntIn2 - cntOut2 - gam2 - gam3 -end diff --git a/src/modules/audio_processing/aecm/main/matlab/matlab/calcStepSize.m b/src/modules/audio_processing/aecm/main/matlab/matlab/calcStepSize.m deleted file mode 100644 index ae1365f..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/matlab/calcStepSize.m +++ /dev/null @@ -1,105 +0,0 @@ -function [mu, aecmStructNew] = calcStepSize(energy, dE, aecmStruct, t, logscale) - -if (nargin < 4) - t = 1; - logscale = 1; -elseif (nargin == 4) - logscale = 1; -end -T = aecmStruct.convLength; - -if logscale - currentMuMax = aecmStruct.MU_MIN + (aecmStruct.MU_MAX-aecmStruct.MU_MIN)*min(t,T)/T; - if (aecmStruct.energyMin >= aecmStruct.energyMax) - mu = aecmStruct.MU_MIN; - else - mu = (energy - aecmStruct.energyMin)/(aecmStruct.energyMax - aecmStruct.energyMin)*(currentMuMax-aecmStruct.MU_MIN) + aecmStruct.MU_MIN; - end - mu = 2^mu; - if (energy < aecmStruct.energyLevel) - mu = 0; - end -else - muMin = 0; - muMax = 0.5; - currentMuMax = muMin + (muMax-muMin)*min(t,T)/T; - if (aecmStruct.energyMin >= aecmStruct.energyMax) - mu = muMin; - else - mu = (energy - aecmStruct.energyMin)/(aecmStruct.energyMax - aecmStruct.energyMin)*(currentMuMax-muMin) + muMin; - end -end -dE2 = 1; -dEOffset = -0.5; -offBoost = 5; -if (mu > 0) - if (abs(dE-aecmStruct.ENERGY_DEV_OFFSET) > aecmStruct.ENERGY_DEV_TOL) - aecmStruct.muStruct.countInInterval = 0; - else - aecmStruct.muStruct.countInInterval = aecmStruct.muStruct.countInInterval + 1; - end - if (dE < aecmStruct.ENERGY_DEV_OFFSET - aecmStruct.ENERGY_DEV_TOL) - aecmStruct.muStruct.countOutLowInterval = aecmStruct.muStruct.countOutLowInterval + 1; - else - aecmStruct.muStruct.countOutLowInterval = 0; - end - if (dE > aecmStruct.ENERGY_DEV_OFFSET + aecmStruct.ENERGY_DEV_TOL) - aecmStruct.muStruct.countOutHighInterval = aecmStruct.muStruct.countOutHighInterval + 1; - else - aecmStruct.muStruct.countOutHighInterval = 0; - end -end -muVar = 2^min(-3,5/50*aecmStruct.muStruct.countInInterval-3); -muOff = 2^max(offBoost,min(0,offBoost*(aecmStruct.muStruct.countOutLowInterval-aecmStruct.muStruct.minOutLowInterval)/(aecmStruct.muStruct.maxOutLowInterval-aecmStruct.muStruct.minOutLowInterval))); - -muLow = 1/64; -muVar = 1; -if (t < 2*T) - muDT = 1; - muVar = 1; - mdEVec = 0; - numCross = 0; -else - muDT = min(1,max(muLow,1-(1-muLow)*(dE-aecmStruct.ENERGY_DEV_OFFSET)/aecmStruct.ENERGY_DEV_TOL)); - dEVec = aecmStruct.enerNear(t-63:t)-aecmStruct.enerEcho(t-63:t); - %dEVec = aecmStruct.enerNear(t-20:t)-aecmStruct.enerEcho(t-20:t); - numCross = 0; - currentState = 0; - for ii=1:64 - if (currentState == 0) - currentState = (dEVec(ii) > dE2) - (dEVec(ii) < -2); - elseif ((currentState == 1) & (dEVec(ii) < -2)) - numCross = numCross + 1; - currentState = -1; - elseif ((currentState == -1) & (dEVec(ii) > dE2)) - numCross = numCross + 1; - currentState = 1; - end - end - - %logicDEVec = (dEVec > dE2) - (dEVec < -2); - %numCross = sum(abs(diff(logicDEVec))); - %mdEVec = mean(abs(dEVec-dEOffset)); - %mdEVec = mean(abs(dEVec-mean(dEVec))); - %mdEVec = max(dEVec)-min(dEVec); - %if (mdEVec > 4)%1.5) - % muVar = 0; - %end - muVar = 2^(-floor(numCross/2)); - muVar = 2^(-numCross); -end -%muVar = 1; - - -% if (eStd > (dE2-dEOffset)) -% muVar = 1/8; -% else -% muVar = 1; -% end - -%mu = mu*muDT*muVar*muOff; -mu = mu*muDT*muVar; -mu = min(mu,0.25); -aecmStructNew = aecmStruct; -%aecmStructNew.varMean = mdEVec; -aecmStructNew.varMean = numCross; diff --git a/src/modules/audio_processing/aecm/main/matlab/matlab/fallerEstimator.m b/src/modules/audio_processing/aecm/main/matlab/matlab/fallerEstimator.m deleted file mode 100644 index d038b51..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/matlab/fallerEstimator.m +++ /dev/null @@ -1,42 +0,0 @@ -function [U, Hnew] = fallerEstimator(Y, X, H, mu) - -% Near end signal is stacked frame by frame columnwise in matrix Y and far end in X -% -% Possible estimation procedures are -% 1) LSE -% 2) NLMS -% 3) Separated numerator and denomerator filters -regParam = 1; -[numFreqs, numFrames] = size(Y); -[numFreqs, Q] = size(X); -U = zeros(numFreqs, 1); - -if ((nargin == 3) | (nargin == 5)) - dtd = 0; -end -if (nargin == 4) - dtd = H; -end -Emax = 7; -dEH = Emax-sum(sum(H)); -nu = 2*mu; -% if (nargin < 5) -% H = zeros(numFreqs, Q); -% for kk = 1:numFreqs -% Xmatrix = hankel(X(kk,1:Q),X(kk,Q:end)); -% y = Y(kk,1:end-Q+1)'; -% H(kk,:) = (y'*Xmatrix')*inv(Xmatrix*Xmatrix'+regParam); -% U(kk,1) = H(kk,:)*Xmatrix(:,1); -% end -% else - for kk = 1:numFreqs - x = X(kk,1:Q)'; - y = Y(kk,1); - Htmp = mu*(y-H(kk,:)*x)/(x'*x+regParam)*x; - %Htmp = (mu*(y-H(kk,:)*x)/(x'*x+regParam) - nu/dEH)*x; - H(kk,:) = H(kk,:) + Htmp'; - U(kk,1) = H(kk,:)*x; - end -% end - -Hnew = H; diff --git a/src/modules/audio_processing/aecm/main/matlab/matlab/getBspectrum.m b/src/modules/audio_processing/aecm/main/matlab/matlab/getBspectrum.m deleted file mode 100644 index a4a533d..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/matlab/getBspectrum.m +++ /dev/null @@ -1,22 +0,0 @@ -function bspectrum=getBspectrum(ps,threshold,bandfirst,bandlast) -% function bspectrum=getBspectrum(ps,threshold,bandfirst,bandlast) -% compute binary spectrum using threshold spectrum as pivot -% bspectrum = binary spectrum (binary) -% ps=current power spectrum (float) -% threshold=threshold spectrum (float) -% bandfirst = first band considered -% bandlast = last band considered - -% initialization stuff - if( length(ps)<bandlast | bandlast>32 | length(ps)~=length(threshold)) - error('BinDelayEst:spectrum:invalid','Dimensionality error'); -end - -% get current binary spectrum -diff = ps - threshold; -bspectrum=uint32(0); -for(i=bandfirst:bandlast) - if( diff(i)>0 ) - bspectrum = bitset(bspectrum,i); - end -end diff --git a/src/modules/audio_processing/aecm/main/matlab/matlab/hisser2.m b/src/modules/audio_processing/aecm/main/matlab/matlab/hisser2.m deleted file mode 100644 index 5a414f9..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/matlab/hisser2.m +++ /dev/null @@ -1,21 +0,0 @@ -function bcount=hisser2(bs,bsr,bandfirst,bandlast) -% function bcount=hisser(bspectrum,bandfirst,bandlast) -% histogram for the binary spectra -% bcount= array of bit counts -% bs=binary spectrum (one int32 number each) -% bsr=reference binary spectra (one int32 number each) -% blockSize = histogram over blocksize blocks -% bandfirst = first band considered -% bandlast = last band considered - -% weight all delays equally -maxDelay = length(bsr); - -% compute counts (two methods; the first works better and is operational) -bcount=zeros(maxDelay,1); -for(i=1:maxDelay) - % the delay should have low count for low-near&high-far and high-near&low-far - bcount(i)= sum(bitget(bitxor(bs,bsr(i)),bandfirst:bandlast)); - % the delay should have low count for low-near&high-far (works less well) -% bcount(i)= sum(bitget(bitand(bsr(i),bitxor(bs,bsr(i))),bandfirst:bandlast)); -end diff --git a/src/modules/audio_processing/aecm/main/matlab/matlab/mainProgram.m b/src/modules/audio_processing/aecm/main/matlab/matlab/mainProgram.m deleted file mode 100644 index eeb2aaa..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/matlab/mainProgram.m +++ /dev/null @@ -1,283 +0,0 @@ -useHTC = 1; % Set this if you want to run a single file and set file names below. Otherwise use simEnvironment to run from several scenarios in a row -delayCompensation_flag = 0; % Set this flag to one if you want to turn on the delay compensation/enhancement -global FARENDFFT; -global NEARENDFFT; -global F; - -if useHTC -% fid=fopen('./htcTouchHd/nb/aecFar.pcm'); xFar=fread(fid,'short'); fclose(fid); -% fid=fopen('./htcTouchHd/nb/aecNear.pcm'); yNear=fread(fid,'short'); fclose(fid); -% fid=fopen('./samsungBlackjack/nb/aecFar.pcm'); xFar=fread(fid,'short'); fclose(fid); -% fid=fopen('./samsungBlackjack/nb/aecNear.pcm'); yNear=fread(fid,'short'); fclose(fid); -% fid=fopen('aecFarPoor.pcm'); xFar=fread(fid,'short'); fclose(fid); -% fid=fopen('aecNearPoor.pcm'); yNear=fread(fid,'short'); fclose(fid); -% fid=fopen('out_aes.pcm'); outAES=fread(fid,'short'); fclose(fid); - fid=fopen('aecFar4.pcm'); xFar=fread(fid,'short'); fclose(fid); - fid=fopen('aecNear4.pcm'); yNear=fread(fid,'short'); fclose(fid); - yNearSpeech = zeros(size(xFar)); - fs = 8000; - frameSize = 64; -% frameSize = 128; - fs = 16000; -% frameSize = 256; -%F = load('fftValues.txt'); -%FARENDFFT = F(:,1:33); -%NEARENDFFT = F(:,34:66); - -else - loadFileFar = [speakerType, '_s_',scenario,'_far_b.wav']; - [xFar,fs,nbits] = wavread(loadFileFar); - xFar = xFar*2^(nbits-1); - loadFileNear = [speakerType, '_s_',scenario,'_near_b.wav']; - [yNear,fs,nbits] = wavread(loadFileNear); - yNear = yNear*2^(nbits-1); - loadFileNearSpeech = [speakerType, '_s_',scenario,'_nearSpeech_b.wav']; - [yNearSpeech,fs,nbits] = wavread(loadFileNearSpeech); - yNearSpeech = yNearSpeech*2^(nbits-1); - frameSize = 256; -end - -dtRegions = []; - -% General settings for the AECM -setupStruct = struct(... - 'stepSize_flag', 1,... % This flag turns on the step size calculation. If turned off, mu = 0.25. - 'supGain_flag', 0,... % This flag turns on the suppression gain calculation. If turned off, gam = 1. - 'channelUpdate_flag', 0,... % This flag turns on the channel update. If turned off, H is updated for convLength and then kept constant. - 'nlp_flag', 0,... % Turn on/off NLP - 'withVAD_flag', 0,... % Turn on/off NLP - 'useSubBand', 0,... % Set to 1 if to use subBands - 'useDelayEstimation', 1,... % Set to 1 if to use delay estimation - 'support', frameSize,... % # of samples per frame - 'samplingfreq',fs,... % Sampling frequency - 'oversampling', 2,... % Overlap between blocks/frames - 'updatel', 0,... % # of samples between blocks - 'hsupport1', 0,... % # of bins in frequency domain - 'factor', 0,... % synthesis window amplification - 'tlength', 0,... % # of samples of entire file - 'updateno', 0,... % # of updates - 'nb', 1,... % # of blocks - 'currentBlock', 0,... % - 'win', zeros(frameSize,1),...% Window to apply for fft and synthesis - 'avtime', 1,... % Time (in sec.) to perform averaging - 'estLen', 0,... % Averaging in # of blocks - 'A_GAIN', 10.0,... % - 'suppress_overdrive', 1.0,... % overdrive factor for suppression 1.4 is good - 'gamma_echo', 1.0,... % same as suppress_overdrive but at different place - 'de_echo_bound', 0.0,... % - 'nl_alpha', 0.4,... % memory; seems not very critical - 'nlSeverity', 0.2,... % nonlinearity severity: 0 does nothing; 1 suppresses all - 'numInBand', [],... % # of frequency bins in resp. subBand - 'centerFreq', [],... % Center frequency of resp. subBand - 'dtRegions', dtRegions,... % Regions where we have DT - 'subBandLength', frameSize/2);%All bins - %'subBandLength', 11); %Something's wrong when subBandLength even - %'nl_alpha', 0.8,... % memory; seems not very critical - -delayStruct = struct(... - 'bandfirst', 8,... - 'bandlast', 25,... - 'smlength', 600,... - 'maxDelay', 0.4,... - 'oneGoodEstimate', 0,... - 'delayAdjust', 0,... - 'maxDelayb', 0); -% More parameters in delayStruct are constructed in "updateSettings" below - -% Make struct settings -[setupStruct, delayStruct] = updateSettings(yNear, xFar, setupStruct, delayStruct); -setupStruct.numInBand = ones(setupStruct.hsupport1,1); - -Q = 1; % Time diversity in channel -% General settings for the step size calculation -muStruct = struct(... - 'countInInterval', 0,... - 'countOutHighInterval', 0,... - 'countOutLowInterval', 0,... - 'minInInterval', 50,... - 'minOutHighInterval', 10,... - 'minOutLowInterval', 10,... - 'maxOutLowInterval', 50); -% General settings for the AECM -aecmStruct = struct(... - 'plotIt', 0,... % Set to 0 to turn off plotting - 'useSubBand', 0,... - 'bandFactor', 1,... - 'H', zeros(setupStruct.subBandLength+1,Q),... - 'HStored', zeros(setupStruct.subBandLength+1,Q),... - 'X', zeros(setupStruct.subBandLength+1,Q),... - 'energyThres', 0.28,... - 'energyThresMSE', 0.4,... - 'energyMin', inf,... - 'energyMax', -inf,... - 'energyLevel', 0,... - 'energyLevelMSE', 0,... - 'convLength', 100,... - 'gammaLog', ones(setupStruct.updateno,1),... - 'muLog', ones(setupStruct.updateno,1),... - 'enerFar', zeros(setupStruct.updateno,1),... - 'enerNear', zeros(setupStruct.updateno,1),... - 'enerEcho', zeros(setupStruct.updateno,1),... - 'enerEchoStored', zeros(setupStruct.updateno,1),... - 'enerOut', zeros(setupStruct.updateno,1),... - 'runningfmean', 0,... - 'muStruct', muStruct,... - 'varMean', 0,... - 'countMseH', 0,... - 'mseHThreshold', 1.1,... - 'mseHStoredOld', inf,... - 'mseHLatestOld', inf,... - 'delayLatestS', zeros(1,51),... - 'feedbackDelay', 0,... - 'feedbackDelayUpdate', 0,... - 'cntIn', 0,... - 'cntOut', 0,... - 'FAR_ENERGY_MIN', 1,... - 'ENERGY_DEV_OFFSET', 0.5,... - 'ENERGY_DEV_TOL', 1.5,... - 'MU_MIN', -16,... - 'MU_MAX', -2,... - 'newDelayCurve', 0); - -% Adjust speech signals -xFar = [zeros(setupStruct.hsupport1-1,1);xFar(1:setupStruct.tlength)]; -yNear = [zeros(setupStruct.hsupport1-1,1);yNear(1:setupStruct.tlength)]; -yNearSpeech = [zeros(setupStruct.hsupport1-1,1);yNearSpeech(1:setupStruct.tlength)]; -xFar = xFar(1:setupStruct.tlength); -yNear = yNear(1:setupStruct.tlength); - -% Set figure settings -if aecmStruct.plotIt - figure(13) - set(gcf,'doublebuffer','on') -end -%%%%%%%%%% -% Here starts the algorithm -% Dividing into frames and then estimating the near end speech -%%%%%%%%%% -fTheFarEnd = complex(zeros(setupStruct.hsupport1,1)); -afTheFarEnd = zeros(setupStruct.hsupport1,setupStruct.updateno+1); -fFar = zeros(setupStruct.hsupport1,setupStruct.updateno+1); -fmicrophone = complex(zeros(setupStruct.hsupport1,1)); -afmicrophone = zeros(setupStruct.hsupport1,setupStruct.updateno+1); -fNear = zeros(setupStruct.hsupport1,setupStruct.updateno+1); -femicrophone = complex(zeros(setupStruct.hsupport1,1)); -emicrophone = zeros(setupStruct.tlength,1); - -if (setupStruct.useDelayEstimation == 2) - delSamples = [1641 1895 2032 1895 2311 2000 2350 2222 NaN 2332 2330 2290 2401 2415 NaN 2393 2305 2381 2398]; - delBlocks = round(delSamples/setupStruct.updatel); - delStarts = floor([25138 46844 105991 169901 195739 218536 241803 333905 347703 362660 373753 745135 765887 788078 806257 823835 842443 860139 881869]/setupStruct.updatel); -else - delStarts = []; -end - -for i=1:setupStruct.updateno - setupStruct.currentBlock = i; - - sb = (i-1)*setupStruct.updatel + 1; - se = sb + setupStruct.support - 1; - - %%%%%%% - % Analysis FFTs - %%%%%%% - % Far end signal - temp = fft(setupStruct.win .* xFar(sb:se))/frameSize; - fTheFarEnd = temp(1:setupStruct.hsupport1); - afTheFarEnd(:,i) = abs(fTheFarEnd); - fFar(:,i) = fTheFarEnd; - % Near end signal - temp = fft(setupStruct.win .* yNear(sb:se))/frameSize;%,pause - fmicrophone = temp(1:setupStruct.hsupport1); - afmicrophone(:,i) = abs(fmicrophone); - fNear(:,i) = fmicrophone; - %abs(fmicrophone),pause - % The true near end speaker (if we have such info) - temp = fft(setupStruct.win .* yNearSpeech(sb:se)); - aftrueSpeech = abs(temp(1:setupStruct.hsupport1)); - - if(i == 1000) - %break; - end - - % Perform delay estimation - if (setupStruct.useDelayEstimation == 1) - % Delay Estimation - delayStruct = align(fTheFarEnd, fmicrophone, delayStruct, i); - %delayStruct.delay(i) = 39;%19; - idel = max(i - delayStruct.delay(i) + 1,1); - - if delayCompensation_flag - % If we have a new delay estimate from Bastiaan's alg. update the offset - if (delayStruct.delay(i) ~= delayStruct.delay(max(1,i-1))) - delayStruct.delayAdjust = delayStruct.delayAdjust + delayStruct.delay(i) - delayStruct.delay(i-1); - end - % Store the compensated delay - delayStruct.delayNew(i) = delayStruct.delay(i) - delayStruct.delayAdjust; - if (delayStruct.delayNew(i) < 1) - % Something's wrong - pause,break - end - % Compensate with the offset estimate - idel = idel + delayStruct.delayAdjust; - end - if 0%aecmStruct.plotIt - figure(1) - plot(1:i,delayStruct.delay(1:i),'k:',1:i,delayStruct.delayNew(1:i),'k--','LineWidth',2),drawnow - end - elseif (setupStruct.useDelayEstimation == 2) - % Use "manual delay" - delIndex = find(delStarts<i); - if isempty(delIndex) - idel = i; - else - idel = i - delBlocks(max(delIndex)); - if isnan(idel) - idel = i - delBlocks(max(delIndex)-1); - end - end - else - % No delay estimation - %idel = max(i - 18, 1); - idel = max(i - 50, 1); - end - - %%%%%%%% - % This is the AECM algorithm - % - % Output is the new frequency domain signal (hopefully) echo compensated - %%%%%%%% - [femicrophone, aecmStruct] = AECMobile(fmicrophone, afTheFarEnd(:,idel), setupStruct, aecmStruct); - %[femicrophone, aecmStruct] = AECMobile(fmicrophone, FARENDFFT(idel,:)'/2^F(idel,end-1), setupStruct, aecmStruct); - - if aecmStruct.feedbackDelayUpdate - % If the feedback tells us there is a new offset out there update the enhancement - delayStruct.delayAdjust = delayStruct.delayAdjust + aecmStruct.feedbackDelay; - aecmStruct.feedbackDelayUpdate = 0; - end - - % reconstruction; first make spectrum odd - temp = [femicrophone; flipud(conj(femicrophone(2:(setupStruct.hsupport1-1))))]; - emicrophone(sb:se) = emicrophone(sb:se) + setupStruct.factor * setupStruct.win .* real(ifft(temp))*frameSize; - if max(isnan(emicrophone(sb:se))) - % Something's wrong with the output at block i - i - break - end -end - - -if useHTC - fid=fopen('aecOutMatlabC.pcm','w');fwrite(fid,int16(emicrophone),'short');fclose(fid); - %fid=fopen('farendFFT.txt','w');fwrite(fid,int16(afTheFarEnd(:)),'short');fclose(fid); - %fid=fopen('farendFFTreal.txt','w');fwrite(fid,int16(imag(fFar(:))),'short');fclose(fid); - %fid=fopen('farendFFTimag.txt','w');fwrite(fid,int16(real(fFar(:))),'short');fclose(fid); - %fid=fopen('nearendFFT.txt','w');fwrite(fid,int16(afmicrophone(:)),'short');fclose(fid); - %fid=fopen('nearendFFTreal.txt','w');fwrite(fid,int16(real(fNear(:))),'short');fclose(fid); - %fid=fopen('nearendFFTimag.txt','w');fwrite(fid,int16(imag(fNear(:))),'short');fclose(fid); -end -if useHTC - %spclab(setupStruct.samplingfreq,xFar,yNear,emicrophone) -else - spclab(setupStruct.samplingfreq,xFar,yNear,emicrophone,yNearSpeech) -end diff --git a/src/modules/audio_processing/aecm/main/matlab/matlab/simEnvironment.m b/src/modules/audio_processing/aecm/main/matlab/matlab/simEnvironment.m deleted file mode 100644 index 3ebe701..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/matlab/simEnvironment.m +++ /dev/null @@ -1,15 +0,0 @@ -speakerType = 'fm'; -%for k=2:5 -%for k=[2 4 5] -for k=3 - scenario = int2str(k); - fprintf('Current scenario: %d\n',k) - mainProgram - %saveFile = [speakerType, '_s_',scenario,'_delayEst_v2_vad_man.wav']; - %wavwrite(emic,fs,nbits,saveFile); - %saveFile = ['P:\Engineering_share\BjornV\AECM\',speakerType, '_s_',scenario,'_delayEst_v2_vad_man.pcm']; - %saveFile = [speakerType, '_s_',scenario,'_adaptMu_adaptGamma_withVar_gammFilt_HSt.pcm']; - saveFile = ['scenario_',scenario,'_090417_backupH_nlp.pcm']; - fid=fopen(saveFile,'w');fwrite(fid,int16(emicrophone),'short');fclose(fid); - %pause -end diff --git a/src/modules/audio_processing/aecm/main/matlab/matlab/updateSettings.m b/src/modules/audio_processing/aecm/main/matlab/matlab/updateSettings.m deleted file mode 100644 index c805f1d..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/matlab/updateSettings.m +++ /dev/null @@ -1,94 +0,0 @@ -function [setupStructNew, delayStructNew] = updateSettings(microphone, TheFarEnd, setupStruct, delayStruct); - -% other, constants -setupStruct.hsupport1 = setupStruct.support/2 + 1; -setupStruct.factor = 2 / setupStruct.oversampling; -setupStruct.updatel = setupStruct.support/setupStruct.oversampling; -setupStruct.estLen = round(setupStruct.avtime * setupStruct.samplingfreq/setupStruct.updatel); - -% compute some constants -blockLen = setupStruct.support/setupStruct.oversampling; -delayStruct.maxDelayb = floor(setupStruct.samplingfreq*delayStruct.maxDelay/setupStruct.updatel); % in blocks - -%input -tlength = min([length(microphone),length(TheFarEnd)]); -updateno = floor(tlength/setupStruct.updatel); -setupStruct.tlength = setupStruct.updatel*updateno; -setupStruct.updateno = updateno - setupStruct.oversampling + 1; - -% signal length -n = floor(min([length(TheFarEnd), length(microphone)])/setupStruct.support)*setupStruct.support; -setupStruct.nb = n/blockLen - setupStruct.oversampling + 1; % in blocks - -setupStruct.win = sqrt([0 ; hanning(setupStruct.support-1)]); - -% Construct filterbank in Bark-scale - -K = setupStruct.subBandLength; %Something's wrong when K even -erbs = 21.4*log10(0.00437*setupStruct.samplingfreq/2+1); -fe = (10.^((0:K)'*erbs/K/21.4)-1)/0.00437; -setupStruct.centerFreq = fe; -H = diag(ones(1,K-1))+diag(ones(1,K-2),-1); -Hinv = inv(H); -aty = 2*Hinv(end,:)*fe(2:end-1); -boundary = aty - (setupStruct.samplingfreq/2 + fe(end-1))/2; -if rem(K,2) - x1 = min([fe(2)/2, -boundary]); -else - x1 = max([0, boundary]); -end -%x1 -g = fe(2:end-1); -g(1) = g(1) - x1/2; -x = 2*Hinv*g; -x = [x1;x]; -%figure(42), clf -xy = zeros((K+1)*4,1); -yy = zeros((K+1)*4,1); -xy(1:4) = [fe(1) fe(1) x(1) x(1)]'; -yy(1:4) = [0 1 1 0]'/x(1); -for kk=2:K - xy((kk-1)*4+(1:4)) = [x(kk-1) x(kk-1) x(kk) x(kk)]'; - yy((kk-1)*4+(1:4)) = [0 1 1 0]'/(x(kk)-x(kk-1)); -end -xy(end-3:end) = [x(K) x(K) fe(end) fe(end)]'; -yy(end-3:end) = [0 1 1 0]'/(fe(end)*2-2*x(K)); -%plot(xy,yy,'LineWidth',2) -%fill(xy,yy,'y') - -x = [0;x]; -xk = x*setupStruct.hsupport1/setupStruct.samplingfreq*2; -%setupStruct.erbBoundaries = xk; -numInBand = zeros(length(xk),1); -xh = (0:setupStruct.hsupport1-1); - -for kk=1:length(xk) - if (kk==length(xk)) - numInBand(kk) = length(find(xh>=xk(kk))); - else - numInBand(kk) = length(intersect(find(xh>=xk(kk)),find(xh<xk(kk+1)))); - end -end -setupStruct.numInBand = numInBand; - -setupStructNew = setupStruct; - -delayStructNew = struct(... - 'sxAll2',zeros(setupStructNew.hsupport1,setupStructNew.nb),... - 'syAll2',zeros(setupStructNew.hsupport1,setupStructNew.nb),... - 'z200',zeros(5,setupStructNew.hsupport1),... - 'z500',zeros(5,delayStruct.maxDelayb+1),... - 'bxspectrum',uint32(zeros(setupStructNew.nb,1)),... - 'byspectrum',uint32(zeros(setupStructNew.nb,1)),... - 'bandfirst',delayStruct.bandfirst,'bandlast',delayStruct.bandlast,... - 'bxhist',uint32(zeros(delayStruct.maxDelayb+1,1)),... - 'bcount',zeros(1+delayStruct.maxDelayb,setupStructNew.nb),... - 'fout',zeros(1+delayStruct.maxDelayb,setupStructNew.nb),... - 'new',zeros(1+delayStruct.maxDelayb,setupStructNew.nb),... - 'smlength',delayStruct.smlength,... - 'maxDelay', delayStruct.maxDelay,... - 'maxDelayb', delayStruct.maxDelayb,... - 'oneGoodEstimate', 0,... - 'delayAdjust', 0,... - 'delayNew',zeros(setupStructNew.nb,1),... - 'delay',zeros(setupStructNew.nb,1)); diff --git a/src/modules/audio_processing/aecm/main/matlab/waitbar_j.m b/src/modules/audio_processing/aecm/main/matlab/waitbar_j.m deleted file mode 100644 index 50b9ccf..0000000 --- a/src/modules/audio_processing/aecm/main/matlab/waitbar_j.m +++ /dev/null @@ -1,234 +0,0 @@ -function fout = waitbar_j(x,whichbar, varargin) -%WAITBAR Display wait bar. -% H = WAITBAR(X,'title', property, value, property, value, ...) -% creates and displays a waitbar of fractional length X. The -% handle to the waitbar figure is returned in H. -% X should be between 0 and 1. Optional arguments property and -% value allow to set corresponding waitbar figure properties. -% Property can also be an action keyword 'CreateCancelBtn', in -% which case a cancel button will be added to the figure, and -% the passed value string will be executed upon clicking on the -% cancel button or the close figure button. -% -% WAITBAR(X) will set the length of the bar in the most recently -% created waitbar window to the fractional length X. -% -% WAITBAR(X,H) will set the length of the bar in waitbar H -% to the fractional length X. -% -% WAITBAR(X,H,'updated title') will update the title text in -% the waitbar figure, in addition to setting the fractional -% length to X. -% -% WAITBAR is typically used inside a FOR loop that performs a -% lengthy computation. A sample usage is shown below: -% -% h = waitbar(0,'Please wait...'); -% for i=1:100, -% % computation here % -% waitbar(i/100,h) -% end -% close(h) - -% Clay M. Thompson 11-9-92 -% Vlad Kolesnikov 06-7-99 -% Copyright 1984-2001 The MathWorks, Inc. -% $Revision: 1.22 $ $Date: 2001/04/15 12:03:29 $ - -if nargin>=2 - if ischar(whichbar) - type=2; %we are initializing - name=whichbar; - elseif isnumeric(whichbar) - type=1; %we are updating, given a handle - f=whichbar; - else - error(['Input arguments of type ' class(whichbar) ' not valid.']) - end -elseif nargin==1 - f = findobj(allchild(0),'flat','Tag','TMWWaitbar'); - - if isempty(f) - type=2; - name='Waitbar'; - else - type=1; - f=f(1); - end -else - error('Input arguments not valid.'); -end - -x = max(0,min(100*x,100)); - -switch type - case 1, % waitbar(x) update - p = findobj(f,'Type','patch'); - l = findobj(f,'Type','line'); - if isempty(f) | isempty(p) | isempty(l), - error('Couldn''t find waitbar handles.'); - end - xpatch = get(p,'XData'); - xpatch = [0 x x 0]; - set(p,'XData',xpatch) - xline = get(l,'XData'); - set(l,'XData',xline); - - if nargin>2, - % Update waitbar title: - hAxes = findobj(f,'type','axes'); - hTitle = get(hAxes,'title'); - set(hTitle,'string',varargin{1}); - end - - case 2, % waitbar(x,name) initialize - vertMargin = 0; - if nargin > 2, - % we have optional arguments: property-value pairs - if rem (nargin, 2 ) ~= 0 - error( 'Optional initialization arguments must be passed in pairs' ); - end - end - - oldRootUnits = get(0,'Units'); - - set(0, 'Units', 'points'); - screenSize = get(0,'ScreenSize'); - - axFontSize=get(0,'FactoryAxesFontSize'); - - pointsPerPixel = 72/get(0,'ScreenPixelsPerInch'); - - width = 360 * pointsPerPixel; - height = 75 * pointsPerPixel; - pos = [screenSize(3)/2-width/2 screenSize(4)/2-height/2 width height]; - -%pos= [501.75 589.5 393.75 52.5]; - f = figure(... - 'Units', 'points', ... - 'BusyAction', 'queue', ... - 'Position', pos, ... - 'Resize','on', ... - 'CreateFcn','', ... - 'NumberTitle','off', ... - 'IntegerHandle','off', ... - 'MenuBar', 'none', ... - 'Tag','TMWWaitbar',... - 'Interruptible', 'off', ... - 'Visible','on'); - - %%%%%%%%%%%%%%%%%%%%% - % set figure properties as passed to the fcn - % pay special attention to the 'cancel' request - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - if nargin > 2, - propList = varargin(1:2:end); - valueList = varargin(2:2:end); - cancelBtnCreated = 0; - for ii = 1:length( propList ) - try - if strcmp(lower(propList{ii}), 'createcancelbtn' ) & ~cancelBtnCreated - cancelBtnHeight = 23 * pointsPerPixel; - cancelBtnWidth = 60 * pointsPerPixel; - newPos = pos; - vertMargin = vertMargin + cancelBtnHeight; - newPos(4) = newPos(4)+vertMargin; - callbackFcn = [valueList{ii}]; - set( f, 'Position', newPos, 'CloseRequestFcn', callbackFcn ); - cancelButt = uicontrol('Parent',f, ... - 'Units','points', ... - 'Callback',callbackFcn, ... - 'ButtonDownFcn', callbackFcn, ... - 'Enable','on', ... - 'Interruptible','off', ... - 'Position', [pos(3)-cancelBtnWidth*1.4, 7, ... - cancelBtnWidth, cancelBtnHeight], ... - 'String','Cancel', ... - 'Tag','TMWWaitbarCancelButton'); - cancelBtnCreated = 1; - else - % simply set the prop/value pair of the figure - set( f, propList{ii}, valueList{ii}); - end - catch - disp ( ['Warning: could not set property ''' propList{ii} ''' with value ''' num2str(valueList{ii}) '''' ] ); - end - end - end - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - - colormap([]); - - axNorm=[.05 .3 .9 .2]; - % axNorm=[1 1 1 1]; - axPos=axNorm.*[pos(3:4),pos(3:4)] + [0 vertMargin 0 0]; - - h = axes('XLim',[0 100],... - 'YLim',[0 1],... - 'Box','on', ... - 'Units','Points',... - 'FontSize', axFontSize,... - 'Position',axPos,... - 'XTickMode','manual',... - 'YTickMode','manual',... - 'XTick',[],... - 'YTick',[],... - 'XTickLabelMode','manual',... - 'XTickLabel',[],... - 'YTickLabelMode','manual',... - 'YTickLabel',[]); - - tHandle=title(name); - tHandle=get(h,'title'); - oldTitleUnits=get(tHandle,'Units'); - set(tHandle,... - 'Units', 'points',... - 'String', name); - - tExtent=get(tHandle,'Extent'); - set(tHandle,'Units',oldTitleUnits); - - titleHeight=tExtent(4)+axPos(2)+axPos(4)+5; - if titleHeight>pos(4) - pos(4)=titleHeight; - pos(2)=screenSize(4)/2-pos(4)/2; - figPosDirty=logical(1); - else - figPosDirty=logical(0); - end - - if tExtent(3)>pos(3)*1.10; - pos(3)=min(tExtent(3)*1.10,screenSize(3)); - pos(1)=screenSize(3)/2-pos(3)/2; - - axPos([1,3])=axNorm([1,3])*pos(3); - set(h,'Position',axPos); - - figPosDirty=logical(1); - end - - if figPosDirty - set(f,'Position',pos); - end - - xpatch = [0 x x 0]; - ypatch = [0 0 1 1]; - xline = [100 0 0 100 100]; - yline = [0 0 1 1 0]; - - p = patch(xpatch,ypatch,'r','EdgeColor','r','EraseMode','none'); - l = line(xline,yline,'EraseMode','none'); - set(l,'Color',get(gca,'XColor')); - - - set(f,'HandleVisibility','callback','visible','on', 'resize','off'); - - set(0, 'Units', oldRootUnits); -end % case -drawnow; - -if nargout==1, - fout = f; -end diff --git a/src/modules/audio_processing/aecm/main/source/aecm.gypi b/src/modules/audio_processing/aecm/main/source/aecm.gypi index 3c63c52..bbfb1ca 100644 --- a/src/modules/audio_processing/aecm/main/source/aecm.gypi +++ b/src/modules/audio_processing/aecm/main/source/aecm.gypi @@ -28,8 +28,6 @@ 'echo_control_mobile.c', 'aecm_core.c', 'aecm_core.h', - 'aecm_delay_estimator.c', - 'aecm_delay_estimator.h', ], }, ], diff --git a/src/modules/audio_processing/aecm/main/source/aecm_core.c b/src/modules/audio_processing/aecm/main/source/aecm_core.c index b7dae90..13bffae 100644 --- a/src/modules/audio_processing/aecm/main/source/aecm_core.c +++ b/src/modules/audio_processing/aecm/main/source/aecm_core.c @@ -13,8 +13,8 @@ #include <assert.h> #include <stdlib.h> -#include "aecm_delay_estimator.h" #include "echo_control_mobile.h" +#include "delay_estimator.h" #include "ring_buffer.h" #include "typedefs.h" @@ -153,11 +153,13 @@ int WebRtcAecm_CreateCore(AecmCore_t **aecmInst) return -1; } - if (WebRtcAecm_CreateDelayEstimator(&aecm->delay_estimator, PART_LEN1, MAX_DELAY) == -1) - { - WebRtcAecm_FreeCore(aecm); - aecm = NULL; - return -1; + if (WebRtc_CreateDelayEstimator(&aecm->delay_estimator, + PART_LEN1, + MAX_DELAY, + 1) == -1) { + WebRtcAecm_FreeCore(aecm); + aecm = NULL; + return -1; } // Init some aecm pointers. 16 and 32 byte alignment is only necessary @@ -242,9 +244,8 @@ int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq) aecm->seed = 666; aecm->totCount = 0; - if (WebRtcAecm_InitDelayEstimator(aecm->delay_estimator) != 0) - { - return -1; + if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) { + return -1; } // Initialize to reasonable values @@ -339,7 +340,7 @@ int WebRtcAecm_FreeCore(AecmCore_t *aecm) WebRtcApm_FreeBuffer(aecm->nearCleanFrameBuf); WebRtcApm_FreeBuffer(aecm->outFrameBuf); - WebRtcAecm_FreeDelayEstimator(aecm->delay_estimator); + WebRtc_FreeDelayEstimator(aecm->delay_estimator); free(aecm); return 0; @@ -1161,6 +1162,7 @@ int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, WebRtc_Word16 supGain; WebRtc_Word16 zeros32, zeros16; WebRtc_Word16 zerosDBufNoisy, zerosDBufClean, zerosXBuf; + int far_q; WebRtc_Word16 resolutionDiff, qDomainDiff; const int kMinPrefBand = 4; @@ -1200,10 +1202,10 @@ int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, #endif // Transform far end signal from time domain to frequency domain. - zerosXBuf = TimeToFrequencyDomain(aecm->xBuf, - dfw, - xfa, - &xfaSum); + far_q = TimeToFrequencyDomain(aecm->xBuf, + dfw, + xfa, + &xfaSum); // Transform noisy near end signal from time domain to frequency domain. zerosDBufNoisy = TimeToFrequencyDomain(aecm->dBufNoisy, @@ -1211,7 +1213,7 @@ int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, dfaNoisy, &dfaNoisySum); aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain; - aecm->dfaNoisyQDomain = zerosDBufNoisy; + aecm->dfaNoisyQDomain = (WebRtc_Word16)zerosDBufNoisy; if (nearendClean == NULL) @@ -1228,7 +1230,7 @@ int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, dfaClean, &dfaCleanSum); aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain; - aecm->dfaCleanQDomain = zerosDBufClean; + aecm->dfaCleanQDomain = (WebRtc_Word16)zerosDBufClean; } #ifdef ARM_WINM_LOG_ @@ -1243,12 +1245,12 @@ int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, // Get the delay // Save far-end history and estimate delay - delay = WebRtcAecm_DelayEstimatorProcess(aecm->delay_estimator, - xfa, - dfaNoisy, - PART_LEN1, - zerosXBuf, - aecm->currentVADValue); + delay = WebRtc_DelayEstimatorProcess(aecm->delay_estimator, + xfa, + dfaNoisy, + PART_LEN1, + far_q, + aecm->currentVADValue); if (delay < 0) { return -1; @@ -1272,16 +1274,21 @@ int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, QueryPerformanceCounter((LARGE_INTEGER*)&start); #endif // Get aligned far end spectrum - far_spectrum_ptr = WebRtcAecm_GetAlignedFarend(aecm->delay_estimator, - PART_LEN1, - &zerosXBuf); + far_spectrum_ptr = WebRtc_AlignedFarend(aecm->delay_estimator, + PART_LEN1, + &far_q); + zerosXBuf = (WebRtc_Word16) far_q; if (far_spectrum_ptr == NULL) { return -1; } // Calculate log(energy) and update energy threshold levels - WebRtcAecm_CalcEnergies(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisySum, echoEst32); + WebRtcAecm_CalcEnergies(aecm, + far_spectrum_ptr, + zerosXBuf, + dfaNoisySum, + echoEst32); // Calculate stepsize mu = WebRtcAecm_CalcStepSize(aecm); @@ -1923,4 +1930,3 @@ void WebRtcAecm_ResetAdaptiveChannel(AecmCore_t* aecm) } #endif // !(defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM_NEON)) - diff --git a/src/modules/audio_processing/aecm/main/source/aecm_core.h b/src/modules/audio_processing/aecm/main/source/aecm_core.h index e431c71..0dfdb04 100644 --- a/src/modules/audio_processing/aecm/main/source/aecm_core.h +++ b/src/modules/audio_processing/aecm/main/source/aecm_core.h @@ -178,7 +178,7 @@ typedef struct WebRtc_Word16 farEnergyMaxMin; WebRtc_Word16 farEnergyVAD; WebRtc_Word16 farEnergyMSE; - WebRtc_Word16 currentVADValue; + int currentVADValue; WebRtc_Word16 vadUpdateCount; WebRtc_Word16 startupState; diff --git a/src/modules/audio_processing/aecm/main/source/aecm_delay_estimator.c b/src/modules/audio_processing/aecm/main/source/aecm_delay_estimator.c deleted file mode 100644 index 2ed9e03..0000000 --- a/src/modules/audio_processing/aecm/main/source/aecm_delay_estimator.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "aecm_delay_estimator.h" - -#include <assert.h> -#include <stdlib.h> - -#include "signal_processing_library.h" -#include "typedefs.h" - -typedef struct -{ - // Pointers to mean values of spectrum and bit counts - WebRtc_Word32* mean_far_spectrum; - WebRtc_Word32* mean_near_spectrum; - WebRtc_Word32* mean_bit_counts; - - // Arrays only used locally in DelayEstimatorProcess() but whose size - // is determined at run-time. - WebRtc_Word32* bit_counts; - WebRtc_Word32* far_spectrum_32; - WebRtc_Word32* near_spectrum_32; - - // Binary history variables - WebRtc_UWord32* binary_far_history; - - // Far end history variables - WebRtc_UWord16* far_history; - int far_history_position; - WebRtc_Word16* far_q_domains; - - // Delay histogram variables - WebRtc_Word16* delay_histogram; - WebRtc_Word16 vad_counter; - - // Delay memory - int last_delay; - - // Buffer size parameters - int history_size; - int spectrum_size; - -} DelayEstimator_t; - -// Only bit |kBandFirst| through bit |kBandLast| are processed -// |kBandFirst| - |kBandLast| must be < 32 -static const int kBandFirst = 12; -static const int kBandLast = 43; - -static __inline WebRtc_UWord32 SetBit(WebRtc_UWord32 in, - WebRtc_Word32 pos) -{ - WebRtc_UWord32 mask = WEBRTC_SPL_LSHIFT_W32(1, pos); - WebRtc_UWord32 out = (in | mask); - - return out; -} - -// Compares the binary vector |binary_vector| with all rows of the binary -// matrix |binary_matrix| and counts per row the number of times they have the -// same value. -// Input: -// - binary_vector : binary "vector" stored in a long -// - binary_matrix : binary "matrix" stored as a vector of long -// - matrix_size : size of binary "matrix" -// Output: -// - bit_counts : "Vector" stored as a long, containing for each -// row the number of times the matrix row and the -// input vector have the same value -// -static void BitCountComparison(const WebRtc_UWord32 binary_vector, - const WebRtc_UWord32* binary_matrix, - int matrix_size, - WebRtc_Word32* bit_counts) -{ - int n = 0; - WebRtc_UWord32 a = binary_vector; - register WebRtc_UWord32 tmp; - - // compare binary vector |binary_vector| with all rows of the binary matrix - // |binary_matrix| - for (; n < matrix_size; n++) - { - a = (binary_vector ^ binary_matrix[n]); - // Returns bit counts in tmp - tmp = a - ((a >> 1) & 033333333333) - ((a >> 2) & 011111111111); - tmp = ((tmp + (tmp >> 3)) & 030707070707); - tmp = (tmp + (tmp >> 6)); - tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077; - - bit_counts[n] = (WebRtc_Word32)tmp; - } -} - -// Computes the binary spectrum by comparing the input |spectrum| with a -// |threshold_spectrum|. -// -// Input: -// - spectrum : Spectrum of which the binary spectrum should -// be calculated. -// - threshold_spectrum : Threshold spectrum with which the input -// spectrum is compared. -// Return: -// - out : Binary spectrum -// -static WebRtc_UWord32 GetBinarySpectrum(WebRtc_Word32* spectrum, - WebRtc_Word32* threshold_spectrum) -{ - int k = kBandFirst; - WebRtc_UWord32 out = 0; - - for (; k <= kBandLast; k++) - { - if (spectrum[k] > threshold_spectrum[k]) - { - out = SetBit(out, k - kBandFirst); - } - } - - return out; -} - -// Calculates the mean recursively. -// -// Input: -// - new_value : new additional value -// - factor : factor for smoothing -// -// Input/Output: -// - mean_value : pointer to the mean value that should be updated -// -static void MeanEstimator(const WebRtc_Word32 new_value, - int factor, - WebRtc_Word32* mean_value) -{ - WebRtc_Word32 mean_new = *mean_value; - WebRtc_Word32 diff = new_value - mean_new; - - // mean_new = mean_value + ((new_value - mean_value) >> factor); - if (diff < 0) - { - diff = -WEBRTC_SPL_RSHIFT_W32(-diff, factor); - } - else - { - diff = WEBRTC_SPL_RSHIFT_W32(diff, factor); - } - mean_new += diff; - - *mean_value = mean_new; -} - -// Moves the pointer to the next entry and inserts new far end spectrum and -// corresponding Q-domain in its buffer. -// -// Input: -// - handle : 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(DelayEstimator_t* self, - WebRtc_UWord16* far_spectrum, - WebRtc_Word16 far_q) -{ - // Get new buffer position - self->far_history_position++; - if (self->far_history_position >= self->history_size) - { - self->far_history_position = 0; - } - // Update Q-domain buffer - self->far_q_domains[self->far_history_position] = far_q; - // Update far end spectrum buffer - memcpy(&(self->far_history[self->far_history_position * self->spectrum_size]), - far_spectrum, - sizeof(WebRtc_UWord16) * self->spectrum_size); -} - -int WebRtcAecm_FreeDelayEstimator(void* handle) -{ - DelayEstimator_t* self = (DelayEstimator_t*)handle; - - if (self == NULL) - { - return -1; - } - - if (self->mean_far_spectrum != NULL) - { - free(self->mean_far_spectrum); - self->mean_far_spectrum = NULL; - } - if (self->mean_near_spectrum != NULL) - { - free(self->mean_near_spectrum); - self->mean_near_spectrum = NULL; - } - if (self->mean_bit_counts != NULL) - { - free(self->mean_bit_counts); - self->mean_bit_counts = NULL; - } - if (self->bit_counts != NULL) - { - free(self->bit_counts); - self->bit_counts = NULL; - } - if (self->far_spectrum_32 != NULL) - { - free(self->far_spectrum_32); - self->far_spectrum_32 = NULL; - } - if (self->near_spectrum_32 != NULL) - { - free(self->near_spectrum_32); - self->near_spectrum_32 = NULL; - } - if (self->far_history != NULL) - { - free(self->far_history); - self->far_history = NULL; - } - if (self->binary_far_history != NULL) - { - free(self->binary_far_history); - self->binary_far_history = NULL; - } - if (self->far_q_domains != NULL) - { - free(self->far_q_domains); - self->far_q_domains = NULL; - } - if (self->delay_histogram != NULL) - { - free(self->delay_histogram); - self->delay_histogram = NULL; - } - - free(self); - - return 0; -} - -int WebRtcAecm_CreateDelayEstimator(void** handle, - int spectrum_size, - int history_size) -{ - DelayEstimator_t *self = NULL; - // Check if the sub band used in the delay estimation is small enough to - // fit in a Word32. - assert(kBandLast - kBandFirst < 32); - if (spectrum_size < kBandLast) - { - return -1; - } - if (history_size < 0) - { - return -1; - } - - self = malloc(sizeof(DelayEstimator_t)); - *handle = self; - if (self == NULL) - { - return -1; - } - - self->mean_far_spectrum = NULL; - self->mean_near_spectrum = NULL; - self->bit_counts = NULL; - self->far_spectrum_32 = NULL; - self->near_spectrum_32 = NULL; - self->far_history = NULL; - self->mean_bit_counts = NULL; - self->binary_far_history = NULL; - self->far_q_domains = NULL; - self->delay_histogram = NULL; - - // Allocate memory for spectrum buffers - self->mean_far_spectrum = malloc(spectrum_size * sizeof(WebRtc_Word32)); - if (self->mean_far_spectrum == NULL) - { - WebRtcAecm_FreeDelayEstimator(self); - self = NULL; - return -1; - } - self->mean_near_spectrum = malloc(spectrum_size * sizeof(WebRtc_Word32)); - if (self->mean_near_spectrum == NULL) - { - WebRtcAecm_FreeDelayEstimator(self); - self = NULL; - return -1; - } - self->mean_bit_counts = malloc(history_size * sizeof(WebRtc_Word32)); - if (self->mean_bit_counts == NULL) - { - WebRtcAecm_FreeDelayEstimator(self); - self = NULL; - return -1; - } - self->bit_counts = malloc(history_size * sizeof(WebRtc_Word32)); - if (self->bit_counts == NULL) - { - WebRtcAecm_FreeDelayEstimator(self); - self = NULL; - return -1; - } - self->far_spectrum_32 = malloc(spectrum_size * sizeof(WebRtc_Word32)); - if (self->far_spectrum_32 == NULL) - { - WebRtcAecm_FreeDelayEstimator(self); - self = NULL; - return -1; - } - self->near_spectrum_32 = malloc(spectrum_size * sizeof(WebRtc_Word32)); - if (self->near_spectrum_32 == NULL) - { - WebRtcAecm_FreeDelayEstimator(self); - self = NULL; - return -1; - } - // Allocate memory for history buffers - self->far_history = malloc(spectrum_size * history_size * - sizeof(WebRtc_UWord16)); - if (self->far_history == NULL) - { - WebRtcAecm_FreeDelayEstimator(self); - self = NULL; - return -1; - } - self->binary_far_history = malloc(history_size * sizeof(WebRtc_UWord32)); - if (self->binary_far_history == NULL) - { - WebRtcAecm_FreeDelayEstimator(self); - self = NULL; - return -1; - } - self->far_q_domains = malloc(history_size * sizeof(WebRtc_Word16)); - if (self->far_q_domains == NULL) - { - WebRtcAecm_FreeDelayEstimator(self); - self = NULL; - return -1; - } - self->delay_histogram = malloc(history_size * sizeof(WebRtc_Word16)); - if (self->delay_histogram == NULL) - { - WebRtcAecm_FreeDelayEstimator(self); - self = NULL; - return -1; - } - - self->spectrum_size = spectrum_size; - self->history_size = history_size; - - return 0; -} - -int WebRtcAecm_InitDelayEstimator(void* handle) -{ - DelayEstimator_t* self = (DelayEstimator_t*)handle; - - if (self == NULL) - { - return -1; - } - // Set averaged far and near end spectra to zero - memset(self->mean_far_spectrum, - 0, - sizeof(WebRtc_Word32) * self->spectrum_size); - memset(self->mean_near_spectrum, - 0, - sizeof(WebRtc_Word32) * self->spectrum_size); - // Set averaged bit counts to zero - memset(self->mean_bit_counts, - 0, - sizeof(WebRtc_Word32) * self->history_size); - memset(self->bit_counts, - 0, - sizeof(WebRtc_Word32) * self->history_size); - memset(self->far_spectrum_32, - 0, - sizeof(WebRtc_Word32) * self->spectrum_size); - memset(self->near_spectrum_32, - 0, - sizeof(WebRtc_Word32) * self->spectrum_size); - // Set far end histories to zero - memset(self->binary_far_history, - 0, - sizeof(WebRtc_UWord32) * self->history_size); - memset(self->far_history, - 0, - sizeof(WebRtc_UWord16) * self->spectrum_size * - self->history_size); - memset(self->far_q_domains, - 0, - sizeof(WebRtc_Word16) * self->history_size); - - self->far_history_position = self->history_size; - // Set delay histogram to zero - memset(self->delay_histogram, - 0, - sizeof(WebRtc_Word16) * self->history_size); - // Set VAD counter to zero - self->vad_counter = 0; - // Set delay memory to zero - self->last_delay = 0; - - return 0; -} - -int WebRtcAecm_DelayEstimatorProcess(void* handle, - WebRtc_UWord16* far_spectrum, - WebRtc_UWord16* near_spectrum, - int spectrum_size, - WebRtc_Word16 far_q, - WebRtc_Word16 vad_value) -{ - DelayEstimator_t* self = (DelayEstimator_t*)handle; - - WebRtc_UWord32 bxspectrum, byspectrum; - - int i; - - WebRtc_Word32 dtmp1; - - WebRtc_Word16 maxHistLvl = 0; - WebRtc_Word16 minpos = -1; - - const int kVadCountThreshold = 25; - const int kMaxHistogram = 600; - - if (self == NULL) - { - return -1; - } - - if (spectrum_size != self->spectrum_size) - { - // Data sizes don't match - return -1; - } - if (far_q > 15) - { - // If far_Q is larger than 15 we can not guarantee no wrap around - return -1; - } - - // Update far end history - UpdateFarHistory(self, far_spectrum, far_q); - // Update the far and near end means - for (i = 0; i < self->spectrum_size; i++) - { - self->far_spectrum_32[i] = (WebRtc_Word32)far_spectrum[i]; - MeanEstimator(self->far_spectrum_32[i], 6, &(self->mean_far_spectrum[i])); - - self->near_spectrum_32[i] = (WebRtc_Word32)near_spectrum[i]; - MeanEstimator(self->near_spectrum_32[i], 6, &(self->mean_near_spectrum[i])); - } - - // Shift binary spectrum history - memmove(&(self->binary_far_history[1]), - &(self->binary_far_history[0]), - (self->history_size - 1) * sizeof(WebRtc_UWord32)); - - // Get binary spectra - bxspectrum = GetBinarySpectrum(self->far_spectrum_32, self->mean_far_spectrum); - byspectrum = GetBinarySpectrum(self->near_spectrum_32, self->mean_near_spectrum); - // Insert new binary spectrum - self->binary_far_history[0] = bxspectrum; - - // Compare with delayed spectra - BitCountComparison(byspectrum, - self->binary_far_history, - self->history_size, - self->bit_counts); - - // Smooth bit count curve - for (i = 0; i < self->history_size; i++) - { - // Update sum - // |bit_counts| is constrained to [0, 32], meaning we can smooth with a - // factor up to 2^26. We use Q9. - dtmp1 = WEBRTC_SPL_LSHIFT_W32(self->bit_counts[i], 9); // Q9 - MeanEstimator(dtmp1, 9, &(self->mean_bit_counts[i])); - } - - // Find minimum position of bit count curve - minpos = WebRtcSpl_MinIndexW32(self->mean_bit_counts, self->history_size); - - // If the farend has been active sufficiently long, begin accumulating a - // histogram of the minimum positions. Search for the maximum bin to - // determine the delay. - if (vad_value == 1) - { - if (self->vad_counter >= kVadCountThreshold) - { - // Increment the histogram at the current minimum position. - if (self->delay_histogram[minpos] < kMaxHistogram) - { - self->delay_histogram[minpos] += 3; - } - -#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT) - // Decrement the entire histogram. - // Select the histogram index corresponding to the maximum bin as - // the delay. - self->last_delay = 0; - for (i = 0; i < self->history_size; i++) - { - if (self->delay_histogram[i] > 0) - { - self->delay_histogram[i]--; - } - if (self->delay_histogram[i] > maxHistLvl) - { - maxHistLvl = self->delay_histogram[i]; - self->last_delay = i; - } - } -#else - self->last_delay = 0; - - for (i = 0; i < self->history_size; i++) - { - WebRtc_Word16 tempVar = self->delay_histogram[i]; - - // Decrement the entire histogram. - if (tempVar > 0) - { - tempVar--; - self->delay_histogram[i] = tempVar; - - // Select the histogram index corresponding to the maximum - // bin as the delay. - if (tempVar > maxHistLvl) - { - maxHistLvl = tempVar; - self->last_delay = i; - } - } - } -#endif - } else - { - self->vad_counter++; - } - } else - { - self->vad_counter = 0; - } - - return self->last_delay; -} - -const WebRtc_UWord16* WebRtcAecm_GetAlignedFarend(void* handle, - int far_spectrum_size, - WebRtc_Word16* far_q) -{ - DelayEstimator_t* self = (DelayEstimator_t*)handle; - int buffer_position = 0; - - if (self == NULL) - { - return NULL; - } - if (far_spectrum_size != self->spectrum_size) - { - return NULL; - } - - // Get buffer position - buffer_position = self->far_history_position - self->last_delay; - if (buffer_position < 0) - { - buffer_position += self->history_size; - } - // Get Q-domain - *far_q = self->far_q_domains[buffer_position]; - // Return far end spectrum - return (self->far_history + (buffer_position * self->spectrum_size)); - -} - -int WebRtcAecm_GetLastDelay(void* handle) -{ - DelayEstimator_t* self = (DelayEstimator_t*)handle; - - if (self == NULL) - { - return -1; - } - - // Return last calculated delay - return self->last_delay; -} diff --git a/src/modules/audio_processing/aecm/main/source/aecm_delay_estimator.h b/src/modules/audio_processing/aecm/main/source/aecm_delay_estimator.h deleted file mode 100644 index 5ce57fa..0000000 --- a/src/modules/audio_processing/aecm/main/source/aecm_delay_estimator.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -// Performs delay estimation on a block by block basis -// The return value is 0 - OK and -1 - Error, unless otherwise stated. - -#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_DELAY_ESTIMATOR_H_ -#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_DELAY_ESTIMATOR_H_ - -#include "typedefs.h" - -// Releases the memory allocated by WebRtcAecm_CreateDelayEstimator(...) -// Input: -// - handle : Pointer to the delay estimation instance -// -int WebRtcAecm_FreeDelayEstimator(void* handle); - -// Allocates the memory needed by the delay estimation. The memory needs to be -// initialized separately using the WebRtcAecm_InitDelayEstimator(...) function. -// -// Input: -// - handle : Instance that should be created -// - spectrum_size : Size of the spectrum used both in far end and near -// end. Used to allocate memory for spectrum specific -// buffers. -// - history_size : Size of the far end history used to estimate the -// delay from. Used to allocate memory for history -// specific buffers. -// -// Output: -// - handle : Created instance -// -int WebRtcAecm_CreateDelayEstimator(void** handle, - int spectrum_size, - int history_size); - -// Initializes the delay estimation instance created with -// WebRtcAecm_CreateDelayEstimator(...) -// Input: -// - handle : Pointer to the delay estimation instance -// -// Output: -// - handle : Initialized instance -// -int WebRtcAecm_InitDelayEstimator(void* handle); - -// Estimates and returns the delay between the far end and near end blocks. -// Input: -// - handle : Pointer to the delay estimation instance -// - far_spectrum : Pointer to the far end spectrum data -// - 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) -// - far_q : The Q-domain of the far end data -// - vad_value : The VAD decision of the current block -// -// Output: -// - handle : Updated instance -// -// Return value: -// - delay : >= 0 - Calculated delay value -// -1 - Error -// -int WebRtcAecm_DelayEstimatorProcess(void* handle, - WebRtc_UWord16* far_spectrum, - WebRtc_UWord16* near_spectrum, - int spectrum_size, - WebRtc_Word16 far_q, - WebRtc_Word16 vad_value); - -// Returns a pointer to the far end spectrum aligned to current near end -// spectrum. The function WebRtcAecm_DelayEstimatorProcess(...) should -// have been called before WebRtcAecm_GetAlignedFarend(...). Otherwise, you get -// the pointer to the previous frame. The memory is only valid until the next -// call of WebRtcAecm_DelayEstimatorProcess(...). -// -// Inputs: -// - handle : Pointer to the delay estimation instance -// -// Output: -// - far_spectrum_size : Size of far_spectrum allocated by the caller -// - far_q : The Q-domain of the aligned far end spectrum -// -// Return value: -// - far_spectrum : Pointer to the aligned far end spectrum -// NULL - Error -// -const WebRtc_UWord16* WebRtcAecm_GetAlignedFarend(void* handle, - int far_spectrum_size, - WebRtc_Word16* far_q); - -// Returns the last calculated delay updated by the function -// WebRtcAecm_DelayEstimatorProcess(...) -// -// Inputs: -// - handle : Pointer to the delay estimation instance -// -// Return value: -// - delay : >= 0 - Last calculated delay value -// -1 - Error -// -int WebRtcAecm_GetLastDelay(void* handle); - -#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_DELAY_ESTIMATOR_H_ diff --git a/src/modules/audio_processing/agc/main/matlab/getGains.m b/src/modules/audio_processing/agc/main/matlab/getGains.m deleted file mode 100644 index e0234b8..0000000 --- a/src/modules/audio_processing/agc/main/matlab/getGains.m +++ /dev/null @@ -1,32 +0,0 @@ -% Outputs a file for testing purposes. -% -% Adjust the following parameters to suit. Their purpose becomes more clear on -% viewing the gain plots. -% MaxGain: Max gain in dB -% MinGain: Min gain at overload (0 dBov) in dB -% CompRatio: Compression ratio, essentially determines the slope of the gain -% function between the max and min gains -% Knee: The smoothness of the transition to max gain (smaller is smoother) -MaxGain = 5; MinGain = 0; CompRatio = 3; Knee = 1; - -% Compute gains -zeros = 0:31; lvl = 2.^(1-zeros); -A = -10*log10(lvl) * (CompRatio - 1) / CompRatio; -B = MaxGain - MinGain; -gains = round(2^16*10.^(0.05 * (MinGain + B * ( log(exp(-Knee*A)+exp(-Knee*B)) - log(1+exp(-Knee*B)) ) / log(1/(1+exp(Knee*B)))))); -fprintf(1, '\t%i, %i, %i, %i,\n', gains); - -% Save gains to file -fid = fopen('gains', 'wb'); -if fid == -1 - error(sprintf('Unable to open file %s', filename)); - return -end -fwrite(fid, gains, 'int32'); -fclose(fid); - -% Plotting -in = 10*log10(lvl); out = 20*log10(gains/65536); -subplot(121); plot(in, out); axis([-60, 0, -5, 30]); grid on; xlabel('Input (dB)'); ylabel('Gain (dB)'); -subplot(122); plot(in, in+out); axis([-60, 0, -60, 10]); grid on; xlabel('Input (dB)'); ylabel('Output (dB)'); -zoom on; diff --git a/src/modules/audio_processing/main/apm_tests.gypi b/src/modules/audio_processing/main/apm_tests.gypi index 8c27ff9..126baae 100644 --- a/src/modules/audio_processing/main/apm_tests.gypi +++ b/src/modules/audio_processing/main/apm_tests.gypi @@ -27,6 +27,7 @@ 'audio_processing', '<(webrtc_root)/common_audio/common_audio.gyp:spl', '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers', + '<(webrtc_root)/../test/test.gyp:test_support', '<(webrtc_root)/../testing/gtest.gyp:gtest', '<(webrtc_root)/../testing/gtest.gyp:gtest_main', '<(webrtc_root)/../third_party/protobuf/protobuf.gyp:protobuf_lite', diff --git a/src/modules/audio_processing/main/interface/audio_processing.h b/src/modules/audio_processing/main/interface/audio_processing.h index 350ef82..3dc698b 100644 --- a/src/modules/audio_processing/main/interface/audio_processing.h +++ b/src/modules/audio_processing/main/interface/audio_processing.h @@ -322,6 +322,16 @@ class EchoCancellation { // TODO(ajm): discuss the metrics update period. virtual int GetMetrics(Metrics* metrics) = 0; + // Enables computation and logging of delay values. Statistics are obtained + // through |GetDelayMetrics()|. + virtual int enable_delay_logging(bool enable) = 0; + virtual bool is_delay_logging_enabled() const = 0; + + // The delay metrics consists of the delay |median| and the delay standard + // deviation |std|. The values are averaged over the time period since the + // last call to |GetDelayMetrics()|. + virtual int GetDelayMetrics(int* median, int* std) = 0; + protected: virtual ~EchoCancellation() {}; }; @@ -486,6 +496,7 @@ class HighPassFilter { }; // An estimation component used to retrieve level metrics. +// NOTE: currently unavailable. All methods return errors. class LevelEstimator { public: virtual int Enable(bool enable) = 0; @@ -539,6 +550,10 @@ class NoiseSuppression { // The voice activity detection (VAD) component analyzes the stream to // determine if voice is present. A facility is also provided to pass in an // external VAD decision. +// +// In addition to |stream_has_voice()| the VAD decision is provided through the +// |AudioFrame| passed to |ProcessStream()|. The |_vadActivity| member will be +// modified to reflect the current decision. class VoiceDetection { public: virtual int Enable(bool enable) = 0; diff --git a/src/modules/audio_processing/main/source/audio_buffer.cc b/src/modules/audio_processing/main/source/audio_buffer.cc index 6b20fce..f7c55b4 100644 --- a/src/modules/audio_processing/main/source/audio_buffer.cc +++ b/src/modules/audio_processing/main/source/audio_buffer.cc @@ -10,8 +10,6 @@ #include "audio_buffer.h" -#include "module_common_types.h" - namespace webrtc { namespace { @@ -64,21 +62,22 @@ struct SplitAudioChannel { WebRtc_Word32 synthesis_filter_state2[6]; }; -// TODO(am): check range of input parameters? -AudioBuffer::AudioBuffer(WebRtc_Word32 max_num_channels, - WebRtc_Word32 samples_per_channel) - : max_num_channels_(max_num_channels), - num_channels_(0), - num_mixed_channels_(0), - num_mixed_low_pass_channels_(0), - samples_per_channel_(samples_per_channel), - samples_per_split_channel_(samples_per_channel), - reference_copied_(false), - data_(NULL), - channels_(NULL), - split_channels_(NULL), - mixed_low_pass_channels_(NULL), - low_pass_reference_channels_(NULL) { +// TODO(andrew): check range of input parameters? +AudioBuffer::AudioBuffer(int max_num_channels, + int samples_per_channel) + : max_num_channels_(max_num_channels), + num_channels_(0), + num_mixed_channels_(0), + num_mixed_low_pass_channels_(0), + samples_per_channel_(samples_per_channel), + samples_per_split_channel_(samples_per_channel), + reference_copied_(false), + activity_(AudioFrame::kVadUnknown), + data_(NULL), + channels_(NULL), + split_channels_(NULL), + mixed_low_pass_channels_(NULL), + low_pass_reference_channels_(NULL) { if (max_num_channels_ > 1) { channels_ = new AudioChannel[max_num_channels_]; mixed_low_pass_channels_ = new AudioChannel[max_num_channels_]; @@ -109,7 +108,7 @@ AudioBuffer::~AudioBuffer() { } } -WebRtc_Word16* AudioBuffer::data(WebRtc_Word32 channel) const { +WebRtc_Word16* AudioBuffer::data(int channel) const { assert(channel >= 0 && channel < num_channels_); if (data_ != NULL) { return data_; @@ -118,7 +117,7 @@ WebRtc_Word16* AudioBuffer::data(WebRtc_Word32 channel) const { return channels_[channel].data; } -WebRtc_Word16* AudioBuffer::low_pass_split_data(WebRtc_Word32 channel) const { +WebRtc_Word16* AudioBuffer::low_pass_split_data(int channel) const { assert(channel >= 0 && channel < num_channels_); if (split_channels_ == NULL) { return data(channel); @@ -127,7 +126,7 @@ WebRtc_Word16* AudioBuffer::low_pass_split_data(WebRtc_Word32 channel) const { return split_channels_[channel].low_pass_data; } -WebRtc_Word16* AudioBuffer::high_pass_split_data(WebRtc_Word32 channel) const { +WebRtc_Word16* AudioBuffer::high_pass_split_data(int channel) const { assert(channel >= 0 && channel < num_channels_); if (split_channels_ == NULL) { return NULL; @@ -136,13 +135,13 @@ WebRtc_Word16* AudioBuffer::high_pass_split_data(WebRtc_Word32 channel) const { return split_channels_[channel].high_pass_data; } -WebRtc_Word16* AudioBuffer::mixed_low_pass_data(WebRtc_Word32 channel) const { +WebRtc_Word16* AudioBuffer::mixed_low_pass_data(int channel) const { assert(channel >= 0 && channel < num_mixed_low_pass_channels_); return mixed_low_pass_channels_[channel].data; } -WebRtc_Word16* AudioBuffer::low_pass_reference(WebRtc_Word32 channel) const { +WebRtc_Word16* AudioBuffer::low_pass_reference(int channel) const { assert(channel >= 0 && channel < num_channels_); if (!reference_copied_) { return NULL; @@ -151,58 +150,67 @@ WebRtc_Word16* AudioBuffer::low_pass_reference(WebRtc_Word32 channel) const { return low_pass_reference_channels_[channel].data; } -WebRtc_Word32* AudioBuffer::analysis_filter_state1(WebRtc_Word32 channel) const { +WebRtc_Word32* AudioBuffer::analysis_filter_state1(int channel) const { assert(channel >= 0 && channel < num_channels_); return split_channels_[channel].analysis_filter_state1; } -WebRtc_Word32* AudioBuffer::analysis_filter_state2(WebRtc_Word32 channel) const { +WebRtc_Word32* AudioBuffer::analysis_filter_state2(int channel) const { assert(channel >= 0 && channel < num_channels_); return split_channels_[channel].analysis_filter_state2; } -WebRtc_Word32* AudioBuffer::synthesis_filter_state1(WebRtc_Word32 channel) const { +WebRtc_Word32* AudioBuffer::synthesis_filter_state1(int channel) const { assert(channel >= 0 && channel < num_channels_); return split_channels_[channel].synthesis_filter_state1; } -WebRtc_Word32* AudioBuffer::synthesis_filter_state2(WebRtc_Word32 channel) const { +WebRtc_Word32* AudioBuffer::synthesis_filter_state2(int channel) const { assert(channel >= 0 && channel < num_channels_); return split_channels_[channel].synthesis_filter_state2; } -WebRtc_Word32 AudioBuffer::num_channels() const { +void AudioBuffer::set_activity(AudioFrame::VADActivity activity) { + activity_ = activity; +} + +AudioFrame::VADActivity AudioBuffer::activity() { + return activity_; +} + +int AudioBuffer::num_channels() const { return num_channels_; } -WebRtc_Word32 AudioBuffer::samples_per_channel() const { +int AudioBuffer::samples_per_channel() const { return samples_per_channel_; } -WebRtc_Word32 AudioBuffer::samples_per_split_channel() const { +int AudioBuffer::samples_per_split_channel() const { return samples_per_split_channel_; } -// TODO(ajm): Do deinterleaving and mixing in one step? -void AudioBuffer::DeinterleaveFrom(AudioFrame* audioFrame) { - assert(audioFrame->_audioChannel <= max_num_channels_); - assert(audioFrame->_payloadDataLengthInSamples == samples_per_channel_); +// TODO(andrew): Do deinterleaving and mixing in one step? +void AudioBuffer::DeinterleaveFrom(AudioFrame* frame) { + assert(frame->_audioChannel <= max_num_channels_); + assert(frame->_payloadDataLengthInSamples == samples_per_channel_); - num_channels_ = audioFrame->_audioChannel; + num_channels_ = frame->_audioChannel; num_mixed_channels_ = 0; num_mixed_low_pass_channels_ = 0; reference_copied_ = false; + activity_ = frame->_vadActivity; if (num_channels_ == 1) { // We can get away with a pointer assignment in this case. - data_ = audioFrame->_payloadData; + data_ = frame->_payloadData; return; } + WebRtc_Word16* interleaved = frame->_payloadData; for (int i = 0; i < num_channels_; i++) { WebRtc_Word16* deinterleaved = channels_[i].data; - WebRtc_Word16* interleaved = audioFrame->_payloadData; - WebRtc_Word32 interleaved_idx = i; + int interleaved_idx = i; for (int j = 0; j < samples_per_channel_; j++) { deinterleaved[j] = interleaved[interleaved_idx]; interleaved_idx += num_channels_; @@ -210,27 +218,28 @@ void AudioBuffer::DeinterleaveFrom(AudioFrame* audioFrame) { } } -void AudioBuffer::InterleaveTo(AudioFrame* audioFrame) const { - assert(audioFrame->_audioChannel == num_channels_); - assert(audioFrame->_payloadDataLengthInSamples == samples_per_channel_); +void AudioBuffer::InterleaveTo(AudioFrame* frame) const { + assert(frame->_audioChannel == num_channels_); + assert(frame->_payloadDataLengthInSamples == samples_per_channel_); + frame->_vadActivity = activity_; if (num_channels_ == 1) { if (num_mixed_channels_ == 1) { - memcpy(audioFrame->_payloadData, + memcpy(frame->_payloadData, channels_[0].data, sizeof(WebRtc_Word16) * samples_per_channel_); } else { // These should point to the same buffer in this case. - assert(data_ == audioFrame->_payloadData); + assert(data_ == frame->_payloadData); } return; } + WebRtc_Word16* interleaved = frame->_payloadData; for (int i = 0; i < num_channels_; i++) { WebRtc_Word16* deinterleaved = channels_[i].data; - WebRtc_Word16* interleaved = audioFrame->_payloadData; - WebRtc_Word32 interleaved_idx = i; + int interleaved_idx = i; for (int j = 0; j < samples_per_channel_; j++) { interleaved[interleaved_idx] = deinterleaved[j]; interleaved_idx += num_channels_; @@ -238,9 +247,10 @@ void AudioBuffer::InterleaveTo(AudioFrame* audioFrame) const { } } -// TODO(ajm): would be good to support the no-mix case with pointer assignment. -// TODO(ajm): handle mixing to multiple channels? -void AudioBuffer::Mix(WebRtc_Word32 num_mixed_channels) { +// TODO(andrew): would be good to support the no-mix case with pointer +// assignment. +// TODO(andrew): handle mixing to multiple channels? +void AudioBuffer::Mix(int num_mixed_channels) { // We currently only support the stereo to mono case. assert(num_channels_ == 2); assert(num_mixed_channels == 1); @@ -254,7 +264,7 @@ void AudioBuffer::Mix(WebRtc_Word32 num_mixed_channels) { num_mixed_channels_ = num_mixed_channels; } -void AudioBuffer::CopyAndMixLowPass(WebRtc_Word32 num_mixed_channels) { +void AudioBuffer::CopyAndMixLowPass(int num_mixed_channels) { // We currently only support the stereo to mono case. assert(num_channels_ == 2); assert(num_mixed_channels == 1); diff --git a/src/modules/audio_processing/main/source/audio_buffer.h b/src/modules/audio_processing/main/source/audio_buffer.h index 15f850b..1bdd3c7 100644 --- a/src/modules/audio_processing/main/source/audio_buffer.h +++ b/src/modules/audio_processing/main/source/audio_buffer.h @@ -11,55 +11,58 @@ #ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_ #define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_ +#include "module_common_types.h" #include "typedefs.h" - namespace webrtc { struct AudioChannel; struct SplitAudioChannel; -class AudioFrame; class AudioBuffer { public: - AudioBuffer(WebRtc_Word32 max_num_channels, WebRtc_Word32 samples_per_channel); + AudioBuffer(int max_num_channels, int samples_per_channel); virtual ~AudioBuffer(); - WebRtc_Word32 num_channels() const; - WebRtc_Word32 samples_per_channel() const; - WebRtc_Word32 samples_per_split_channel() const; + int num_channels() const; + int samples_per_channel() const; + int samples_per_split_channel() const; + + WebRtc_Word16* data(int channel) const; + WebRtc_Word16* low_pass_split_data(int channel) const; + WebRtc_Word16* high_pass_split_data(int channel) const; + WebRtc_Word16* mixed_low_pass_data(int channel) const; + WebRtc_Word16* low_pass_reference(int channel) const; - WebRtc_Word16* data(WebRtc_Word32 channel) const; - WebRtc_Word16* low_pass_split_data(WebRtc_Word32 channel) const; - WebRtc_Word16* high_pass_split_data(WebRtc_Word32 channel) const; - WebRtc_Word16* mixed_low_pass_data(WebRtc_Word32 channel) const; - WebRtc_Word16* low_pass_reference(WebRtc_Word32 channel) const; + WebRtc_Word32* analysis_filter_state1(int channel) const; + WebRtc_Word32* analysis_filter_state2(int channel) const; + WebRtc_Word32* synthesis_filter_state1(int channel) const; + WebRtc_Word32* synthesis_filter_state2(int channel) const; - WebRtc_Word32* analysis_filter_state1(WebRtc_Word32 channel) const; - WebRtc_Word32* analysis_filter_state2(WebRtc_Word32 channel) const; - WebRtc_Word32* synthesis_filter_state1(WebRtc_Word32 channel) const; - WebRtc_Word32* synthesis_filter_state2(WebRtc_Word32 channel) const; + void set_activity(AudioFrame::VADActivity activity); + AudioFrame::VADActivity activity(); void DeinterleaveFrom(AudioFrame* audioFrame); void InterleaveTo(AudioFrame* audioFrame) const; - void Mix(WebRtc_Word32 num_mixed_channels); - void CopyAndMixLowPass(WebRtc_Word32 num_mixed_channels); + void Mix(int num_mixed_channels); + void CopyAndMixLowPass(int num_mixed_channels); void CopyLowPassToReference(); private: - const WebRtc_Word32 max_num_channels_; - WebRtc_Word32 num_channels_; - WebRtc_Word32 num_mixed_channels_; - WebRtc_Word32 num_mixed_low_pass_channels_; - const WebRtc_Word32 samples_per_channel_; - WebRtc_Word32 samples_per_split_channel_; + const int max_num_channels_; + int num_channels_; + int num_mixed_channels_; + int num_mixed_low_pass_channels_; + const int samples_per_channel_; + int samples_per_split_channel_; bool reference_copied_; + AudioFrame::VADActivity activity_; WebRtc_Word16* data_; - // TODO(ajm): Prefer to make these vectors if permitted... + // TODO(andrew): use vectors here. AudioChannel* channels_; SplitAudioChannel* split_channels_; - // TODO(ajm): improve this, we don't need the full 32 kHz space here. + // TODO(andrew): improve this, we don't need the full 32 kHz space here. AudioChannel* mixed_low_pass_channels_; AudioChannel* low_pass_reference_channels_; }; diff --git a/src/modules/audio_processing/main/source/echo_cancellation_impl.cc b/src/modules/audio_processing/main/source/echo_cancellation_impl.cc index 886d5f1..61940b1 100644 --- a/src/modules/audio_processing/main/source/echo_cancellation_impl.cc +++ b/src/modules/audio_processing/main/source/echo_cancellation_impl.cc @@ -66,7 +66,8 @@ EchoCancellationImpl::EchoCancellationImpl(const AudioProcessingImpl* apm) device_sample_rate_hz_(48000), stream_drift_samples_(0), was_stream_drift_set_(false), - stream_has_echo_(false) {} + stream_has_echo_(false), + delay_logging_enabled_(false) {} EchoCancellationImpl::~EchoCancellationImpl() {} @@ -283,6 +284,39 @@ bool EchoCancellationImpl::stream_has_echo() const { return stream_has_echo_; } +int EchoCancellationImpl::enable_delay_logging(bool enable) { + CriticalSectionScoped crit_scoped(*apm_->crit()); + delay_logging_enabled_ = enable; + return Configure(); +} + +bool EchoCancellationImpl::is_delay_logging_enabled() const { + return delay_logging_enabled_; +} + +// TODO(bjornv): How should we handle the multi-channel case? +int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) { + CriticalSectionScoped crit_scoped(*apm_->crit()); + if (median == NULL) { + return apm_->kNullPointerError; + } + if (std == NULL) { + return apm_->kNullPointerError; + } + + if (!is_component_enabled() || !delay_logging_enabled_) { + return apm_->kNotEnabledError; + } + + Handle* my_handle = static_cast<Handle*>(handle(0)); + if (WebRtcAec_GetDelayMetrics(my_handle, median, std) != + apm_->kNoError) { + return GetHandleError(my_handle); + } + + return apm_->kNoError; +} + int EchoCancellationImpl::Initialize() { int err = ProcessingComponent::Initialize(); if (err != apm_->kNoError || !is_component_enabled()) { @@ -332,6 +366,7 @@ int EchoCancellationImpl::ConfigureHandle(void* handle) const { config.metricsMode = metrics_enabled_; config.nlpMode = MapSetting(suppression_level_); config.skewMode = drift_compensation_enabled_; + config.delay_logging = delay_logging_enabled_; return WebRtcAec_set_config(static_cast<Handle*>(handle), config); } diff --git a/src/modules/audio_processing/main/source/echo_cancellation_impl.h b/src/modules/audio_processing/main/source/echo_cancellation_impl.h index 071c18f..a483a3a 100644 --- a/src/modules/audio_processing/main/source/echo_cancellation_impl.h +++ b/src/modules/audio_processing/main/source/echo_cancellation_impl.h @@ -49,6 +49,9 @@ class EchoCancellationImpl : public EchoCancellation, virtual bool are_metrics_enabled() const; virtual bool stream_has_echo() const; virtual int GetMetrics(Metrics* metrics); + virtual int enable_delay_logging(bool enable); + virtual bool is_delay_logging_enabled() const; + virtual int GetDelayMetrics(int* median, int* std); // ProcessingComponent implementation. virtual void* CreateHandle() const; @@ -66,6 +69,7 @@ class EchoCancellationImpl : public EchoCancellation, int stream_drift_samples_; bool was_stream_drift_set_; bool stream_has_echo_; + bool delay_logging_enabled_; }; } // namespace webrtc diff --git a/src/modules/audio_processing/main/source/voice_detection_impl.cc b/src/modules/audio_processing/main/source/voice_detection_impl.cc index 3eb446e..49aac2e 100644 --- a/src/modules/audio_processing/main/source/voice_detection_impl.cc +++ b/src/modules/audio_processing/main/source/voice_detection_impl.cc @@ -74,16 +74,16 @@ int VoiceDetectionImpl::ProcessCaptureAudio(AudioBuffer* audio) { // TODO(ajm): concatenate data in frame buffer here. - int vad_ret_val; - vad_ret_val = WebRtcVad_Process(static_cast<Handle*>(handle(0)), - apm_->split_sample_rate_hz(), - mixed_data, - frame_size_samples_); - - if (vad_ret_val == 0) { + int vad_ret = WebRtcVad_Process(static_cast<Handle*>(handle(0)), + apm_->split_sample_rate_hz(), + mixed_data, + frame_size_samples_); + if (vad_ret == 0) { stream_has_voice_ = false; - } else if (vad_ret_val == 1) { + audio->set_activity(AudioFrame::kVadPassive); + } else if (vad_ret == 1) { stream_has_voice_ = true; + audio->set_activity(AudioFrame::kVadActive); } else { return apm_->kUnspecifiedError; } diff --git a/src/modules/audio_processing/main/test/process_test/process_test.cc b/src/modules/audio_processing/main/test/process_test/process_test.cc index f6b6d69..130f3ee 100644 --- a/src/modules/audio_processing/main/test/process_test/process_test.cc +++ b/src/modules/audio_processing/main/test/process_test/process_test.cc @@ -28,6 +28,7 @@ using webrtc::AudioFrame; using webrtc::AudioProcessing; +using webrtc::EchoCancellation; using webrtc::GainControl; using webrtc::NoiseSuppression; using webrtc::TickInterval; @@ -61,6 +62,12 @@ bool ReadMessageFromFile(FILE* file, return msg->ParseFromArray(array, usize); } +void PrintStat(const AudioProcessing::Statistic& stat) { + printf("%d, %d, %d\n", stat.average, + stat.maximum, + stat.minimum); +} + void usage() { printf( "Usage: process_test [options] [-pb PROTOBUF_FILE]\n" @@ -86,6 +93,8 @@ void usage() { printf("\n -aec Echo cancellation\n"); printf(" --drift_compensation\n"); printf(" --no_drift_compensation\n"); + printf(" --no_echo_metrics\n"); + printf(" --no_delay_logging\n"); printf("\n -aecm Echo control mobile\n"); printf(" --aecm_echo_path_in_file FILE\n"); printf(" --aecm_echo_path_out_file FILE\n"); @@ -107,6 +116,7 @@ void usage() { printf(" --vad_out_file FILE\n"); printf("\n"); printf("Modifiers:\n"); + printf(" --noasm Disable SSE optimization.\n"); printf(" --perf Measure performance.\n"); printf(" --quiet Suppress text output.\n"); printf(" --no_progress Suppress progress.\n"); @@ -156,7 +166,7 @@ void void_main(int argc, char* argv[]) { //bool interleaved = true; for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "-pb") == 0) { + if (strcmp(argv[i], "-pb") == 0) { i++; ASSERT_LT(i, argc) << "Specify protobuf filename after -pb"; pb_filename = argv[i]; @@ -208,9 +218,10 @@ void void_main(int argc, char* argv[]) { } else if (strcmp(argv[i], "-aec") == 0) { ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true)); - - } else if (strcmp(argv[i], "-noasm") == 0) { - WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM; + ASSERT_EQ(apm->kNoError, + apm->echo_cancellation()->enable_metrics(true)); + ASSERT_EQ(apm->kNoError, + apm->echo_cancellation()->enable_delay_logging(true)); } else if (strcmp(argv[i], "--drift_compensation") == 0) { ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true)); @@ -223,6 +234,16 @@ void void_main(int argc, char* argv[]) { ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->enable_drift_compensation(false)); + } else if (strcmp(argv[i], "--no_echo_metrics") == 0) { + ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true)); + ASSERT_EQ(apm->kNoError, + apm->echo_cancellation()->enable_metrics(false)); + + } else if (strcmp(argv[i], "--no_delay_logging") == 0) { + ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true)); + ASSERT_EQ(apm->kNoError, + apm->echo_cancellation()->enable_delay_logging(false)); + } else if (strcmp(argv[i], "-aecm") == 0) { ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true)); @@ -316,6 +337,11 @@ void void_main(int argc, char* argv[]) { ASSERT_LT(i, argc) << "Specify filename after --vad_out_file"; vad_out_filename = argv[i]; + } else if (strcmp(argv[i], "--noasm") == 0) { + WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM; + // We need to reinitialize here if components have already been enabled. + ASSERT_EQ(apm->kNoError, apm->Initialize()); + } else if (strcmp(argv[i], "--perf") == 0) { perf_testing = true; @@ -460,13 +486,6 @@ void void_main(int argc, char* argv[]) { << aecm_echo_path_out_filename; } - enum Events { - kInitializeEvent, - kRenderEvent, - kCaptureEvent, - kResetEventDeprecated - }; - int16_t event = 0; size_t read_count = 0; int reverse_count = 0; int primary_count = 0; @@ -642,9 +661,15 @@ void void_main(int argc, char* argv[]) { } ASSERT_TRUE(feof(pb_file)); - printf("100%% complete\r"); } else { + enum Events { + kInitializeEvent, + kRenderEvent, + kCaptureEvent, + kResetEventDeprecated + }; + int16_t event = 0; while (simulating || feof(event_file) == 0) { std::ostringstream trace_stream; trace_stream << "Processed frames: " << reverse_count << " (reverse), " @@ -708,6 +733,10 @@ void void_main(int argc, char* argv[]) { if (simulating) { if (read_count != far_frame._payloadDataLengthInSamples) { + // Read an equal amount from the near file to avoid errors due to + // not reaching end-of-file. + EXPECT_EQ(0, fseek(near_file, read_count * sizeof(WebRtc_Word16), + SEEK_CUR)); break; // This is expected. } } else { @@ -828,6 +857,7 @@ void void_main(int argc, char* argv[]) { } } } + printf("100%% complete\r"); if (aecm_echo_path_out_file != NULL) { const size_t path_size = @@ -845,6 +875,27 @@ void void_main(int argc, char* argv[]) { if (verbose) { printf("\nProcessed frames: %d (primary), %d (reverse)\n", primary_count, reverse_count); + + if (apm->echo_cancellation()->are_metrics_enabled()) { + EchoCancellation::Metrics metrics; + apm->echo_cancellation()->GetMetrics(&metrics); + printf("\n--Echo metrics--\n"); + printf("(avg, max, min)\n"); + printf("ERL: "); + PrintStat(metrics.echo_return_loss); + printf("ERLE: "); + PrintStat(metrics.echo_return_loss_enhancement); + printf("ANLP: "); + PrintStat(metrics.a_nlp); + } + if (apm->echo_cancellation()->is_delay_logging_enabled()) { + int median = 0; + int std = 0; + apm->echo_cancellation()->GetDelayMetrics(&median, &std); + printf("\n--Delay metrics--\n"); + printf("Median: %3d\n", median); + printf("Standard deviation: %3d\n", std); + } } if (!pb_file) { diff --git a/src/modules/audio_processing/main/test/unit_test/unit_test.cc b/src/modules/audio_processing/main/test/unit_test/unit_test.cc index 0563fdf..b0609d9 100644 --- a/src/modules/audio_processing/main/test/unit_test/unit_test.cc +++ b/src/modules/audio_processing/main/test/unit_test/unit_test.cc @@ -10,12 +10,13 @@ #include <stdio.h> -#include <gtest/gtest.h> +#include "gtest/gtest.h" #include "audio_processing.h" #include "event_wrapper.h" #include "module_common_types.h" #include "signal_processing_library.h" +#include "testsupport/fileutils.h" #include "thread_wrapper.h" #include "trace.h" #ifdef WEBRTC_ANDROID @@ -42,12 +43,6 @@ namespace { // be set to true with the command-line switch --write_output_data. bool write_output_data = false; -#if defined(WEBRTC_APM_UNIT_TEST_FIXED_PROFILE) -const char kOutputFileName[] = "output_data_fixed.pb"; -#elif defined(WEBRTC_APM_UNIT_TEST_FLOAT_PROFILE) -const char kOutputFileName[] = "output_data_float.pb"; -#endif - class ApmEnvironment : public ::testing::Environment { public: virtual void SetUp() { @@ -65,7 +60,9 @@ class ApmTest : public ::testing::Test { ApmTest(); virtual void SetUp(); virtual void TearDown(); - + // Path to where the resource files to be used for this test are located. + const std::string kResourcePath; + const std::string kOutputFileName; webrtc::AudioProcessing* apm_; webrtc::AudioFrame* frame_; webrtc::AudioFrame* revframe_; @@ -74,7 +71,14 @@ class ApmTest : public ::testing::Test { }; ApmTest::ApmTest() - : apm_(NULL), + : kResourcePath(webrtc::test::GetProjectRootPath() + + "test/data/audio_processing/"), +#if defined(WEBRTC_APM_UNIT_TEST_FIXED_PROFILE) + kOutputFileName(kResourcePath + "output_data_fixed.pb"), +#elif defined(WEBRTC_APM_UNIT_TEST_FLOAT_PROFILE) + kOutputFileName(kResourcePath + "output_data_float.pb"), +#endif + apm_(NULL), frame_(NULL), revframe_(NULL), far_file_(NULL), @@ -98,10 +102,14 @@ void ApmTest::SetUp() { revframe_->_audioChannel = 2; revframe_->_frequencyInHz = 32000; - far_file_ = fopen("aec_far.pcm", "rb"); - ASSERT_TRUE(far_file_ != NULL) << "Could not open input file aec_far.pcm\n"; - near_file_ = fopen("aec_near.pcm", "rb"); - ASSERT_TRUE(near_file_ != NULL) << "Could not open input file aec_near.pcm\n"; + std::string input_filename = kResourcePath + "aec_far.pcm"; + far_file_ = fopen(input_filename.c_str(), "rb"); + ASSERT_TRUE(far_file_ != NULL) << "Could not open input file " << + input_filename << "\n"; + input_filename = kResourcePath + "aec_near.pcm"; + near_file_ = fopen(input_filename.c_str(), "rb"); + ASSERT_TRUE(near_file_ != NULL) << "Could not open input file " << + input_filename << "\n"; } void ApmTest::TearDown() { @@ -177,11 +185,9 @@ void WriteStatsMessage(const AudioProcessing::Statistic& output, message->set_minimum(output.minimum); } -void WriteMessageLiteToFile(const char* filename, +void WriteMessageLiteToFile(const std::string filename, const ::google::protobuf::MessageLite& message) { - assert(filename != NULL); - - FILE* file = fopen(filename, "wb"); + FILE* file = fopen(filename.c_str(), "wb"); ASSERT_TRUE(file != NULL) << "Could not open " << filename; int size = message.ByteSize(); ASSERT_GT(size, 0); @@ -196,12 +202,11 @@ void WriteMessageLiteToFile(const char* filename, fclose(file); } -void ReadMessageLiteFromFile(const char* filename, +void ReadMessageLiteFromFile(const std::string filename, ::google::protobuf::MessageLite* message) { - assert(filename != NULL); assert(message != NULL); - FILE* file = fopen(filename, "rb"); + FILE* file = fopen(filename.c_str(), "rb"); ASSERT_TRUE(file != NULL) << "Could not open " << filename; int size = 0; ASSERT_EQ(1u, fread(&size, sizeof(int), 1, file)); @@ -457,6 +462,8 @@ TEST_F(ApmTest, Process) { apm_->echo_cancellation()->enable_drift_compensation(true)); EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->enable_metrics(true)); + EXPECT_EQ(apm_->kNoError, + apm_->echo_cancellation()->enable_delay_logging(true)); EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); EXPECT_EQ(apm_->kNoError, @@ -555,6 +562,7 @@ TEST_F(ApmTest, Process) { &temp_data[0], sizeof(WebRtc_Word16) * read_count); } + frame_->_vadActivity = AudioFrame::kVadUnknown; EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_)); @@ -571,6 +579,9 @@ TEST_F(ApmTest, Process) { } if (apm_->voice_detection()->stream_has_voice()) { has_voice_count++; + EXPECT_EQ(AudioFrame::kVadActive, frame_->_vadActivity); + } else { + EXPECT_EQ(AudioFrame::kVadPassive, frame_->_vadActivity); } frame_count++; @@ -587,6 +598,10 @@ TEST_F(ApmTest, Process) { EchoCancellation::Metrics echo_metrics; EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->GetMetrics(&echo_metrics)); + int median = 0; + int std = 0; + EXPECT_EQ(apm_->kNoError, + apm_->echo_cancellation()->GetDelayMetrics(&median, &std)); #endif if (!write_output_data) { @@ -608,6 +623,11 @@ TEST_F(ApmTest, Process) { reference.echo_return_loss_enhancement()); TestStats(echo_metrics.a_nlp, reference.a_nlp()); + + webrtc::audioproc::Test::DelayMetrics reference_delay = + test->delay_metrics(); + EXPECT_EQ(median, reference_delay.median()); + EXPECT_EQ(std, reference_delay.std()); #endif } else { test->set_has_echo_count(has_echo_count); @@ -628,6 +648,11 @@ TEST_F(ApmTest, Process) { message->mutable_echo_return_loss_enhancement()); WriteStatsMessage(echo_metrics.a_nlp, message->mutable_a_nlp()); + + webrtc::audioproc::Test::DelayMetrics* message_delay = + test->mutable_delay_metrics(); + message_delay->set_median(median); + message_delay->set_std(std); #endif } @@ -692,6 +717,18 @@ TEST_F(ApmTest, EchoCancellation) { apm_->echo_cancellation()->enable_metrics(false)); EXPECT_FALSE(apm_->echo_cancellation()->are_metrics_enabled()); + int median = 0; + int std = 0; + EXPECT_EQ(apm_->kNotEnabledError, + apm_->echo_cancellation()->GetDelayMetrics(&median, &std)); + + EXPECT_EQ(apm_->kNoError, + apm_->echo_cancellation()->enable_delay_logging(true)); + EXPECT_TRUE(apm_->echo_cancellation()->is_delay_logging_enabled()); + EXPECT_EQ(apm_->kNoError, + apm_->echo_cancellation()->enable_delay_logging(false)); + EXPECT_FALSE(apm_->echo_cancellation()->is_delay_logging_enabled()); + EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); EXPECT_TRUE(apm_->echo_cancellation()->is_enabled()); EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false)); @@ -966,27 +1003,27 @@ TEST_F(ApmTest, VoiceDetection) { EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false)); EXPECT_FALSE(apm_->voice_detection()->is_enabled()); - // TODO(bjornv): Add tests for streamed voice; stream_has_voice() -} - -// Below are some ideas for tests from VPM. - -/*TEST_F(VideoProcessingModuleTest, GetVersionTest) -{ -} - -TEST_F(VideoProcessingModuleTest, HandleNullBuffer) -{ -} + // Test that AudioFrame activity is maintained when VAD is disabled. + EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false)); + AudioFrame::VADActivity activity[] = { + AudioFrame::kVadActive, + AudioFrame::kVadPassive, + AudioFrame::kVadUnknown + }; + for (size_t i = 0; i < sizeof(activity)/sizeof(*activity); i++) { + frame_->_vadActivity = activity[i]; + EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_)); + EXPECT_EQ(activity[i], frame_->_vadActivity); + } -TEST_F(VideoProcessingModuleTest, HandleBadSize) -{ -} + // Test that AudioFrame activity is set when VAD is enabled. + EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true)); + frame_->_vadActivity = AudioFrame::kVadUnknown; + EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_)); + EXPECT_NE(AudioFrame::kVadUnknown, frame_->_vadActivity); -TEST_F(VideoProcessingModuleTest, IdenticalResultsAfterReset) -{ + // TODO(bjornv): Add tests for streamed voice; stream_has_voice() } -*/ } // namespace int main(int argc, char** argv) { diff --git a/src/modules/audio_processing/main/test/unit_test/unittest.proto b/src/modules/audio_processing/main/test/unit_test/unittest.proto index 3dde02b..cdfacc4 100644 --- a/src/modules/audio_processing/main/test/unit_test/unittest.proto +++ b/src/modules/audio_processing/main/test/unit_test/unittest.proto @@ -35,6 +35,13 @@ message Test { } optional EchoMetrics echo_metrics = 11; + + message DelayMetrics { + optional int32 median = 1; + optional int32 std = 2; + } + + optional DelayMetrics delay_metrics = 12; } message OutputData { diff --git a/src/modules/audio_processing/ns/main/interface/noise_suppression.h b/src/modules/audio_processing/ns/main/interface/noise_suppression.h index f28a10a..907faf4 100644 --- a/src/modules/audio_processing/ns/main/interface/noise_suppression.h +++ b/src/modules/audio_processing/ns/main/interface/noise_suppression.h @@ -30,7 +30,7 @@ extern "C" { * Return value : 0 - Ok * -1 - Error (probably length is not sufficient) */ -int WebRtcNs_get_version(char *version, short length); +int WebRtcNs_get_version(char* version, short length); /* @@ -46,7 +46,7 @@ int WebRtcNs_get_version(char *version, short length); * Return value : 0 - Ok * -1 - Error */ -int WebRtcNs_Create(NsHandle **NS_inst); +int WebRtcNs_Create(NsHandle** NS_inst); /* @@ -59,7 +59,7 @@ int WebRtcNs_Create(NsHandle **NS_inst); * Return value : 0 - Ok * -1 - Error */ -int WebRtcNs_Free(NsHandle *NS_inst); +int WebRtcNs_Free(NsHandle* NS_inst); /* @@ -75,7 +75,7 @@ int WebRtcNs_Free(NsHandle *NS_inst); * Return value : 0 - Ok * -1 - Error */ -int WebRtcNs_Init(NsHandle *NS_inst, WebRtc_UWord32 fs); +int WebRtcNs_Init(NsHandle* NS_inst, WebRtc_UWord32 fs); /* * This changes the aggressiveness of the noise suppression method. @@ -90,7 +90,7 @@ int WebRtcNs_Init(NsHandle *NS_inst, WebRtc_UWord32 fs); * Return value : 0 - Ok * -1 - Error */ -int WebRtcNs_set_policy(NsHandle *NS_inst, int mode); +int WebRtcNs_set_policy(NsHandle* NS_inst, int mode); /* @@ -111,11 +111,11 @@ int WebRtcNs_set_policy(NsHandle *NS_inst, int mode); * Return value : 0 - OK * -1 - Error */ -int WebRtcNs_Process(NsHandle *NS_inst, - short *spframe, - short *spframe_H, - short *outframe, - short *outframe_H); +int WebRtcNs_Process(NsHandle* NS_inst, + short* spframe, + short* spframe_H, + short* outframe, + short* outframe_H); #ifdef __cplusplus } diff --git a/src/modules/audio_processing/ns/main/interface/noise_suppression_x.h b/src/modules/audio_processing/ns/main/interface/noise_suppression_x.h index 35fea2f..14443fa 100644 --- a/src/modules/audio_processing/ns/main/interface/noise_suppression_x.h +++ b/src/modules/audio_processing/ns/main/interface/noise_suppression_x.h @@ -11,7 +11,7 @@ #ifndef WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_INTERFACE_NOISE_SUPPRESSION_X_H_ #define WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_INTERFACE_NOISE_SUPPRESSION_X_H_ -#include "signal_processing_library.h" +#include "typedefs.h" typedef struct NsxHandleT NsxHandle; @@ -30,7 +30,7 @@ extern "C" { * Return value : 0 - Ok * -1 - Error (probably length is not sufficient) */ -int WebRtcNsx_get_version(char *version, short length); +int WebRtcNsx_get_version(char* version, short length); /* @@ -46,7 +46,7 @@ int WebRtcNsx_get_version(char *version, short length); * Return value : 0 - Ok * -1 - Error */ -int WebRtcNsx_Create(NsxHandle **nsxInst); +int WebRtcNsx_Create(NsxHandle** nsxInst); /* @@ -59,7 +59,7 @@ int WebRtcNsx_Create(NsxHandle **nsxInst); * Return value : 0 - Ok * -1 - Error */ -int WebRtcNsx_Free(NsxHandle *nsxInst); +int WebRtcNsx_Free(NsxHandle* nsxInst); /* @@ -75,7 +75,7 @@ int WebRtcNsx_Free(NsxHandle *nsxInst); * Return value : 0 - Ok * -1 - Error */ -int WebRtcNsx_Init(NsxHandle *nsxInst, WebRtc_UWord32 fs); +int WebRtcNsx_Init(NsxHandle* nsxInst, WebRtc_UWord32 fs); /* * This changes the aggressiveness of the noise suppression method. @@ -90,7 +90,7 @@ int WebRtcNsx_Init(NsxHandle *nsxInst, WebRtc_UWord32 fs); * Return value : 0 - Ok * -1 - Error */ -int WebRtcNsx_set_policy(NsxHandle *nsxInst, int mode); +int WebRtcNsx_set_policy(NsxHandle* nsxInst, int mode); /* * This functions does noise suppression for the inserted speech frame. The @@ -110,11 +110,11 @@ int WebRtcNsx_set_policy(NsxHandle *nsxInst, int mode); * Return value : 0 - OK * -1 - Error */ -int WebRtcNsx_Process(NsxHandle *nsxInst, - short *speechFrame, - short *speechFrameHB, - short *outFrame, - short *outFrameHB); +int WebRtcNsx_Process(NsxHandle* nsxInst, + short* speechFrame, + short* speechFrameHB, + short* outFrame, + short* outFrameHB); #ifdef __cplusplus } diff --git a/src/modules/audio_processing/ns/main/source/noise_suppression.c b/src/modules/audio_processing/ns/main/source/noise_suppression.c index aed10b1..d33caa9 100644 --- a/src/modules/audio_processing/ns/main/source/noise_suppression.c +++ b/src/modules/audio_processing/ns/main/source/noise_suppression.c @@ -15,55 +15,51 @@ #include "ns_core.h" #include "defines.h" -int WebRtcNs_get_version(char *versionStr, short length) -{ - const char version[] = "NS 2.2.0"; - const short versionLen = (short)strlen(version) + 1; // +1 for null-termination +int WebRtcNs_get_version(char* versionStr, short length) { + const char version[] = "NS 2.2.0"; + const short versionLen = (short)strlen(version) + 1; // +1: null-termination - if (versionStr == NULL) { - return -1; - } + if (versionStr == NULL) { + return -1; + } - if (versionLen > length) { - return -1; - } + if (versionLen > length) { + return -1; + } - strncpy(versionStr, version, versionLen); + strncpy(versionStr, version, versionLen); - return 0; + return 0; } -int WebRtcNs_Create(NsHandle **NS_inst) -{ - *NS_inst = (NsHandle*) malloc(sizeof(NSinst_t)); - if (*NS_inst!=NULL) { - (*(NSinst_t**)NS_inst)->initFlag=0; - return 0; - } else { - return -1; - } +int WebRtcNs_Create(NsHandle** NS_inst) { + *NS_inst = (NsHandle*) malloc(sizeof(NSinst_t)); + if (*NS_inst != NULL) { + (*(NSinst_t**)NS_inst)->initFlag = 0; + return 0; + } else { + return -1; + } } -int WebRtcNs_Free(NsHandle *NS_inst) -{ - free(NS_inst); - return 0; +int WebRtcNs_Free(NsHandle* NS_inst) { + free(NS_inst); + return 0; } -int WebRtcNs_Init(NsHandle *NS_inst, WebRtc_UWord32 fs) -{ - return WebRtcNs_InitCore((NSinst_t*) NS_inst, fs); +int WebRtcNs_Init(NsHandle* NS_inst, WebRtc_UWord32 fs) { + return WebRtcNs_InitCore((NSinst_t*) NS_inst, fs); } -int WebRtcNs_set_policy(NsHandle *NS_inst, int mode) -{ - return WebRtcNs_set_policy_core((NSinst_t*) NS_inst, mode); +int WebRtcNs_set_policy(NsHandle* NS_inst, int mode) { + return WebRtcNs_set_policy_core((NSinst_t*) NS_inst, mode); } -int WebRtcNs_Process(NsHandle *NS_inst, short *spframe, short *spframe_H, short *outframe, short *outframe_H) -{ - return WebRtcNs_ProcessCore((NSinst_t*) NS_inst, spframe, spframe_H, outframe, outframe_H); +int WebRtcNs_Process(NsHandle* NS_inst, short* spframe, short* spframe_H, + short* outframe, short* outframe_H) { + return WebRtcNs_ProcessCore( + (NSinst_t*) NS_inst, spframe, spframe_H, outframe, outframe_H); } diff --git a/src/modules/audio_processing/ns/main/source/noise_suppression_x.c b/src/modules/audio_processing/ns/main/source/noise_suppression_x.c index f1ad730..afdea7b 100644 --- a/src/modules/audio_processing/ns/main/source/noise_suppression_x.c +++ b/src/modules/audio_processing/ns/main/source/noise_suppression_x.c @@ -15,60 +15,51 @@ #include "nsx_core.h" #include "nsx_defines.h" -int WebRtcNsx_get_version(char *versionStr, short length) -{ - const char version[] = "NS\t3.1.0"; - const short versionLen = (short)strlen(version) + 1; // +1 for null-termination +int WebRtcNsx_get_version(char* versionStr, short length) { + const char version[] = "NS\t3.1.0"; + const short versionLen = (short)strlen(version) + 1; // +1: null-termination - if (versionStr == NULL) - { - return -1; - } + if (versionStr == NULL) { + return -1; + } - if (versionLen > length) - { - return -1; - } + if (versionLen > length) { + return -1; + } - strncpy(versionStr, version, versionLen); + strncpy(versionStr, version, versionLen); - return 0; + return 0; } -int WebRtcNsx_Create(NsxHandle **nsxInst) -{ - *nsxInst = (NsxHandle*)malloc(sizeof(NsxInst_t)); - if (*nsxInst != NULL) - { - (*(NsxInst_t**)nsxInst)->initFlag = 0; - return 0; - } else - { - return -1; - } +int WebRtcNsx_Create(NsxHandle** nsxInst) { + *nsxInst = (NsxHandle*)malloc(sizeof(NsxInst_t)); + if (*nsxInst != NULL) { + (*(NsxInst_t**)nsxInst)->initFlag = 0; + return 0; + } else { + return -1; + } } -int WebRtcNsx_Free(NsxHandle *nsxInst) -{ - free(nsxInst); - return 0; +int WebRtcNsx_Free(NsxHandle* nsxInst) { + free(nsxInst); + return 0; } -int WebRtcNsx_Init(NsxHandle *nsxInst, WebRtc_UWord32 fs) -{ - return WebRtcNsx_InitCore((NsxInst_t*)nsxInst, fs); +int WebRtcNsx_Init(NsxHandle* nsxInst, WebRtc_UWord32 fs) { + return WebRtcNsx_InitCore((NsxInst_t*)nsxInst, fs); } -int WebRtcNsx_set_policy(NsxHandle *nsxInst, int mode) -{ - return WebRtcNsx_set_policy_core((NsxInst_t*)nsxInst, mode); +int WebRtcNsx_set_policy(NsxHandle* nsxInst, int mode) { + return WebRtcNsx_set_policy_core((NsxInst_t*)nsxInst, mode); } -int WebRtcNsx_Process(NsxHandle *nsxInst, short *speechFrame, short *speechFrameHB, - short *outFrame, short *outFrameHB) -{ - return WebRtcNsx_ProcessCore((NsxInst_t*)nsxInst, speechFrame, speechFrameHB, outFrame, - outFrameHB); +int WebRtcNsx_Process(NsxHandle* nsxInst, short* speechFrame, + short* speechFrameHB, short* outFrame, + short* outFrameHB) { + return WebRtcNsx_ProcessCore( + (NsxInst_t*)nsxInst, speechFrame, speechFrameHB, outFrame, outFrameHB); } diff --git a/src/modules/audio_processing/ns/main/source/ns_core.c b/src/modules/audio_processing/ns/main/source/ns_core.c index 10a1b83..791d419 100644 --- a/src/modules/audio_processing/ns/main/source/ns_core.c +++ b/src/modules/audio_processing/ns/main/source/ns_core.c @@ -19,673 +19,586 @@ #include "signal_processing_library.h" // Set Feature Extraction Parameters -void WebRtcNs_set_feature_extraction_parameters(NSinst_t *inst) -{ - //bin size of histogram - inst->featureExtractionParams.binSizeLrt = (float)0.1; - inst->featureExtractionParams.binSizeSpecFlat = (float)0.05; - inst->featureExtractionParams.binSizeSpecDiff = (float)0.1; - - //range of histogram over which lrt threshold is computed - inst->featureExtractionParams.rangeAvgHistLrt = (float)1.0; - - //scale parameters: multiply dominant peaks of the histograms by scale factor to obtain - // thresholds for prior model - inst->featureExtractionParams.factor1ModelPars = (float)1.20; //for lrt and spectral diff - inst->featureExtractionParams.factor2ModelPars = (float)0.9; //for spectral_flatness: - // used when noise is flatter than speech - - //peak limit for spectral flatness (varies between 0 and 1) - inst->featureExtractionParams.thresPosSpecFlat = (float)0.6; - - //limit on spacing of two highest peaks in histogram: spacing determined by bin size - inst->featureExtractionParams.limitPeakSpacingSpecFlat = 2 - * inst->featureExtractionParams.binSizeSpecFlat; - inst->featureExtractionParams.limitPeakSpacingSpecDiff = 2 - * inst->featureExtractionParams.binSizeSpecDiff; - - //limit on relevance of second peak: - inst->featureExtractionParams.limitPeakWeightsSpecFlat = (float)0.5; - inst->featureExtractionParams.limitPeakWeightsSpecDiff = (float)0.5; - - // fluctuation limit of lrt feature - inst->featureExtractionParams.thresFluctLrt = (float)0.05; - - //limit on the max and min values for the feature thresholds - inst->featureExtractionParams.maxLrt = (float)1.0; - inst->featureExtractionParams.minLrt = (float)0.20; - - inst->featureExtractionParams.maxSpecFlat = (float)0.95; - inst->featureExtractionParams.minSpecFlat = (float)0.10; - - inst->featureExtractionParams.maxSpecDiff = (float)1.0; - inst->featureExtractionParams.minSpecDiff = (float)0.16; - - //criteria of weight of histogram peak to accept/reject feature - inst->featureExtractionParams.thresWeightSpecFlat = (int)(0.3 - * (inst->modelUpdatePars[1])); //for spectral flatness - inst->featureExtractionParams.thresWeightSpecDiff = (int)(0.3 - * (inst->modelUpdatePars[1])); //for spectral difference +void WebRtcNs_set_feature_extraction_parameters(NSinst_t* inst) { + //bin size of histogram + inst->featureExtractionParams.binSizeLrt = (float)0.1; + inst->featureExtractionParams.binSizeSpecFlat = (float)0.05; + inst->featureExtractionParams.binSizeSpecDiff = (float)0.1; + + //range of histogram over which lrt threshold is computed + inst->featureExtractionParams.rangeAvgHistLrt = (float)1.0; + + //scale parameters: multiply dominant peaks of the histograms by scale factor to obtain + // thresholds for prior model + inst->featureExtractionParams.factor1ModelPars = (float)1.20; //for lrt and spectral diff + inst->featureExtractionParams.factor2ModelPars = (float)0.9; //for spectral_flatness: + // used when noise is flatter than speech + + //peak limit for spectral flatness (varies between 0 and 1) + inst->featureExtractionParams.thresPosSpecFlat = (float)0.6; + + //limit on spacing of two highest peaks in histogram: spacing determined by bin size + inst->featureExtractionParams.limitPeakSpacingSpecFlat = + 2 * inst->featureExtractionParams.binSizeSpecFlat; + inst->featureExtractionParams.limitPeakSpacingSpecDiff = + 2 * inst->featureExtractionParams.binSizeSpecDiff; + + //limit on relevance of second peak: + inst->featureExtractionParams.limitPeakWeightsSpecFlat = (float)0.5; + inst->featureExtractionParams.limitPeakWeightsSpecDiff = (float)0.5; + + // fluctuation limit of lrt feature + inst->featureExtractionParams.thresFluctLrt = (float)0.05; + + //limit on the max and min values for the feature thresholds + inst->featureExtractionParams.maxLrt = (float)1.0; + inst->featureExtractionParams.minLrt = (float)0.20; + + inst->featureExtractionParams.maxSpecFlat = (float)0.95; + inst->featureExtractionParams.minSpecFlat = (float)0.10; + + inst->featureExtractionParams.maxSpecDiff = (float)1.0; + inst->featureExtractionParams.minSpecDiff = (float)0.16; + + //criteria of weight of histogram peak to accept/reject feature + inst->featureExtractionParams.thresWeightSpecFlat = (int)(0.3 + * (inst->modelUpdatePars[1])); //for spectral flatness + inst->featureExtractionParams.thresWeightSpecDiff = (int)(0.3 + * (inst->modelUpdatePars[1])); //for spectral difference } // Initialize state -int WebRtcNs_InitCore(NSinst_t *inst, WebRtc_UWord32 fs) -{ - int i; - //We only support 10ms frames - - //check for valid pointer - if (inst == NULL) - { - return -1; - } +int WebRtcNs_InitCore(NSinst_t* inst, WebRtc_UWord32 fs) { + int i; + //We only support 10ms frames + + //check for valid pointer + if (inst == NULL) { + return -1; + } + + // Initialization of struct + if (fs == 8000 || fs == 16000 || fs == 32000) { + inst->fs = fs; + } else { + return -1; + } + inst->windShift = 0; + if (fs == 8000) { + // We only support 10ms frames + inst->blockLen = 80; + inst->blockLen10ms = 80; + inst->anaLen = 128; + inst->window = kBlocks80w128; + inst->outLen = 0; + } else if (fs == 16000) { + // We only support 10ms frames + inst->blockLen = 160; + inst->blockLen10ms = 160; + inst->anaLen = 256; + inst->window = kBlocks160w256; + inst->outLen = 0; + } else if (fs == 32000) { + // We only support 10ms frames + inst->blockLen = 160; + inst->blockLen10ms = 160; + inst->anaLen = 256; + inst->window = kBlocks160w256; + inst->outLen = 0; + } + inst->magnLen = inst->anaLen / 2 + 1; // Number of frequency bins + + // Initialize fft work arrays. + inst->ip[0] = 0; // Setting this triggers initialization. + memset(inst->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX); + rdft(inst->anaLen, 1, inst->dataBuf, inst->ip, inst->wfft); + + memset(inst->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX); + memset(inst->syntBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX); + + //for HB processing + memset(inst->dataBufHB, 0, sizeof(float) * ANAL_BLOCKL_MAX); + + //for quantile noise estimation + memset(inst->quantile, 0, sizeof(float) * HALF_ANAL_BLOCKL); + for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) { + inst->lquantile[i] = (float)8.0; + inst->density[i] = (float)0.3; + } + + for (i = 0; i < SIMULT; i++) { + inst->counter[i] = (int)floor((float)(END_STARTUP_LONG * (i + 1)) / (float)SIMULT); + } + + inst->updates = 0; + + // Wiener filter initialization + for (i = 0; i < HALF_ANAL_BLOCKL; i++) { + inst->smooth[i] = (float)1.0; + } + + // Set the aggressiveness: default + inst->aggrMode = 0; + + //initialize variables for new method + inst->priorSpeechProb = (float)0.5; //prior prob for speech/noise + for (i = 0; i < HALF_ANAL_BLOCKL; i++) { + inst->magnPrev[i] = (float)0.0; //previous mag spectrum + inst->noisePrev[i] = (float)0.0; //previous noise-spectrum + inst->logLrtTimeAvg[i] = LRT_FEATURE_THR; //smooth LR ratio (same as threshold) + inst->magnAvgPause[i] = (float)0.0; //conservative noise spectrum estimate + inst->speechProbHB[i] = (float)0.0; //for estimation of HB in second pass + inst->initMagnEst[i] = (float)0.0; //initial average mag spectrum + } + + //feature quantities + inst->featureData[0] = SF_FEATURE_THR; //spectral flatness (start on threshold) + inst->featureData[1] = (float)0.0; //spectral entropy: not used in this version + inst->featureData[2] = (float)0.0; //spectral variance: not used in this version + inst->featureData[3] = LRT_FEATURE_THR; //average lrt factor (start on threshold) + inst->featureData[4] = SF_FEATURE_THR; //spectral template diff (start on threshold) + inst->featureData[5] = (float)0.0; //normalization for spectral-diff + inst->featureData[6] = (float)0.0; //window time-average of input magnitude spectrum + + //histogram quantities: used to estimate/update thresholds for features + for (i = 0; i < HIST_PAR_EST; i++) { + inst->histLrt[i] = 0; + inst->histSpecFlat[i] = 0; + inst->histSpecDiff[i] = 0; + } + + inst->blockInd = -1; //frame counter + inst->priorModelPars[0] = LRT_FEATURE_THR; //default threshold for lrt feature + inst->priorModelPars[1] = (float)0.5; //threshold for spectral flatness: + // determined on-line + inst->priorModelPars[2] = (float)1.0; //sgn_map par for spectral measure: + // 1 for flatness measure + inst->priorModelPars[3] = (float)0.5; //threshold for template-difference feature: + // determined on-line + inst->priorModelPars[4] = (float)1.0; //default weighting parameter for lrt feature + inst->priorModelPars[5] = (float)0.0; //default weighting parameter for + // spectral flatness feature + inst->priorModelPars[6] = (float)0.0; //default weighting parameter for + // spectral difference feature + + inst->modelUpdatePars[0] = 2; //update flag for parameters: + // 0 no update, 1=update once, 2=update every window + inst->modelUpdatePars[1] = 500; //window for update + inst->modelUpdatePars[2] = 0; //counter for update of conservative noise spectrum + //counter if the feature thresholds are updated during the sequence + inst->modelUpdatePars[3] = inst->modelUpdatePars[1]; + + inst->signalEnergy = 0.0; + inst->sumMagn = 0.0; + inst->whiteNoiseLevel = 0.0; + inst->pinkNoiseNumerator = 0.0; + inst->pinkNoiseExp = 0.0; + + WebRtcNs_set_feature_extraction_parameters(inst); // Set feature configuration + + //default mode + WebRtcNs_set_policy_core(inst, 0); + + + memset(inst->outBuf, 0, sizeof(float) * 3 * BLOCKL_MAX); + + inst->initFlag = 1; + return 0; +} - // Initialization of struct - if (fs == 8000 || fs == 16000 || fs == 32000) - { - inst->fs = fs; - } - else - { - return -1; - } - inst->windShift = 0; - if (fs == 8000) - { - // We only support 10ms frames - inst->blockLen = 80; - inst->blockLen10ms = 80; - inst->anaLen = 128; - inst->window = kBlocks80w128; - inst->outLen = 0; - } - else if (fs == 16000) - { - // We only support 10ms frames - inst->blockLen = 160; - inst->blockLen10ms = 160; - inst->anaLen = 256; - inst->window = kBlocks160w256; - inst->outLen = 0; - } - else if (fs==32000) - { - // We only support 10ms frames - inst->blockLen = 160; - inst->blockLen10ms = 160; - inst->anaLen = 256; - inst->window = kBlocks160w256; - inst->outLen = 0; +int WebRtcNs_set_policy_core(NSinst_t* inst, int mode) { + // allow for modes:0,1,2,3 + if (mode < 0 || mode > 3) { + return (-1); + } + + inst->aggrMode = mode; + if (mode == 0) { + inst->overdrive = (float)1.0; + inst->denoiseBound = (float)0.5; + inst->gainmap = 0; + } else if (mode == 1) { + //inst->overdrive = (float)1.25; + inst->overdrive = (float)1.0; + inst->denoiseBound = (float)0.25; + inst->gainmap = 1; + } else if (mode == 2) { + //inst->overdrive = (float)1.25; + inst->overdrive = (float)1.1; + inst->denoiseBound = (float)0.125; + inst->gainmap = 1; + } else if (mode == 3) { + //inst->overdrive = (float)1.30; + inst->overdrive = (float)1.25; + inst->denoiseBound = (float)0.09; + inst->gainmap = 1; + } + return 0; +} + +// Estimate noise +void WebRtcNs_NoiseEstimation(NSinst_t* inst, float* magn, float* noise) { + int i, s, offset; + float lmagn[HALF_ANAL_BLOCKL], delta; + + if (inst->updates < END_STARTUP_LONG) { + inst->updates++; + } + + for (i = 0; i < inst->magnLen; i++) { + lmagn[i] = (float)log(magn[i]); + } + + // loop over simultaneous estimates + for (s = 0; s < SIMULT; s++) { + offset = s * inst->magnLen; + + // newquantest(...) + for (i = 0; i < inst->magnLen; i++) { + // compute delta + if (inst->density[offset + i] > 1.0) { + delta = FACTOR * (float)1.0 / inst->density[offset + i]; + } else { + delta = FACTOR; + } + + // update log quantile estimate + if (lmagn[i] > inst->lquantile[offset + i]) { + inst->lquantile[offset + i] += QUANTILE * delta + / (float)(inst->counter[s] + 1); + } else { + inst->lquantile[offset + i] -= ((float)1.0 - QUANTILE) * delta + / (float)(inst->counter[s] + 1); + } + + // update density estimate + if (fabs(lmagn[i] - inst->lquantile[offset + i]) < WIDTH) { + inst->density[offset + i] = ((float)inst->counter[s] * inst->density[offset + + i] + (float)1.0 / ((float)2.0 * WIDTH)) / (float)(inst->counter[s] + 1); + } + } // end loop over magnitude spectrum + + if (inst->counter[s] >= END_STARTUP_LONG) { + inst->counter[s] = 0; + if (inst->updates >= END_STARTUP_LONG) { + for (i = 0; i < inst->magnLen; i++) { + inst->quantile[i] = (float)exp(inst->lquantile[offset + i]); + } + } } - inst->magnLen = inst->anaLen / 2 + 1; // Number of frequency bins - // Initialize fft work arrays. - inst->ip[0] = 0; // Setting this triggers initialization. - memset(inst->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX); - rdft(inst->anaLen, 1, inst->dataBuf, inst->ip, inst->wfft); + inst->counter[s]++; + } // end loop over simultaneous estimates - memset(inst->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX); - memset(inst->syntBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX); + // Sequentially update the noise during startup + if (inst->updates < END_STARTUP_LONG) { + // Use the last "s" to get noise during startup that differ from zero. + for (i = 0; i < inst->magnLen; i++) { + inst->quantile[i] = (float)exp(inst->lquantile[offset + i]); + } + } - //for HB processing - memset(inst->dataBufHB, 0, sizeof(float) * ANAL_BLOCKL_MAX); + for (i = 0; i < inst->magnLen; i++) { + noise[i] = inst->quantile[i]; + } +} - //for quantile noise estimation - memset(inst->quantile, 0, sizeof(float) * HALF_ANAL_BLOCKL); - for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) - { - inst->lquantile[i] = (float)8.0; - inst->density[i] = (float)0.3; +// Extract thresholds for feature parameters +// histograms are computed over some window_size (given by inst->modelUpdatePars[1]) +// thresholds and weights are extracted every window +// flag 0 means update histogram only, flag 1 means compute the thresholds/weights +// threshold and weights are returned in: inst->priorModelPars +void WebRtcNs_FeatureParameterExtraction(NSinst_t* inst, int flag) { + int i, useFeatureSpecFlat, useFeatureSpecDiff, numHistLrt; + int maxPeak1, maxPeak2; + int weightPeak1SpecFlat, weightPeak2SpecFlat, weightPeak1SpecDiff, weightPeak2SpecDiff; + + float binMid, featureSum; + float posPeak1SpecFlat, posPeak2SpecFlat, posPeak1SpecDiff, posPeak2SpecDiff; + float fluctLrt, avgHistLrt, avgSquareHistLrt, avgHistLrtCompl; + + //3 features: lrt, flatness, difference + //lrt_feature = inst->featureData[3]; + //flat_feature = inst->featureData[0]; + //diff_feature = inst->featureData[4]; + + //update histograms + if (flag == 0) { + // LRT + if ((inst->featureData[3] < HIST_PAR_EST * inst->featureExtractionParams.binSizeLrt) + && (inst->featureData[3] >= 0.0)) { + i = (int)(inst->featureData[3] / inst->featureExtractionParams.binSizeLrt); + inst->histLrt[i]++; } - - for (i = 0; i < SIMULT; i++) - { - inst->counter[i] = (int)floor((float)(END_STARTUP_LONG * (i + 1)) / (float)SIMULT); + // Spectral flatness + if ((inst->featureData[0] < HIST_PAR_EST + * inst->featureExtractionParams.binSizeSpecFlat) + && (inst->featureData[0] >= 0.0)) { + i = (int)(inst->featureData[0] / inst->featureExtractionParams.binSizeSpecFlat); + inst->histSpecFlat[i]++; } - - inst->updates = 0; - - // Wiener filter initialization - for (i = 0; i < HALF_ANAL_BLOCKL; i++) - { - inst->smooth[i] = (float)1.0; + // Spectral difference + if ((inst->featureData[4] < HIST_PAR_EST + * inst->featureExtractionParams.binSizeSpecDiff) + && (inst->featureData[4] >= 0.0)) { + i = (int)(inst->featureData[4] / inst->featureExtractionParams.binSizeSpecDiff); + inst->histSpecDiff[i]++; } - - // Set the aggressiveness: default - inst->aggrMode = 0; - - //initialize variables for new method - inst->priorSpeechProb = (float)0.5; //prior prob for speech/noise - for (i = 0; i < HALF_ANAL_BLOCKL; i++) - { - inst->magnPrev[i] = (float)0.0; //previous mag spectrum - inst->noisePrev[i] = (float)0.0; //previous noise-spectrum - inst->logLrtTimeAvg[i] = LRT_FEATURE_THR; //smooth LR ratio (same as threshold) - inst->magnAvgPause[i] = (float)0.0; //conservative noise spectrum estimate - inst->speechProbHB[i] = (float)0.0; //for estimation of HB in second pass - inst->initMagnEst[i] = (float)0.0; //initial average mag spectrum + } + + // extract parameters for speech/noise probability + if (flag == 1) { + //lrt feature: compute the average over inst->featureExtractionParams.rangeAvgHistLrt + avgHistLrt = 0.0; + avgHistLrtCompl = 0.0; + avgSquareHistLrt = 0.0; + numHistLrt = 0; + for (i = 0; i < HIST_PAR_EST; i++) { + binMid = ((float)i + (float)0.5) * inst->featureExtractionParams.binSizeLrt; + if (binMid <= inst->featureExtractionParams.rangeAvgHistLrt) { + avgHistLrt += inst->histLrt[i] * binMid; + numHistLrt += inst->histLrt[i]; + } + avgSquareHistLrt += inst->histLrt[i] * binMid * binMid; + avgHistLrtCompl += inst->histLrt[i] * binMid; } - - //feature quantities - inst->featureData[0] = SF_FEATURE_THR; //spectral flatness (start on threshold) - inst->featureData[1] = (float)0.0; //spectral entropy: not used in this version - inst->featureData[2] = (float)0.0; //spectral variance: not used in this version - inst->featureData[3] = LRT_FEATURE_THR; //average lrt factor (start on threshold) - inst->featureData[4] = SF_FEATURE_THR; //spectral template diff (start on threshold) - inst->featureData[5] = (float)0.0; //normalization for spectral-diff - inst->featureData[6] = (float)0.0; //window time-average of input magnitude spectrum - - //histogram quantities: used to estimate/update thresholds for features - for (i = 0; i < HIST_PAR_EST; i++) - { - inst->histLrt[i] = 0; - inst->histSpecFlat[i] = 0; - inst->histSpecDiff[i] = 0; + if (numHistLrt > 0) { + avgHistLrt = avgHistLrt / ((float)numHistLrt); } + avgHistLrtCompl = avgHistLrtCompl / ((float)inst->modelUpdatePars[1]); + avgSquareHistLrt = avgSquareHistLrt / ((float)inst->modelUpdatePars[1]); + fluctLrt = avgSquareHistLrt - avgHistLrt * avgHistLrtCompl; + // get threshold for lrt feature: + if (fluctLrt < inst->featureExtractionParams.thresFluctLrt) { + //very low fluct, so likely noise + inst->priorModelPars[0] = inst->featureExtractionParams.maxLrt; + } else { + inst->priorModelPars[0] = inst->featureExtractionParams.factor1ModelPars + * avgHistLrt; + // check if value is within min/max range + if (inst->priorModelPars[0] < inst->featureExtractionParams.minLrt) { + inst->priorModelPars[0] = inst->featureExtractionParams.minLrt; + } + if (inst->priorModelPars[0] > inst->featureExtractionParams.maxLrt) { + inst->priorModelPars[0] = inst->featureExtractionParams.maxLrt; + } + } + // done with lrt feature - inst->blockInd = -1; //frame counter - inst->priorModelPars[0] = LRT_FEATURE_THR; //default threshold for lrt feature - inst->priorModelPars[1] = (float)0.5; //threshold for spectral flatness: - // determined on-line - inst->priorModelPars[2] = (float)1.0; //sgn_map par for spectral measure: - // 1 for flatness measure - inst->priorModelPars[3] = (float)0.5; //threshold for template-difference feature: - // determined on-line - inst->priorModelPars[4] = (float)1.0; //default weighting parameter for lrt feature - inst->priorModelPars[5] = (float)0.0; //default weighting parameter for - // spectral flatness feature - inst->priorModelPars[6] = (float)0.0; //default weighting parameter for - // spectral difference feature - - inst->modelUpdatePars[0] = 2; //update flag for parameters: - // 0 no update, 1=update once, 2=update every window - inst->modelUpdatePars[1] = 500; //window for update - inst->modelUpdatePars[2] = 0; //counter for update of conservative noise spectrum - //counter if the feature thresholds are updated during the sequence - inst->modelUpdatePars[3] = inst->modelUpdatePars[1]; - - inst->signalEnergy = 0.0; - inst->sumMagn = 0.0; - inst->whiteNoiseLevel = 0.0; - inst->pinkNoiseNumerator = 0.0; - inst->pinkNoiseExp = 0.0; - - WebRtcNs_set_feature_extraction_parameters(inst); // Set feature configuration - - //default mode - WebRtcNs_set_policy_core(inst, 0); - - - memset(inst->outBuf, 0, sizeof(float) * 3 * BLOCKL_MAX); - - inst->initFlag = 1; - return 0; -} - -int WebRtcNs_set_policy_core(NSinst_t *inst, int mode) -{ - // allow for modes:0,1,2,3 - if (mode < 0 || mode > 3) - { - return (-1); + // + // for spectral flatness and spectral difference: compute the main peaks of histogram + maxPeak1 = 0; + maxPeak2 = 0; + posPeak1SpecFlat = 0.0; + posPeak2SpecFlat = 0.0; + weightPeak1SpecFlat = 0; + weightPeak2SpecFlat = 0; + + // peaks for flatness + for (i = 0; i < HIST_PAR_EST; i++) { + binMid = ((float)i + (float)0.5) * inst->featureExtractionParams.binSizeSpecFlat; + if (inst->histSpecFlat[i] > maxPeak1) { + // Found new "first" peak + maxPeak2 = maxPeak1; + weightPeak2SpecFlat = weightPeak1SpecFlat; + posPeak2SpecFlat = posPeak1SpecFlat; + + maxPeak1 = inst->histSpecFlat[i]; + weightPeak1SpecFlat = inst->histSpecFlat[i]; + posPeak1SpecFlat = binMid; + } else if (inst->histSpecFlat[i] > maxPeak2) { + // Found new "second" peak + maxPeak2 = inst->histSpecFlat[i]; + weightPeak2SpecFlat = inst->histSpecFlat[i]; + posPeak2SpecFlat = binMid; + } } - inst->aggrMode = mode; - if (mode == 0) - { - inst->overdrive = (float)1.0; - inst->denoiseBound = (float)0.5; - inst->gainmap = 0; + //compute two peaks for spectral difference + maxPeak1 = 0; + maxPeak2 = 0; + posPeak1SpecDiff = 0.0; + posPeak2SpecDiff = 0.0; + weightPeak1SpecDiff = 0; + weightPeak2SpecDiff = 0; + // peaks for spectral difference + for (i = 0; i < HIST_PAR_EST; i++) { + binMid = ((float)i + (float)0.5) * inst->featureExtractionParams.binSizeSpecDiff; + if (inst->histSpecDiff[i] > maxPeak1) { + // Found new "first" peak + maxPeak2 = maxPeak1; + weightPeak2SpecDiff = weightPeak1SpecDiff; + posPeak2SpecDiff = posPeak1SpecDiff; + + maxPeak1 = inst->histSpecDiff[i]; + weightPeak1SpecDiff = inst->histSpecDiff[i]; + posPeak1SpecDiff = binMid; + } else if (inst->histSpecDiff[i] > maxPeak2) { + // Found new "second" peak + maxPeak2 = inst->histSpecDiff[i]; + weightPeak2SpecDiff = inst->histSpecDiff[i]; + posPeak2SpecDiff = binMid; + } } - else if (mode == 1) - { - //inst->overdrive = (float)1.25; - inst->overdrive = (float)1.0; - inst->denoiseBound = (float)0.25; - inst->gainmap = 1; + + // for spectrum flatness feature + useFeatureSpecFlat = 1; + // merge the two peaks if they are close + if ((fabs(posPeak2SpecFlat - posPeak1SpecFlat) + < inst->featureExtractionParams.limitPeakSpacingSpecFlat) + && (weightPeak2SpecFlat + > inst->featureExtractionParams.limitPeakWeightsSpecFlat + * weightPeak1SpecFlat)) { + weightPeak1SpecFlat += weightPeak2SpecFlat; + posPeak1SpecFlat = (float)0.5 * (posPeak1SpecFlat + posPeak2SpecFlat); } - else if (mode == 2) - { - //inst->overdrive = (float)1.25; - inst->overdrive = (float)1.1; - inst->denoiseBound = (float)0.125; - inst->gainmap = 1; + //reject if weight of peaks is not large enough, or peak value too small + if (weightPeak1SpecFlat < inst->featureExtractionParams.thresWeightSpecFlat + || posPeak1SpecFlat < inst->featureExtractionParams.thresPosSpecFlat) { + useFeatureSpecFlat = 0; } - else if (mode == 3) - { - //inst->overdrive = (float)1.30; - inst->overdrive = (float)1.25; - inst->denoiseBound = (float)0.09; - inst->gainmap = 1; + // if selected, get the threshold + if (useFeatureSpecFlat == 1) { + // compute the threshold + inst->priorModelPars[1] = inst->featureExtractionParams.factor2ModelPars + * posPeak1SpecFlat; + //check if value is within min/max range + if (inst->priorModelPars[1] < inst->featureExtractionParams.minSpecFlat) { + inst->priorModelPars[1] = inst->featureExtractionParams.minSpecFlat; + } + if (inst->priorModelPars[1] > inst->featureExtractionParams.maxSpecFlat) { + inst->priorModelPars[1] = inst->featureExtractionParams.maxSpecFlat; + } } - return 0; -} + // done with flatness feature -// Estimate noise -void WebRtcNs_NoiseEstimation(NSinst_t *inst, float *magn, float *noise) -{ - int i, s, offset; - float lmagn[HALF_ANAL_BLOCKL], delta; - - if (inst->updates < END_STARTUP_LONG) - { - inst->updates++; + // for template feature + useFeatureSpecDiff = 1; + // merge the two peaks if they are close + if ((fabs(posPeak2SpecDiff - posPeak1SpecDiff) + < inst->featureExtractionParams.limitPeakSpacingSpecDiff) + && (weightPeak2SpecDiff + > inst->featureExtractionParams.limitPeakWeightsSpecDiff + * weightPeak1SpecDiff)) { + weightPeak1SpecDiff += weightPeak2SpecDiff; + posPeak1SpecDiff = (float)0.5 * (posPeak1SpecDiff + posPeak2SpecDiff); } - - for (i = 0; i < inst->magnLen; i++) - { - lmagn[i] = (float)log(magn[i]); + // get the threshold value + inst->priorModelPars[3] = inst->featureExtractionParams.factor1ModelPars + * posPeak1SpecDiff; + //reject if weight of peaks is not large enough + if (weightPeak1SpecDiff < inst->featureExtractionParams.thresWeightSpecDiff) { + useFeatureSpecDiff = 0; } - - // loop over simultaneous estimates - for (s = 0; s < SIMULT; s++) - { - offset = s * inst->magnLen; - - // newquantest(...) - for (i = 0; i < inst->magnLen; i++) - { - // compute delta - if (inst->density[offset + i] > 1.0) - { - delta = FACTOR * (float)1.0 / inst->density[offset + i]; - } - else - { - delta = FACTOR; - } - - // update log quantile estimate - if (lmagn[i] > inst->lquantile[offset + i]) - { - inst->lquantile[offset + i] += QUANTILE * delta - / (float)(inst->counter[s] + 1); - } - else - { - inst->lquantile[offset + i] -= ((float)1.0 - QUANTILE) * delta - / (float)(inst->counter[s] + 1); - } - - // update density estimate - if (fabs(lmagn[i] - inst->lquantile[offset + i]) < WIDTH) - { - inst->density[offset + i] = ((float)inst->counter[s] * inst->density[offset - + i] + (float)1.0 / ((float)2.0 * WIDTH)) / (float)(inst->counter[s] - + 1); - } - } // end loop over magnitude spectrum - - if (inst->counter[s] >= END_STARTUP_LONG) - { - inst->counter[s] = 0; - if (inst->updates >= END_STARTUP_LONG) - { - for (i = 0; i < inst->magnLen; i++) - { - inst->quantile[i] = (float)exp(inst->lquantile[offset + i]); - } - } - } - - inst->counter[s]++; - } // end loop over simultaneous estimates - - // Sequentially update the noise during startup - if (inst->updates < END_STARTUP_LONG) - { - // Use the last "s" to get noise during startup that differ from zero. - for (i = 0; i < inst->magnLen; i++) - { - inst->quantile[i] = (float)exp(inst->lquantile[offset + i]); - } + //check if value is within min/max range + if (inst->priorModelPars[3] < inst->featureExtractionParams.minSpecDiff) { + inst->priorModelPars[3] = inst->featureExtractionParams.minSpecDiff; } - - for (i = 0; i < inst->magnLen; i++) - { - noise[i] = inst->quantile[i]; + if (inst->priorModelPars[3] > inst->featureExtractionParams.maxSpecDiff) { + inst->priorModelPars[3] = inst->featureExtractionParams.maxSpecDiff; } -} + // done with spectral difference feature -// Extract thresholds for feature parameters -// histograms are computed over some window_size (given by inst->modelUpdatePars[1]) -// thresholds and weights are extracted every window -// flag 0 means update histogram only, flag 1 means compute the thresholds/weights -// threshold and weights are returned in: inst->priorModelPars -void WebRtcNs_FeatureParameterExtraction(NSinst_t *inst, int flag) -{ - int i, useFeatureSpecFlat, useFeatureSpecDiff, numHistLrt; - int maxPeak1, maxPeak2; - int weightPeak1SpecFlat, weightPeak2SpecFlat, weightPeak1SpecDiff, weightPeak2SpecDiff; - - float binMid, featureSum; - float posPeak1SpecFlat, posPeak2SpecFlat, posPeak1SpecDiff, posPeak2SpecDiff; - float fluctLrt, avgHistLrt, avgSquareHistLrt, avgHistLrtCompl; - - //3 features: lrt, flatness, difference - //lrt_feature = inst->featureData[3]; - //flat_feature = inst->featureData[0]; - //diff_feature = inst->featureData[4]; - - //update histograms - if (flag == 0) - { - // LRT - if ((inst->featureData[3] < HIST_PAR_EST * inst->featureExtractionParams.binSizeLrt) - && (inst->featureData[3] >= 0.0)) - { - i = (int)(inst->featureData[3] / inst->featureExtractionParams.binSizeLrt); - inst->histLrt[i]++; - } - // Spectral flatness - if ((inst->featureData[0] < HIST_PAR_EST - * inst->featureExtractionParams.binSizeSpecFlat) - && (inst->featureData[0] >= 0.0)) - { - i = (int)(inst->featureData[0] / inst->featureExtractionParams.binSizeSpecFlat); - inst->histSpecFlat[i]++; - } - // Spectral difference - if ((inst->featureData[4] < HIST_PAR_EST - * inst->featureExtractionParams.binSizeSpecDiff) - && (inst->featureData[4] >= 0.0)) - { - i = (int)(inst->featureData[4] / inst->featureExtractionParams.binSizeSpecDiff); - inst->histSpecDiff[i]++; - } + // don't use template feature if fluctuation of lrt feature is very low: + // most likely just noise state + if (fluctLrt < inst->featureExtractionParams.thresFluctLrt) { + useFeatureSpecDiff = 0; } - // extract parameters for speech/noise probability - if (flag == 1) - { - //lrt feature: compute the average over inst->featureExtractionParams.rangeAvgHistLrt - avgHistLrt = 0.0; - avgHistLrtCompl = 0.0; - avgSquareHistLrt = 0.0; - numHistLrt = 0; - for (i = 0; i < HIST_PAR_EST; i++) - { - binMid = ((float)i + (float)0.5) * inst->featureExtractionParams.binSizeLrt; - if (binMid <= inst->featureExtractionParams.rangeAvgHistLrt) - { - avgHistLrt += inst->histLrt[i] * binMid; - numHistLrt += inst->histLrt[i]; - } - avgSquareHistLrt += inst->histLrt[i] * binMid * binMid; - avgHistLrtCompl += inst->histLrt[i] * binMid; - } - if (numHistLrt > 0) - { - avgHistLrt = avgHistLrt / ((float)numHistLrt); - } - avgHistLrtCompl = avgHistLrtCompl / ((float)inst->modelUpdatePars[1]); - avgSquareHistLrt = avgSquareHistLrt / ((float)inst->modelUpdatePars[1]); - fluctLrt = avgSquareHistLrt - avgHistLrt * avgHistLrtCompl; - // get threshold for lrt feature: - if (fluctLrt < inst->featureExtractionParams.thresFluctLrt) - { - //very low fluct, so likely noise - inst->priorModelPars[0] = inst->featureExtractionParams.maxLrt; - } - else - { - inst->priorModelPars[0] = inst->featureExtractionParams.factor1ModelPars - * avgHistLrt; - // check if value is within min/max range - if (inst->priorModelPars[0] < inst->featureExtractionParams.minLrt) - { - inst->priorModelPars[0] = inst->featureExtractionParams.minLrt; - } - if (inst->priorModelPars[0] > inst->featureExtractionParams.maxLrt) - { - inst->priorModelPars[0] = inst->featureExtractionParams.maxLrt; - } - } - // done with lrt feature - - // - // for spectral flatness and spectral difference: compute the main peaks of histogram - maxPeak1 = 0; - maxPeak2 = 0; - posPeak1SpecFlat = 0.0; - posPeak2SpecFlat = 0.0; - weightPeak1SpecFlat = 0; - weightPeak2SpecFlat = 0; - - // peaks for flatness - for (i = 0; i < HIST_PAR_EST; i++) - { - binMid = ((float)i + (float)0.5) * inst->featureExtractionParams.binSizeSpecFlat; - if (inst->histSpecFlat[i] > maxPeak1) - { - // Found new "first" peak - maxPeak2 = maxPeak1; - weightPeak2SpecFlat = weightPeak1SpecFlat; - posPeak2SpecFlat = posPeak1SpecFlat; - - maxPeak1 = inst->histSpecFlat[i]; - weightPeak1SpecFlat = inst->histSpecFlat[i]; - posPeak1SpecFlat = binMid; - } - else if (inst->histSpecFlat[i] > maxPeak2) - { - // Found new "second" peak - maxPeak2 = inst->histSpecFlat[i]; - weightPeak2SpecFlat = inst->histSpecFlat[i]; - posPeak2SpecFlat = binMid; - } - } - - //compute two peaks for spectral difference - maxPeak1 = 0; - maxPeak2 = 0; - posPeak1SpecDiff = 0.0; - posPeak2SpecDiff = 0.0; - weightPeak1SpecDiff = 0; - weightPeak2SpecDiff = 0; - // peaks for spectral difference - for (i = 0; i < HIST_PAR_EST; i++) - { - binMid = ((float)i + (float)0.5) * inst->featureExtractionParams.binSizeSpecDiff; - if (inst->histSpecDiff[i] > maxPeak1) - { - // Found new "first" peak - maxPeak2 = maxPeak1; - weightPeak2SpecDiff = weightPeak1SpecDiff; - posPeak2SpecDiff = posPeak1SpecDiff; - - maxPeak1 = inst->histSpecDiff[i]; - weightPeak1SpecDiff = inst->histSpecDiff[i]; - posPeak1SpecDiff = binMid; - } - else if (inst->histSpecDiff[i] > maxPeak2) - { - // Found new "second" peak - maxPeak2 = inst->histSpecDiff[i]; - weightPeak2SpecDiff = inst->histSpecDiff[i]; - posPeak2SpecDiff = binMid; - } - } - - // for spectrum flatness feature - useFeatureSpecFlat = 1; - // merge the two peaks if they are close - if ((fabs(posPeak2SpecFlat - posPeak1SpecFlat) - < inst->featureExtractionParams.limitPeakSpacingSpecFlat) - && (weightPeak2SpecFlat - > inst->featureExtractionParams.limitPeakWeightsSpecFlat - * weightPeak1SpecFlat)) - { - weightPeak1SpecFlat += weightPeak2SpecFlat; - posPeak1SpecFlat = (float)0.5 * (posPeak1SpecFlat + posPeak2SpecFlat); - } - //reject if weight of peaks is not large enough, or peak value too small - if (weightPeak1SpecFlat < inst->featureExtractionParams.thresWeightSpecFlat - || posPeak1SpecFlat < inst->featureExtractionParams.thresPosSpecFlat) - { - useFeatureSpecFlat = 0; - } - // if selected, get the threshold - if (useFeatureSpecFlat == 1) - { - // compute the threshold - inst->priorModelPars[1] = inst->featureExtractionParams.factor2ModelPars - * posPeak1SpecFlat; - //check if value is within min/max range - if (inst->priorModelPars[1] < inst->featureExtractionParams.minSpecFlat) - { - inst->priorModelPars[1] = inst->featureExtractionParams.minSpecFlat; - } - if (inst->priorModelPars[1] > inst->featureExtractionParams.maxSpecFlat) - { - inst->priorModelPars[1] = inst->featureExtractionParams.maxSpecFlat; - } - } - // done with flatness feature - - // for template feature - useFeatureSpecDiff = 1; - // merge the two peaks if they are close - if ((fabs(posPeak2SpecDiff - posPeak1SpecDiff) - < inst->featureExtractionParams.limitPeakSpacingSpecDiff) - && (weightPeak2SpecDiff - > inst->featureExtractionParams.limitPeakWeightsSpecDiff - * weightPeak1SpecDiff)) - { - weightPeak1SpecDiff += weightPeak2SpecDiff; - posPeak1SpecDiff = (float)0.5 * (posPeak1SpecDiff + posPeak2SpecDiff); - } - // get the threshold value - inst->priorModelPars[3] = inst->featureExtractionParams.factor1ModelPars - * posPeak1SpecDiff; - //reject if weight of peaks is not large enough - if (weightPeak1SpecDiff < inst->featureExtractionParams.thresWeightSpecDiff) - { - useFeatureSpecDiff = 0; - } - //check if value is within min/max range - if (inst->priorModelPars[3] < inst->featureExtractionParams.minSpecDiff) - { - inst->priorModelPars[3] = inst->featureExtractionParams.minSpecDiff; - } - if (inst->priorModelPars[3] > inst->featureExtractionParams.maxSpecDiff) - { - inst->priorModelPars[3] = inst->featureExtractionParams.maxSpecDiff; - } - // done with spectral difference feature - - // don't use template feature if fluctuation of lrt feature is very low: - // most likely just noise state - if (fluctLrt < inst->featureExtractionParams.thresFluctLrt) - { - useFeatureSpecDiff = 0; - } - - // select the weights between the features - // inst->priorModelPars[4] is weight for lrt: always selected - // inst->priorModelPars[5] is weight for spectral flatness - // inst->priorModelPars[6] is weight for spectral difference - featureSum = (float)(1 + useFeatureSpecFlat + useFeatureSpecDiff); - inst->priorModelPars[4] = (float)1.0 / featureSum; - inst->priorModelPars[5] = ((float)useFeatureSpecFlat) / featureSum; - inst->priorModelPars[6] = ((float)useFeatureSpecDiff) / featureSum; - - // set hists to zero for next update - if (inst->modelUpdatePars[0] >= 1) - { - for (i = 0; i < HIST_PAR_EST; i++) - { - inst->histLrt[i] = 0; - inst->histSpecFlat[i] = 0; - inst->histSpecDiff[i] = 0; - } - } - } // end of flag == 1 + // select the weights between the features + // inst->priorModelPars[4] is weight for lrt: always selected + // inst->priorModelPars[5] is weight for spectral flatness + // inst->priorModelPars[6] is weight for spectral difference + featureSum = (float)(1 + useFeatureSpecFlat + useFeatureSpecDiff); + inst->priorModelPars[4] = (float)1.0 / featureSum; + inst->priorModelPars[5] = ((float)useFeatureSpecFlat) / featureSum; + inst->priorModelPars[6] = ((float)useFeatureSpecDiff) / featureSum; + + // set hists to zero for next update + if (inst->modelUpdatePars[0] >= 1) { + for (i = 0; i < HIST_PAR_EST; i++) { + inst->histLrt[i] = 0; + inst->histSpecFlat[i] = 0; + inst->histSpecDiff[i] = 0; + } + } + } // end of flag == 1 } // Compute spectral flatness on input spectrum // magnIn is the magnitude spectrum // spectral flatness is returned in inst->featureData[0] -void WebRtcNs_ComputeSpectralFlatness(NSinst_t *inst, float *magnIn) -{ - int i; - int shiftLP = 1; //option to remove first bin(s) from spectral measures - float avgSpectralFlatnessNum, avgSpectralFlatnessDen, spectralTmp; - - // comute spectral measures - // for flatness - avgSpectralFlatnessNum = 0.0; - avgSpectralFlatnessDen = inst->sumMagn; - for (i = 0; i < shiftLP; i++) - { - avgSpectralFlatnessDen -= magnIn[i]; +void WebRtcNs_ComputeSpectralFlatness(NSinst_t* inst, float* magnIn) { + int i; + int shiftLP = 1; //option to remove first bin(s) from spectral measures + float avgSpectralFlatnessNum, avgSpectralFlatnessDen, spectralTmp; + + // comute spectral measures + // for flatness + avgSpectralFlatnessNum = 0.0; + avgSpectralFlatnessDen = inst->sumMagn; + for (i = 0; i < shiftLP; i++) { + avgSpectralFlatnessDen -= magnIn[i]; + } + // compute log of ratio of the geometric to arithmetic mean: check for log(0) case + for (i = shiftLP; i < inst->magnLen; i++) { + if (magnIn[i] > 0.0) { + avgSpectralFlatnessNum += (float)log(magnIn[i]); + } else { + inst->featureData[0] -= SPECT_FL_TAVG * inst->featureData[0]; + return; } - // compute log of ratio of the geometric to arithmetic mean: check for log(0) case - for (i = shiftLP; i < inst->magnLen; i++) - { - if (magnIn[i] > 0.0) - { - avgSpectralFlatnessNum += (float)log(magnIn[i]); - } - else - { - inst->featureData[0] -= SPECT_FL_TAVG * inst->featureData[0]; - return; - } - } - //normalize - avgSpectralFlatnessDen = avgSpectralFlatnessDen / inst->magnLen; - avgSpectralFlatnessNum = avgSpectralFlatnessNum / inst->magnLen; + } + //normalize + avgSpectralFlatnessDen = avgSpectralFlatnessDen / inst->magnLen; + avgSpectralFlatnessNum = avgSpectralFlatnessNum / inst->magnLen; - //ratio and inverse log: check for case of log(0) - spectralTmp = (float)exp(avgSpectralFlatnessNum) / avgSpectralFlatnessDen; + //ratio and inverse log: check for case of log(0) + spectralTmp = (float)exp(avgSpectralFlatnessNum) / avgSpectralFlatnessDen; - //time-avg update of spectral flatness feature - inst->featureData[0] += SPECT_FL_TAVG * (spectralTmp - inst->featureData[0]); - // done with flatness feature + //time-avg update of spectral flatness feature + inst->featureData[0] += SPECT_FL_TAVG * (spectralTmp - inst->featureData[0]); + // done with flatness feature } // Compute the difference measure between input spectrum and a template/learned noise spectrum // magnIn is the input spectrum // the reference/template spectrum is inst->magnAvgPause[i] // returns (normalized) spectral difference in inst->featureData[4] -void WebRtcNs_ComputeSpectralDifference(NSinst_t *inst, float *magnIn) -{ - // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 / var(magnAvgPause) - int i; - float avgPause, avgMagn, covMagnPause, varPause, varMagn, avgDiffNormMagn; - - avgPause = 0.0; - avgMagn = inst->sumMagn; - // compute average quantities - for (i = 0; i < inst->magnLen; i++) - { - //conservative smooth noise spectrum from pause frames - avgPause += inst->magnAvgPause[i]; - } - avgPause = avgPause / ((float)inst->magnLen); - avgMagn = avgMagn / ((float)inst->magnLen); - - covMagnPause = 0.0; - varPause = 0.0; - varMagn = 0.0; - // compute variance and covariance quantities - for (i = 0; i < inst->magnLen; i++) - { - covMagnPause += (magnIn[i] - avgMagn) * (inst->magnAvgPause[i] - avgPause); - varPause += (inst->magnAvgPause[i] - avgPause) * (inst->magnAvgPause[i] - avgPause); - varMagn += (magnIn[i] - avgMagn) * (magnIn[i] - avgMagn); - } - covMagnPause = covMagnPause / ((float)inst->magnLen); - varPause = varPause / ((float)inst->magnLen); - varMagn = varMagn / ((float)inst->magnLen); - // update of average magnitude spectrum - inst->featureData[6] += inst->signalEnergy; - - avgDiffNormMagn = varMagn - (covMagnPause * covMagnPause) / (varPause + (float)0.0001); - // normalize and compute time-avg update of difference feature - avgDiffNormMagn = (float)(avgDiffNormMagn / (inst->featureData[5] + (float)0.0001)); - inst->featureData[4] += SPECT_DIFF_TAVG * (avgDiffNormMagn - inst->featureData[4]); +void WebRtcNs_ComputeSpectralDifference(NSinst_t* inst, float* magnIn) { + // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 / var(magnAvgPause) + int i; + float avgPause, avgMagn, covMagnPause, varPause, varMagn, avgDiffNormMagn; + + avgPause = 0.0; + avgMagn = inst->sumMagn; + // compute average quantities + for (i = 0; i < inst->magnLen; i++) { + //conservative smooth noise spectrum from pause frames + avgPause += inst->magnAvgPause[i]; + } + avgPause = avgPause / ((float)inst->magnLen); + avgMagn = avgMagn / ((float)inst->magnLen); + + covMagnPause = 0.0; + varPause = 0.0; + varMagn = 0.0; + // compute variance and covariance quantities + for (i = 0; i < inst->magnLen; i++) { + covMagnPause += (magnIn[i] - avgMagn) * (inst->magnAvgPause[i] - avgPause); + varPause += (inst->magnAvgPause[i] - avgPause) * (inst->magnAvgPause[i] - avgPause); + varMagn += (magnIn[i] - avgMagn) * (magnIn[i] - avgMagn); + } + covMagnPause = covMagnPause / ((float)inst->magnLen); + varPause = varPause / ((float)inst->magnLen); + varMagn = varMagn / ((float)inst->magnLen); + // update of average magnitude spectrum + inst->featureData[6] += inst->signalEnergy; + + avgDiffNormMagn = varMagn - (covMagnPause * covMagnPause) / (varPause + (float)0.0001); + // normalize and compute time-avg update of difference feature + avgDiffNormMagn = (float)(avgDiffNormMagn / (inst->featureData[5] + (float)0.0001)); + inst->featureData[4] += SPECT_DIFF_TAVG * (avgDiffNormMagn - inst->featureData[4]); } // Compute speech/noise probability @@ -694,807 +607,699 @@ void WebRtcNs_ComputeSpectralDifference(NSinst_t *inst, float *magnIn) //noise is the noise spectrum //snrLocPrior is the prior snr for each freq. //snr loc_post is the post snr for each freq. -void WebRtcNs_SpeechNoiseProb(NSinst_t *inst, float *probSpeechFinal, float *snrLocPrior, - float *snrLocPost) -{ - int i, sgnMap; - float invLrt, gainPrior, indPrior; - float logLrtTimeAvgKsum, besselTmp; - float indicator0, indicator1, indicator2; - float tmpFloat1, tmpFloat2; - float weightIndPrior0, weightIndPrior1, weightIndPrior2; - float threshPrior0, threshPrior1, threshPrior2; - float widthPrior, widthPrior0, widthPrior1, widthPrior2; - - widthPrior0 = WIDTH_PR_MAP; - widthPrior1 = (float)2.0 * WIDTH_PR_MAP; //width for pause region: - // lower range, so increase width in tanh map - widthPrior2 = (float)2.0 * WIDTH_PR_MAP; //for spectral-difference measure - - //threshold parameters for features - threshPrior0 = inst->priorModelPars[0]; - threshPrior1 = inst->priorModelPars[1]; - threshPrior2 = inst->priorModelPars[3]; - - //sign for flatness feature - sgnMap = (int)(inst->priorModelPars[2]); - - //weight parameters for features - weightIndPrior0 = inst->priorModelPars[4]; - weightIndPrior1 = inst->priorModelPars[5]; - weightIndPrior2 = inst->priorModelPars[6]; - - // compute feature based on average LR factor - // this is the average over all frequencies of the smooth log lrt - logLrtTimeAvgKsum = 0.0; - for (i = 0; i < inst->magnLen; i++) - { - tmpFloat1 = (float)1.0 + (float)2.0 * snrLocPrior[i]; - tmpFloat2 = (float)2.0 * snrLocPrior[i] / (tmpFloat1 + (float)0.0001); - besselTmp = (snrLocPost[i] + (float)1.0) * tmpFloat2; - inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - (float)log(tmpFloat1) - - inst->logLrtTimeAvg[i]); - logLrtTimeAvgKsum += inst->logLrtTimeAvg[i]; - } - logLrtTimeAvgKsum = (float)logLrtTimeAvgKsum / (inst->magnLen); - inst->featureData[3] = logLrtTimeAvgKsum; - // done with computation of LR factor - - // - //compute the indicator functions - // - - // average lrt feature - widthPrior = widthPrior0; - //use larger width in tanh map for pause regions - if (logLrtTimeAvgKsum < threshPrior0) - { - widthPrior = widthPrior1; - } - // compute indicator function: sigmoid map - indicator0 = (float)0.5 * ((float)tanh(widthPrior * (logLrtTimeAvgKsum - threshPrior0)) - + (float)1.0); - - //spectral flatness feature - tmpFloat1 = inst->featureData[0]; - widthPrior = widthPrior0; - //use larger width in tanh map for pause regions - if (sgnMap == 1 && (tmpFloat1 > threshPrior1)) - { - widthPrior = widthPrior1; - } - if (sgnMap == -1 && (tmpFloat1 < threshPrior1)) - { - widthPrior = widthPrior1; - } - // compute indicator function: sigmoid map - indicator1 = (float)0.5 * ((float)tanh( - (float)sgnMap * widthPrior * (threshPrior1 - - tmpFloat1)) + (float)1.0); - - //for template spectrum-difference - tmpFloat1 = inst->featureData[4]; - widthPrior = widthPrior0; - //use larger width in tanh map for pause regions - if (tmpFloat1 < threshPrior2) - { - widthPrior = widthPrior2; - } - // compute indicator function: sigmoid map - indicator2 = (float)0.5 * ((float)tanh(widthPrior * (tmpFloat1 - threshPrior2)) - + (float)1.0); - - //combine the indicator function with the feature weights - indPrior = weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 + weightIndPrior2 - * indicator2; - // done with computing indicator function - - //compute the prior probability - inst->priorSpeechProb += PRIOR_UPDATE * (indPrior - inst->priorSpeechProb); - // make sure probabilities are within range: keep floor to 0.01 - if (inst->priorSpeechProb > 1.0) - { - inst->priorSpeechProb = (float)1.0; - } - if (inst->priorSpeechProb < 0.01) - { - inst->priorSpeechProb = (float)0.01; - } - - //final speech probability: combine prior model with LR factor: - gainPrior = ((float)1.0 - inst->priorSpeechProb) / (inst->priorSpeechProb + (float)0.0001); - for (i = 0; i < inst->magnLen; i++) - { - invLrt = (float)exp(-inst->logLrtTimeAvg[i]); - invLrt = (float)gainPrior * invLrt; - probSpeechFinal[i] = (float)1.0 / ((float)1.0 + invLrt); - } +void WebRtcNs_SpeechNoiseProb(NSinst_t* inst, float* probSpeechFinal, float* snrLocPrior, + float* snrLocPost) { + int i, sgnMap; + float invLrt, gainPrior, indPrior; + float logLrtTimeAvgKsum, besselTmp; + float indicator0, indicator1, indicator2; + float tmpFloat1, tmpFloat2; + float weightIndPrior0, weightIndPrior1, weightIndPrior2; + float threshPrior0, threshPrior1, threshPrior2; + float widthPrior, widthPrior0, widthPrior1, widthPrior2; + + widthPrior0 = WIDTH_PR_MAP; + widthPrior1 = (float)2.0 * WIDTH_PR_MAP; //width for pause region: + // lower range, so increase width in tanh map + widthPrior2 = (float)2.0 * WIDTH_PR_MAP; //for spectral-difference measure + + //threshold parameters for features + threshPrior0 = inst->priorModelPars[0]; + threshPrior1 = inst->priorModelPars[1]; + threshPrior2 = inst->priorModelPars[3]; + + //sign for flatness feature + sgnMap = (int)(inst->priorModelPars[2]); + + //weight parameters for features + weightIndPrior0 = inst->priorModelPars[4]; + weightIndPrior1 = inst->priorModelPars[5]; + weightIndPrior2 = inst->priorModelPars[6]; + + // compute feature based on average LR factor + // this is the average over all frequencies of the smooth log lrt + logLrtTimeAvgKsum = 0.0; + for (i = 0; i < inst->magnLen; i++) { + tmpFloat1 = (float)1.0 + (float)2.0 * snrLocPrior[i]; + tmpFloat2 = (float)2.0 * snrLocPrior[i] / (tmpFloat1 + (float)0.0001); + besselTmp = (snrLocPost[i] + (float)1.0) * tmpFloat2; + inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - (float)log(tmpFloat1) + - inst->logLrtTimeAvg[i]); + logLrtTimeAvgKsum += inst->logLrtTimeAvg[i]; + } + logLrtTimeAvgKsum = (float)logLrtTimeAvgKsum / (inst->magnLen); + inst->featureData[3] = logLrtTimeAvgKsum; + // done with computation of LR factor + + // + //compute the indicator functions + // + + // average lrt feature + widthPrior = widthPrior0; + //use larger width in tanh map for pause regions + if (logLrtTimeAvgKsum < threshPrior0) { + widthPrior = widthPrior1; + } + // compute indicator function: sigmoid map + indicator0 = (float)0.5 * ((float)tanh(widthPrior * + (logLrtTimeAvgKsum - threshPrior0)) + (float)1.0); + + //spectral flatness feature + tmpFloat1 = inst->featureData[0]; + widthPrior = widthPrior0; + //use larger width in tanh map for pause regions + if (sgnMap == 1 && (tmpFloat1 > threshPrior1)) { + widthPrior = widthPrior1; + } + if (sgnMap == -1 && (tmpFloat1 < threshPrior1)) { + widthPrior = widthPrior1; + } + // compute indicator function: sigmoid map + indicator1 = (float)0.5 * ((float)tanh((float)sgnMap * + widthPrior * (threshPrior1 - tmpFloat1)) + (float)1.0); + + //for template spectrum-difference + tmpFloat1 = inst->featureData[4]; + widthPrior = widthPrior0; + //use larger width in tanh map for pause regions + if (tmpFloat1 < threshPrior2) { + widthPrior = widthPrior2; + } + // compute indicator function: sigmoid map + indicator2 = (float)0.5 * ((float)tanh(widthPrior * (tmpFloat1 - threshPrior2)) + + (float)1.0); + + //combine the indicator function with the feature weights + indPrior = weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 + weightIndPrior2 + * indicator2; + // done with computing indicator function + + //compute the prior probability + inst->priorSpeechProb += PRIOR_UPDATE * (indPrior - inst->priorSpeechProb); + // make sure probabilities are within range: keep floor to 0.01 + if (inst->priorSpeechProb > 1.0) { + inst->priorSpeechProb = (float)1.0; + } + if (inst->priorSpeechProb < 0.01) { + inst->priorSpeechProb = (float)0.01; + } + + //final speech probability: combine prior model with LR factor: + gainPrior = ((float)1.0 - inst->priorSpeechProb) / (inst->priorSpeechProb + (float)0.0001); + for (i = 0; i < inst->magnLen; i++) { + invLrt = (float)exp(-inst->logLrtTimeAvg[i]); + invLrt = (float)gainPrior * invLrt; + probSpeechFinal[i] = (float)1.0 / ((float)1.0 + invLrt); + } } -int WebRtcNs_ProcessCore(NSinst_t *inst, - short *speechFrame, - short *speechFrameHB, - short *outFrame, - short *outFrameHB) -{ - // main routine for noise reduction - - int flagHB = 0; - int i; - const int kStartBand = 5; // Skip first frequency bins during estimation. - int updateParsFlag; - - float energy1, energy2, gain, factor, factor1, factor2; - float signalEnergy, sumMagn; - float snrPrior, currentEstimateStsa; - float tmpFloat1, tmpFloat2, tmpFloat3, probSpeech, probNonSpeech; - float gammaNoiseTmp, gammaNoiseOld; - float noiseUpdateTmp, fTmp, dTmp; - float fin[BLOCKL_MAX], fout[BLOCKL_MAX]; - float winData[ANAL_BLOCKL_MAX]; - float magn[HALF_ANAL_BLOCKL], noise[HALF_ANAL_BLOCKL]; - float theFilter[HALF_ANAL_BLOCKL], theFilterTmp[HALF_ANAL_BLOCKL]; - float snrLocPost[HALF_ANAL_BLOCKL], snrLocPrior[HALF_ANAL_BLOCKL]; - float probSpeechFinal[HALF_ANAL_BLOCKL], previousEstimateStsa[HALF_ANAL_BLOCKL]; - float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL]; - // Variables during startup - float sum_log_i = 0.0; - float sum_log_i_square = 0.0; - float sum_log_magn = 0.0; - float sum_log_i_log_magn = 0.0; - float parametric_noise = 0.0; - float parametric_exp = 0.0; - float parametric_num = 0.0; - - // SWB variables - int deltaBweHB = 1; - int deltaGainHB = 1; - float decayBweHB = 1.0; - float gainMapParHB = 1.0; - float gainTimeDomainHB = 1.0; - float avgProbSpeechHB, avgProbSpeechHBTmp, avgFilterGainHB, gainModHB; - - // Check that initiation has been done - if (inst->initFlag != 1) - { - return (-1); - } - // Check for valid pointers based on sampling rate - if (inst->fs == 32000) - { - if (speechFrameHB == NULL) - { - return -1; - } - flagHB = 1; - // range for averaging low band quantities for H band gain - deltaBweHB = (int)inst->magnLen / 4; - deltaGainHB = deltaBweHB; +int WebRtcNs_ProcessCore(NSinst_t* inst, + short* speechFrame, + short* speechFrameHB, + short* outFrame, + short* outFrameHB) { + // main routine for noise reduction + + int flagHB = 0; + int i; + const int kStartBand = 5; // Skip first frequency bins during estimation. + int updateParsFlag; + + float energy1, energy2, gain, factor, factor1, factor2; + float signalEnergy, sumMagn; + float snrPrior, currentEstimateStsa; + float tmpFloat1, tmpFloat2, tmpFloat3, probSpeech, probNonSpeech; + float gammaNoiseTmp, gammaNoiseOld; + float noiseUpdateTmp, fTmp, dTmp; + float fin[BLOCKL_MAX], fout[BLOCKL_MAX]; + float winData[ANAL_BLOCKL_MAX]; + float magn[HALF_ANAL_BLOCKL], noise[HALF_ANAL_BLOCKL]; + float theFilter[HALF_ANAL_BLOCKL], theFilterTmp[HALF_ANAL_BLOCKL]; + float snrLocPost[HALF_ANAL_BLOCKL], snrLocPrior[HALF_ANAL_BLOCKL]; + float probSpeechFinal[HALF_ANAL_BLOCKL], previousEstimateStsa[HALF_ANAL_BLOCKL]; + float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL]; + // Variables during startup + float sum_log_i = 0.0; + float sum_log_i_square = 0.0; + float sum_log_magn = 0.0; + float sum_log_i_log_magn = 0.0; + float parametric_noise = 0.0; + float parametric_exp = 0.0; + float parametric_num = 0.0; + + // SWB variables + int deltaBweHB = 1; + int deltaGainHB = 1; + float decayBweHB = 1.0; + float gainMapParHB = 1.0; + float gainTimeDomainHB = 1.0; + float avgProbSpeechHB, avgProbSpeechHBTmp, avgFilterGainHB, gainModHB; + + // Check that initiation has been done + if (inst->initFlag != 1) { + return (-1); + } + // Check for valid pointers based on sampling rate + if (inst->fs == 32000) { + if (speechFrameHB == NULL) { + return -1; } - // - updateParsFlag = inst->modelUpdatePars[0]; - // - - //for LB do all processing + flagHB = 1; + // range for averaging low band quantities for H band gain + deltaBweHB = (int)inst->magnLen / 4; + deltaGainHB = deltaBweHB; + } + // + updateParsFlag = inst->modelUpdatePars[0]; + // + + //for LB do all processing + // convert to float + for (i = 0; i < inst->blockLen10ms; i++) { + fin[i] = (float)speechFrame[i]; + } + // update analysis buffer for L band + memcpy(inst->dataBuf, inst->dataBuf + inst->blockLen10ms, + sizeof(float) * (inst->anaLen - inst->blockLen10ms)); + memcpy(inst->dataBuf + inst->anaLen - inst->blockLen10ms, fin, + sizeof(float) * inst->blockLen10ms); + + if (flagHB == 1) { // convert to float - for (i = 0; i < inst->blockLen10ms; i++) - { - fin[i] = (float)speechFrame[i]; + for (i = 0; i < inst->blockLen10ms; i++) { + fin[i] = (float)speechFrameHB[i]; } - // update analysis buffer for L band - memcpy(inst->dataBuf, inst->dataBuf + inst->blockLen10ms, + // update analysis buffer for H band + memcpy(inst->dataBufHB, inst->dataBufHB + inst->blockLen10ms, sizeof(float) * (inst->anaLen - inst->blockLen10ms)); - memcpy(inst->dataBuf + inst->anaLen - inst->blockLen10ms, fin, + memcpy(inst->dataBufHB + inst->anaLen - inst->blockLen10ms, fin, sizeof(float) * inst->blockLen10ms); - - if (flagHB == 1) - { - // convert to float - for (i = 0; i < inst->blockLen10ms; i++) - { - fin[i] = (float)speechFrameHB[i]; - } - // update analysis buffer for H band - memcpy(inst->dataBufHB, inst->dataBufHB + inst->blockLen10ms, - sizeof(float) * (inst->anaLen - inst->blockLen10ms)); - memcpy(inst->dataBufHB + inst->anaLen - inst->blockLen10ms, fin, - sizeof(float) * inst->blockLen10ms); + } + + // check if processing needed + if (inst->outLen == 0) { + // windowing + energy1 = 0.0; + for (i = 0; i < inst->anaLen; i++) { + winData[i] = inst->window[i] * inst->dataBuf[i]; + energy1 += winData[i] * winData[i]; } - - // check if processing needed - if (inst->outLen == 0) - { - // windowing - energy1 = 0.0; - for (i = 0; i < inst->anaLen; i++) - { - winData[i] = inst->window[i] * inst->dataBuf[i]; - energy1 += winData[i] * winData[i]; + if (energy1 == 0.0) { + // synthesize the special case of zero input + // we want to avoid updating statistics in this case: + // Updating feature statistics when we have zeros only will cause thresholds to + // move towards zero signal situations. This in turn has the effect that once the + // signal is "turned on" (non-zero values) everything will be treated as speech + // and there is no noise suppression effect. Depending on the duration of the + // inactive signal it takes a considerable amount of time for the system to learn + // what is noise and what is speech. + + // read out fully processed segment + for (i = inst->windShift; i < inst->blockLen + inst->windShift; i++) { + fout[i - inst->windShift] = inst->syntBuf[i]; + } + // update synthesis buffer + memcpy(inst->syntBuf, inst->syntBuf + inst->blockLen, + sizeof(float) * (inst->anaLen - inst->blockLen)); + memset(inst->syntBuf + inst->anaLen - inst->blockLen, 0, + sizeof(float) * inst->blockLen); + + // out buffer + inst->outLen = inst->blockLen - inst->blockLen10ms; + if (inst->blockLen > inst->blockLen10ms) { + for (i = 0; i < inst->outLen; i++) { + inst->outBuf[i] = fout[i + inst->blockLen10ms]; } - if (energy1 == 0.0) - { - // synthesize the special case of zero input - // we want to avoid updating statistics in this case: - // Updating feature statistics when we have zeros only will cause thresholds to - // move towards zero signal situations. This in turn has the effect that once the - // signal is "turned on" (non-zero values) everything will be treated as speech - // and there is no noise suppression effect. Depending on the duration of the - // inactive signal it takes a considerable amount of time for the system to learn - // what is noise and what is speech. - - // read out fully processed segment - for (i = inst->windShift; i < inst->blockLen + inst->windShift; i++) - { - fout[i - inst->windShift] = inst->syntBuf[i]; - } - // update synthesis buffer - memcpy(inst->syntBuf, inst->syntBuf + inst->blockLen, - sizeof(float) * (inst->anaLen - inst->blockLen)); - memset(inst->syntBuf + inst->anaLen - inst->blockLen, 0, - sizeof(float) * inst->blockLen); - - // out buffer - inst->outLen = inst->blockLen - inst->blockLen10ms; - if (inst->blockLen > inst->blockLen10ms) - { - for (i = 0; i < inst->outLen; i++) - { - inst->outBuf[i] = fout[i + inst->blockLen10ms]; - } - } - // convert to short - for (i = 0; i < inst->blockLen10ms; i++) - { - dTmp = fout[i]; - if (dTmp < WEBRTC_SPL_WORD16_MIN) - { - dTmp = WEBRTC_SPL_WORD16_MIN; - } - else if (dTmp > WEBRTC_SPL_WORD16_MAX) - { - dTmp = WEBRTC_SPL_WORD16_MAX; - } - outFrame[i] = (short)dTmp; - } - - // for time-domain gain of HB - if (flagHB == 1) - { - for (i = 0; i < inst->blockLen10ms; i++) - { - dTmp = inst->dataBufHB[i]; - if (dTmp < WEBRTC_SPL_WORD16_MIN) - { - dTmp = WEBRTC_SPL_WORD16_MIN; - } - else if (dTmp > WEBRTC_SPL_WORD16_MAX) - { - dTmp = WEBRTC_SPL_WORD16_MAX; - } - outFrameHB[i] = (short)dTmp; - } - } // end of H band gain computation - // - return 0; + } + // convert to short + for (i = 0; i < inst->blockLen10ms; i++) { + dTmp = fout[i]; + if (dTmp < WEBRTC_SPL_WORD16_MIN) { + dTmp = WEBRTC_SPL_WORD16_MIN; + } else if (dTmp > WEBRTC_SPL_WORD16_MAX) { + dTmp = WEBRTC_SPL_WORD16_MAX; } + outFrame[i] = (short)dTmp; + } - // - inst->blockInd++; // Update the block index only when we process a block. - // FFT - rdft(inst->anaLen, 1, winData, inst->ip, inst->wfft); - - imag[0] = 0; - real[0] = winData[0]; - magn[0] = (float)(fabs(real[0]) + 1.0f); - imag[inst->magnLen - 1] = 0; - real[inst->magnLen - 1] = winData[1]; - magn[inst->magnLen - 1] = (float)(fabs(real[inst->magnLen - 1]) + 1.0f); - signalEnergy = (float)(real[0] * real[0]) + (float)(real[inst->magnLen - 1] - * real[inst->magnLen - 1]); - sumMagn = magn[0] + magn[inst->magnLen - 1]; - if (inst->blockInd < END_STARTUP_SHORT) - { - inst->initMagnEst[0] += magn[0]; - inst->initMagnEst[inst->magnLen - 1] += magn[inst->magnLen - 1]; - tmpFloat2 = log((float)(inst->magnLen - 1)); - sum_log_i = tmpFloat2; - sum_log_i_square = tmpFloat2 * tmpFloat2; - tmpFloat1 = log(magn[inst->magnLen - 1]); - sum_log_magn = tmpFloat1; - sum_log_i_log_magn = tmpFloat2 * tmpFloat1; - } - for (i = 1; i < inst->magnLen - 1; i++) - { - real[i] = winData[2 * i]; - imag[i] = winData[2 * i + 1]; - // magnitude spectrum - fTmp = real[i] * real[i]; - fTmp += imag[i] * imag[i]; - signalEnergy += fTmp; - magn[i] = ((float)sqrt(fTmp)) + 1.0f; - sumMagn += magn[i]; - if (inst->blockInd < END_STARTUP_SHORT) - { - inst->initMagnEst[i] += magn[i]; - if (i >= kStartBand) - { - tmpFloat2 = log((float)i); - sum_log_i += tmpFloat2; - sum_log_i_square += tmpFloat2 * tmpFloat2; - tmpFloat1 = log(magn[i]); - sum_log_magn += tmpFloat1; - sum_log_i_log_magn += tmpFloat2 * tmpFloat1; - } - } + // for time-domain gain of HB + if (flagHB == 1) { + for (i = 0; i < inst->blockLen10ms; i++) { + dTmp = inst->dataBufHB[i]; + if (dTmp < WEBRTC_SPL_WORD16_MIN) { + dTmp = WEBRTC_SPL_WORD16_MIN; + } else if (dTmp > WEBRTC_SPL_WORD16_MAX) { + dTmp = WEBRTC_SPL_WORD16_MAX; + } + outFrameHB[i] = (short)dTmp; } - signalEnergy = signalEnergy / ((float)inst->magnLen); - inst->signalEnergy = signalEnergy; - inst->sumMagn = sumMagn; - - //compute spectral flatness on input spectrum - WebRtcNs_ComputeSpectralFlatness(inst, magn); - // quantile noise estimate - WebRtcNs_NoiseEstimation(inst, magn, noise); - //compute simplified noise model during startup - if (inst->blockInd < END_STARTUP_SHORT) - { - // Estimate White noise - inst->whiteNoiseLevel += sumMagn / ((float)inst->magnLen) * inst->overdrive; - // Estimate Pink noise parameters - tmpFloat1 = sum_log_i_square * ((float)(inst->magnLen - kStartBand)); - tmpFloat1 -= (sum_log_i * sum_log_i); - tmpFloat2 = (sum_log_i_square * sum_log_magn - sum_log_i * sum_log_i_log_magn); - tmpFloat3 = tmpFloat2 / tmpFloat1; - // Constrain the estimated spectrum to be positive - if (tmpFloat3 < 0.0f) - { - tmpFloat3 = 0.0f; - } - inst->pinkNoiseNumerator += tmpFloat3; - tmpFloat2 = (sum_log_i * sum_log_magn); - tmpFloat2 -= ((float)(inst->magnLen - kStartBand)) * sum_log_i_log_magn; - tmpFloat3 = tmpFloat2 / tmpFloat1; - // Constrain the pink noise power to be in the interval [0, 1]; - if (tmpFloat3 < 0.0f) - { - tmpFloat3 = 0.0f; - } - if (tmpFloat3 > 1.0f) - { - tmpFloat3 = 1.0f; - } - inst->pinkNoiseExp += tmpFloat3; - - // Calculate frequency independent parts of parametric noise estimate. - if (inst->pinkNoiseExp == 0.0f) - { - // Use white noise estimate - parametric_noise = inst->whiteNoiseLevel; - } - else - { - // Use pink noise estimate - parametric_num = exp(inst->pinkNoiseNumerator / (float)(inst->blockInd + 1)); - parametric_num *= (float)(inst->blockInd + 1); - parametric_exp = inst->pinkNoiseExp / (float)(inst->blockInd + 1); - parametric_noise = parametric_num / pow((float)kStartBand, parametric_exp); - } - for (i = 0; i < inst->magnLen; i++) - { - // Estimate the background noise using the white and pink noise parameters - if ((inst->pinkNoiseExp > 0.0f) && (i >= kStartBand)) - { - // Use pink noise estimate - parametric_noise = parametric_num / pow((float)i, parametric_exp); - } - theFilterTmp[i] = (inst->initMagnEst[i] - inst->overdrive * parametric_noise); - theFilterTmp[i] /= (inst->initMagnEst[i] + (float)0.0001); - // Weight quantile noise with modeled noise - noise[i] *= (inst->blockInd); - tmpFloat2 = parametric_noise * (END_STARTUP_SHORT - inst->blockInd); - noise[i] += (tmpFloat2 / (float)(inst->blockInd + 1)); - noise[i] /= END_STARTUP_SHORT; - } + } // end of H band gain computation + // + return 0; + } + + // + inst->blockInd++; // Update the block index only when we process a block. + // FFT + rdft(inst->anaLen, 1, winData, inst->ip, inst->wfft); + + imag[0] = 0; + real[0] = winData[0]; + magn[0] = (float)(fabs(real[0]) + 1.0f); + imag[inst->magnLen - 1] = 0; + real[inst->magnLen - 1] = winData[1]; + magn[inst->magnLen - 1] = (float)(fabs(real[inst->magnLen - 1]) + 1.0f); + signalEnergy = (float)(real[0] * real[0]) + + (float)(real[inst->magnLen - 1] * real[inst->magnLen - 1]); + sumMagn = magn[0] + magn[inst->magnLen - 1]; + if (inst->blockInd < END_STARTUP_SHORT) { + inst->initMagnEst[0] += magn[0]; + inst->initMagnEst[inst->magnLen - 1] += magn[inst->magnLen - 1]; + tmpFloat2 = log((float)(inst->magnLen - 1)); + sum_log_i = tmpFloat2; + sum_log_i_square = tmpFloat2 * tmpFloat2; + tmpFloat1 = log(magn[inst->magnLen - 1]); + sum_log_magn = tmpFloat1; + sum_log_i_log_magn = tmpFloat2 * tmpFloat1; + } + for (i = 1; i < inst->magnLen - 1; i++) { + real[i] = winData[2 * i]; + imag[i] = winData[2 * i + 1]; + // magnitude spectrum + fTmp = real[i] * real[i]; + fTmp += imag[i] * imag[i]; + signalEnergy += fTmp; + magn[i] = ((float)sqrt(fTmp)) + 1.0f; + sumMagn += magn[i]; + if (inst->blockInd < END_STARTUP_SHORT) { + inst->initMagnEst[i] += magn[i]; + if (i >= kStartBand) { + tmpFloat2 = log((float)i); + sum_log_i += tmpFloat2; + sum_log_i_square += tmpFloat2 * tmpFloat2; + tmpFloat1 = log(magn[i]); + sum_log_magn += tmpFloat1; + sum_log_i_log_magn += tmpFloat2 * tmpFloat1; } - //compute average signal during END_STARTUP_LONG time: - // used to normalize spectral difference measure - if (inst->blockInd < END_STARTUP_LONG) - { - inst->featureData[5] *= inst->blockInd; - inst->featureData[5] += signalEnergy; - inst->featureData[5] /= (inst->blockInd + 1); + } + } + signalEnergy = signalEnergy / ((float)inst->magnLen); + inst->signalEnergy = signalEnergy; + inst->sumMagn = sumMagn; + + //compute spectral flatness on input spectrum + WebRtcNs_ComputeSpectralFlatness(inst, magn); + // quantile noise estimate + WebRtcNs_NoiseEstimation(inst, magn, noise); + //compute simplified noise model during startup + if (inst->blockInd < END_STARTUP_SHORT) { + // Estimate White noise + inst->whiteNoiseLevel += sumMagn / ((float)inst->magnLen) * inst->overdrive; + // Estimate Pink noise parameters + tmpFloat1 = sum_log_i_square * ((float)(inst->magnLen - kStartBand)); + tmpFloat1 -= (sum_log_i * sum_log_i); + tmpFloat2 = (sum_log_i_square * sum_log_magn - sum_log_i * sum_log_i_log_magn); + tmpFloat3 = tmpFloat2 / tmpFloat1; + // Constrain the estimated spectrum to be positive + if (tmpFloat3 < 0.0f) { + tmpFloat3 = 0.0f; + } + inst->pinkNoiseNumerator += tmpFloat3; + tmpFloat2 = (sum_log_i * sum_log_magn); + tmpFloat2 -= ((float)(inst->magnLen - kStartBand)) * sum_log_i_log_magn; + tmpFloat3 = tmpFloat2 / tmpFloat1; + // Constrain the pink noise power to be in the interval [0, 1]; + if (tmpFloat3 < 0.0f) { + tmpFloat3 = 0.0f; + } + if (tmpFloat3 > 1.0f) { + tmpFloat3 = 1.0f; + } + inst->pinkNoiseExp += tmpFloat3; + + // Calculate frequency independent parts of parametric noise estimate. + if (inst->pinkNoiseExp == 0.0f) { + // Use white noise estimate + parametric_noise = inst->whiteNoiseLevel; + } else { + // Use pink noise estimate + parametric_num = exp(inst->pinkNoiseNumerator / (float)(inst->blockInd + 1)); + parametric_num *= (float)(inst->blockInd + 1); + parametric_exp = inst->pinkNoiseExp / (float)(inst->blockInd + 1); + parametric_noise = parametric_num / pow((float)kStartBand, parametric_exp); + } + for (i = 0; i < inst->magnLen; i++) { + // Estimate the background noise using the white and pink noise parameters + if ((inst->pinkNoiseExp > 0.0f) && (i >= kStartBand)) { + // Use pink noise estimate + parametric_noise = parametric_num / pow((float)i, parametric_exp); } + theFilterTmp[i] = (inst->initMagnEst[i] - inst->overdrive * parametric_noise); + theFilterTmp[i] /= (inst->initMagnEst[i] + (float)0.0001); + // Weight quantile noise with modeled noise + noise[i] *= (inst->blockInd); + tmpFloat2 = parametric_noise * (END_STARTUP_SHORT - inst->blockInd); + noise[i] += (tmpFloat2 / (float)(inst->blockInd + 1)); + noise[i] /= END_STARTUP_SHORT; + } + } + //compute average signal during END_STARTUP_LONG time: + // used to normalize spectral difference measure + if (inst->blockInd < END_STARTUP_LONG) { + inst->featureData[5] *= inst->blockInd; + inst->featureData[5] += signalEnergy; + inst->featureData[5] /= (inst->blockInd + 1); + } #ifdef PROCESS_FLOW_0 - if (inst->blockInd > END_STARTUP_LONG) - { - //option: average the quantile noise: for check with AEC2 - for (i = 0; i < inst->magnLen; i++) - { - noise[i] = (float)0.6 * inst->noisePrev[i] + (float)0.4 * noise[i]; - } - for (i = 0; i < inst->magnLen; i++) - { - // Wiener with over sub-substraction: - theFilter[i] = (magn[i] - inst->overdrive * noise[i]) / (magn[i] + (float)0.0001); - } - } + if (inst->blockInd > END_STARTUP_LONG) { + //option: average the quantile noise: for check with AEC2 + for (i = 0; i < inst->magnLen; i++) { + noise[i] = (float)0.6 * inst->noisePrev[i] + (float)0.4 * noise[i]; + } + for (i = 0; i < inst->magnLen; i++) { + // Wiener with over sub-substraction: + theFilter[i] = (magn[i] - inst->overdrive * noise[i]) / (magn[i] + (float)0.0001); + } + } #else - //start processing at frames == converged+1 - // - // STEP 1: compute prior and post snr based on quantile noise est - // - - // compute DD estimate of prior SNR: needed for new method - for (i = 0; i < inst->magnLen; i++) - { - // post snr - snrLocPost[i] = (float)0.0; - if (magn[i] > noise[i]) - { - snrLocPost[i] = magn[i] / (noise[i] + (float)0.0001) - (float)1.0; - } - // previous post snr - // previous estimate: based on previous frame with gain filter - previousEstimateStsa[i] = inst->magnPrev[i] / (inst->noisePrev[i] + (float)0.0001) - * (inst->smooth[i]); - // DD estimate is sum of two terms: current estimate and previous estimate - // directed decision update of snrPrior - snrLocPrior[i] = DD_PR_SNR * previousEstimateStsa[i] + ((float)1.0 - DD_PR_SNR) - * snrLocPost[i]; - // post and prior snr needed for step 2 - } // end of loop over freqs + //start processing at frames == converged+1 + // + // STEP 1: compute prior and post snr based on quantile noise est + // + + // compute DD estimate of prior SNR: needed for new method + for (i = 0; i < inst->magnLen; i++) { + // post snr + snrLocPost[i] = (float)0.0; + if (magn[i] > noise[i]) { + snrLocPost[i] = magn[i] / (noise[i] + (float)0.0001) - (float)1.0; + } + // previous post snr + // previous estimate: based on previous frame with gain filter + previousEstimateStsa[i] = inst->magnPrev[i] / (inst->noisePrev[i] + (float)0.0001) + * (inst->smooth[i]); + // DD estimate is sum of two terms: current estimate and previous estimate + // directed decision update of snrPrior + snrLocPrior[i] = DD_PR_SNR * previousEstimateStsa[i] + ((float)1.0 - DD_PR_SNR) + * snrLocPost[i]; + // post and prior snr needed for step 2 + } // end of loop over freqs #ifdef PROCESS_FLOW_1 - for (i = 0; i < inst->magnLen; i++) - { - // gain filter - tmpFloat1 = inst->overdrive + snrLocPrior[i]; - tmpFloat2 = (float)snrLocPrior[i] / tmpFloat1; - theFilter[i] = (float)tmpFloat2; - } // end of loop over freqs + for (i = 0; i < inst->magnLen; i++) { + // gain filter + tmpFloat1 = inst->overdrive + snrLocPrior[i]; + tmpFloat2 = (float)snrLocPrior[i] / tmpFloat1; + theFilter[i] = (float)tmpFloat2; + } // end of loop over freqs #endif - // done with step 1: dd computation of prior and post snr + // done with step 1: dd computation of prior and post snr - // - //STEP 2: compute speech/noise likelihood - // + // + //STEP 2: compute speech/noise likelihood + // #ifdef PROCESS_FLOW_2 - // compute difference of input spectrum with learned/estimated noise spectrum - WebRtcNs_ComputeSpectralDifference(inst, magn); - // compute histograms for parameter decisions (thresholds and weights for features) - // parameters are extracted once every window time (=inst->modelUpdatePars[1]) - if (updateParsFlag >= 1) - { - // counter update - inst->modelUpdatePars[3]--; - // update histogram - if (inst->modelUpdatePars[3] > 0) - { - WebRtcNs_FeatureParameterExtraction(inst, 0); - } - // compute model parameters - if (inst->modelUpdatePars[3] == 0) - { - WebRtcNs_FeatureParameterExtraction(inst, 1); - inst->modelUpdatePars[3] = inst->modelUpdatePars[1]; - // if wish to update only once, set flag to zero - if (updateParsFlag == 1) - { - inst->modelUpdatePars[0] = 0; - } - else - { - // update every window: - // get normalization for spectral difference for next window estimate - inst->featureData[6] = inst->featureData[6] - / ((float)inst->modelUpdatePars[1]); - inst->featureData[5] = (float)0.5 * (inst->featureData[6] - + inst->featureData[5]); - inst->featureData[6] = (float)0.0; - } - } + // compute difference of input spectrum with learned/estimated noise spectrum + WebRtcNs_ComputeSpectralDifference(inst, magn); + // compute histograms for parameter decisions (thresholds and weights for features) + // parameters are extracted once every window time (=inst->modelUpdatePars[1]) + if (updateParsFlag >= 1) { + // counter update + inst->modelUpdatePars[3]--; + // update histogram + if (inst->modelUpdatePars[3] > 0) { + WebRtcNs_FeatureParameterExtraction(inst, 0); + } + // compute model parameters + if (inst->modelUpdatePars[3] == 0) { + WebRtcNs_FeatureParameterExtraction(inst, 1); + inst->modelUpdatePars[3] = inst->modelUpdatePars[1]; + // if wish to update only once, set flag to zero + if (updateParsFlag == 1) { + inst->modelUpdatePars[0] = 0; + } else { + // update every window: + // get normalization for spectral difference for next window estimate + inst->featureData[6] = inst->featureData[6] + / ((float)inst->modelUpdatePars[1]); + inst->featureData[5] = (float)0.5 * (inst->featureData[6] + + inst->featureData[5]); + inst->featureData[6] = (float)0.0; } - // compute speech/noise probability - WebRtcNs_SpeechNoiseProb(inst, probSpeechFinal, snrLocPrior, snrLocPost); - // time-avg parameter for noise update - gammaNoiseTmp = NOISE_UPDATE; - for (i = 0; i < inst->magnLen; i++) - { - probSpeech = probSpeechFinal[i]; - probNonSpeech = (float)1.0 - probSpeech; - // temporary noise update: - // use it for speech frames if update value is less than previous - noiseUpdateTmp = gammaNoiseTmp * inst->noisePrev[i] + ((float)1.0 - gammaNoiseTmp) - * (probNonSpeech * magn[i] + probSpeech * inst->noisePrev[i]); - // - // time-constant based on speech/noise state - gammaNoiseOld = gammaNoiseTmp; - gammaNoiseTmp = NOISE_UPDATE; - // increase gamma (i.e., less noise update) for frame likely to be speech - if (probSpeech > PROB_RANGE) - { - gammaNoiseTmp = SPEECH_UPDATE; - } - // conservative noise update - if (probSpeech < PROB_RANGE) - { - inst->magnAvgPause[i] += GAMMA_PAUSE * (magn[i] - inst->magnAvgPause[i]); - } - // noise update - if (gammaNoiseTmp == gammaNoiseOld) - { - noise[i] = noiseUpdateTmp; - } - else - { - noise[i] = gammaNoiseTmp * inst->noisePrev[i] + ((float)1.0 - gammaNoiseTmp) - * (probNonSpeech * magn[i] + probSpeech * inst->noisePrev[i]); - // allow for noise update downwards: - // if noise update decreases the noise, it is safe, so allow it to happen - if (noiseUpdateTmp < noise[i]) - { - noise[i] = noiseUpdateTmp; - } - } - } // end of freq loop - // done with step 2: noise update - - // - // STEP 3: compute dd update of prior snr and post snr based on new noise estimate - // - for (i = 0; i < inst->magnLen; i++) - { - // post and prior snr - currentEstimateStsa = (float)0.0; - if (magn[i] > noise[i]) - { - currentEstimateStsa = magn[i] / (noise[i] + (float)0.0001) - (float)1.0; - } - // DD estimate is sume of two terms: current estimate and previous estimate - // directed decision update of snrPrior - snrPrior = DD_PR_SNR * previousEstimateStsa[i] + ((float)1.0 - DD_PR_SNR) - * currentEstimateStsa; - // gain filter - tmpFloat1 = inst->overdrive + snrPrior; - tmpFloat2 = (float)snrPrior / tmpFloat1; - theFilter[i] = (float)tmpFloat2; - } // end of loop over freqs - // done with step3 + } + } + // compute speech/noise probability + WebRtcNs_SpeechNoiseProb(inst, probSpeechFinal, snrLocPrior, snrLocPost); + // time-avg parameter for noise update + gammaNoiseTmp = NOISE_UPDATE; + for (i = 0; i < inst->magnLen; i++) { + probSpeech = probSpeechFinal[i]; + probNonSpeech = (float)1.0 - probSpeech; + // temporary noise update: + // use it for speech frames if update value is less than previous + noiseUpdateTmp = gammaNoiseTmp * inst->noisePrev[i] + ((float)1.0 - gammaNoiseTmp) + * (probNonSpeech * magn[i] + probSpeech * inst->noisePrev[i]); + // + // time-constant based on speech/noise state + gammaNoiseOld = gammaNoiseTmp; + gammaNoiseTmp = NOISE_UPDATE; + // increase gamma (i.e., less noise update) for frame likely to be speech + if (probSpeech > PROB_RANGE) { + gammaNoiseTmp = SPEECH_UPDATE; + } + // conservative noise update + if (probSpeech < PROB_RANGE) { + inst->magnAvgPause[i] += GAMMA_PAUSE * (magn[i] - inst->magnAvgPause[i]); + } + // noise update + if (gammaNoiseTmp == gammaNoiseOld) { + noise[i] = noiseUpdateTmp; + } else { + noise[i] = gammaNoiseTmp * inst->noisePrev[i] + ((float)1.0 - gammaNoiseTmp) + * (probNonSpeech * magn[i] + probSpeech * inst->noisePrev[i]); + // allow for noise update downwards: + // if noise update decreases the noise, it is safe, so allow it to happen + if (noiseUpdateTmp < noise[i]) { + noise[i] = noiseUpdateTmp; + } + } + } // end of freq loop + // done with step 2: noise update + + // + // STEP 3: compute dd update of prior snr and post snr based on new noise estimate + // + for (i = 0; i < inst->magnLen; i++) { + // post and prior snr + currentEstimateStsa = (float)0.0; + if (magn[i] > noise[i]) { + currentEstimateStsa = magn[i] / (noise[i] + (float)0.0001) - (float)1.0; + } + // DD estimate is sume of two terms: current estimate and previous estimate + // directed decision update of snrPrior + snrPrior = DD_PR_SNR * previousEstimateStsa[i] + ((float)1.0 - DD_PR_SNR) + * currentEstimateStsa; + // gain filter + tmpFloat1 = inst->overdrive + snrPrior; + tmpFloat2 = (float)snrPrior / tmpFloat1; + theFilter[i] = (float)tmpFloat2; + } // end of loop over freqs + // done with step3 #endif #endif - for (i = 0; i < inst->magnLen; i++) - { - // flooring bottom - if (theFilter[i] < inst->denoiseBound) - { - theFilter[i] = inst->denoiseBound; - } - // flooring top - if (theFilter[i] > (float)1.0) - { - theFilter[i] = 1.0; - } - if (inst->blockInd < END_STARTUP_SHORT) - { - // flooring bottom - if (theFilterTmp[i] < inst->denoiseBound) - { - theFilterTmp[i] = inst->denoiseBound; - } - // flooring top - if (theFilterTmp[i] > (float)1.0) - { - theFilterTmp[i] = 1.0; - } - // Weight the two suppression filters - theFilter[i] *= (inst->blockInd); - theFilterTmp[i] *= (END_STARTUP_SHORT - inst->blockInd); - theFilter[i] += theFilterTmp[i]; - theFilter[i] /= (END_STARTUP_SHORT); - } - // smoothing + for (i = 0; i < inst->magnLen; i++) { + // flooring bottom + if (theFilter[i] < inst->denoiseBound) { + theFilter[i] = inst->denoiseBound; + } + // flooring top + if (theFilter[i] > (float)1.0) { + theFilter[i] = 1.0; + } + if (inst->blockInd < END_STARTUP_SHORT) { + // flooring bottom + if (theFilterTmp[i] < inst->denoiseBound) { + theFilterTmp[i] = inst->denoiseBound; + } + // flooring top + if (theFilterTmp[i] > (float)1.0) { + theFilterTmp[i] = 1.0; + } + // Weight the two suppression filters + theFilter[i] *= (inst->blockInd); + theFilterTmp[i] *= (END_STARTUP_SHORT - inst->blockInd); + theFilter[i] += theFilterTmp[i]; + theFilter[i] /= (END_STARTUP_SHORT); + } + // smoothing #ifdef PROCESS_FLOW_0 - inst->smooth[i] *= SMOOTH; // value set to 0.7 in define.h file - inst->smooth[i] += ((float)1.0 - SMOOTH) * theFilter[i]; + inst->smooth[i] *= SMOOTH; // value set to 0.7 in define.h file + inst->smooth[i] += ((float)1.0 - SMOOTH) * theFilter[i]; #else - inst->smooth[i] = theFilter[i]; + inst->smooth[i] = theFilter[i]; #endif - real[i] *= inst->smooth[i]; - imag[i] *= inst->smooth[i]; - } - // keep track of noise and magn spectrum for next frame - for (i = 0; i < inst->magnLen; i++) - { - inst->noisePrev[i] = noise[i]; - inst->magnPrev[i] = magn[i]; - } - // back to time domain - winData[0] = real[0]; - winData[1] = real[inst->magnLen - 1]; - for (i = 1; i < inst->magnLen - 1; i++) - { - winData[2 * i] = real[i]; - winData[2 * i + 1] = imag[i]; - } - rdft(inst->anaLen, -1, winData, inst->ip, inst->wfft); + real[i] *= inst->smooth[i]; + imag[i] *= inst->smooth[i]; + } + // keep track of noise and magn spectrum for next frame + for (i = 0; i < inst->magnLen; i++) { + inst->noisePrev[i] = noise[i]; + inst->magnPrev[i] = magn[i]; + } + // back to time domain + winData[0] = real[0]; + winData[1] = real[inst->magnLen - 1]; + for (i = 1; i < inst->magnLen - 1; i++) { + winData[2 * i] = real[i]; + winData[2 * i + 1] = imag[i]; + } + rdft(inst->anaLen, -1, winData, inst->ip, inst->wfft); - for (i = 0; i < inst->anaLen; i++) - { - real[i] = 2.0f * winData[i] / inst->anaLen; // fft scaling - } + for (i = 0; i < inst->anaLen; i++) { + real[i] = 2.0f * winData[i] / inst->anaLen; // fft scaling + } - //scale factor: only do it after END_STARTUP_LONG time - factor = (float)1.0; - if (inst->gainmap == 1 && inst->blockInd > END_STARTUP_LONG) - { - factor1 = (float)1.0; - factor2 = (float)1.0; + //scale factor: only do it after END_STARTUP_LONG time + factor = (float)1.0; + if (inst->gainmap == 1 && inst->blockInd > END_STARTUP_LONG) { + factor1 = (float)1.0; + factor2 = (float)1.0; - energy2 = 0.0; - for (i = 0; i < inst->anaLen;i++) - { - energy2 += (float)real[i] * (float)real[i]; - } - gain = (float)sqrt(energy2 / (energy1 + (float)1.0)); + energy2 = 0.0; + for (i = 0; i < inst->anaLen; i++) { + energy2 += (float)real[i] * (float)real[i]; + } + gain = (float)sqrt(energy2 / (energy1 + (float)1.0)); #ifdef PROCESS_FLOW_2 - // scaling for new version - if (gain > B_LIM) - { - factor1 = (float)1.0 + (float)1.3 * (gain - B_LIM); - if (gain * factor1 > (float)1.0) - { - factor1 = (float)1.0 / gain; - } - } - if (gain < B_LIM) - { - //don't reduce scale too much for pause regions: - // attenuation here should be controlled by flooring - if (gain <= inst->denoiseBound) - { - gain = inst->denoiseBound; - } - factor2 = (float)1.0 - (float)0.3 * (B_LIM - gain); - } - //combine both scales with speech/noise prob: - // note prior (priorSpeechProb) is not frequency dependent - factor = inst->priorSpeechProb * factor1 + ((float)1.0 - inst->priorSpeechProb) - * factor2; + // scaling for new version + if (gain > B_LIM) { + factor1 = (float)1.0 + (float)1.3 * (gain - B_LIM); + if (gain * factor1 > (float)1.0) { + factor1 = (float)1.0 / gain; + } + } + if (gain < B_LIM) { + //don't reduce scale too much for pause regions: + // attenuation here should be controlled by flooring + if (gain <= inst->denoiseBound) { + gain = inst->denoiseBound; + } + factor2 = (float)1.0 - (float)0.3 * (B_LIM - gain); + } + //combine both scales with speech/noise prob: + // note prior (priorSpeechProb) is not frequency dependent + factor = inst->priorSpeechProb * factor1 + ((float)1.0 - inst->priorSpeechProb) + * factor2; #else - if (gain > B_LIM) - { - factor = (float)1.0 + (float)1.3 * (gain - B_LIM); - } - else - { - factor = (float)1.0 + (float)2.0 * (gain - B_LIM); - } - if (gain * factor > (float)1.0) - { - factor = (float)1.0 / gain; - } + if (gain > B_LIM) { + factor = (float)1.0 + (float)1.3 * (gain - B_LIM); + } else { + factor = (float)1.0 + (float)2.0 * (gain - B_LIM); + } + if (gain * factor > (float)1.0) { + factor = (float)1.0 / gain; + } #endif - } // out of inst->gainmap==1 + } // out of inst->gainmap==1 - // synthesis - for (i = 0; i < inst->anaLen; i++) - { - inst->syntBuf[i] += factor * inst->window[i] * (float)real[i]; - } - // read out fully processed segment - for (i = inst->windShift; i < inst->blockLen + inst->windShift; i++) - { - fout[i - inst->windShift] = inst->syntBuf[i]; - } - // update synthesis buffer - memcpy(inst->syntBuf, inst->syntBuf + inst->blockLen, - sizeof(float) * (inst->anaLen - inst->blockLen)); - memset(inst->syntBuf + inst->anaLen - inst->blockLen, 0, - sizeof(float) * inst->blockLen); - - // out buffer - inst->outLen = inst->blockLen - inst->blockLen10ms; - if (inst->blockLen > inst->blockLen10ms) - { - for (i = 0; i < inst->outLen; i++) - { - inst->outBuf[i] = fout[i + inst->blockLen10ms]; - } - } - } // end of if out.len==0 - else - { - for (i = 0; i < inst->blockLen10ms; i++) - { - fout[i] = inst->outBuf[i]; - } - memcpy(inst->outBuf, inst->outBuf + inst->blockLen10ms, - sizeof(float) * (inst->outLen - inst->blockLen10ms)); - memset(inst->outBuf + inst->outLen - inst->blockLen10ms, 0, - sizeof(float) * inst->blockLen10ms); - inst->outLen -= inst->blockLen10ms; + // synthesis + for (i = 0; i < inst->anaLen; i++) { + inst->syntBuf[i] += factor * inst->window[i] * (float)real[i]; } - - // convert to short - for (i = 0; i < inst->blockLen10ms; i++) - { - dTmp = fout[i]; - if (dTmp < WEBRTC_SPL_WORD16_MIN) - { - dTmp = WEBRTC_SPL_WORD16_MIN; - } - else if (dTmp > WEBRTC_SPL_WORD16_MAX) - { - dTmp = WEBRTC_SPL_WORD16_MAX; - } - outFrame[i] = (short)dTmp; + // read out fully processed segment + for (i = inst->windShift; i < inst->blockLen + inst->windShift; i++) { + fout[i - inst->windShift] = inst->syntBuf[i]; } + // update synthesis buffer + memcpy(inst->syntBuf, inst->syntBuf + inst->blockLen, + sizeof(float) * (inst->anaLen - inst->blockLen)); + memset(inst->syntBuf + inst->anaLen - inst->blockLen, 0, + sizeof(float) * inst->blockLen); + + // out buffer + inst->outLen = inst->blockLen - inst->blockLen10ms; + if (inst->blockLen > inst->blockLen10ms) { + for (i = 0; i < inst->outLen; i++) { + inst->outBuf[i] = fout[i + inst->blockLen10ms]; + } + } + } // end of if out.len==0 + else { + for (i = 0; i < inst->blockLen10ms; i++) { + fout[i] = inst->outBuf[i]; + } + memcpy(inst->outBuf, inst->outBuf + inst->blockLen10ms, + sizeof(float) * (inst->outLen - inst->blockLen10ms)); + memset(inst->outBuf + inst->outLen - inst->blockLen10ms, 0, + sizeof(float) * inst->blockLen10ms); + inst->outLen -= inst->blockLen10ms; + } + + // convert to short + for (i = 0; i < inst->blockLen10ms; i++) { + dTmp = fout[i]; + if (dTmp < WEBRTC_SPL_WORD16_MIN) { + dTmp = WEBRTC_SPL_WORD16_MIN; + } else if (dTmp > WEBRTC_SPL_WORD16_MAX) { + dTmp = WEBRTC_SPL_WORD16_MAX; + } + outFrame[i] = (short)dTmp; + } - // for time-domain gain of HB - if (flagHB == 1) - { - for (i = 0; i < inst->magnLen; i++) - { - inst->speechProbHB[i] = probSpeechFinal[i]; - } - if (inst->blockInd > END_STARTUP_LONG) - { - // average speech prob from low band - // avg over second half (i.e., 4->8kHz) of freq. spectrum - avgProbSpeechHB = 0.0; - for (i = inst->magnLen - deltaBweHB - 1; i < inst->magnLen - 1; i++) - { - avgProbSpeechHB += inst->speechProbHB[i]; - } - avgProbSpeechHB = avgProbSpeechHB / ((float)deltaBweHB); - // average filter gain from low band - // average over second half (i.e., 4->8kHz) of freq. spectrum - avgFilterGainHB = 0.0; - for (i = inst->magnLen - deltaGainHB - 1; i < inst->magnLen - 1; i++) - { - avgFilterGainHB += inst->smooth[i]; - } - avgFilterGainHB = avgFilterGainHB / ((float)(deltaGainHB)); - avgProbSpeechHBTmp = (float)2.0 * avgProbSpeechHB - (float)1.0; - // gain based on speech prob: - gainModHB = (float)0.5 * ((float)1.0 + (float)tanh(gainMapParHB * avgProbSpeechHBTmp)); - //combine gain with low band gain - gainTimeDomainHB = (float)0.5 * gainModHB + (float)0.5 * avgFilterGainHB; - if (avgProbSpeechHB >= (float)0.5) - { - gainTimeDomainHB = (float)0.25 * gainModHB + (float)0.75 * avgFilterGainHB; - } - gainTimeDomainHB = gainTimeDomainHB * decayBweHB; - } // end of converged - //make sure gain is within flooring range - // flooring bottom - if (gainTimeDomainHB < inst->denoiseBound) - { - gainTimeDomainHB = inst->denoiseBound; - } - // flooring top - if (gainTimeDomainHB > (float)1.0) - { - gainTimeDomainHB = 1.0; - } - //apply gain - for (i = 0; i < inst->blockLen10ms; i++) - { - dTmp = gainTimeDomainHB * inst->dataBufHB[i]; - if (dTmp < WEBRTC_SPL_WORD16_MIN) - { - dTmp = WEBRTC_SPL_WORD16_MIN; - } - else if (dTmp > WEBRTC_SPL_WORD16_MAX) - { - dTmp = WEBRTC_SPL_WORD16_MAX; - } - outFrameHB[i] = (short)dTmp; - } - } // end of H band gain computation - // + // for time-domain gain of HB + if (flagHB == 1) { + for (i = 0; i < inst->magnLen; i++) { + inst->speechProbHB[i] = probSpeechFinal[i]; + } + if (inst->blockInd > END_STARTUP_LONG) { + // average speech prob from low band + // avg over second half (i.e., 4->8kHz) of freq. spectrum + avgProbSpeechHB = 0.0; + for (i = inst->magnLen - deltaBweHB - 1; i < inst->magnLen - 1; i++) { + avgProbSpeechHB += inst->speechProbHB[i]; + } + avgProbSpeechHB = avgProbSpeechHB / ((float)deltaBweHB); + // average filter gain from low band + // average over second half (i.e., 4->8kHz) of freq. spectrum + avgFilterGainHB = 0.0; + for (i = inst->magnLen - deltaGainHB - 1; i < inst->magnLen - 1; i++) { + avgFilterGainHB += inst->smooth[i]; + } + avgFilterGainHB = avgFilterGainHB / ((float)(deltaGainHB)); + avgProbSpeechHBTmp = (float)2.0 * avgProbSpeechHB - (float)1.0; + // gain based on speech prob: + gainModHB = (float)0.5 * ((float)1.0 + (float)tanh(gainMapParHB * avgProbSpeechHBTmp)); + //combine gain with low band gain + gainTimeDomainHB = (float)0.5 * gainModHB + (float)0.5 * avgFilterGainHB; + if (avgProbSpeechHB >= (float)0.5) { + gainTimeDomainHB = (float)0.25 * gainModHB + (float)0.75 * avgFilterGainHB; + } + gainTimeDomainHB = gainTimeDomainHB * decayBweHB; + } // end of converged + //make sure gain is within flooring range + // flooring bottom + if (gainTimeDomainHB < inst->denoiseBound) { + gainTimeDomainHB = inst->denoiseBound; + } + // flooring top + if (gainTimeDomainHB > (float)1.0) { + gainTimeDomainHB = 1.0; + } + //apply gain + for (i = 0; i < inst->blockLen10ms; i++) { + dTmp = gainTimeDomainHB * inst->dataBufHB[i]; + if (dTmp < WEBRTC_SPL_WORD16_MIN) { + dTmp = WEBRTC_SPL_WORD16_MIN; + } else if (dTmp > WEBRTC_SPL_WORD16_MAX) { + dTmp = WEBRTC_SPL_WORD16_MAX; + } + outFrameHB[i] = (short)dTmp; + } + } // end of H band gain computation + // - return 0; + return 0; } diff --git a/src/modules/audio_processing/ns/main/source/ns_core.h b/src/modules/audio_processing/ns/main/source/ns_core.h index f72e22b..2f4c34f 100644 --- a/src/modules/audio_processing/ns/main/source/ns_core.h +++ b/src/modules/audio_processing/ns/main/source/ns_core.h @@ -15,95 +15,95 @@ typedef struct NSParaExtract_t_ { - //bin size of histogram - float binSizeLrt; - float binSizeSpecFlat; - float binSizeSpecDiff; - //range of histogram over which lrt threshold is computed - float rangeAvgHistLrt; - //scale parameters: multiply dominant peaks of the histograms by scale factor to obtain - //thresholds for prior model - float factor1ModelPars; //for lrt and spectral difference - float factor2ModelPars; //for spectral_flatness: used when noise is flatter than speech - //peak limit for spectral flatness (varies between 0 and 1) - float thresPosSpecFlat; - //limit on spacing of two highest peaks in histogram: spacing determined by bin size - float limitPeakSpacingSpecFlat; - float limitPeakSpacingSpecDiff; - //limit on relevance of second peak: - float limitPeakWeightsSpecFlat; - float limitPeakWeightsSpecDiff; - //limit on fluctuation of lrt feature - float thresFluctLrt; - //limit on the max and min values for the feature thresholds - float maxLrt; - float minLrt; - float maxSpecFlat; - float minSpecFlat; - float maxSpecDiff; - float minSpecDiff; - //criteria of weight of histogram peak to accept/reject feature - int thresWeightSpecFlat; - int thresWeightSpecDiff; + //bin size of histogram + float binSizeLrt; + float binSizeSpecFlat; + float binSizeSpecDiff; + //range of histogram over which lrt threshold is computed + float rangeAvgHistLrt; + //scale parameters: multiply dominant peaks of the histograms by scale factor to obtain + //thresholds for prior model + float factor1ModelPars; //for lrt and spectral difference + float factor2ModelPars; //for spectral_flatness: used when noise is flatter than speech + //peak limit for spectral flatness (varies between 0 and 1) + float thresPosSpecFlat; + //limit on spacing of two highest peaks in histogram: spacing determined by bin size + float limitPeakSpacingSpecFlat; + float limitPeakSpacingSpecDiff; + //limit on relevance of second peak: + float limitPeakWeightsSpecFlat; + float limitPeakWeightsSpecDiff; + //limit on fluctuation of lrt feature + float thresFluctLrt; + //limit on the max and min values for the feature thresholds + float maxLrt; + float minLrt; + float maxSpecFlat; + float minSpecFlat; + float maxSpecDiff; + float minSpecDiff; + //criteria of weight of histogram peak to accept/reject feature + int thresWeightSpecFlat; + int thresWeightSpecDiff; } NSParaExtract_t; typedef struct NSinst_t_ { - WebRtc_UWord32 fs; - int blockLen; - int blockLen10ms; - int windShift; - int outLen; - int anaLen; - int magnLen; - int aggrMode; - const float* window; - float dataBuf[ANAL_BLOCKL_MAX]; - float syntBuf[ANAL_BLOCKL_MAX]; - float outBuf[3 * BLOCKL_MAX]; - - int initFlag; - // parameters for quantile noise estimation - float density[SIMULT * HALF_ANAL_BLOCKL]; - float lquantile[SIMULT * HALF_ANAL_BLOCKL]; - float quantile[HALF_ANAL_BLOCKL]; - int counter[SIMULT]; - int updates; - // parameters for Wiener filter - float smooth[HALF_ANAL_BLOCKL]; - float overdrive; - float denoiseBound; - int gainmap; - // fft work arrays. - int ip[IP_LENGTH]; - float wfft[W_LENGTH]; - - // parameters for new method: some not needed, will reduce/cleanup later - WebRtc_Word32 blockInd; //frame index counter - int modelUpdatePars[4]; //parameters for updating or estimating - // thresholds/weights for prior model - float priorModelPars[7]; //parameters for prior model - float noisePrev[HALF_ANAL_BLOCKL]; //noise spectrum from previous frame - float magnPrev[HALF_ANAL_BLOCKL]; //magnitude spectrum of previous frame - float logLrtTimeAvg[HALF_ANAL_BLOCKL]; //log lrt factor with time-smoothing - float priorSpeechProb; //prior speech/noise probability - float featureData[7]; //data for features - float magnAvgPause[HALF_ANAL_BLOCKL]; //conservative noise spectrum estimate - float signalEnergy; //energy of magn - float sumMagn; //sum of magn - float whiteNoiseLevel; //initial noise estimate - float initMagnEst[HALF_ANAL_BLOCKL]; //initial magnitude spectrum estimate - float pinkNoiseNumerator; //pink noise parameter: numerator - float pinkNoiseExp; //pink noise parameter: power of freq - NSParaExtract_t featureExtractionParams; //parameters for feature extraction - //histograms for parameter estimation - int histLrt[HIST_PAR_EST]; - int histSpecFlat[HIST_PAR_EST]; - int histSpecDiff[HIST_PAR_EST]; - //quantities for high band estimate - float speechProbHB[HALF_ANAL_BLOCKL]; //final speech/noise prob: prior + LRT - float dataBufHB[ANAL_BLOCKL_MAX]; //buffering data for HB + WebRtc_UWord32 fs; + int blockLen; + int blockLen10ms; + int windShift; + int outLen; + int anaLen; + int magnLen; + int aggrMode; + const float* window; + float dataBuf[ANAL_BLOCKL_MAX]; + float syntBuf[ANAL_BLOCKL_MAX]; + float outBuf[3 * BLOCKL_MAX]; + + int initFlag; + // parameters for quantile noise estimation + float density[SIMULT* HALF_ANAL_BLOCKL]; + float lquantile[SIMULT* HALF_ANAL_BLOCKL]; + float quantile[HALF_ANAL_BLOCKL]; + int counter[SIMULT]; + int updates; + // parameters for Wiener filter + float smooth[HALF_ANAL_BLOCKL]; + float overdrive; + float denoiseBound; + int gainmap; + // fft work arrays. + int ip[IP_LENGTH]; + float wfft[W_LENGTH]; + + // parameters for new method: some not needed, will reduce/cleanup later + WebRtc_Word32 blockInd; //frame index counter + int modelUpdatePars[4]; //parameters for updating or estimating + // thresholds/weights for prior model + float priorModelPars[7]; //parameters for prior model + float noisePrev[HALF_ANAL_BLOCKL]; //noise spectrum from previous frame + float magnPrev[HALF_ANAL_BLOCKL]; //magnitude spectrum of previous frame + float logLrtTimeAvg[HALF_ANAL_BLOCKL]; //log lrt factor with time-smoothing + float priorSpeechProb; //prior speech/noise probability + float featureData[7]; //data for features + float magnAvgPause[HALF_ANAL_BLOCKL]; //conservative noise spectrum estimate + float signalEnergy; //energy of magn + float sumMagn; //sum of magn + float whiteNoiseLevel; //initial noise estimate + float initMagnEst[HALF_ANAL_BLOCKL]; //initial magnitude spectrum estimate + float pinkNoiseNumerator; //pink noise parameter: numerator + float pinkNoiseExp; //pink noise parameter: power of freq + NSParaExtract_t featureExtractionParams; //parameters for feature extraction + //histograms for parameter estimation + int histLrt[HIST_PAR_EST]; + int histSpecFlat[HIST_PAR_EST]; + int histSpecDiff[HIST_PAR_EST]; + //quantities for high band estimate + float speechProbHB[HALF_ANAL_BLOCKL]; //final speech/noise prob: prior + LRT + float dataBufHB[ANAL_BLOCKL_MAX]; //buffering data for HB } NSinst_t; @@ -127,7 +127,7 @@ extern "C" { * Return value : 0 - Ok * -1 - Error */ -int WebRtcNs_InitCore(NSinst_t *inst, WebRtc_UWord32 fs); +int WebRtcNs_InitCore(NSinst_t* inst, WebRtc_UWord32 fs); /**************************************************************************** * WebRtcNs_set_policy_core(...) @@ -144,7 +144,7 @@ int WebRtcNs_InitCore(NSinst_t *inst, WebRtc_UWord32 fs); * Return value : 0 - Ok * -1 - Error */ -int WebRtcNs_set_policy_core(NSinst_t *inst, int mode); +int WebRtcNs_set_policy_core(NSinst_t* inst, int mode); /**************************************************************************** * WebRtcNs_ProcessCore @@ -166,11 +166,11 @@ int WebRtcNs_set_policy_core(NSinst_t *inst, int mode); */ -int WebRtcNs_ProcessCore(NSinst_t *inst, - short *inFrameLow, - short *inFrameHigh, - short *outFrameLow, - short *outFrameHigh); +int WebRtcNs_ProcessCore(NSinst_t* inst, + short* inFrameLow, + short* inFrameHigh, + short* outFrameLow, + short* outFrameHigh); #ifdef __cplusplus diff --git a/src/modules/audio_processing/ns/main/source/nsx_core.c b/src/modules/audio_processing/ns/main/source/nsx_core.c index f499cbe..967d849 100644 --- a/src/modules/audio_processing/ns/main/source/nsx_core.c +++ b/src/modules/audio_processing/ns/main/source/nsx_core.c @@ -14,71 +14,72 @@ #include <math.h> #include <string.h> #include <stdlib.h> +#include <stdio.h> #include "nsx_core.h" // Skip first frequency bins during estimation. (0 <= value < 64) static const int kStartBand = 5; -// Rounding -static const WebRtc_Word16 kRoundTable[16] = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, - 2048, 4096, 8192, 16384}; - // Constants to compensate for shifting signal log(2^shifts). -const WebRtc_Word16 WebRtcNsx_kLogTable[9] = {0, 177, 355, 532, 710, 887, 1065, 1242, 1420}; - -const WebRtc_Word16 WebRtcNsx_kCounterDiv[201] = {32767, 16384, 10923, 8192, 6554, 5461, 4681, - 4096, 3641, 3277, 2979, 2731, 2521, 2341, 2185, 2048, 1928, 1820, 1725, 1638, 1560, - 1489, 1425, 1365, 1311, 1260, 1214, 1170, 1130, 1092, 1057, 1024, 993, 964, 936, 910, - 886, 862, 840, 819, 799, 780, 762, 745, 728, 712, 697, 683, 669, 655, 643, 630, 618, - 607, 596, 585, 575, 565, 555, 546, 537, 529, 520, 512, 504, 496, 489, 482, 475, 468, - 462, 455, 449, 443, 437, 431, 426, 420, 415, 410, 405, 400, 395, 390, 386, 381, 377, - 372, 368, 364, 360, 356, 352, 349, 345, 341, 338, 334, 331, 328, 324, 321, 318, 315, - 312, 309, 306, 303, 301, 298, 295, 293, 290, 287, 285, 282, 280, 278, 275, 273, 271, - 269, 266, 264, 262, 260, 258, 256, 254, 252, 250, 248, 246, 245, 243, 241, 239, 237, - 236, 234, 232, 231, 229, 228, 226, 224, 223, 221, 220, 218, 217, 216, 214, 213, 211, - 210, 209, 207, 206, 205, 204, 202, 201, 200, 199, 197, 196, 195, 194, 193, 192, 191, - 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, - 172, 172, 171, 170, 169, 168, 167, 166, 165, 165, 164, 163}; +const WebRtc_Word16 WebRtcNsx_kLogTable[9] = { + 0, 177, 355, 532, 710, 887, 1065, 1242, 1420 +}; + +const WebRtc_Word16 WebRtcNsx_kCounterDiv[201] = { + 32767, 16384, 10923, 8192, 6554, 5461, 4681, + 4096, 3641, 3277, 2979, 2731, 2521, 2341, 2185, 2048, 1928, 1820, 1725, 1638, 1560, + 1489, 1425, 1365, 1311, 1260, 1214, 1170, 1130, 1092, 1057, 1024, 993, 964, 936, 910, + 886, 862, 840, 819, 799, 780, 762, 745, 728, 712, 697, 683, 669, 655, 643, 630, 618, + 607, 596, 585, 575, 565, 555, 546, 537, 529, 520, 512, 504, 496, 489, 482, 475, 468, + 462, 455, 449, 443, 437, 431, 426, 420, 415, 410, 405, 400, 395, 390, 386, 381, 377, + 372, 368, 364, 360, 356, 352, 349, 345, 341, 338, 334, 331, 328, 324, 321, 318, 315, + 312, 309, 306, 303, 301, 298, 295, 293, 290, 287, 285, 282, 280, 278, 275, 273, 271, + 269, 266, 264, 262, 260, 258, 256, 254, 252, 250, 248, 246, 245, 243, 241, 239, 237, + 236, 234, 232, 231, 229, 228, 226, 224, 223, 221, 220, 218, 217, 216, 214, 213, 211, + 210, 209, 207, 206, 205, 204, 202, 201, 200, 199, 197, 196, 195, 194, 193, 192, 191, + 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, + 172, 172, 171, 170, 169, 168, 167, 166, 165, 165, 164, 163 +}; const WebRtc_Word16 WebRtcNsx_kLogTableFrac[256] = { - 0, 1, 3, 4, 6, 7, 9, 10, 11, 13, 14, 16, 17, 18, 20, 21, - 22, 24, 25, 26, 28, 29, 30, 32, 33, 34, 36, 37, 38, 40, 41, 42, - 44, 45, 46, 47, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, - 63, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, - 82, 84, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 178, - 179, 180, 181, 182, 183, 184, 185, 185, 186, 187, 188, 189, 190, 191, 192, 192, - 193, 194, 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206, - 207, 208, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 216, 217, 218, 219, - 220, 220, 221, 222, 223, 224, 224, 225, 226, 227, 228, 228, 229, 230, 231, 231, - 232, 233, 234, 234, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243, 244, - 244, 245, 246, 247, 247, 248, 249, 249, 250, 251, 252, 252, 253, 254, 255, 255 + 0, 1, 3, 4, 6, 7, 9, 10, 11, 13, 14, 16, 17, 18, 20, 21, + 22, 24, 25, 26, 28, 29, 30, 32, 33, 34, 36, 37, 38, 40, 41, 42, + 44, 45, 46, 47, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, + 63, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, + 82, 84, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 178, + 179, 180, 181, 182, 183, 184, 185, 185, 186, 187, 188, 189, 190, 191, 192, 192, + 193, 194, 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206, + 207, 208, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 216, 217, 218, 219, + 220, 220, 221, 222, 223, 224, 224, 225, 226, 227, 228, 228, 229, 230, 231, 231, + 232, 233, 234, 234, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243, 244, + 244, 245, 246, 247, 247, 248, 249, 249, 250, 251, 252, 252, 253, 254, 255, 255 }; static const WebRtc_Word16 kPowTableFrac[1024] = { - 0, 1, 1, 2, 3, 3, 4, 5, - 6, 6, 7, 8, 8, 9, 10, 10, - 11, 12, 13, 13, 14, 15, 15, 16, - 17, 17, 18, 19, 20, 20, 21, 22, - 22, 23, 24, 25, 25, 26, 27, 27, - 28, 29, 30, 30, 31, 32, 32, 33, - 34, 35, 35, 36, 37, 37, 38, 39, - 40, 40, 41, 42, 42, 43, 44, 45, - 45, 46, 47, 48, 48, 49, 50, 50, - 51, 52, 53, 53, 54, 55, 56, 56, - 57, 58, 58, 59, 60, 61, 61, 62, - 63, 64, 64, 65, 66, 67, 67, 68, - 69, 69, 70, 71, 72, 72, 73, 74, - 75, 75, 76, 77, 78, 78, 79, 80, - 81, 81, 82, 83, 84, 84, 85, 86, - 87, 87, 88, 89, 90, 90, 91, 92, - 93, 93, 94, 95, 96, 96, 97, 98, - 99, 100, 100, 101, 102, 103, 103, 104, + 0, 1, 1, 2, 3, 3, 4, 5, + 6, 6, 7, 8, 8, 9, 10, 10, + 11, 12, 13, 13, 14, 15, 15, 16, + 17, 17, 18, 19, 20, 20, 21, 22, + 22, 23, 24, 25, 25, 26, 27, 27, + 28, 29, 30, 30, 31, 32, 32, 33, + 34, 35, 35, 36, 37, 37, 38, 39, + 40, 40, 41, 42, 42, 43, 44, 45, + 45, 46, 47, 48, 48, 49, 50, 50, + 51, 52, 53, 53, 54, 55, 56, 56, + 57, 58, 58, 59, 60, 61, 61, 62, + 63, 64, 64, 65, 66, 67, 67, 68, + 69, 69, 70, 71, 72, 72, 73, 74, + 75, 75, 76, 77, 78, 78, 79, 80, + 81, 81, 82, 83, 84, 84, 85, 86, + 87, 87, 88, 89, 90, 90, 91, 92, + 93, 93, 94, 95, 96, 96, 97, 98, + 99, 100, 100, 101, 102, 103, 103, 104, 105, 106, 106, 107, 108, 109, 109, 110, 111, 112, 113, 113, 114, 115, 116, 116, 117, 118, 119, 119, 120, 121, 122, 123, @@ -187,609 +188,612 @@ static const WebRtc_Word16 kPowTableFrac[1024] = { 969, 971, 972, 973, 975, 976, 977, 979, 980, 981, 983, 984, 986, 987, 988, 990, 991, 992, 994, 995, 996, 998, 999, 1001, - 1002, 1003, 1005, 1006, 1007, 1009, 1010, 1012, - 1013, 1014, 1016, 1017, 1018, 1020, 1021, 1023 + 1002, 1003, 1005, 1006, 1007, 1009, 1010, 1012, + 1013, 1014, 1016, 1017, 1018, 1020, 1021, 1023 }; -static const WebRtc_Word16 kIndicatorTable[17] = {0, 2017, 3809, 5227, 6258, 6963, 7424, 7718, - 7901, 8014, 8084, 8126, 8152, 8168, 8177, 8183, 8187}; +static const WebRtc_Word16 kIndicatorTable[17] = { + 0, 2017, 3809, 5227, 6258, 6963, 7424, 7718, + 7901, 8014, 8084, 8126, 8152, 8168, 8177, 8183, 8187 +}; // hybrib Hanning & flat window static const WebRtc_Word16 kBlocks80w128x[128] = { - 0, 536, 1072, 1606, 2139, 2669, 3196, 3720, 4240, 4756, 5266, - 5771, 6270, 6762, 7246, 7723, 8192, 8652, 9102, 9543, 9974, 10394, - 10803, 11200, 11585, 11958, 12318, 12665, 12998, 13318, 13623, 13913, 14189, - 14449, 14694, 14924, 15137, 15334, 15515, 15679, 15826, 15956, 16069, 16165, - 16244, 16305, 16349, 16375, 16384, 16384, 16384, 16384, 16384, 16384, 16384, - 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, - 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, - 16384, 16384, 16384, 16384, 16375, 16349, 16305, 16244, 16165, 16069, 15956, - 15826, 15679, 15515, 15334, 15137, 14924, 14694, 14449, 14189, 13913, 13623, - 13318, 12998, 12665, 12318, 11958, 11585, 11200, 10803, 10394, 9974, 9543, - 9102, 8652, 8192, 7723, 7246, 6762, 6270, 5771, 5266, 4756, 4240, - 3720, 3196, 2669, 2139, 1606, 1072, 536 + 0, 536, 1072, 1606, 2139, 2669, 3196, 3720, 4240, 4756, 5266, + 5771, 6270, 6762, 7246, 7723, 8192, 8652, 9102, 9543, 9974, 10394, + 10803, 11200, 11585, 11958, 12318, 12665, 12998, 13318, 13623, 13913, 14189, + 14449, 14694, 14924, 15137, 15334, 15515, 15679, 15826, 15956, 16069, 16165, + 16244, 16305, 16349, 16375, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16375, 16349, 16305, 16244, 16165, 16069, 15956, + 15826, 15679, 15515, 15334, 15137, 14924, 14694, 14449, 14189, 13913, 13623, + 13318, 12998, 12665, 12318, 11958, 11585, 11200, 10803, 10394, 9974, 9543, + 9102, 8652, 8192, 7723, 7246, 6762, 6270, 5771, 5266, 4756, 4240, + 3720, 3196, 2669, 2139, 1606, 1072, 536 }; // hybrib Hanning & flat window static const WebRtc_Word16 kBlocks160w256x[256] = { - 0, 268, 536, 804, 1072, 1339, 1606, 1872, - 2139, 2404, 2669, 2933, 3196, 3459, 3720, 3981, - 4240, 4499, 4756, 5012, 5266, 5520, 5771, 6021, - 6270, 6517, 6762, 7005, 7246, 7486, 7723, 7959, - 8192, 8423, 8652, 8878, 9102, 9324, 9543, 9760, - 9974, 10185, 10394, 10600, 10803, 11003, 11200, 11394, -11585, 11773, 11958, 12140, 12318, 12493, 12665, 12833, -12998, 13160, 13318, 13472, 13623, 13770, 13913, 14053, -14189, 14321, 14449, 14574, 14694, 14811, 14924, 15032, -15137, 15237, 15334, 15426, 15515, 15599, 15679, 15754, -15826, 15893, 15956, 16015, 16069, 16119, 16165, 16207, -16244, 16277, 16305, 16329, 16349, 16364, 16375, 16382, -16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, -16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, -16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, -16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, -16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, -16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, -16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, -16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, -16384, 16382, 16375, 16364, 16349, 16329, 16305, 16277, -16244, 16207, 16165, 16119, 16069, 16015, 15956, 15893, -15826, 15754, 15679, 15599, 15515, 15426, 15334, 15237, -15137, 15032, 14924, 14811, 14694, 14574, 14449, 14321, -14189, 14053, 13913, 13770, 13623, 13472, 13318, 13160, -12998, 12833, 12665, 12493, 12318, 12140, 11958, 11773, -11585, 11394, 11200, 11003, 10803, 10600, 10394, 10185, - 9974, 9760, 9543, 9324, 9102, 8878, 8652, 8423, - 8192, 7959, 7723, 7486, 7246, 7005, 6762, 6517, - 6270, 6021, 5771, 5520, 5266, 5012, 4756, 4499, - 4240, 3981, 3720, 3459, 3196, 2933, 2669, 2404, - 2139, 1872, 1606, 1339, 1072, 804, 536, 268 + 0, 268, 536, 804, 1072, 1339, 1606, 1872, + 2139, 2404, 2669, 2933, 3196, 3459, 3720, 3981, + 4240, 4499, 4756, 5012, 5266, 5520, 5771, 6021, + 6270, 6517, 6762, 7005, 7246, 7486, 7723, 7959, + 8192, 8423, 8652, 8878, 9102, 9324, 9543, 9760, + 9974, 10185, 10394, 10600, 10803, 11003, 11200, 11394, + 11585, 11773, 11958, 12140, 12318, 12493, 12665, 12833, + 12998, 13160, 13318, 13472, 13623, 13770, 13913, 14053, + 14189, 14321, 14449, 14574, 14694, 14811, 14924, 15032, + 15137, 15237, 15334, 15426, 15515, 15599, 15679, 15754, + 15826, 15893, 15956, 16015, 16069, 16119, 16165, 16207, + 16244, 16277, 16305, 16329, 16349, 16364, 16375, 16382, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16382, 16375, 16364, 16349, 16329, 16305, 16277, + 16244, 16207, 16165, 16119, 16069, 16015, 15956, 15893, + 15826, 15754, 15679, 15599, 15515, 15426, 15334, 15237, + 15137, 15032, 14924, 14811, 14694, 14574, 14449, 14321, + 14189, 14053, 13913, 13770, 13623, 13472, 13318, 13160, + 12998, 12833, 12665, 12493, 12318, 12140, 11958, 11773, + 11585, 11394, 11200, 11003, 10803, 10600, 10394, 10185, + 9974, 9760, 9543, 9324, 9102, 8878, 8652, 8423, + 8192, 7959, 7723, 7486, 7246, 7005, 6762, 6517, + 6270, 6021, 5771, 5520, 5266, 5012, 4756, 4499, + 4240, 3981, 3720, 3459, 3196, 2933, 2669, 2404, + 2139, 1872, 1606, 1339, 1072, 804, 536, 268 }; -// Gain factor table: Input value in Q8 and output value in Q13 +// Gain factor1 table: Input value in Q8 and output value in Q13 +// original floating point code +// if (gain > blim) { +// factor1 = 1.0 + 1.3 * (gain - blim); +// if (gain * factor1 > 1.0) { +// factor1 = 1.0 / gain; +// } +// } else { +// factor1 = 1.0; +// } static const WebRtc_Word16 kFactor1Table[257] = { - 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8233, 8274, 8315, 8355, 8396, 8436, 8475, 8515, 8554, 8592, 8631, 8669, - 8707, 8745, 8783, 8820, 8857, 8894, 8931, 8967, 9003, 9039, 9075, 9111, 9146, 9181, - 9216, 9251, 9286, 9320, 9354, 9388, 9422, 9456, 9489, 9523, 9556, 9589, 9622, 9655, - 9687, 9719, 9752, 9784, 9816, 9848, 9879, 9911, 9942, 9973, 10004, 10035, 10066, - 10097, 10128, 10158, 10188, 10218, 10249, 10279, 10308, 10338, 10368, 10397, 10426, - 10456, 10485, 10514, 10543, 10572, 10600, 10629, 10657, 10686, 10714, 10742, 10770, - 10798, 10826, 10854, 10882, 10847, 10810, 10774, 10737, 10701, 10666, 10631, 10596, - 10562, 10527, 10494, 10460, 10427, 10394, 10362, 10329, 10297, 10266, 10235, 10203, - 10173, 10142, 10112, 10082, 10052, 10023, 9994, 9965, 9936, 9908, 9879, 9851, 9824, - 9796, 9769, 9742, 9715, 9689, 9662, 9636, 9610, 9584, 9559, 9534, 9508, 9484, 9459, - 9434, 9410, 9386, 9362, 9338, 9314, 9291, 9268, 9245, 9222, 9199, 9176, 9154, 9132, - 9110, 9088, 9066, 9044, 9023, 9002, 8980, 8959, 8939, 8918, 8897, 8877, 8857, 8836, - 8816, 8796, 8777, 8757, 8738, 8718, 8699, 8680, 8661, 8642, 8623, 8605, 8586, 8568, - 8550, 8532, 8514, 8496, 8478, 8460, 8443, 8425, 8408, 8391, 8373, 8356, 8339, 8323, - 8306, 8289, 8273, 8256, 8240, 8224, 8208, 8192 + 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8233, 8274, 8315, 8355, 8396, 8436, 8475, 8515, 8554, 8592, 8631, 8669, + 8707, 8745, 8783, 8820, 8857, 8894, 8931, 8967, 9003, 9039, 9075, 9111, 9146, 9181, + 9216, 9251, 9286, 9320, 9354, 9388, 9422, 9456, 9489, 9523, 9556, 9589, 9622, 9655, + 9687, 9719, 9752, 9784, 9816, 9848, 9879, 9911, 9942, 9973, 10004, 10035, 10066, + 10097, 10128, 10158, 10188, 10218, 10249, 10279, 10308, 10338, 10368, 10397, 10426, + 10456, 10485, 10514, 10543, 10572, 10600, 10629, 10657, 10686, 10714, 10742, 10770, + 10798, 10826, 10854, 10882, 10847, 10810, 10774, 10737, 10701, 10666, 10631, 10596, + 10562, 10527, 10494, 10460, 10427, 10394, 10362, 10329, 10297, 10266, 10235, 10203, + 10173, 10142, 10112, 10082, 10052, 10023, 9994, 9965, 9936, 9908, 9879, 9851, 9824, + 9796, 9769, 9742, 9715, 9689, 9662, 9636, 9610, 9584, 9559, 9534, 9508, 9484, 9459, + 9434, 9410, 9386, 9362, 9338, 9314, 9291, 9268, 9245, 9222, 9199, 9176, 9154, 9132, + 9110, 9088, 9066, 9044, 9023, 9002, 8980, 8959, 8939, 8918, 8897, 8877, 8857, 8836, + 8816, 8796, 8777, 8757, 8738, 8718, 8699, 8680, 8661, 8642, 8623, 8605, 8586, 8568, + 8550, 8532, 8514, 8496, 8478, 8460, 8443, 8425, 8408, 8391, 8373, 8356, 8339, 8323, + 8306, 8289, 8273, 8256, 8240, 8224, 8208, 8192 }; +// For Factor2 tables +// original floating point code +// if (gain > blim) { +// factor2 = 1.0; +// } else { +// factor2 = 1.0 - 0.3 * (blim - gain); +// if (gain <= inst->denoiseBound) { +// factor2 = 1.0 - 0.3 * (blim - inst->denoiseBound); +// } +// } +// // Gain factor table: Input value in Q8 and output value in Q13 static const WebRtc_Word16 kFactor2Aggressiveness1[257] = { - 7577, 7577, 7577, 7577, 7577, 7577, - 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7596, 7614, 7632, - 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, - 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016, - 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162, - 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192 + 7577, 7577, 7577, 7577, 7577, 7577, + 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7596, 7614, 7632, + 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, + 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016, + 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162, + 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192 }; // Gain factor table: Input value in Q8 and output value in Q13 static const WebRtc_Word16 kFactor2Aggressiveness2[257] = { - 7270, 7270, 7270, 7270, 7270, 7306, - 7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632, - 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, - 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016, - 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162, - 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192 + 7270, 7270, 7270, 7270, 7270, 7306, + 7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632, + 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, + 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016, + 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162, + 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192 }; // Gain factor table: Input value in Q8 and output value in Q13 static const WebRtc_Word16 kFactor2Aggressiveness3[257] = { - 7184, 7184, 7184, 7229, 7270, 7306, - 7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632, - 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, - 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016, - 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162, - 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192 + 7184, 7184, 7184, 7229, 7270, 7306, + 7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632, + 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, + 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016, + 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162, + 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192 }; // sum of log2(i) from table index to inst->anaLen2 in Q5 // Note that the first table value is invalid, since log2(0) = -infinity static const WebRtc_Word16 kSumLogIndex[66] = { - 0, 22917, 22917, 22885, 22834, 22770, 22696, 22613, - 22524, 22428, 22326, 22220, 22109, 21994, 21876, 21754, - 21629, 21501, 21370, 21237, 21101, 20963, 20822, 20679, - 20535, 20388, 20239, 20089, 19937, 19783, 19628, 19470, - 19312, 19152, 18991, 18828, 18664, 18498, 18331, 18164, - 17994, 17824, 17653, 17480, 17306, 17132, 16956, 16779, - 16602, 16423, 16243, 16063, 15881, 15699, 15515, 15331, - 15146, 14960, 14774, 14586, 14398, 14209, 14019, 13829, - 13637, 13445 + 0, 22917, 22917, 22885, 22834, 22770, 22696, 22613, + 22524, 22428, 22326, 22220, 22109, 21994, 21876, 21754, + 21629, 21501, 21370, 21237, 21101, 20963, 20822, 20679, + 20535, 20388, 20239, 20089, 19937, 19783, 19628, 19470, + 19312, 19152, 18991, 18828, 18664, 18498, 18331, 18164, + 17994, 17824, 17653, 17480, 17306, 17132, 16956, 16779, + 16602, 16423, 16243, 16063, 15881, 15699, 15515, 15331, + 15146, 14960, 14774, 14586, 14398, 14209, 14019, 13829, + 13637, 13445 }; // sum of log2(i)^2 from table index to inst->anaLen2 in Q2 // Note that the first table value is invalid, since log2(0) = -infinity static const WebRtc_Word16 kSumSquareLogIndex[66] = { - 0, 16959, 16959, 16955, 16945, 16929, 16908, 16881, - 16850, 16814, 16773, 16729, 16681, 16630, 16575, 16517, - 16456, 16392, 16325, 16256, 16184, 16109, 16032, 15952, - 15870, 15786, 15700, 15612, 15521, 15429, 15334, 15238, - 15140, 15040, 14938, 14834, 14729, 14622, 14514, 14404, - 14292, 14179, 14064, 13947, 13830, 13710, 13590, 13468, - 13344, 13220, 13094, 12966, 12837, 12707, 12576, 12444, - 12310, 12175, 12039, 11902, 11763, 11624, 11483, 11341, - 11198, 11054 + 0, 16959, 16959, 16955, 16945, 16929, 16908, 16881, + 16850, 16814, 16773, 16729, 16681, 16630, 16575, 16517, + 16456, 16392, 16325, 16256, 16184, 16109, 16032, 15952, + 15870, 15786, 15700, 15612, 15521, 15429, 15334, 15238, + 15140, 15040, 14938, 14834, 14729, 14622, 14514, 14404, + 14292, 14179, 14064, 13947, 13830, 13710, 13590, 13468, + 13344, 13220, 13094, 12966, 12837, 12707, 12576, 12444, + 12310, 12175, 12039, 11902, 11763, 11624, 11483, 11341, + 11198, 11054 }; // log2(table index) in Q12 // Note that the first table value is invalid, since log2(0) = -infinity static const WebRtc_Word16 kLogIndex[129] = { - 0, 0, 4096, 6492, 8192, 9511, 10588, 11499, - 12288, 12984, 13607, 14170, 14684, 15157, 15595, 16003, - 16384, 16742, 17080, 17400, 17703, 17991, 18266, 18529, - 18780, 19021, 19253, 19476, 19691, 19898, 20099, 20292, - 20480, 20662, 20838, 21010, 21176, 21338, 21496, 21649, - 21799, 21945, 22087, 22226, 22362, 22495, 22625, 22752, - 22876, 22998, 23117, 23234, 23349, 23462, 23572, 23680, - 23787, 23892, 23994, 24095, 24195, 24292, 24388, 24483, - 24576, 24668, 24758, 24847, 24934, 25021, 25106, 25189, - 25272, 25354, 25434, 25513, 25592, 25669, 25745, 25820, - 25895, 25968, 26041, 26112, 26183, 26253, 26322, 26390, - 26458, 26525, 26591, 26656, 26721, 26784, 26848, 26910, - 26972, 27033, 27094, 27154, 27213, 27272, 27330, 27388, - 27445, 27502, 27558, 27613, 27668, 27722, 27776, 27830, - 27883, 27935, 27988, 28039, 28090, 28141, 28191, 28241, - 28291, 28340, 28388, 28437, 28484, 28532, 28579, 28626, - 28672 + 0, 0, 4096, 6492, 8192, 9511, 10588, 11499, + 12288, 12984, 13607, 14170, 14684, 15157, 15595, 16003, + 16384, 16742, 17080, 17400, 17703, 17991, 18266, 18529, + 18780, 19021, 19253, 19476, 19691, 19898, 20099, 20292, + 20480, 20662, 20838, 21010, 21176, 21338, 21496, 21649, + 21799, 21945, 22087, 22226, 22362, 22495, 22625, 22752, + 22876, 22998, 23117, 23234, 23349, 23462, 23572, 23680, + 23787, 23892, 23994, 24095, 24195, 24292, 24388, 24483, + 24576, 24668, 24758, 24847, 24934, 25021, 25106, 25189, + 25272, 25354, 25434, 25513, 25592, 25669, 25745, 25820, + 25895, 25968, 26041, 26112, 26183, 26253, 26322, 26390, + 26458, 26525, 26591, 26656, 26721, 26784, 26848, 26910, + 26972, 27033, 27094, 27154, 27213, 27272, 27330, 27388, + 27445, 27502, 27558, 27613, 27668, 27722, 27776, 27830, + 27883, 27935, 27988, 28039, 28090, 28141, 28191, 28241, + 28291, 28340, 28388, 28437, 28484, 28532, 28579, 28626, + 28672 }; // determinant of estimation matrix in Q0 corresponding to the log2 tables above // Note that the first table value is invalid, since log2(0) = -infinity static const WebRtc_Word16 kDeterminantEstMatrix[66] = { - 0, 29814, 25574, 22640, 20351, 18469, 16873, 15491, - 14277, 13199, 12233, 11362, 10571, 9851, 9192, 8587, - 8030, 7515, 7038, 6596, 6186, 5804, 5448, 5115, - 4805, 4514, 4242, 3988, 3749, 3524, 3314, 3116, - 2930, 2755, 2590, 2435, 2289, 2152, 2022, 1900, - 1785, 1677, 1575, 1478, 1388, 1302, 1221, 1145, - 1073, 1005, 942, 881, 825, 771, 721, 674, - 629, 587, 547, 510, 475, 442, 411, 382, - 355, 330 + 0, 29814, 25574, 22640, 20351, 18469, 16873, 15491, + 14277, 13199, 12233, 11362, 10571, 9851, 9192, 8587, + 8030, 7515, 7038, 6596, 6186, 5804, 5448, 5115, + 4805, 4514, 4242, 3988, 3749, 3524, 3314, 3116, + 2930, 2755, 2590, 2435, 2289, 2152, 2022, 1900, + 1785, 1677, 1575, 1478, 1388, 1302, 1221, 1145, + 1073, 1005, 942, 881, 825, 771, 721, 674, + 629, 587, 547, 510, 475, 442, 411, 382, + 355, 330 }; -void WebRtcNsx_UpdateNoiseEstimate(NsxInst_t *inst, int offset) -{ - WebRtc_Word32 tmp32no1 = 0; - WebRtc_Word32 tmp32no2 = 0; - - WebRtc_Word16 tmp16no1 = 0; - WebRtc_Word16 tmp16no2 = 0; - WebRtc_Word16 exp2Const = 11819; // Q13 - - int i = 0; - - tmp16no2 = WebRtcSpl_MaxValueW16(inst->noiseEstLogQuantile + offset, inst->magnLen); - inst->qNoise = 14 - - (int)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(exp2Const, tmp16no2, 21); - for (i = 0; i < inst->magnLen; i++) - { - // inst->quantile[i]=exp(inst->lquantile[offset+i]); - // in Q21 - tmp32no2 = WEBRTC_SPL_MUL_16_16(exp2Const, inst->noiseEstLogQuantile[offset + i]); - tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF)); - tmp16no1 = -(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no2, 21); - tmp16no1 += 21;// shift 21 to get result in Q0 - tmp16no1 -= (WebRtc_Word16)inst->qNoise; //shift to get result in Q(qNoise) - if (tmp16no1 > 0) - { - inst->noiseEstQuantile[i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1 + - kRoundTable[tmp16no1], tmp16no1); - } - else - { - inst->noiseEstQuantile[i] = (WebRtc_Word16)WEBRTC_SPL_LSHIFT_W32(tmp32no1, - -tmp16no1); - } +void WebRtcNsx_UpdateNoiseEstimate(NsxInst_t* inst, int offset) { + WebRtc_Word32 tmp32no1 = 0; + WebRtc_Word32 tmp32no2 = 0; + + WebRtc_Word16 tmp16no1 = 0; + WebRtc_Word16 tmp16no2 = 0; + const WebRtc_Word16 kExp2Const = 11819; // Q13 + + int i = 0; + + tmp16no2 = WebRtcSpl_MaxValueW16(inst->noiseEstLogQuantile + offset, + inst->magnLen); + // Guarantee a Q-domain as high as possible and still fit in int16 + inst->qNoise = 14 - (int) WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + kExp2Const, tmp16no2, 21); + for (i = 0; i < inst->magnLen; i++) { + // inst->quantile[i]=exp(inst->lquantile[offset+i]); + // in Q21 + tmp32no2 = WEBRTC_SPL_MUL_16_16(kExp2Const, + inst->noiseEstLogQuantile[offset + i]); + tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF)); // 2^21 + frac + tmp16no1 = -(WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32no2, 21); + tmp16no1 += 21;// shift 21 to get result in Q0 + tmp16no1 -= (WebRtc_Word16) inst->qNoise; //shift to get result in Q(qNoise) + if (tmp16no1 > 0) { + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1, tmp16no1); + } else { + tmp32no1 = WEBRTC_SPL_LSHIFT_W32(tmp32no1, -tmp16no1); + } + // TODO(bjornv): Replace with WebRtcSpl_SatW32ToW16(...) when available. + if (tmp32no1 > 32767) { + tmp32no1 = 32767; + } else if (tmp32no1 < -32768) { + tmp32no1 = -32768; } + tmp16no1 = (WebRtc_Word16) tmp32no1; + inst->noiseEstQuantile[i] = tmp16no1; + } } -void WebRtcNsx_CalcParametricNoiseEstimate(NsxInst_t *inst, +void WebRtcNsx_CalcParametricNoiseEstimate(NsxInst_t* inst, WebRtc_Word16 pink_noise_exp_avg, WebRtc_Word32 pink_noise_num_avg, int freq_index, - WebRtc_UWord32 *noise_estimate, - WebRtc_UWord32 *noise_estimate_avg) -{ - WebRtc_Word32 tmp32no1 = 0; - WebRtc_Word32 tmp32no2 = 0; - - WebRtc_Word16 int_part = 0; - WebRtc_Word16 frac_part = 0; - - // Use pink noise estimate - // noise_estimate = 2^(pinkNoiseNumerator + pinkNoiseExp * log2(j)) - assert(freq_index > 0); - tmp32no2 = WEBRTC_SPL_MUL_16_16(pink_noise_exp_avg, kLogIndex[freq_index]); // Q26 - tmp32no2 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, 15); // Q11 - tmp32no1 = pink_noise_num_avg - tmp32no2; // Q11 - - // Calculate output: 2^tmp32no1 - // Output in Q(minNorm-stages) - tmp32no1 += WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)(inst->minNorm - inst->stages), 11); - if (tmp32no1 > 0) - { - int_part = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 11); - frac_part = (WebRtc_Word16)(tmp32no1 & 0x000007ff); // Q11 - // Piecewise linear approximation of 'b' in - // 2^(int_part+frac_part) = 2^int_part * (1 + b) - // 'b' is given in Q11 and below stored in frac_part. - if (WEBRTC_SPL_RSHIFT_W32(frac_part, 10)) - { - // Upper fractional part - tmp32no2 = WEBRTC_SPL_MUL_32_16(2048 - frac_part, 1244); // Q21 - tmp32no2 = 2048 - WEBRTC_SPL_RSHIFT_W32(tmp32no2, 10); - } - else - { - // Lower fractional part - tmp32no2 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(frac_part, 804), 10); - } - // Shift fractional part to Q(minNorm-stages) - tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, int_part - 11); - *noise_estimate_avg = WEBRTC_SPL_LSHIFT_U32(1, int_part) + (WebRtc_UWord32)tmp32no2; - // Scale up to initMagnEst, which is not block averaged - *noise_estimate = (*noise_estimate_avg) * (WebRtc_UWord32)(inst->blockIndex + 1); + WebRtc_UWord32* noise_estimate, + WebRtc_UWord32* noise_estimate_avg) { + WebRtc_Word32 tmp32no1 = 0; + WebRtc_Word32 tmp32no2 = 0; + + WebRtc_Word16 int_part = 0; + WebRtc_Word16 frac_part = 0; + + // Use pink noise estimate + // noise_estimate = 2^(pinkNoiseNumerator + pinkNoiseExp * log2(j)) + assert(freq_index >= 0); + assert(freq_index < 129); + tmp32no2 = WEBRTC_SPL_MUL_16_16(pink_noise_exp_avg, kLogIndex[freq_index]); // Q26 + tmp32no2 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, 15); // Q11 + tmp32no1 = pink_noise_num_avg - tmp32no2; // Q11 + + // Calculate output: 2^tmp32no1 + // Output in Q(minNorm-stages) + tmp32no1 += WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)(inst->minNorm - inst->stages), 11); + if (tmp32no1 > 0) { + int_part = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 11); + frac_part = (WebRtc_Word16)(tmp32no1 & 0x000007ff); // Q11 + // Piecewise linear approximation of 'b' in + // 2^(int_part+frac_part) = 2^int_part * (1 + b) + // 'b' is given in Q11 and below stored in frac_part. + if (WEBRTC_SPL_RSHIFT_W16(frac_part, 10)) { + // Upper fractional part + tmp32no2 = WEBRTC_SPL_MUL_16_16(2048 - frac_part, 1244); // Q21 + tmp32no2 = 2048 - WEBRTC_SPL_RSHIFT_W32(tmp32no2, 10); + } else { + // Lower fractional part + tmp32no2 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(frac_part, 804), 10); } + // Shift fractional part to Q(minNorm-stages) + tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, int_part - 11); + *noise_estimate_avg = WEBRTC_SPL_LSHIFT_U32(1, int_part) + (WebRtc_UWord32)tmp32no2; + // Scale up to initMagnEst, which is not block averaged + *noise_estimate = (*noise_estimate_avg) * (WebRtc_UWord32)(inst->blockIndex + 1); + } } // Initialize state -WebRtc_Word32 WebRtcNsx_InitCore(NsxInst_t *inst, WebRtc_UWord32 fs) -{ - int i; - - //check for valid pointer - if (inst == NULL) - { - return -1; - } - // - - // Initialization of struct - if (fs == 8000 || fs == 16000 || fs == 32000) - { - inst->fs = fs; - } else - { - return -1; - } - - if (fs == 8000) - { - inst->blockLen10ms = 80; - inst->anaLen = 128; - inst->stages = 7; - inst->window = kBlocks80w128x; - inst->thresholdLogLrt = 131072; //default threshold for LRT feature - inst->maxLrt = 0x0040000; - inst->minLrt = 52429; - } else if (fs == 16000) - { - inst->blockLen10ms = 160; - inst->anaLen = 256; - inst->stages = 8; - inst->window = kBlocks160w256x; - inst->thresholdLogLrt = 212644; //default threshold for LRT feature - inst->maxLrt = 0x0080000; - inst->minLrt = 104858; - } else if (fs == 32000) - { - inst->blockLen10ms = 160; - inst->anaLen = 256; - inst->stages = 8; - inst->window = kBlocks160w256x; - inst->thresholdLogLrt = 212644; //default threshold for LRT feature - inst->maxLrt = 0x0080000; - inst->minLrt = 104858; - } - inst->anaLen2 = WEBRTC_SPL_RSHIFT_W16(inst->anaLen, 1); - inst->magnLen = inst->anaLen2 + 1; - - WebRtcSpl_ZerosArrayW16(inst->analysisBuffer, ANAL_BLOCKL_MAX); - WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer, ANAL_BLOCKL_MAX); - - // for HB processing - WebRtcSpl_ZerosArrayW16(inst->dataBufHBFX, ANAL_BLOCKL_MAX); - // for quantile noise estimation - WebRtcSpl_ZerosArrayW16(inst->noiseEstQuantile, HALF_ANAL_BLOCKL); - for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) - { - inst->noiseEstLogQuantile[i] = 2048; // Q8 - inst->noiseEstDensity[i] = 153; // Q9 - } - for (i = 0; i < SIMULT; i++) - { - inst->noiseEstCounter[i] = (WebRtc_Word16)(END_STARTUP_LONG * (i + 1)) / SIMULT; - } - - // Initialize suppression filter with ones - WebRtcSpl_MemSetW16((WebRtc_Word16*)inst->noiseSupFilter, 16384, HALF_ANAL_BLOCKL); - - // Set the aggressiveness: default - inst->aggrMode = 0; - - //initialize variables for new method - inst->priorNonSpeechProb = 8192; // Q14(0.5) prior probability for speech/noise - for (i = 0; i < HALF_ANAL_BLOCKL; i++) - { - inst->prevMagnU16[i] = 0; - inst->prevNoiseU32[i] = 0; //previous noise-spectrum - inst->logLrtTimeAvgW32[i] = 0; //smooth LR ratio - inst->avgMagnPause[i] = 0; //conservative noise spectrum estimate - inst->initMagnEst[i] = 0; //initial average magnitude spectrum - } - - //feature quantities - inst->thresholdSpecDiff = 50; //threshold for difference feature: determined on-line - inst->thresholdSpecFlat = 20480; //threshold for flatness: determined on-line - inst->featureLogLrt = inst->thresholdLogLrt; //average LRT factor (= threshold) - inst->featureSpecFlat = inst->thresholdSpecFlat; //spectral flatness (= threshold) - inst->featureSpecDiff = inst->thresholdSpecDiff; //spectral difference (= threshold) - inst->weightLogLrt = 6; //default weighting par for LRT feature - inst->weightSpecFlat = 0; //default weighting par for spectral flatness feature - inst->weightSpecDiff = 0; //default weighting par for spectral difference feature - - inst->curAvgMagnEnergy = 0; //window time-average of input magnitude spectrum - inst->timeAvgMagnEnergy = 0; //normalization for spectral difference - inst->timeAvgMagnEnergyTmp = 0; //normalization for spectral difference - - //histogram quantities: used to estimate/update thresholds for features - WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST); - WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST); - WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST); - - inst->blockIndex = -1; //frame counter - - //inst->modelUpdate = 500; //window for update - inst->modelUpdate = (1 << STAT_UPDATES); //window for update - inst->cntThresUpdate = 0; //counter feature thresholds updates - - inst->sumMagn = 0; - inst->magnEnergy = 0; - inst->prevQMagn = 0; - inst->qNoise = 0; - inst->prevQNoise = 0; - - inst->energyIn = 0; - inst->scaleEnergyIn = 0; - - inst->whiteNoiseLevel = 0; - inst->pinkNoiseNumerator = 0; - inst->pinkNoiseExp = 0; - inst->minNorm = 15; // Start with full scale - inst->zeroInputSignal = 0; - - //default mode - WebRtcNsx_set_policy_core(inst, 0); +WebRtc_Word32 WebRtcNsx_InitCore(NsxInst_t* inst, WebRtc_UWord32 fs) { + int i; + + //check for valid pointer + if (inst == NULL) { + return -1; + } + // + + // Initialization of struct + if (fs == 8000 || fs == 16000 || fs == 32000) { + inst->fs = fs; + } else { + return -1; + } + + if (fs == 8000) { + inst->blockLen10ms = 80; + inst->anaLen = 128; + inst->stages = 7; + inst->window = kBlocks80w128x; + inst->thresholdLogLrt = 131072; //default threshold for LRT feature + inst->maxLrt = 0x0040000; + inst->minLrt = 52429; + } else if (fs == 16000) { + inst->blockLen10ms = 160; + inst->anaLen = 256; + inst->stages = 8; + inst->window = kBlocks160w256x; + inst->thresholdLogLrt = 212644; //default threshold for LRT feature + inst->maxLrt = 0x0080000; + inst->minLrt = 104858; + } else if (fs == 32000) { + inst->blockLen10ms = 160; + inst->anaLen = 256; + inst->stages = 8; + inst->window = kBlocks160w256x; + inst->thresholdLogLrt = 212644; //default threshold for LRT feature + inst->maxLrt = 0x0080000; + inst->minLrt = 104858; + } + inst->anaLen2 = WEBRTC_SPL_RSHIFT_W16(inst->anaLen, 1); + inst->magnLen = inst->anaLen2 + 1; + + WebRtcSpl_ZerosArrayW16(inst->analysisBuffer, ANAL_BLOCKL_MAX); + WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer, ANAL_BLOCKL_MAX); + + // for HB processing + WebRtcSpl_ZerosArrayW16(inst->dataBufHBFX, ANAL_BLOCKL_MAX); + // for quantile noise estimation + WebRtcSpl_ZerosArrayW16(inst->noiseEstQuantile, HALF_ANAL_BLOCKL); + for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) { + inst->noiseEstLogQuantile[i] = 2048; // Q8 + inst->noiseEstDensity[i] = 153; // Q9 + } + for (i = 0; i < SIMULT; i++) { + inst->noiseEstCounter[i] = (WebRtc_Word16)(END_STARTUP_LONG * (i + 1)) / SIMULT; + } + + // Initialize suppression filter with ones + WebRtcSpl_MemSetW16((WebRtc_Word16*)inst->noiseSupFilter, 16384, HALF_ANAL_BLOCKL); + + // Set the aggressiveness: default + inst->aggrMode = 0; + + //initialize variables for new method + inst->priorNonSpeechProb = 8192; // Q14(0.5) prior probability for speech/noise + for (i = 0; i < HALF_ANAL_BLOCKL; i++) { + inst->prevMagnU16[i] = 0; + inst->prevNoiseU32[i] = 0; //previous noise-spectrum + inst->logLrtTimeAvgW32[i] = 0; //smooth LR ratio + inst->avgMagnPause[i] = 0; //conservative noise spectrum estimate + inst->initMagnEst[i] = 0; //initial average magnitude spectrum + } + + //feature quantities + inst->thresholdSpecDiff = 50; //threshold for difference feature: determined on-line + inst->thresholdSpecFlat = 20480; //threshold for flatness: determined on-line + inst->featureLogLrt = inst->thresholdLogLrt; //average LRT factor (= threshold) + inst->featureSpecFlat = inst->thresholdSpecFlat; //spectral flatness (= threshold) + inst->featureSpecDiff = inst->thresholdSpecDiff; //spectral difference (= threshold) + inst->weightLogLrt = 6; //default weighting par for LRT feature + inst->weightSpecFlat = 0; //default weighting par for spectral flatness feature + inst->weightSpecDiff = 0; //default weighting par for spectral difference feature + + inst->curAvgMagnEnergy = 0; //window time-average of input magnitude spectrum + inst->timeAvgMagnEnergy = 0; //normalization for spectral difference + inst->timeAvgMagnEnergyTmp = 0; //normalization for spectral difference + + //histogram quantities: used to estimate/update thresholds for features + WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST); + WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST); + WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST); + + inst->blockIndex = -1; //frame counter + + //inst->modelUpdate = 500; //window for update + inst->modelUpdate = (1 << STAT_UPDATES); //window for update + inst->cntThresUpdate = 0; //counter feature thresholds updates + + inst->sumMagn = 0; + inst->magnEnergy = 0; + inst->prevQMagn = 0; + inst->qNoise = 0; + inst->prevQNoise = 0; + + inst->energyIn = 0; + inst->scaleEnergyIn = 0; + + inst->whiteNoiseLevel = 0; + inst->pinkNoiseNumerator = 0; + inst->pinkNoiseExp = 0; + inst->minNorm = 15; // Start with full scale + inst->zeroInputSignal = 0; + + //default mode + WebRtcNsx_set_policy_core(inst, 0); #ifdef NS_FILEDEBUG - inst->infile=fopen("indebug.pcm","wb"); - inst->outfile=fopen("outdebug.pcm","wb"); - inst->file1=fopen("file1.pcm","wb"); - inst->file2=fopen("file2.pcm","wb"); - inst->file3=fopen("file3.pcm","wb"); - inst->file4=fopen("file4.pcm","wb"); - inst->file5=fopen("file5.pcm","wb"); + inst->infile = fopen("indebug.pcm", "wb"); + inst->outfile = fopen("outdebug.pcm", "wb"); + inst->file1 = fopen("file1.pcm", "wb"); + inst->file2 = fopen("file2.pcm", "wb"); + inst->file3 = fopen("file3.pcm", "wb"); + inst->file4 = fopen("file4.pcm", "wb"); + inst->file5 = fopen("file5.pcm", "wb"); #endif - inst->initFlag = 1; + inst->initFlag = 1; - return 0; + return 0; } -int WebRtcNsx_set_policy_core(NsxInst_t *inst, int mode) -{ - // allow for modes:0,1,2,3 - if (mode < 0 || mode > 3) - { - return -1; - } - - inst->aggrMode = mode; - if (mode == 0) - { - inst->overdrive = 256; // Q8(1.0) - inst->denoiseBound = 8192; // Q14(0.5) - inst->gainMap = 0; // No gain compensation - } else if (mode == 1) - { - inst->overdrive = 256; // Q8(1.0) - inst->denoiseBound = 4096; // Q14(0.25) - inst->factor2Table = kFactor2Aggressiveness1; - inst->gainMap = 1; - } else if (mode == 2) - { - inst->overdrive = 282; // ~= Q8(1.1) - inst->denoiseBound = 2048; // Q14(0.125) - inst->factor2Table = kFactor2Aggressiveness2; - inst->gainMap = 1; - } else if (mode == 3) - { - inst->overdrive = 320; // Q8(1.25) - inst->denoiseBound = 1475; // ~= Q14(0.09) - inst->factor2Table = kFactor2Aggressiveness3; - inst->gainMap = 1; - } - return 0; +int WebRtcNsx_set_policy_core(NsxInst_t* inst, int mode) { + // allow for modes:0,1,2,3 + if (mode < 0 || mode > 3) { + return -1; + } + + inst->aggrMode = mode; + if (mode == 0) { + inst->overdrive = 256; // Q8(1.0) + inst->denoiseBound = 8192; // Q14(0.5) + inst->gainMap = 0; // No gain compensation + } else if (mode == 1) { + inst->overdrive = 256; // Q8(1.0) + inst->denoiseBound = 4096; // Q14(0.25) + inst->factor2Table = kFactor2Aggressiveness1; + inst->gainMap = 1; + } else if (mode == 2) { + inst->overdrive = 282; // ~= Q8(1.1) + inst->denoiseBound = 2048; // Q14(0.125) + inst->factor2Table = kFactor2Aggressiveness2; + inst->gainMap = 1; + } else if (mode == 3) { + inst->overdrive = 320; // Q8(1.25) + inst->denoiseBound = 1475; // ~= Q14(0.09) + inst->factor2Table = kFactor2Aggressiveness3; + inst->gainMap = 1; + } + return 0; } #if !(defined(WEBRTC_ARCH_ARM_NEON) && defined(WEBRTC_ANDROID)) -void WebRtcNsx_NoiseEstimation(NsxInst_t *inst, WebRtc_UWord16 *magn, WebRtc_UWord32 *noise, - WebRtc_Word16 *qNoise) -{ - WebRtc_Word32 numerator; - - WebRtc_Word16 lmagn[HALF_ANAL_BLOCKL], counter, countDiv, countProd, delta, zeros, frac; - WebRtc_Word16 log2, tabind, logval, tmp16, tmp16no1, tmp16no2; - WebRtc_Word16 log2Const = 22713; // Q15 - WebRtc_Word16 widthFactor = 21845; - - int i, s, offset; - - numerator = FACTOR_Q16; - - tabind = inst->stages - inst->normData; - if (tabind < 0) - { - logval = -WebRtcNsx_kLogTable[-tabind]; - } else - { - logval = WebRtcNsx_kLogTable[tabind]; +void WebRtcNsx_NoiseEstimation(NsxInst_t* inst, WebRtc_UWord16* magn, WebRtc_UWord32* noise, + WebRtc_Word16* qNoise) { + WebRtc_Word32 numerator; + + WebRtc_Word16 lmagn[HALF_ANAL_BLOCKL], counter, countDiv, countProd, delta, zeros, frac; + WebRtc_Word16 log2, tabind, logval, tmp16, tmp16no1, tmp16no2; + WebRtc_Word16 log2Const = 22713; // Q15 + WebRtc_Word16 widthFactor = 21845; + + int i, s, offset; + + numerator = FACTOR_Q16; + + tabind = inst->stages - inst->normData; + assert(tabind < 9); + assert(tabind > -9); + if (tabind < 0) { + logval = -WebRtcNsx_kLogTable[-tabind]; + } else { + logval = WebRtcNsx_kLogTable[tabind]; + } + + // lmagn(i)=log(magn(i))=log(2)*log2(magn(i)) + // magn is in Q(-stages), and the real lmagn values are: + // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages) + // lmagn in Q8 + for (i = 0; i < inst->magnLen; i++) { + if (magn[i]) { + zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magn[i]); + frac = (WebRtc_Word16)((((WebRtc_UWord32)magn[i] << zeros) & 0x7FFFFFFF) >> 23); + // log2(magn(i)) + assert(frac < 256); + log2 = (WebRtc_Word16)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); + // log2(magn(i))*log(2) + lmagn[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(log2, log2Const, 15); + // + log(2^stages) + lmagn[i] += logval; + } else { + lmagn[i] = logval;//0; } - - // lmagn(i)=log(magn(i))=log(2)*log2(magn(i)) - // magn is in Q(-stages), and the real lmagn values are: - // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages) - // lmagn in Q8 - for (i = 0; i < inst->magnLen; i++) - { - if (magn[i]) - { - zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magn[i]); - frac = (WebRtc_Word16)((((WebRtc_UWord32)magn[i] << zeros) & 0x7FFFFFFF) >> 23); - // log2(magn(i)) - log2 = (WebRtc_Word16)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); - // log2(magn(i))*log(2) - lmagn[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(log2, log2Const, 15); - // + log(2^stages) - lmagn[i] += logval; - } else - { - lmagn[i] = logval;//0; + } + + // loop over simultaneous estimates + for (s = 0; s < SIMULT; s++) { + offset = s * inst->magnLen; + + // Get counter values from state + counter = inst->noiseEstCounter[s]; + assert(counter < 201); + countDiv = WebRtcNsx_kCounterDiv[counter]; + countProd = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(counter, countDiv); + + // quant_est(...) + for (i = 0; i < inst->magnLen; i++) { + // compute delta + if (inst->noiseEstDensity[offset + i] > 512) { + delta = WebRtcSpl_DivW32W16ResW16(numerator, + inst->noiseEstDensity[offset + i]); + } else { + delta = FACTOR_Q7; + if (inst->blockIndex < END_STARTUP_LONG) { + // Smaller step size during startup. This prevents from using + // unrealistic values causing overflow. + delta = FACTOR_Q7_STARTUP; } - } - - // loop over simultaneous estimates - for (s = 0; s < SIMULT; s++) - { - offset = s * inst->magnLen; - - // Get counter values from state - counter = inst->noiseEstCounter[s]; - countDiv = WebRtcNsx_kCounterDiv[counter]; - countProd = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(counter, countDiv); - - // quant_est(...) - for (i = 0; i < inst->magnLen; i++) - { - // compute delta - if (inst->noiseEstDensity[offset + i] > 512) - { - delta = WebRtcSpl_DivW32W16ResW16(numerator, - inst->noiseEstDensity[offset + i]); - } else - { - delta = FACTOR_Q7; - } - - // update log quantile estimate - tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(delta, countDiv, 14); - if (lmagn[i] > inst->noiseEstLogQuantile[offset + i]) - { - // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2 - // CounterDiv=1/inst->counter[s] in Q15 - tmp16 += 2; - tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 2); - inst->noiseEstLogQuantile[offset + i] += tmp16no1; - } else - { - tmp16 += 1; - tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 1); - // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2 - tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, 3, 1); - inst->noiseEstLogQuantile[offset + i] -= tmp16no2; - } - - // update density estimate - if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i]) - < WIDTH_Q8) - { - tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( - inst->noiseEstDensity[offset + i], countProd, 15); - tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(widthFactor, - countDiv, 15); - inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2; - } - } // end loop over magnitude spectrum - - if (counter >= END_STARTUP_LONG) - { - inst->noiseEstCounter[s] = 0; - if (inst->blockIndex >= END_STARTUP_LONG) - { - WebRtcNsx_UpdateNoiseEstimate(inst, offset); - } + } + + // update log quantile estimate + tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(delta, countDiv, 14); + if (lmagn[i] > inst->noiseEstLogQuantile[offset + i]) { + // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2 + // CounterDiv=1/(inst->counter[s]+1) in Q15 + tmp16 += 2; + tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 2); + inst->noiseEstLogQuantile[offset + i] += tmp16no1; + } else { + tmp16 += 1; + tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 1); + // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2 + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, 3, 1); + inst->noiseEstLogQuantile[offset + i] -= tmp16no2; + if (inst->noiseEstLogQuantile[offset + i] < logval) { + // This is the smallest fixed point representation we can + // have, hence we limit the output. + inst->noiseEstLogQuantile[offset + i] = logval; } - inst->noiseEstCounter[s]++; - - } // end loop over simultaneous estimates - - // Sequentially update the noise during startup - if (inst->blockIndex < END_STARTUP_LONG) - { + } + + // update density estimate + if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i]) + < WIDTH_Q8) { + tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + inst->noiseEstDensity[offset + i], countProd, 15); + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(widthFactor, + countDiv, 15); + inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2; + } + } // end loop over magnitude spectrum + + if (counter >= END_STARTUP_LONG) { + inst->noiseEstCounter[s] = 0; + if (inst->blockIndex >= END_STARTUP_LONG) { WebRtcNsx_UpdateNoiseEstimate(inst, offset); + } } + inst->noiseEstCounter[s]++; - for (i = 0; i < inst->magnLen; i++) - { - noise[i] = (WebRtc_UWord32)(inst->noiseEstQuantile[i]); // Q(qNoise) - } - (*qNoise) = (WebRtc_Word16)inst->qNoise; + } // end loop over simultaneous estimates + + // Sequentially update the noise during startup + if (inst->blockIndex < END_STARTUP_LONG) { + WebRtcNsx_UpdateNoiseEstimate(inst, offset); + } + + for (i = 0; i < inst->magnLen; i++) { + noise[i] = (WebRtc_UWord32)(inst->noiseEstQuantile[i]); // Q(qNoise) + } + (*qNoise) = (WebRtc_Word16)inst->qNoise; } #endif // !(defined(WEBRTC_ARCH_ARM_NEON) && defined(WEBRTC_ANDROID)) @@ -798,293 +802,269 @@ void WebRtcNsx_NoiseEstimation(NsxInst_t *inst, WebRtc_UWord16 *magn, WebRtc_UWo // thresholds and weights are extracted every window // flag 0 means update histogram only, flag 1 means compute the thresholds/weights // threshold and weights are returned in: inst->priorModelPars -void WebRtcNsx_FeatureParameterExtraction(NsxInst_t *inst, int flag) -{ - WebRtc_UWord32 tmpU32; - WebRtc_UWord32 histIndex; - WebRtc_UWord32 posPeak1SpecFlatFX, posPeak2SpecFlatFX; - WebRtc_UWord32 posPeak1SpecDiffFX, posPeak2SpecDiffFX; - - WebRtc_Word32 tmp32; - WebRtc_Word32 fluctLrtFX, thresFluctLrtFX; - WebRtc_Word32 avgHistLrtFX, avgSquareHistLrtFX, avgHistLrtComplFX; - - WebRtc_Word16 j; - WebRtc_Word16 numHistLrt; - - int i; - int useFeatureSpecFlat, useFeatureSpecDiff, featureSum; - int maxPeak1, maxPeak2; - int weightPeak1SpecFlat, weightPeak2SpecFlat; - int weightPeak1SpecDiff, weightPeak2SpecDiff; - - //update histograms - if (!flag) - { - // LRT - // Type casting to UWord32 is safe since negative values will not be wrapped to larger - // values than HIST_PAR_EST - histIndex = (WebRtc_UWord32)(inst->featureLogLrt); - if (histIndex < HIST_PAR_EST) - { - inst->histLrt[histIndex]++; - } - // Spectral flatness - // (inst->featureSpecFlat*20)>>10 = (inst->featureSpecFlat*5)>>8 - histIndex = WEBRTC_SPL_RSHIFT_U32(inst->featureSpecFlat * 5, 8); - if (histIndex < HIST_PAR_EST) - { - inst->histSpecFlat[histIndex]++; - } - // Spectral difference - histIndex = HIST_PAR_EST; - if (inst->timeAvgMagnEnergy) - { - // Guard against division by zero - // If timeAvgMagnEnergy == 0 we have no normalizing statistics and therefore can't - // update the histogram - histIndex = WEBRTC_SPL_UDIV((inst->featureSpecDiff * 5) >> inst->stages, - inst->timeAvgMagnEnergy); - } - if (histIndex < HIST_PAR_EST) - { - inst->histSpecDiff[histIndex]++; - } +void WebRtcNsx_FeatureParameterExtraction(NsxInst_t* inst, int flag) { + WebRtc_UWord32 tmpU32; + WebRtc_UWord32 histIndex; + WebRtc_UWord32 posPeak1SpecFlatFX, posPeak2SpecFlatFX; + WebRtc_UWord32 posPeak1SpecDiffFX, posPeak2SpecDiffFX; + + WebRtc_Word32 tmp32; + WebRtc_Word32 fluctLrtFX, thresFluctLrtFX; + WebRtc_Word32 avgHistLrtFX, avgSquareHistLrtFX, avgHistLrtComplFX; + + WebRtc_Word16 j; + WebRtc_Word16 numHistLrt; + + int i; + int useFeatureSpecFlat, useFeatureSpecDiff, featureSum; + int maxPeak1, maxPeak2; + int weightPeak1SpecFlat, weightPeak2SpecFlat; + int weightPeak1SpecDiff, weightPeak2SpecDiff; + + //update histograms + if (!flag) { + // LRT + // Type casting to UWord32 is safe since negative values will not be wrapped to larger + // values than HIST_PAR_EST + histIndex = (WebRtc_UWord32)(inst->featureLogLrt); + if (histIndex < HIST_PAR_EST) { + inst->histLrt[histIndex]++; + } + // Spectral flatness + // (inst->featureSpecFlat*20)>>10 = (inst->featureSpecFlat*5)>>8 + histIndex = WEBRTC_SPL_RSHIFT_U32(inst->featureSpecFlat * 5, 8); + if (histIndex < HIST_PAR_EST) { + inst->histSpecFlat[histIndex]++; + } + // Spectral difference + histIndex = HIST_PAR_EST; + if (inst->timeAvgMagnEnergy > 0) { + // Guard against division by zero + // If timeAvgMagnEnergy == 0 we have no normalizing statistics and + // therefore can't update the histogram + histIndex = WEBRTC_SPL_UDIV((inst->featureSpecDiff * 5) >> inst->stages, + inst->timeAvgMagnEnergy); + } + if (histIndex < HIST_PAR_EST) { + inst->histSpecDiff[histIndex]++; + } + } + + // extract parameters for speech/noise probability + if (flag) { + useFeatureSpecDiff = 1; + //for LRT feature: + // compute the average over inst->featureExtractionParams.rangeAvgHistLrt + avgHistLrtFX = 0; + avgSquareHistLrtFX = 0; + numHistLrt = 0; + for (i = 0; i < BIN_SIZE_LRT; i++) { + j = (2 * i + 1); + tmp32 = WEBRTC_SPL_MUL_16_16(inst->histLrt[i], j); + avgHistLrtFX += tmp32; + numHistLrt += inst->histLrt[i]; + avgSquareHistLrtFX += WEBRTC_SPL_MUL_32_16(tmp32, j); + } + avgHistLrtComplFX = avgHistLrtFX; + for (; i < HIST_PAR_EST; i++) { + j = (2 * i + 1); + tmp32 = WEBRTC_SPL_MUL_16_16(inst->histLrt[i], j); + avgHistLrtComplFX += tmp32; + avgSquareHistLrtFX += WEBRTC_SPL_MUL_32_16(tmp32, j); + } + fluctLrtFX = WEBRTC_SPL_MUL(avgSquareHistLrtFX, numHistLrt); + fluctLrtFX -= WEBRTC_SPL_MUL(avgHistLrtFX, avgHistLrtComplFX); + thresFluctLrtFX = THRES_FLUCT_LRT * numHistLrt; + // get threshold for LRT feature: + tmpU32 = (FACTOR_1_LRT_DIFF * (WebRtc_UWord32)avgHistLrtFX); + if ((fluctLrtFX < thresFluctLrtFX) || (numHistLrt == 0) || + (tmpU32 > (WebRtc_UWord32)(100 * numHistLrt))) { + //very low fluctuation, so likely noise + inst->thresholdLogLrt = inst->maxLrt; + } else { + tmp32 = (WebRtc_Word32)((tmpU32 << (9 + inst->stages)) / numHistLrt / + 25); + // check if value is within min/max range + inst->thresholdLogLrt = WEBRTC_SPL_SAT(inst->maxLrt, + tmp32, + inst->minLrt); + } + if (fluctLrtFX < thresFluctLrtFX) { + // Do not use difference feature if fluctuation of LRT feature is very low: + // most likely just noise state + useFeatureSpecDiff = 0; } - // extract parameters for speech/noise probability - if (flag) - { - useFeatureSpecDiff = 1; - //for LRT feature: - // compute the average over inst->featureExtractionParams.rangeAvgHistLrt - avgHistLrtFX = 0; - avgSquareHistLrtFX = 0; - numHistLrt = 0; - for (i = 0; i < BIN_SIZE_LRT; i++) - { - j = (2 * i + 1); - tmp32 = WEBRTC_SPL_MUL_16_16(inst->histLrt[i], j); - avgHistLrtFX += tmp32; - numHistLrt += inst->histLrt[i]; - avgSquareHistLrtFX += WEBRTC_SPL_MUL_32_16(tmp32, j); - } - avgHistLrtComplFX = avgHistLrtFX; - for (; i < HIST_PAR_EST; i++) - { - j = (2 * i + 1); - tmp32 = WEBRTC_SPL_MUL_16_16(inst->histLrt[i], j); - avgHistLrtComplFX += tmp32; - avgSquareHistLrtFX += WEBRTC_SPL_MUL_32_16(tmp32, j); - } - fluctLrtFX = WEBRTC_SPL_MUL(avgSquareHistLrtFX, numHistLrt); - fluctLrtFX -= WEBRTC_SPL_MUL(avgHistLrtFX, avgHistLrtComplFX); - thresFluctLrtFX = THRES_FLUCT_LRT * numHistLrt; - // get threshold for LRT feature: - tmpU32 = (FACTOR_1_LRT_DIFF * (WebRtc_UWord32)avgHistLrtFX); - if ((fluctLrtFX < thresFluctLrtFX) || (numHistLrt == 0) || (tmpU32 - > (WebRtc_UWord32)(100 * numHistLrt))) - { - inst->thresholdLogLrt = inst->maxLrt; //very low fluctuation, so likely noise - } else - { - tmp32 = (WebRtc_Word32)((tmpU32 << (9 + inst->stages)) / numHistLrt / 25); - // check if value is within min/max range - inst->thresholdLogLrt = WEBRTC_SPL_SAT(inst->maxLrt, tmp32, inst->minLrt); - } - if (fluctLrtFX < thresFluctLrtFX) - { - // Do not use difference feature if fluctuation of LRT feature is very low: - // most likely just noise state - useFeatureSpecDiff = 0; - } + // for spectral flatness and spectral difference: compute the main peaks of histogram + maxPeak1 = 0; + maxPeak2 = 0; + posPeak1SpecFlatFX = 0; + posPeak2SpecFlatFX = 0; + weightPeak1SpecFlat = 0; + weightPeak2SpecFlat = 0; + + // peaks for flatness + for (i = 0; i < HIST_PAR_EST; i++) { + if (inst->histSpecFlat[i] > maxPeak1) { + // Found new "first" peak + maxPeak2 = maxPeak1; + weightPeak2SpecFlat = weightPeak1SpecFlat; + posPeak2SpecFlatFX = posPeak1SpecFlatFX; + + maxPeak1 = inst->histSpecFlat[i]; + weightPeak1SpecFlat = inst->histSpecFlat[i]; + posPeak1SpecFlatFX = (WebRtc_UWord32)(2 * i + 1); + } else if (inst->histSpecFlat[i] > maxPeak2) { + // Found new "second" peak + maxPeak2 = inst->histSpecFlat[i]; + weightPeak2SpecFlat = inst->histSpecFlat[i]; + posPeak2SpecFlatFX = (WebRtc_UWord32)(2 * i + 1); + } + } - // for spectral flatness and spectral difference: compute the main peaks of histogram - maxPeak1 = 0; - maxPeak2 = 0; - posPeak1SpecFlatFX = 0; - posPeak2SpecFlatFX = 0; - weightPeak1SpecFlat = 0; - weightPeak2SpecFlat = 0; - - // peaks for flatness - for (i = 0; i < HIST_PAR_EST; i++) - { - if (inst->histSpecFlat[i] > maxPeak1) - { - // Found new "first" peak - maxPeak2 = maxPeak1; - weightPeak2SpecFlat = weightPeak1SpecFlat; - posPeak2SpecFlatFX = posPeak1SpecFlatFX; - - maxPeak1 = inst->histSpecFlat[i]; - weightPeak1SpecFlat = inst->histSpecFlat[i]; - posPeak1SpecFlatFX = (WebRtc_UWord32)(2 * i + 1); - } else if (inst->histSpecFlat[i] > maxPeak2) - { - // Found new "second" peak - maxPeak2 = inst->histSpecFlat[i]; - weightPeak2SpecFlat = inst->histSpecFlat[i]; - posPeak2SpecFlatFX = (WebRtc_UWord32)(2 * i + 1); - } - } + // for spectral flatness feature + useFeatureSpecFlat = 1; + // merge the two peaks if they are close + if ((posPeak1SpecFlatFX - posPeak2SpecFlatFX < LIM_PEAK_SPACE_FLAT_DIFF) + && (weightPeak2SpecFlat * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecFlat)) { + weightPeak1SpecFlat += weightPeak2SpecFlat; + posPeak1SpecFlatFX = (posPeak1SpecFlatFX + posPeak2SpecFlatFX) >> 1; + } + //reject if weight of peaks is not large enough, or peak value too small + if (weightPeak1SpecFlat < THRES_WEIGHT_FLAT_DIFF || posPeak1SpecFlatFX + < THRES_PEAK_FLAT) { + useFeatureSpecFlat = 0; + } else { // if selected, get the threshold + // compute the threshold and check if value is within min/max range + inst->thresholdSpecFlat = WEBRTC_SPL_SAT(MAX_FLAT_Q10, FACTOR_2_FLAT_Q10 + * posPeak1SpecFlatFX, MIN_FLAT_Q10); //Q10 + } + // done with flatness feature - // for spectral flatness feature - useFeatureSpecFlat = 1; - // merge the two peaks if they are close - if ((posPeak1SpecFlatFX - posPeak2SpecFlatFX < LIM_PEAK_SPACE_FLAT_DIFF) - && (weightPeak2SpecFlat * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecFlat)) - { - weightPeak1SpecFlat += weightPeak2SpecFlat; - posPeak1SpecFlatFX = (posPeak1SpecFlatFX + posPeak2SpecFlatFX) >> 1; - } - //reject if weight of peaks is not large enough, or peak value too small - if (weightPeak1SpecFlat < THRES_WEIGHT_FLAT_DIFF || posPeak1SpecFlatFX - < THRES_PEAK_FLAT) - { - useFeatureSpecFlat = 0; - } else // if selected, get the threshold - { - // compute the threshold and check if value is within min/max range - inst->thresholdSpecFlat = WEBRTC_SPL_SAT(MAX_FLAT_Q10, FACTOR_2_FLAT_Q10 - * posPeak1SpecFlatFX, MIN_FLAT_Q10); //Q10 - } - // done with flatness feature - - if (useFeatureSpecDiff) - { - //compute two peaks for spectral difference - maxPeak1 = 0; - maxPeak2 = 0; - posPeak1SpecDiffFX = 0; - posPeak2SpecDiffFX = 0; - weightPeak1SpecDiff = 0; - weightPeak2SpecDiff = 0; - // peaks for spectral difference - for (i = 0; i < HIST_PAR_EST; i++) - { - if (inst->histSpecDiff[i] > maxPeak1) - { - // Found new "first" peak - maxPeak2 = maxPeak1; - weightPeak2SpecDiff = weightPeak1SpecDiff; - posPeak2SpecDiffFX = posPeak1SpecDiffFX; - - maxPeak1 = inst->histSpecDiff[i]; - weightPeak1SpecDiff = inst->histSpecDiff[i]; - posPeak1SpecDiffFX = (WebRtc_UWord32)(2 * i + 1); - } else if (inst->histSpecDiff[i] > maxPeak2) - { - // Found new "second" peak - maxPeak2 = inst->histSpecDiff[i]; - weightPeak2SpecDiff = inst->histSpecDiff[i]; - posPeak2SpecDiffFX = (WebRtc_UWord32)(2 * i + 1); - } - } - - // merge the two peaks if they are close - if ((posPeak1SpecDiffFX - posPeak2SpecDiffFX < LIM_PEAK_SPACE_FLAT_DIFF) - && (weightPeak2SpecDiff * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecDiff)) - { - weightPeak1SpecDiff += weightPeak2SpecDiff; - posPeak1SpecDiffFX = (posPeak1SpecDiffFX + posPeak2SpecDiffFX) >> 1; - } - // get the threshold value and check if value is within min/max range - inst->thresholdSpecDiff = WEBRTC_SPL_SAT(MAX_DIFF, FACTOR_1_LRT_DIFF - * posPeak1SpecDiffFX, MIN_DIFF); //5x bigger - //reject if weight of peaks is not large enough - if (weightPeak1SpecDiff < THRES_WEIGHT_FLAT_DIFF) - { - useFeatureSpecDiff = 0; - } - // done with spectral difference feature + if (useFeatureSpecDiff) { + //compute two peaks for spectral difference + maxPeak1 = 0; + maxPeak2 = 0; + posPeak1SpecDiffFX = 0; + posPeak2SpecDiffFX = 0; + weightPeak1SpecDiff = 0; + weightPeak2SpecDiff = 0; + // peaks for spectral difference + for (i = 0; i < HIST_PAR_EST; i++) { + if (inst->histSpecDiff[i] > maxPeak1) { + // Found new "first" peak + maxPeak2 = maxPeak1; + weightPeak2SpecDiff = weightPeak1SpecDiff; + posPeak2SpecDiffFX = posPeak1SpecDiffFX; + + maxPeak1 = inst->histSpecDiff[i]; + weightPeak1SpecDiff = inst->histSpecDiff[i]; + posPeak1SpecDiffFX = (WebRtc_UWord32)(2 * i + 1); + } else if (inst->histSpecDiff[i] > maxPeak2) { + // Found new "second" peak + maxPeak2 = inst->histSpecDiff[i]; + weightPeak2SpecDiff = inst->histSpecDiff[i]; + posPeak2SpecDiffFX = (WebRtc_UWord32)(2 * i + 1); } + } + + // merge the two peaks if they are close + if ((posPeak1SpecDiffFX - posPeak2SpecDiffFX < LIM_PEAK_SPACE_FLAT_DIFF) + && (weightPeak2SpecDiff * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecDiff)) { + weightPeak1SpecDiff += weightPeak2SpecDiff; + posPeak1SpecDiffFX = (posPeak1SpecDiffFX + posPeak2SpecDiffFX) >> 1; + } + // get the threshold value and check if value is within min/max range + inst->thresholdSpecDiff = WEBRTC_SPL_SAT(MAX_DIFF, FACTOR_1_LRT_DIFF + * posPeak1SpecDiffFX, MIN_DIFF); //5x bigger + //reject if weight of peaks is not large enough + if (weightPeak1SpecDiff < THRES_WEIGHT_FLAT_DIFF) { + useFeatureSpecDiff = 0; + } + // done with spectral difference feature + } - // select the weights between the features - // inst->priorModelPars[4] is weight for LRT: always selected - featureSum = 6 / (1 + useFeatureSpecFlat + useFeatureSpecDiff); - inst->weightLogLrt = featureSum; - inst->weightSpecFlat = useFeatureSpecFlat * featureSum; - inst->weightSpecDiff = useFeatureSpecDiff * featureSum; - - // set histograms to zero for next update - WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST); - WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST); - WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST); - } // end of flag == 1 + // select the weights between the features + // inst->priorModelPars[4] is weight for LRT: always selected + featureSum = 6 / (1 + useFeatureSpecFlat + useFeatureSpecDiff); + inst->weightLogLrt = featureSum; + inst->weightSpecFlat = useFeatureSpecFlat * featureSum; + inst->weightSpecDiff = useFeatureSpecDiff * featureSum; + + // set histograms to zero for next update + WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST); + WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST); + WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST); + } // end of flag == 1 } // Compute spectral flatness on input spectrum // magn is the magnitude spectrum // spectral flatness is returned in inst->featureSpecFlat -void WebRtcNsx_ComputeSpectralFlatness(NsxInst_t *inst, WebRtc_UWord16 *magn) -{ - WebRtc_UWord32 tmpU32; - WebRtc_UWord32 avgSpectralFlatnessNum, avgSpectralFlatnessDen; - - WebRtc_Word32 tmp32; - WebRtc_Word32 currentSpectralFlatness, logCurSpectralFlatness; - - WebRtc_Word16 zeros, frac, intPart; - - int i; - - // for flatness - avgSpectralFlatnessNum = 0; - avgSpectralFlatnessDen = inst->sumMagn - (WebRtc_UWord32)magn[0]; // Q(normData-stages) - - // compute log of ratio of the geometric to arithmetic mean: check for log(0) case - // flatness = exp( sum(log(magn[i]))/N - log(sum(magn[i])/N) ) - // = exp( sum(log(magn[i]))/N ) * N / sum(magn[i]) - // = 2^( sum(log2(magn[i]))/N - (log2(sum(magn[i])) - log2(N)) ) [This is used] - for (i = 1; i < inst->magnLen; i++) - { - // First bin is excluded from spectrum measures. Number of bins is now a power of 2 - if (magn[i]) - { - zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magn[i]); - frac = (WebRtc_Word16)(((WebRtc_UWord32)((WebRtc_UWord32)(magn[i]) << zeros) - & 0x7FFFFFFF) >> 23); - // log2(magn(i)) - tmpU32 = (WebRtc_UWord32)(((31 - zeros) << 8) - + WebRtcNsx_kLogTableFrac[frac]); // Q8 - avgSpectralFlatnessNum += tmpU32; // Q8 - } else - { - //if at least one frequency component is zero, treat separately - tmpU32 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecFlat, SPECT_FLAT_TAVG_Q14); // Q24 - inst->featureSpecFlat -= WEBRTC_SPL_RSHIFT_U32(tmpU32, 14); // Q10 - return; - } +void WebRtcNsx_ComputeSpectralFlatness(NsxInst_t* inst, WebRtc_UWord16* magn) { + WebRtc_UWord32 tmpU32; + WebRtc_UWord32 avgSpectralFlatnessNum, avgSpectralFlatnessDen; + + WebRtc_Word32 tmp32; + WebRtc_Word32 currentSpectralFlatness, logCurSpectralFlatness; + + WebRtc_Word16 zeros, frac, intPart; + + int i; + + // for flatness + avgSpectralFlatnessNum = 0; + avgSpectralFlatnessDen = inst->sumMagn - (WebRtc_UWord32)magn[0]; // Q(normData-stages) + + // compute log of ratio of the geometric to arithmetic mean: check for log(0) case + // flatness = exp( sum(log(magn[i]))/N - log(sum(magn[i])/N) ) + // = exp( sum(log(magn[i]))/N ) * N / sum(magn[i]) + // = 2^( sum(log2(magn[i]))/N - (log2(sum(magn[i])) - log2(N)) ) [This is used] + for (i = 1; i < inst->magnLen; i++) { + // First bin is excluded from spectrum measures. Number of bins is now a power of 2 + if (magn[i]) { + zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magn[i]); + frac = (WebRtc_Word16)(((WebRtc_UWord32)((WebRtc_UWord32)(magn[i]) << zeros) + & 0x7FFFFFFF) >> 23); + // log2(magn(i)) + assert(frac < 256); + tmpU32 = (WebRtc_UWord32)(((31 - zeros) << 8) + + WebRtcNsx_kLogTableFrac[frac]); // Q8 + avgSpectralFlatnessNum += tmpU32; // Q8 + } else { + //if at least one frequency component is zero, treat separately + tmpU32 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecFlat, SPECT_FLAT_TAVG_Q14); // Q24 + inst->featureSpecFlat -= WEBRTC_SPL_RSHIFT_U32(tmpU32, 14); // Q10 + return; } - //ratio and inverse log: check for case of log(0) - zeros = WebRtcSpl_NormU32(avgSpectralFlatnessDen); - frac = (WebRtc_Word16)(((avgSpectralFlatnessDen << zeros) & 0x7FFFFFFF) >> 23); - // log2(avgSpectralFlatnessDen) - tmp32 = (WebRtc_Word32)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); // Q8 - logCurSpectralFlatness = (WebRtc_Word32)avgSpectralFlatnessNum; - logCurSpectralFlatness += ((WebRtc_Word32)(inst->stages - 1) << (inst->stages + 7)); // Q(8+stages-1) - logCurSpectralFlatness -= (tmp32 << (inst->stages - 1)); - logCurSpectralFlatness = WEBRTC_SPL_LSHIFT_W32(logCurSpectralFlatness, 10 - inst->stages); // Q17 - tmp32 = (WebRtc_Word32)(0x00020000 | (WEBRTC_SPL_ABS_W32(logCurSpectralFlatness) - & 0x0001FFFF)); //Q17 - intPart = -(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(logCurSpectralFlatness, 17); - intPart += 7; // Shift 7 to get the output in Q10 (from Q17 = -17+10) - if (intPart > 0) - { - currentSpectralFlatness = WEBRTC_SPL_RSHIFT_W32(tmp32, intPart); - } else - { - currentSpectralFlatness = WEBRTC_SPL_LSHIFT_W32(tmp32, -intPart); - } - - //time average update of spectral flatness feature - tmp32 = currentSpectralFlatness - (WebRtc_Word32)inst->featureSpecFlat; // Q10 - tmp32 = WEBRTC_SPL_MUL_32_16(SPECT_FLAT_TAVG_Q14, tmp32); // Q24 - inst->featureSpecFlat = (WebRtc_UWord32)((WebRtc_Word32)inst->featureSpecFlat - + WEBRTC_SPL_RSHIFT_W32(tmp32, 14)); // Q10 - // done with flatness feature + } + //ratio and inverse log: check for case of log(0) + zeros = WebRtcSpl_NormU32(avgSpectralFlatnessDen); + frac = (WebRtc_Word16)(((avgSpectralFlatnessDen << zeros) & 0x7FFFFFFF) >> 23); + // log2(avgSpectralFlatnessDen) + assert(frac < 256); + tmp32 = (WebRtc_Word32)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); // Q8 + logCurSpectralFlatness = (WebRtc_Word32)avgSpectralFlatnessNum; + logCurSpectralFlatness += ((WebRtc_Word32)(inst->stages - 1) << (inst->stages + 7)); // Q(8+stages-1) + logCurSpectralFlatness -= (tmp32 << (inst->stages - 1)); + logCurSpectralFlatness = WEBRTC_SPL_LSHIFT_W32(logCurSpectralFlatness, 10 - inst->stages); // Q17 + tmp32 = (WebRtc_Word32)(0x00020000 | (WEBRTC_SPL_ABS_W32(logCurSpectralFlatness) + & 0x0001FFFF)); //Q17 + intPart = -(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(logCurSpectralFlatness, 17); + intPart += 7; // Shift 7 to get the output in Q10 (from Q17 = -17+10) + if (intPart > 0) { + currentSpectralFlatness = WEBRTC_SPL_RSHIFT_W32(tmp32, intPart); + } else { + currentSpectralFlatness = WEBRTC_SPL_LSHIFT_W32(tmp32, -intPart); + } + + //time average update of spectral flatness feature + tmp32 = currentSpectralFlatness - (WebRtc_Word32)inst->featureSpecFlat; // Q10 + tmp32 = WEBRTC_SPL_MUL_32_16(SPECT_FLAT_TAVG_Q14, tmp32); // Q24 + inst->featureSpecFlat = (WebRtc_UWord32)((WebRtc_Word32)inst->featureSpecFlat + + WEBRTC_SPL_RSHIFT_W32(tmp32, 14)); // Q10 + // done with flatness feature } @@ -1092,1403 +1072,1299 @@ void WebRtcNsx_ComputeSpectralFlatness(NsxInst_t *inst, WebRtc_UWord16 *magn) // magn_tmp is the input spectrum // the reference/template spectrum is inst->magn_avg_pause[i] // returns (normalized) spectral difference in inst->featureSpecDiff -void WebRtcNsx_ComputeSpectralDifference(NsxInst_t *inst, WebRtc_UWord16 *magnIn) -{ - // This is to be calculated: - // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 / var(magnAvgPause) - - WebRtc_UWord32 tmpU32no1, tmpU32no2; - WebRtc_UWord32 varMagnUFX, varPauseUFX, avgDiffNormMagnUFX; - - WebRtc_Word32 tmp32no1, tmp32no2; - WebRtc_Word32 avgPauseFX, avgMagnFX, covMagnPauseFX; - WebRtc_Word32 maxPause, minPause; - - WebRtc_Word16 tmp16no1; - - int i, norm32, nShifts; - - avgPauseFX = 0; - maxPause = 0; - minPause = inst->avgMagnPause[0]; // Q(prevQMagn) - // compute average quantities - for (i = 0; i < inst->magnLen; i++) - { - // Compute mean of magn_pause - avgPauseFX += inst->avgMagnPause[i]; // in Q(prevQMagn) - maxPause = WEBRTC_SPL_MAX(maxPause, inst->avgMagnPause[i]); - minPause = WEBRTC_SPL_MIN(minPause, inst->avgMagnPause[i]); +void WebRtcNsx_ComputeSpectralDifference(NsxInst_t* inst, WebRtc_UWord16* magnIn) { + // This is to be calculated: + // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 / var(magnAvgPause) + + WebRtc_UWord32 tmpU32no1, tmpU32no2; + WebRtc_UWord32 varMagnUFX, varPauseUFX, avgDiffNormMagnUFX; + + WebRtc_Word32 tmp32no1, tmp32no2; + WebRtc_Word32 avgPauseFX, avgMagnFX, covMagnPauseFX; + WebRtc_Word32 maxPause, minPause; + + WebRtc_Word16 tmp16no1; + + int i, norm32, nShifts; + + avgPauseFX = 0; + maxPause = 0; + minPause = inst->avgMagnPause[0]; // Q(prevQMagn) + // compute average quantities + for (i = 0; i < inst->magnLen; i++) { + // Compute mean of magn_pause + avgPauseFX += inst->avgMagnPause[i]; // in Q(prevQMagn) + maxPause = WEBRTC_SPL_MAX(maxPause, inst->avgMagnPause[i]); + minPause = WEBRTC_SPL_MIN(minPause, inst->avgMagnPause[i]); + } + // normalize by replacing div of "inst->magnLen" with "inst->stages-1" shifts + avgPauseFX = WEBRTC_SPL_RSHIFT_W32(avgPauseFX, inst->stages - 1); + avgMagnFX = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(inst->sumMagn, inst->stages - 1); + // Largest possible deviation in magnPause for (co)var calculations + tmp32no1 = WEBRTC_SPL_MAX(maxPause - avgPauseFX, avgPauseFX - minPause); + // Get number of shifts to make sure we don't get wrap around in varPause + nShifts = WEBRTC_SPL_MAX(0, 10 + inst->stages - WebRtcSpl_NormW32(tmp32no1)); + + varMagnUFX = 0; + varPauseUFX = 0; + covMagnPauseFX = 0; + for (i = 0; i < inst->magnLen; i++) { + // Compute var and cov of magn and magn_pause + tmp16no1 = (WebRtc_Word16)((WebRtc_Word32)magnIn[i] - avgMagnFX); + tmp32no2 = inst->avgMagnPause[i] - avgPauseFX; + varMagnUFX += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1); // Q(2*qMagn) + tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no2, tmp16no1); // Q(prevQMagn+qMagn) + covMagnPauseFX += tmp32no1; // Q(prevQMagn+qMagn) + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, nShifts); // Q(prevQMagn-minPause) + varPauseUFX += (WebRtc_UWord32)WEBRTC_SPL_MUL(tmp32no1, tmp32no1); // Q(2*(prevQMagn-minPause)) + } + //update of average magnitude spectrum: Q(-2*stages) and averaging replaced by shifts + inst->curAvgMagnEnergy += WEBRTC_SPL_RSHIFT_U32(inst->magnEnergy, 2 * inst->normData + + inst->stages - 1); + + avgDiffNormMagnUFX = varMagnUFX; // Q(2*qMagn) + if ((varPauseUFX) && (covMagnPauseFX)) { + tmpU32no1 = (WebRtc_UWord32)WEBRTC_SPL_ABS_W32(covMagnPauseFX); // Q(prevQMagn+qMagn) + norm32 = WebRtcSpl_NormU32(tmpU32no1) - 16; + if (norm32 > 0) { + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, norm32); // Q(prevQMagn+qMagn+norm32) + } else { + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, -norm32); // Q(prevQMagn+qMagn+norm32) } - // normalize by replacing div of "inst->magnLen" with "inst->stages-1" shifts - avgPauseFX = WEBRTC_SPL_RSHIFT_W32(avgPauseFX, inst->stages - 1); - avgMagnFX = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(inst->sumMagn, inst->stages - 1); - // Largest possible deviation in magnPause for (co)var calculations - tmp32no1 = WEBRTC_SPL_MAX(maxPause - avgPauseFX, avgPauseFX - minPause); - // Get number of shifts to make sure we don't get wrap around in varPause - nShifts = WEBRTC_SPL_MAX(0, 10 + inst->stages - WebRtcSpl_NormW32(tmp32no1)); - - varMagnUFX = 0; - varPauseUFX = 0; - covMagnPauseFX = 0; - for (i = 0; i < inst->magnLen; i++) - { - // Compute var and cov of magn and magn_pause - tmp16no1 = (WebRtc_Word16)((WebRtc_Word32)magnIn[i] - avgMagnFX); - tmp32no2 = inst->avgMagnPause[i] - avgPauseFX; - varMagnUFX += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1); // Q(2*qMagn) - tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no2, tmp16no1); // Q(prevQMagn+qMagn) - covMagnPauseFX += tmp32no1; // Q(prevQMagn+qMagn) - tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, nShifts); // Q(prevQMagn-minPause) - varPauseUFX += (WebRtc_UWord32)WEBRTC_SPL_MUL(tmp32no1, tmp32no1); // Q(2*(prevQMagn-minPause)) - } - //update of average magnitude spectrum: Q(-2*stages) and averaging replaced by shifts - inst->curAvgMagnEnergy += WEBRTC_SPL_RSHIFT_U32(inst->magnEnergy, 2 * inst->normData - + inst->stages - 1); - - avgDiffNormMagnUFX = varMagnUFX; // Q(2*qMagn) - if ((varPauseUFX) && (covMagnPauseFX)) - { - tmpU32no1 = (WebRtc_UWord32)WEBRTC_SPL_ABS_W32(covMagnPauseFX); // Q(prevQMagn+qMagn) - norm32 = WebRtcSpl_NormU32(tmpU32no1) - 16; - if (norm32 > 0) - { - tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, norm32); // Q(prevQMagn+qMagn+norm32) - } else - { - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, -norm32); // Q(prevQMagn+qMagn+norm32) - } - tmpU32no2 = WEBRTC_SPL_UMUL(tmpU32no1, tmpU32no1); // Q(2*(prevQMagn+qMagn-norm32)) - - nShifts += norm32; - nShifts <<= 1; - if (nShifts < 0) - { - varPauseUFX >>= (-nShifts); // Q(2*(qMagn+norm32+minPause)) - nShifts = 0; - } - tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no2, varPauseUFX); // Q(2*(qMagn+norm32-16+minPause)) - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, nShifts); + tmpU32no2 = WEBRTC_SPL_UMUL(tmpU32no1, tmpU32no1); // Q(2*(prevQMagn+qMagn-norm32)) - avgDiffNormMagnUFX -= WEBRTC_SPL_MIN(avgDiffNormMagnUFX, tmpU32no1); // Q(2*qMagn) + nShifts += norm32; + nShifts <<= 1; + if (nShifts < 0) { + varPauseUFX >>= (-nShifts); // Q(2*(qMagn+norm32+minPause)) + nShifts = 0; } - //normalize and compute time average update of difference feature - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(avgDiffNormMagnUFX, 2 * inst->normData); - if (inst->featureSpecDiff > tmpU32no1) - { - tmpU32no2 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecDiff - tmpU32no1, - SPECT_DIFF_TAVG_Q8); // Q(8-2*stages) - inst->featureSpecDiff -= WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 8); // Q(-2*stages) - } else - { - tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no1 - inst->featureSpecDiff, - SPECT_DIFF_TAVG_Q8); // Q(8-2*stages) - inst->featureSpecDiff += WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 8); // Q(-2*stages) + if (varPauseUFX > 0) { + // Q(2*(qMagn+norm32-16+minPause)) + tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no2, varPauseUFX); + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, nShifts); + + // Q(2*qMagn) + avgDiffNormMagnUFX -= WEBRTC_SPL_MIN(avgDiffNormMagnUFX, tmpU32no1); + } else { + avgDiffNormMagnUFX = 0; } + } + //normalize and compute time average update of difference feature + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(avgDiffNormMagnUFX, 2 * inst->normData); + if (inst->featureSpecDiff > tmpU32no1) { + tmpU32no2 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecDiff - tmpU32no1, + SPECT_DIFF_TAVG_Q8); // Q(8-2*stages) + inst->featureSpecDiff -= WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 8); // Q(-2*stages) + } else { + tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no1 - inst->featureSpecDiff, + SPECT_DIFF_TAVG_Q8); // Q(8-2*stages) + inst->featureSpecDiff += WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 8); // Q(-2*stages) + } } // Compute speech/noise probability // speech/noise probability is returned in: probSpeechFinal //snrLocPrior is the prior SNR for each frequency (in Q11) //snrLocPost is the post SNR for each frequency (in Q11) -void WebRtcNsx_SpeechNoiseProb(NsxInst_t *inst, WebRtc_UWord16 *nonSpeechProbFinal, - WebRtc_UWord32 *priorLocSnr, WebRtc_UWord32 *postLocSnr) -{ - WebRtc_UWord32 zeros, num, den, tmpU32no1, tmpU32no2, tmpU32no3; - - WebRtc_Word32 invLrtFX, indPriorFX, tmp32, tmp32no1, tmp32no2, besselTmpFX32; - WebRtc_Word32 frac32, logTmp; - WebRtc_Word32 logLrtTimeAvgKsumFX; - - WebRtc_Word16 indPriorFX16; - WebRtc_Word16 tmp16, tmp16no1, tmp16no2, tmpIndFX, tableIndex, frac, intPart; - - int i, normTmp, normTmp2, nShifts; - - // compute feature based on average LR factor - // this is the average over all frequencies of the smooth log LRT - logLrtTimeAvgKsumFX = 0; - for (i = 0; i < inst->magnLen; i++) - { - besselTmpFX32 = (WebRtc_Word32)postLocSnr[i]; // Q11 - normTmp = WebRtcSpl_NormU32(postLocSnr[i]); - num = WEBRTC_SPL_LSHIFT_U32(postLocSnr[i], normTmp); // Q(11+normTmp) - if (normTmp > 10) - { - den = WEBRTC_SPL_LSHIFT_U32(priorLocSnr[i], normTmp - 11); // Q(normTmp) - } else - { - den = WEBRTC_SPL_RSHIFT_U32(priorLocSnr[i], 11 - normTmp); // Q(normTmp) - } - besselTmpFX32 -= WEBRTC_SPL_UDIV(num, den); // Q11 - - // inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - log(snrLocPrior) - inst->logLrtTimeAvg[i]); - // Here, LRT_TAVG = 0.5 - zeros = WebRtcSpl_NormU32(priorLocSnr[i]); - frac32 = (WebRtc_Word32)(((priorLocSnr[i] << zeros) & 0x7FFFFFFF) >> 19); - tmp32 = WEBRTC_SPL_MUL(frac32, frac32); - tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(tmp32, -43), 19); - tmp32 += WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16)frac32, 5412, 12); - frac32 = tmp32 + 37; - // tmp32 = log2(priorLocSnr[i]) - tmp32 = (WebRtc_Word32)(((31 - zeros) << 12) + frac32) - (11 << 12); // Q12 - logTmp = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32, 178), 8); // log2(priorLocSnr[i])*log(2) - tmp32no1 = WEBRTC_SPL_RSHIFT_W32(logTmp + inst->logLrtTimeAvgW32[i], 1); // Q12 - inst->logLrtTimeAvgW32[i] += (besselTmpFX32 - tmp32no1); // Q12 - - logLrtTimeAvgKsumFX += inst->logLrtTimeAvgW32[i]; // Q12 +void WebRtcNsx_SpeechNoiseProb(NsxInst_t* inst, WebRtc_UWord16* nonSpeechProbFinal, + WebRtc_UWord32* priorLocSnr, WebRtc_UWord32* postLocSnr) { + WebRtc_UWord32 zeros, num, den, tmpU32no1, tmpU32no2, tmpU32no3; + + WebRtc_Word32 invLrtFX, indPriorFX, tmp32, tmp32no1, tmp32no2, besselTmpFX32; + WebRtc_Word32 frac32, logTmp; + WebRtc_Word32 logLrtTimeAvgKsumFX; + + WebRtc_Word16 indPriorFX16; + WebRtc_Word16 tmp16, tmp16no1, tmp16no2, tmpIndFX, tableIndex, frac, intPart; + + int i, normTmp, normTmp2, nShifts; + + // compute feature based on average LR factor + // this is the average over all frequencies of the smooth log LRT + logLrtTimeAvgKsumFX = 0; + for (i = 0; i < inst->magnLen; i++) { + besselTmpFX32 = (WebRtc_Word32)postLocSnr[i]; // Q11 + normTmp = WebRtcSpl_NormU32(postLocSnr[i]); + num = WEBRTC_SPL_LSHIFT_U32(postLocSnr[i], normTmp); // Q(11+normTmp) + if (normTmp > 10) { + den = WEBRTC_SPL_LSHIFT_U32(priorLocSnr[i], normTmp - 11); // Q(normTmp) + } else { + den = WEBRTC_SPL_RSHIFT_U32(priorLocSnr[i], 11 - normTmp); // Q(normTmp) + } + if (den > 0) { + besselTmpFX32 -= WEBRTC_SPL_UDIV(num, den); // Q11 + } else { + besselTmpFX32 -= num; // Q11 } - inst->featureLogLrt = WEBRTC_SPL_RSHIFT_W32(logLrtTimeAvgKsumFX * 5, inst->stages + 10); // 5 = BIN_SIZE_LRT / 2 - // done with computation of LR factor - // - //compute the indicator functions - // + // inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - log(snrLocPrior) - inst->logLrtTimeAvg[i]); + // Here, LRT_TAVG = 0.5 + zeros = WebRtcSpl_NormU32(priorLocSnr[i]); + frac32 = (WebRtc_Word32)(((priorLocSnr[i] << zeros) & 0x7FFFFFFF) >> 19); + tmp32 = WEBRTC_SPL_MUL(frac32, frac32); + tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(tmp32, -43), 19); + tmp32 += WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16)frac32, 5412, 12); + frac32 = tmp32 + 37; + // tmp32 = log2(priorLocSnr[i]) + tmp32 = (WebRtc_Word32)(((31 - zeros) << 12) + frac32) - (11 << 12); // Q12 + logTmp = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32, 178), 8); // log2(priorLocSnr[i])*log(2) + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(logTmp + inst->logLrtTimeAvgW32[i], 1); // Q12 + inst->logLrtTimeAvgW32[i] += (besselTmpFX32 - tmp32no1); // Q12 + + logLrtTimeAvgKsumFX += inst->logLrtTimeAvgW32[i]; // Q12 + } + inst->featureLogLrt = WEBRTC_SPL_RSHIFT_W32(logLrtTimeAvgKsumFX * 5, inst->stages + 10); // 5 = BIN_SIZE_LRT / 2 + // done with computation of LR factor + + // + //compute the indicator functions + // + + // average LRT feature + // FLOAT code + // indicator0 = 0.5 * (tanh(widthPrior * (logLrtTimeAvgKsum - threshPrior0)) + 1.0); + tmpIndFX = 16384; // Q14(1.0) + tmp32no1 = logLrtTimeAvgKsumFX - inst->thresholdLogLrt; // Q12 + nShifts = 7 - inst->stages; // WIDTH_PR_MAP_SHIFT - inst->stages + 5; + //use larger width in tanh map for pause regions + if (tmp32no1 < 0) { + tmpIndFX = 0; + tmp32no1 = -tmp32no1; + //widthPrior = widthPrior * 2.0; + nShifts++; + } + tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, nShifts); // Q14 + // compute indicator function: sigmoid map + tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 14); + if ((tableIndex < 16) && (tableIndex >= 0)) { + tmp16no2 = kIndicatorTable[tableIndex]; + tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; + frac = (WebRtc_Word16)(tmp32no1 & 0x00003fff); // Q14 + tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14); + if (tmpIndFX == 0) { + tmpIndFX = 8192 - tmp16no2; // Q14 + } else { + tmpIndFX = 8192 + tmp16no2; // Q14 + } + } + indPriorFX = WEBRTC_SPL_MUL_16_16(inst->weightLogLrt, tmpIndFX); // 6*Q14 - // average LRT feature - // FLOAT code - // indicator0 = 0.5 * (tanh(widthPrior * (logLrtTimeAvgKsum - threshPrior0)) + 1.0); + //spectral flatness feature + if (inst->weightSpecFlat) { + tmpU32no1 = WEBRTC_SPL_UMUL(inst->featureSpecFlat, 400); // Q10 tmpIndFX = 16384; // Q14(1.0) - tmp32no1 = logLrtTimeAvgKsumFX - inst->thresholdLogLrt; // Q12 - nShifts = 7 - inst->stages; // WIDTH_PR_MAP_SHIFT - inst->stages + 5; //use larger width in tanh map for pause regions - if (tmp32no1 < 0) - { - tmpIndFX = 0; - tmp32no1 = -tmp32no1; - //widthPrior = widthPrior * 2.0; - nShifts++; + tmpU32no2 = inst->thresholdSpecFlat - tmpU32no1; //Q10 + nShifts = 4; + if (inst->thresholdSpecFlat < tmpU32no1) { + tmpIndFX = 0; + tmpU32no2 = tmpU32no1 - inst->thresholdSpecFlat; + //widthPrior = widthPrior * 2.0; + nShifts++; } - tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, nShifts); // Q14 + tmp32no1 = (WebRtc_Word32)WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, + nShifts), 25); //Q14 + tmpU32no1 = WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, nShifts), 25); //Q14 // compute indicator function: sigmoid map - tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 14); - if ((tableIndex < 16) && (tableIndex >= 0)) - { - tmp16no2 = kIndicatorTable[tableIndex]; - tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; - frac = (WebRtc_Word16)(tmp32no1 & 0x00003fff); // Q14 - tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14); - if (tmpIndFX == 0) - { - tmpIndFX = 8192 - tmp16no2; // Q14 - } else - { - tmpIndFX = 8192 + tmp16no2; // Q14 - } + // FLOAT code + // indicator1 = 0.5 * (tanh(sgnMap * widthPrior * (threshPrior1 - tmpFloat1)) + 1.0); + tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14); + if (tableIndex < 16) { + tmp16no2 = kIndicatorTable[tableIndex]; + tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; + frac = (WebRtc_Word16)(tmpU32no1 & 0x00003fff); // Q14 + tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14); + if (tmpIndFX) { + tmpIndFX = 8192 + tmp16no2; // Q14 + } else { + tmpIndFX = 8192 - tmp16no2; // Q14 + } } - indPriorFX = WEBRTC_SPL_MUL_16_16(inst->weightLogLrt, tmpIndFX); // 6*Q14 - - //spectral flatness feature - if (inst->weightSpecFlat) - { - tmpU32no1 = WEBRTC_SPL_UMUL(inst->featureSpecFlat, 400); // Q10 - tmpIndFX = 16384; // Q14(1.0) - //use larger width in tanh map for pause regions - tmpU32no2 = inst->thresholdSpecFlat - tmpU32no1; //Q10 - nShifts = 4; - if (inst->thresholdSpecFlat < tmpU32no1) - { - tmpIndFX = 0; - tmpU32no2 = tmpU32no1 - inst->thresholdSpecFlat; - //widthPrior = widthPrior * 2.0; - nShifts++; - } - tmp32no1 = (WebRtc_Word32)WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, - nShifts), 25); //Q14 - tmpU32no1 = WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, nShifts), 25); //Q14 - // compute indicator function: sigmoid map - // FLOAT code - // indicator1 = 0.5 * (tanh(sgnMap * widthPrior * (threshPrior1 - tmpFloat1)) + 1.0); - tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14); - if (tableIndex < 16) - { - tmp16no2 = kIndicatorTable[tableIndex]; - tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; - frac = (WebRtc_Word16)(tmpU32no1 & 0x00003fff); // Q14 - tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14); - if (tmpIndFX) - { - tmpIndFX = 8192 + tmp16no2; // Q14 - } else - { - tmpIndFX = 8192 - tmp16no2; // Q14 - } - } - indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecFlat, tmpIndFX); // 6*Q14 + indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecFlat, tmpIndFX); // 6*Q14 + } + + //for template spectral-difference + if (inst->weightSpecDiff) { + tmpU32no1 = 0; + if (inst->featureSpecDiff) { + normTmp = WEBRTC_SPL_MIN(20 - inst->stages, + WebRtcSpl_NormU32(inst->featureSpecDiff)); + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(inst->featureSpecDiff, normTmp); // Q(normTmp-2*stages) + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(inst->timeAvgMagnEnergy, 20 - inst->stages + - normTmp); + if (tmpU32no2 > 0) { + // Q(20 - inst->stages) + tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); + } else { + tmpU32no1 = (WebRtc_UWord32)(0x7fffffff); + } } - - //for template spectral-difference - if (inst->weightSpecDiff) - { - tmpU32no1 = 0; - if (inst->featureSpecDiff) - { - normTmp = WEBRTC_SPL_MIN(20 - inst->stages, - WebRtcSpl_NormU32(inst->featureSpecDiff)); - tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(inst->featureSpecDiff, normTmp); // Q(normTmp-2*stages) - tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(inst->timeAvgMagnEnergy, 20 - inst->stages - - normTmp); - if (tmpU32no2) - { - tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q14?? Q(20 - inst->stages) - } else - { - tmpU32no1 = (WebRtc_UWord32)(0x7fffffff); - } - } - tmpU32no3 = WEBRTC_SPL_UDIV(WEBRTC_SPL_LSHIFT_U32(inst->thresholdSpecDiff, 17), 25); - tmpU32no2 = tmpU32no1 - tmpU32no3; - nShifts = 1; - tmpIndFX = 16384; // Q14(1.0) - //use larger width in tanh map for pause regions - if (tmpU32no2 & 0x80000000) - { - tmpIndFX = 0; - tmpU32no2 = tmpU32no3 - tmpU32no1; - //widthPrior = widthPrior * 2.0; - nShifts--; - } - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, nShifts); - // compute indicator function: sigmoid map - /* FLOAT code - indicator2 = 0.5 * (tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.0); - */ - tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14); - if (tableIndex < 16) - { - tmp16no2 = kIndicatorTable[tableIndex]; - tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; - frac = (WebRtc_Word16)(tmpU32no1 & 0x00003fff); // Q14 - tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16no1, frac, - 14); - if (tmpIndFX) - { - tmpIndFX = 8192 + tmp16no2; - } else - { - tmpIndFX = 8192 - tmp16no2; - } - } - indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecDiff, tmpIndFX); // 6*Q14 + tmpU32no3 = WEBRTC_SPL_UDIV(WEBRTC_SPL_LSHIFT_U32(inst->thresholdSpecDiff, 17), 25); + tmpU32no2 = tmpU32no1 - tmpU32no3; + nShifts = 1; + tmpIndFX = 16384; // Q14(1.0) + //use larger width in tanh map for pause regions + if (tmpU32no2 & 0x80000000) { + tmpIndFX = 0; + tmpU32no2 = tmpU32no3 - tmpU32no1; + //widthPrior = widthPrior * 2.0; + nShifts--; } - - //combine the indicator function with the feature weights - // FLOAT code - // indPrior = 1 - (weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 + weightIndPrior2 * indicator2); - indPriorFX16 = WebRtcSpl_DivW32W16ResW16(98307 - indPriorFX, 6); // Q14 - // done with computing indicator function - - //compute the prior probability - // FLOAT code - // inst->priorNonSpeechProb += PRIOR_UPDATE * (indPriorNonSpeech - inst->priorNonSpeechProb); - tmp16 = indPriorFX16 - inst->priorNonSpeechProb; // Q14 - inst->priorNonSpeechProb += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(PRIOR_UPDATE_Q14, - tmp16, 14); // Q14 - - //final speech probability: combine prior model with LR factor: - for (i = 0; i < inst->magnLen; i++) - { - // FLOAT code - // invLrt = exp(inst->logLrtTimeAvg[i]); - // invLrt = inst->priorSpeechProb * invLrt; - // nonSpeechProbFinal[i] = (1.0 - inst->priorSpeechProb) / (1.0 - inst->priorSpeechProb + invLrt); - // invLrt = (1.0 - inst->priorNonSpeechProb) * invLrt; - // nonSpeechProbFinal[i] = inst->priorNonSpeechProb / (inst->priorNonSpeechProb + invLrt); - nonSpeechProbFinal[i] = 0; // Q8 - if ((inst->logLrtTimeAvgW32[i] < 65300) && (inst->priorNonSpeechProb > 0)) - { - tmp32no1 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(inst->logLrtTimeAvgW32[i], 23637), - 14); // Q12 - intPart = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 12); - if (intPart < -8) - { - intPart = -8; - } - frac = (WebRtc_Word16)(tmp32no1 & 0x00000fff); // Q12 - // Quadratic approximation of 2^frac - tmp32no2 = WEBRTC_SPL_RSHIFT_W32(frac * frac * 44, 19); // Q12 - tmp32no2 += WEBRTC_SPL_MUL_16_16_RSFT(frac, 84, 7); // Q12 - invLrtFX = WEBRTC_SPL_LSHIFT_W32(1, 8 + intPart) - + WEBRTC_SPL_SHIFT_W32(tmp32no2, intPart - 4); // Q8 - - normTmp = WebRtcSpl_NormW32(invLrtFX); - normTmp2 = WebRtcSpl_NormW16((16384 - inst->priorNonSpeechProb)); - if (normTmp + normTmp2 < 15) - { - invLrtFX = WEBRTC_SPL_RSHIFT_W32(invLrtFX, 15 - normTmp2 - normTmp); // Q(normTmp+normTmp2-7) - tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); // Q(normTmp+normTmp2+7) - invLrtFX = WEBRTC_SPL_SHIFT_W32(tmp32no1, 7 - normTmp - normTmp2); // Q14 - } else - { - tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); // Q22 - invLrtFX = WEBRTC_SPL_RSHIFT_W32(tmp32no1, 8); // Q14 - } - - tmp32no1 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)inst->priorNonSpeechProb, 8); // Q22 - nonSpeechProbFinal[i] = (WebRtc_UWord16)WEBRTC_SPL_DIV(tmp32no1, - (WebRtc_Word32)inst->priorNonSpeechProb - + invLrtFX); // Q8 - if (7 - normTmp - normTmp2 > 0) - { - nonSpeechProbFinal[i] = 0; // Q8 - } + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, nShifts); + // compute indicator function: sigmoid map + /* FLOAT code + indicator2 = 0.5 * (tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.0); + */ + tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14); + if (tableIndex < 16) { + tmp16no2 = kIndicatorTable[tableIndex]; + tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; + frac = (WebRtc_Word16)(tmpU32no1 & 0x00003fff); // Q14 + tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + tmp16no1, frac, 14); + if (tmpIndFX) { + tmpIndFX = 8192 + tmp16no2; + } else { + tmpIndFX = 8192 - tmp16no2; + } + } + indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecDiff, tmpIndFX); // 6*Q14 + } + + //combine the indicator function with the feature weights + // FLOAT code + // indPrior = 1 - (weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 + weightIndPrior2 * indicator2); + indPriorFX16 = WebRtcSpl_DivW32W16ResW16(98307 - indPriorFX, 6); // Q14 + // done with computing indicator function + + //compute the prior probability + // FLOAT code + // inst->priorNonSpeechProb += PRIOR_UPDATE * (indPriorNonSpeech - inst->priorNonSpeechProb); + tmp16 = indPriorFX16 - inst->priorNonSpeechProb; // Q14 + inst->priorNonSpeechProb += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + PRIOR_UPDATE_Q14, tmp16, 14); // Q14 + + //final speech probability: combine prior model with LR factor: + + memset(nonSpeechProbFinal, 0, sizeof(WebRtc_UWord16) * inst->magnLen); + + if (inst->priorNonSpeechProb > 0) { + for (i = 0; i < inst->magnLen; i++) { + // FLOAT code + // invLrt = exp(inst->logLrtTimeAvg[i]); + // invLrt = inst->priorSpeechProb * invLrt; + // nonSpeechProbFinal[i] = (1.0 - inst->priorSpeechProb) / (1.0 - inst->priorSpeechProb + invLrt); + // invLrt = (1.0 - inst->priorNonSpeechProb) * invLrt; + // nonSpeechProbFinal[i] = inst->priorNonSpeechProb / (inst->priorNonSpeechProb + invLrt); + if (inst->logLrtTimeAvgW32[i] < 65300) { + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(inst->logLrtTimeAvgW32[i], 23637), + 14); // Q12 + intPart = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 12); + if (intPart < -8) { + intPart = -8; + } + frac = (WebRtc_Word16)(tmp32no1 & 0x00000fff); // Q12 + + // Quadratic approximation of 2^frac + tmp32no2 = WEBRTC_SPL_RSHIFT_W32(frac * frac * 44, 19); // Q12 + tmp32no2 += WEBRTC_SPL_MUL_16_16_RSFT(frac, 84, 7); // Q12 + invLrtFX = WEBRTC_SPL_LSHIFT_W32(1, 8 + intPart) + + WEBRTC_SPL_SHIFT_W32(tmp32no2, intPart - 4); // Q8 + + normTmp = WebRtcSpl_NormW32(invLrtFX); + normTmp2 = WebRtcSpl_NormW16((16384 - inst->priorNonSpeechProb)); + if (normTmp + normTmp2 >= 7) { + if (normTmp + normTmp2 < 15) { + invLrtFX = WEBRTC_SPL_RSHIFT_W32(invLrtFX, 15 - normTmp2 - normTmp); + // Q(normTmp+normTmp2-7) + tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); + // Q(normTmp+normTmp2+7) + invLrtFX = WEBRTC_SPL_SHIFT_W32(tmp32no1, 7 - normTmp - normTmp2); // Q14 + } else { + tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); // Q22 + invLrtFX = WEBRTC_SPL_RSHIFT_W32(tmp32no1, 8); // Q14 + } + + tmp32no1 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)inst->priorNonSpeechProb, 8); // Q22 + + nonSpeechProbFinal[i] = (WebRtc_UWord16)WEBRTC_SPL_DIV(tmp32no1, + (WebRtc_Word32)inst->priorNonSpeechProb + invLrtFX); // Q8 } + } } + } } // Transform input (speechFrame) to frequency domain magnitude (magnU16) -void WebRtcNsx_DataAnalysis(NsxInst_t *inst, short *speechFrame, WebRtc_UWord16 *magnU16) -{ - - WebRtc_UWord32 tmpU32no1, tmpU32no2; - - WebRtc_Word32 tmp_1_w32 = 0; - WebRtc_Word32 tmp_2_w32 = 0; - WebRtc_Word32 sum_log_magn = 0; - WebRtc_Word32 sum_log_i_log_magn = 0; - - WebRtc_UWord16 sum_log_magn_u16 = 0; - WebRtc_UWord16 tmp_u16 = 0; - - WebRtc_Word16 sum_log_i = 0; - WebRtc_Word16 sum_log_i_square = 0; - WebRtc_Word16 frac = 0; - WebRtc_Word16 log2 = 0; - WebRtc_Word16 matrix_determinant = 0; - WebRtc_Word16 winData[ANAL_BLOCKL_MAX], maxWinData; - WebRtc_Word16 realImag[ANAL_BLOCKL_MAX << 1]; - - int i, j; - int outCFFT; - int zeros; - int net_norm = 0; - int right_shifts_in_magnU16 = 0; - int right_shifts_in_initMagnEst = 0; - - // For lower band do all processing - // update analysis buffer for L band - WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer, inst->analysisBuffer + inst->blockLen10ms, - inst->anaLen - inst->blockLen10ms); - WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer + inst->anaLen - inst->blockLen10ms, - speechFrame, inst->blockLen10ms); - - // Window data before FFT - for (i = 0; i < inst->anaLen; i++) - { - winData[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(inst->window[i], - inst->analysisBuffer[i], - 14); // Q0 - } - // Get input energy - inst->energyIn = WebRtcSpl_Energy(winData, (int)inst->anaLen, &(inst->scaleEnergyIn)); - - // Reset zero input flag - inst->zeroInputSignal = 0; - // Acquire norm for winData - maxWinData = WebRtcSpl_MaxAbsValueW16(winData, inst->anaLen); - inst->normData = WebRtcSpl_NormW16(maxWinData); - if (maxWinData == 0) - { - // Treat zero input separately. - inst->zeroInputSignal = 1; - return; +void WebRtcNsx_DataAnalysis(NsxInst_t* inst, short* speechFrame, WebRtc_UWord16* magnU16) { + + WebRtc_UWord32 tmpU32no1, tmpU32no2; + + WebRtc_Word32 tmp_1_w32 = 0; + WebRtc_Word32 tmp_2_w32 = 0; + WebRtc_Word32 sum_log_magn = 0; + WebRtc_Word32 sum_log_i_log_magn = 0; + + WebRtc_UWord16 sum_log_magn_u16 = 0; + WebRtc_UWord16 tmp_u16 = 0; + + WebRtc_Word16 sum_log_i = 0; + WebRtc_Word16 sum_log_i_square = 0; + WebRtc_Word16 frac = 0; + WebRtc_Word16 log2 = 0; + WebRtc_Word16 matrix_determinant = 0; + WebRtc_Word16 winData[ANAL_BLOCKL_MAX], maxWinData; + WebRtc_Word16 realImag[ANAL_BLOCKL_MAX << 1]; + + int i, j; + int outCFFT; + int zeros; + int net_norm = 0; + int right_shifts_in_magnU16 = 0; + int right_shifts_in_initMagnEst = 0; + + // For lower band do all processing + // update analysis buffer for L band + WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer, inst->analysisBuffer + inst->blockLen10ms, + inst->anaLen - inst->blockLen10ms); + WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer + inst->anaLen - inst->blockLen10ms, + speechFrame, inst->blockLen10ms); + + // Window data before FFT + for (i = 0; i < inst->anaLen; i++) { + winData[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + inst->window[i], inst->analysisBuffer[i], 14); // Q0 + } + // Get input energy + inst->energyIn = WebRtcSpl_Energy(winData, (int)inst->anaLen, &(inst->scaleEnergyIn)); + + // Reset zero input flag + inst->zeroInputSignal = 0; + // Acquire norm for winData + maxWinData = WebRtcSpl_MaxAbsValueW16(winData, inst->anaLen); + inst->normData = WebRtcSpl_NormW16(maxWinData); + if (maxWinData == 0) { + // Treat zero input separately. + inst->zeroInputSignal = 1; + return; + } + + // Determine the net normalization in the frequency domain + net_norm = inst->stages - inst->normData; + // Track lowest normalization factor and use it to prevent wrap around in shifting + right_shifts_in_magnU16 = inst->normData - inst->minNorm; + right_shifts_in_initMagnEst = WEBRTC_SPL_MAX(-right_shifts_in_magnU16, 0); + inst->minNorm -= right_shifts_in_initMagnEst; + right_shifts_in_magnU16 = WEBRTC_SPL_MAX(right_shifts_in_magnU16, 0); + + // create realImag as winData interleaved with zeros (= imag. part), normalize it + for (i = 0; i < inst->anaLen; i++) { + j = WEBRTC_SPL_LSHIFT_W16(i, 1); + realImag[j] = WEBRTC_SPL_LSHIFT_W16(winData[i], inst->normData); // Q(normData) + realImag[j + 1] = 0; // Insert zeros in imaginary part + } + + // bit-reverse position of elements in array and FFT the array + WebRtcSpl_ComplexBitReverse(realImag, inst->stages); // Q(normData-stages) + outCFFT = WebRtcSpl_ComplexFFT(realImag, inst->stages, 1); + + inst->imag[0] = 0; // Q(normData-stages) + inst->imag[inst->anaLen2] = 0; + inst->real[0] = realImag[0]; // Q(normData-stages) + inst->real[inst->anaLen2] = realImag[inst->anaLen]; + // Q(2*(normData-stages)) + inst->magnEnergy = (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(inst->real[0], inst->real[0]); + inst->magnEnergy += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(inst->real[inst->anaLen2], + inst->real[inst->anaLen2]); + magnU16[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(inst->real[0]); // Q(normData-stages) + magnU16[inst->anaLen2] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(inst->real[inst->anaLen2]); + inst->sumMagn = (WebRtc_UWord32)magnU16[0]; // Q(normData-stages) + inst->sumMagn += (WebRtc_UWord32)magnU16[inst->anaLen2]; + + if (inst->blockIndex >= END_STARTUP_SHORT) { + for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) { + inst->real[i] = realImag[j]; + inst->imag[i] = -realImag[j + 1]; + // magnitude spectrum + // energy in Q(2*(normData-stages)) + tmpU32no1 = (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j], realImag[j]); + tmpU32no1 += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j + 1], realImag[j + 1]); + inst->magnEnergy += tmpU32no1; // Q(2*(normData-stages)) + + magnU16[i] = (WebRtc_UWord16)WebRtcSpl_Sqrt(tmpU32no1); // Q(normData-stages) + inst->sumMagn += (WebRtc_UWord32)magnU16[i]; // Q(normData-stages) } + } else { + // + // Gather information during startup for noise parameter estimation + // - // Determine the net normalization in the frequency domain - net_norm = inst->stages - inst->normData; - // Track lowest normalization factor and use it to prevent wrap around in shifting - right_shifts_in_magnU16 = inst->normData - inst->minNorm; - right_shifts_in_initMagnEst = WEBRTC_SPL_MAX(-right_shifts_in_magnU16, 0); - inst->minNorm -= right_shifts_in_initMagnEst; - right_shifts_in_magnU16 = WEBRTC_SPL_MAX(right_shifts_in_magnU16, 0); - - // create realImag as winData interleaved with zeros (= imag. part), normalize it - for (i = 0; i < inst->anaLen; i++) - { - j = WEBRTC_SPL_LSHIFT_W16(i, 1); - realImag[j] = WEBRTC_SPL_LSHIFT_W16(winData[i], inst->normData); // Q(normData) - realImag[j + 1] = 0; // Insert zeros in imaginary part + // Switch initMagnEst to Q(minNorm-stages) + inst->initMagnEst[0] = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[0], + right_shifts_in_initMagnEst); + inst->initMagnEst[inst->anaLen2] = + WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[inst->anaLen2], + right_shifts_in_initMagnEst); // Q(minNorm-stages) + + // Shift magnU16 to same domain as initMagnEst + tmpU32no1 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[0], + right_shifts_in_magnU16); // Q(minNorm-stages) + tmpU32no2 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[inst->anaLen2], + right_shifts_in_magnU16); // Q(minNorm-stages) + + // Update initMagnEst + inst->initMagnEst[0] += tmpU32no1; // Q(minNorm-stages) + inst->initMagnEst[inst->anaLen2] += tmpU32no2; // Q(minNorm-stages) + + log2 = 0; + if (magnU16[inst->anaLen2]) { + // Calculate log2(magnU16[inst->anaLen2]) + zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magnU16[inst->anaLen2]); + frac = (WebRtc_Word16)((((WebRtc_UWord32)magnU16[inst->anaLen2] << zeros) & + 0x7FFFFFFF) >> 23); // Q8 + // log2(magnU16(i)) in Q8 + assert(frac < 256); + log2 = (WebRtc_Word16)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); } - // bit-reverse position of elements in array and FFT the array - WebRtcSpl_ComplexBitReverse(realImag, inst->stages); // Q(normData-stages) - outCFFT = WebRtcSpl_ComplexFFT(realImag, inst->stages, 1); - - inst->imag[0] = 0; // Q(normData-stages) - inst->imag[inst->anaLen2] = 0; - inst->real[0] = realImag[0]; // Q(normData-stages) - inst->real[inst->anaLen2] = realImag[inst->anaLen]; - // Q(2*(normData-stages)) - inst->magnEnergy = (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(inst->real[0], inst->real[0]); - inst->magnEnergy += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(inst->real[inst->anaLen2], - inst->real[inst->anaLen2]); - magnU16[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(inst->real[0]); // Q(normData-stages) - magnU16[inst->anaLen2] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(inst->real[inst->anaLen2]); - inst->sumMagn = (WebRtc_UWord32)magnU16[0]; // Q(normData-stages) - inst->sumMagn += (WebRtc_UWord32)magnU16[inst->anaLen2]; - - // Gather information during startup for noise parameter estimation - if (inst->blockIndex < END_STARTUP_SHORT) - { - // Switch initMagnEst to Q(minNorm-stages) - inst->initMagnEst[0] = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[0], - right_shifts_in_initMagnEst); - inst->initMagnEst[inst->anaLen2] = - WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[inst->anaLen2], - right_shifts_in_initMagnEst); // Q(minNorm-stages) - - // Shift magnU16 to same domain as initMagnEst - tmpU32no1 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[0], - right_shifts_in_magnU16); // Q(minNorm-stages) - tmpU32no2 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[inst->anaLen2], - right_shifts_in_magnU16); // Q(minNorm-stages) - - // Update initMagnEst - inst->initMagnEst[0] += tmpU32no1; // Q(minNorm-stages) - inst->initMagnEst[inst->anaLen2] += tmpU32no2; // Q(minNorm-stages) - + sum_log_magn = (WebRtc_Word32)log2; // Q8 + // sum_log_i_log_magn in Q17 + sum_log_i_log_magn = (WEBRTC_SPL_MUL_16_16(kLogIndex[inst->anaLen2], log2) >> 3); + + for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) { + inst->real[i] = realImag[j]; + inst->imag[i] = -realImag[j + 1]; + // magnitude spectrum + // energy in Q(2*(normData-stages)) + tmpU32no1 = (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j], realImag[j]); + tmpU32no1 += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j + 1], realImag[j + 1]); + inst->magnEnergy += tmpU32no1; // Q(2*(normData-stages)) + + magnU16[i] = (WebRtc_UWord16)WebRtcSpl_Sqrt(tmpU32no1); // Q(normData-stages) + inst->sumMagn += (WebRtc_UWord32)magnU16[i]; // Q(normData-stages) + + // Switch initMagnEst to Q(minNorm-stages) + inst->initMagnEst[i] = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[i], + right_shifts_in_initMagnEst); + + // Shift magnU16 to same domain as initMagnEst, i.e., Q(minNorm-stages) + tmpU32no1 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[i], + right_shifts_in_magnU16); + // Update initMagnEst + inst->initMagnEst[i] += tmpU32no1; // Q(minNorm-stages) + + if (i >= kStartBand) { + // For pink noise estimation. Collect data neglecting lower frequency band log2 = 0; - if (magnU16[inst->anaLen2]) - { - // Calculate log2(magnU16[inst->anaLen2]) - zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magnU16[inst->anaLen2]); - frac = (WebRtc_Word16)((((WebRtc_UWord32)magnU16[inst->anaLen2] << zeros) & - 0x7FFFFFFF) >> 23); // Q8 - // log2(magnU16(i)) in Q8 - log2 = (WebRtc_Word16)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); + if (magnU16[i]) { + zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magnU16[i]); + frac = (WebRtc_Word16)((((WebRtc_UWord32)magnU16[i] << zeros) & + 0x7FFFFFFF) >> 23); + // log2(magnU16(i)) in Q8 + assert(frac < 256); + log2 = (WebRtc_Word16)(((31 - zeros) << 8) + + WebRtcNsx_kLogTableFrac[frac]); } - - sum_log_magn = (WebRtc_Word32)log2; // Q8 + sum_log_magn += (WebRtc_Word32)log2; // Q8 // sum_log_i_log_magn in Q17 - sum_log_i_log_magn = (WEBRTC_SPL_MUL_16_16(kLogIndex[inst->anaLen2], log2) >> 3); - } - - for (i = 1; i < inst->anaLen2; i++) - { - j = WEBRTC_SPL_LSHIFT_W16(i, 1); - inst->real[i] = realImag[j]; - inst->imag[i] = -realImag[j + 1]; - // magnitude spectrum - // energy in Q(2*(normData-stages)) - tmpU32no1 = (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j], realImag[j]); - tmpU32no1 += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j + 1], realImag[j + 1]); - inst->magnEnergy += tmpU32no1; // Q(2*(normData-stages)) - - magnU16[i] = (WebRtc_UWord16)WebRtcSpl_Sqrt(tmpU32no1); // Q(normData-stages) - inst->sumMagn += (WebRtc_UWord32)magnU16[i]; // Q(normData-stages) - if (inst->blockIndex < END_STARTUP_SHORT) - { - // Switch initMagnEst to Q(minNorm-stages) - inst->initMagnEst[i] = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[i], - right_shifts_in_initMagnEst); - - // Shift magnU16 to same domain as initMagnEst, i.e., Q(minNorm-stages) - tmpU32no1 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[i], - right_shifts_in_magnU16); - // Update initMagnEst - inst->initMagnEst[i] += tmpU32no1; // Q(minNorm-stages) - - if (i >= kStartBand) - { - // For pink noise estimation. Collect data neglecting lower frequency band - log2 = 0; - if (magnU16[i]) - { - zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magnU16[i]); - frac = (WebRtc_Word16)((((WebRtc_UWord32)magnU16[i] << zeros) & - 0x7FFFFFFF) >> 23); - // log2(magnU16(i)) in Q8 - log2 = (WebRtc_Word16)(((31 - zeros) << 8) - + WebRtcNsx_kLogTableFrac[frac]); - } - sum_log_magn += (WebRtc_Word32)log2; // Q8 - // sum_log_i_log_magn in Q17 - sum_log_i_log_magn += (WEBRTC_SPL_MUL_16_16(kLogIndex[i], log2) >> 3); - } - } + sum_log_i_log_magn += (WEBRTC_SPL_MUL_16_16(kLogIndex[i], log2) >> 3); + } } + // //compute simplified noise model during startup - if (inst->blockIndex < END_STARTUP_SHORT) - { - // Estimate White noise - // Switch whiteNoiseLevel to Q(minNorm-stages) - inst->whiteNoiseLevel = WEBRTC_SPL_RSHIFT_U32(inst->whiteNoiseLevel, - right_shifts_in_initMagnEst); - - // Update the average magnitude spectrum, used as noise estimate. - tmpU32no1 = WEBRTC_SPL_UMUL_32_16(inst->sumMagn, inst->overdrive); - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, inst->stages + 8); - - // Replacing division above with 'stages' shifts - // Shift to same Q-domain as whiteNoiseLevel - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, right_shifts_in_magnU16); - // This operation is safe from wrap around as long as END_STARTUP_SHORT < 128 - assert(END_STARTUP_SHORT < 128); - inst->whiteNoiseLevel += tmpU32no1; // Q(minNorm-stages) - - // Estimate Pink noise parameters - // Denominator used in both parameter estimates. - // The value is only dependent on the size of the frequency band (kStartBand) - // and to reduce computational complexity stored in a table (kDeterminantEstMatrix[]) - matrix_determinant = kDeterminantEstMatrix[kStartBand]; // Q0 - sum_log_i = kSumLogIndex[kStartBand]; // Q5 - sum_log_i_square = kSumSquareLogIndex[kStartBand]; // Q2 - if (inst->fs == 8000) - { - // Adjust values to shorter blocks in narrow band. - tmp_1_w32 = (WebRtc_Word32)matrix_determinant; - tmp_1_w32 += WEBRTC_SPL_MUL_16_16_RSFT(kSumLogIndex[65], sum_log_i, 9); - tmp_1_w32 -= WEBRTC_SPL_MUL_16_16_RSFT(kSumLogIndex[65], kSumLogIndex[65], 10); - tmp_1_w32 -= WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)sum_log_i_square, 4); - tmp_1_w32 -= WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16)(inst->magnLen - - kStartBand), kSumSquareLogIndex[65], 2); - matrix_determinant = (WebRtc_Word16)tmp_1_w32; - sum_log_i -= kSumLogIndex[65]; // Q5 - sum_log_i_square -= kSumSquareLogIndex[65]; // Q2 - } + // - // Necessary number of shifts to fit sum_log_magn in a word16 - zeros = 16 - WebRtcSpl_NormW32(sum_log_magn); - if (zeros < 0) - { - zeros = 0; - } - tmp_1_w32 = WEBRTC_SPL_LSHIFT_W32(sum_log_magn, 1); // Q9 - sum_log_magn_u16 = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_W32(tmp_1_w32, zeros);//Q(9-zeros) - - // Calculate and update pinkNoiseNumerator. Result in Q11. - tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i_square, sum_log_magn_u16); // Q(11-zeros) - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32((WebRtc_UWord32)sum_log_i_log_magn, 12); // Q5 - - // Shift the largest value of sum_log_i and tmp32no3 before multiplication - tmp_u16 = WEBRTC_SPL_LSHIFT_U16((WebRtc_UWord16)sum_log_i, 1); // Q6 - if ((WebRtc_UWord32)sum_log_i > tmpU32no1) - { - tmp_u16 = WEBRTC_SPL_RSHIFT_U16(tmp_u16, zeros); - } - else - { - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, zeros); - } - tmp_2_w32 -= (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(tmpU32no1, tmp_u16); // Q(11-zeros) - matrix_determinant = WEBRTC_SPL_RSHIFT_W16(matrix_determinant, zeros); // Q(-zeros) - tmp_2_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q11 - tmp_2_w32 += WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)net_norm, 11); // Q11 - if (tmp_2_w32 < 0) - { - tmp_2_w32 = 0; - } - inst->pinkNoiseNumerator += tmp_2_w32; // Q11 - - // Calculate and update pinkNoiseExp. Result in Q14. - tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i, sum_log_magn_u16); // Q(14-zeros) - tmp_1_w32 = WEBRTC_SPL_RSHIFT_W32(sum_log_i_log_magn, 3 + zeros); - tmp_1_w32 = WEBRTC_SPL_MUL((WebRtc_Word32)(inst->magnLen - kStartBand), - tmp_1_w32); - tmp_2_w32 -= tmp_1_w32; // Q(14-zeros) - if (tmp_2_w32 > 0) - { - // If the exponential parameter is negative force it to zero, which means a - // flat spectrum. - tmp_1_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q14 - inst->pinkNoiseExp += WEBRTC_SPL_SAT(16384, tmp_1_w32, 0); // Q14 - } + // Estimate White noise + + // Switch whiteNoiseLevel to Q(minNorm-stages) + inst->whiteNoiseLevel = WEBRTC_SPL_RSHIFT_U32(inst->whiteNoiseLevel, + right_shifts_in_initMagnEst); + + // Update the average magnitude spectrum, used as noise estimate. + tmpU32no1 = WEBRTC_SPL_UMUL_32_16(inst->sumMagn, inst->overdrive); + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, inst->stages + 8); + + // Replacing division above with 'stages' shifts + // Shift to same Q-domain as whiteNoiseLevel + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, right_shifts_in_magnU16); + // This operation is safe from wrap around as long as END_STARTUP_SHORT < 128 + assert(END_STARTUP_SHORT < 128); + inst->whiteNoiseLevel += tmpU32no1; // Q(minNorm-stages) + + // Estimate Pink noise parameters + // Denominator used in both parameter estimates. + // The value is only dependent on the size of the frequency band (kStartBand) + // and to reduce computational complexity stored in a table (kDeterminantEstMatrix[]) + assert(kStartBand < 66); + matrix_determinant = kDeterminantEstMatrix[kStartBand]; // Q0 + sum_log_i = kSumLogIndex[kStartBand]; // Q5 + sum_log_i_square = kSumSquareLogIndex[kStartBand]; // Q2 + if (inst->fs == 8000) { + // Adjust values to shorter blocks in narrow band. + tmp_1_w32 = (WebRtc_Word32)matrix_determinant; + tmp_1_w32 += WEBRTC_SPL_MUL_16_16_RSFT(kSumLogIndex[65], sum_log_i, 9); + tmp_1_w32 -= WEBRTC_SPL_MUL_16_16_RSFT(kSumLogIndex[65], kSumLogIndex[65], 10); + tmp_1_w32 -= WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)sum_log_i_square, 4); + tmp_1_w32 -= WEBRTC_SPL_MUL_16_16_RSFT( + (WebRtc_Word16)(inst->magnLen - kStartBand), kSumSquareLogIndex[65], 2); + matrix_determinant = (WebRtc_Word16)tmp_1_w32; + sum_log_i -= kSumLogIndex[65]; // Q5 + sum_log_i_square -= kSumSquareLogIndex[65]; // Q2 } -} -void WebRtcNsx_DataSynthesis(NsxInst_t *inst, short *outFrame) -{ - WebRtc_Word32 tmp32no1; - WebRtc_Word32 energyOut; - - WebRtc_Word16 realImag[ANAL_BLOCKL_MAX << 1]; - WebRtc_Word16 tmp16no1, tmp16no2; - WebRtc_Word16 energyRatio; - WebRtc_Word16 gainFactor, gainFactor1, gainFactor2; - - int i, j; - int outCIFFT; - int scaleEnergyOut = 0; - - if (inst->zeroInputSignal) - { - // synthesize the special case of zero input - // read out fully processed segment - for (i = 0; i < inst->blockLen10ms; i++) - { - outFrame[i] = inst->synthesisBuffer[i]; // Q0 - } - // update synthesis buffer - WEBRTC_SPL_MEMCPY_W16(inst->synthesisBuffer, - inst->synthesisBuffer + inst->blockLen10ms, - inst->anaLen - inst->blockLen10ms); - WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms, - inst->blockLen10ms); - return; + // Necessary number of shifts to fit sum_log_magn in a word16 + zeros = 16 - WebRtcSpl_NormW32(sum_log_magn); + if (zeros < 0) { + zeros = 0; } - // Filter the data in the frequency domain - for (i = 0; i < inst->magnLen; i++) - { - inst->real[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(inst->real[i], - (WebRtc_Word16)(inst->noiseSupFilter[i]), 14); // Q(normData-stages) - inst->imag[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(inst->imag[i], - (WebRtc_Word16)(inst->noiseSupFilter[i]), 14); // Q(normData-stages) + tmp_1_w32 = WEBRTC_SPL_LSHIFT_W32(sum_log_magn, 1); // Q9 + sum_log_magn_u16 = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_W32(tmp_1_w32, zeros);//Q(9-zeros) + + // Calculate and update pinkNoiseNumerator. Result in Q11. + tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i_square, sum_log_magn_u16); // Q(11-zeros) + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32((WebRtc_UWord32)sum_log_i_log_magn, 12); // Q5 + + // Shift the largest value of sum_log_i and tmp32no3 before multiplication + tmp_u16 = WEBRTC_SPL_LSHIFT_U16((WebRtc_UWord16)sum_log_i, 1); // Q6 + if ((WebRtc_UWord32)sum_log_i > tmpU32no1) { + tmp_u16 = WEBRTC_SPL_RSHIFT_U16(tmp_u16, zeros); + } else { + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, zeros); } - // back to time domain - // Create spectrum - realImag[0] = inst->real[0]; - realImag[1] = -inst->imag[0]; - for (i = 1; i < inst->anaLen2; i++) - { - j = WEBRTC_SPL_LSHIFT_W16(i, 1); - tmp16no1 = (inst->anaLen << 1) - j; - realImag[j] = inst->real[i]; - realImag[j + 1] = -inst->imag[i]; - realImag[tmp16no1] = inst->real[i]; - realImag[tmp16no1 + 1] = inst->imag[i]; + tmp_2_w32 -= (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(tmpU32no1, tmp_u16); // Q(11-zeros) + matrix_determinant = WEBRTC_SPL_RSHIFT_W16(matrix_determinant, zeros); // Q(-zeros) + tmp_2_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q11 + tmp_2_w32 += WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)net_norm, 11); // Q11 + if (tmp_2_w32 < 0) { + tmp_2_w32 = 0; } - realImag[inst->anaLen] = inst->real[inst->anaLen2]; - realImag[inst->anaLen + 1] = -inst->imag[inst->anaLen2]; - - // bit-reverse position of elements in array and IFFT it - WebRtcSpl_ComplexBitReverse(realImag, inst->stages); - outCIFFT = WebRtcSpl_ComplexIFFT(realImag, inst->stages, 1); - - for (i = 0; i < inst->anaLen; i++) - { - j = WEBRTC_SPL_LSHIFT_W16(i, 1); - tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)realImag[j], outCIFFT - inst->normData); - inst->real[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, tmp32no1, - WEBRTC_SPL_WORD16_MIN); + inst->pinkNoiseNumerator += tmp_2_w32; // Q11 + + // Calculate and update pinkNoiseExp. Result in Q14. + tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i, sum_log_magn_u16); // Q(14-zeros) + tmp_1_w32 = WEBRTC_SPL_RSHIFT_W32(sum_log_i_log_magn, 3 + zeros); + tmp_1_w32 = WEBRTC_SPL_MUL((WebRtc_Word32)(inst->magnLen - kStartBand), + tmp_1_w32); + tmp_2_w32 -= tmp_1_w32; // Q(14-zeros) + if (tmp_2_w32 > 0) { + // If the exponential parameter is negative force it to zero, which means a + // flat spectrum. + tmp_1_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q14 + inst->pinkNoiseExp += WEBRTC_SPL_SAT(16384, tmp_1_w32, 0); // Q14 } + } +} - //scale factor: only do it after END_STARTUP_LONG time - gainFactor = 8192; // 8192 = Q13(1.0) - if (inst->gainMap == 1 && - inst->blockIndex > END_STARTUP_LONG && - inst->energyIn > 0) - { - energyOut = WebRtcSpl_Energy(inst->real, (int)inst->anaLen, &scaleEnergyOut); // Q(-scaleEnergyOut) - if (scaleEnergyOut == 0 && !(energyOut & 0x7f800000)) - { - energyOut = WEBRTC_SPL_SHIFT_W32(energyOut, 8 + scaleEnergyOut - - inst->scaleEnergyIn); - } else - { - inst->energyIn = WEBRTC_SPL_RSHIFT_W32(inst->energyIn, 8 + scaleEnergyOut - - inst->scaleEnergyIn); // Q(-8-scaleEnergyOut) - } +void WebRtcNsx_DataSynthesis(NsxInst_t* inst, short* outFrame) { + WebRtc_Word32 tmp32no1; + WebRtc_Word32 energyOut; - assert(inst->energyIn > 0); - energyRatio = (WebRtc_Word16)WEBRTC_SPL_DIV(energyOut - + WEBRTC_SPL_RSHIFT_W32(inst->energyIn, 1), inst->energyIn); // Q8 - - // // original FLOAT code - // if (gain > blim) { - // factor1=1.0+1.3*(gain-blim); - // if (gain*factor1 > 1.0) { // FLOAT - // factor1 = 1.0/gain; // FLOAT - // } - // } - // else { - // factor1=1.0; // FLOAT - // } - // - // if (gain > blim) { - // factor2=1.0; //FLOAT - // } - // else { - // //don't reduce scale too much for pause regions: attenuation here should be controlled by flooring - // factor2=1.0-0.3*(blim-gain); // FLOAT - // if (gain <= inst->denoiseBound) { - // factor2=1.0-0.3*(blim-inst->denoiseBound); // FLOAT - // } - // } - - // all done in lookup tables now - gainFactor1 = kFactor1Table[energyRatio]; // Q8 - gainFactor2 = inst->factor2Table[energyRatio]; // Q8 - - //combine both scales with speech/noise prob: note prior (priorSpeechProb) is not frequency dependent - - // factor = inst->priorSpeechProb*factor1 + (1.0-inst->priorSpeechProb)*factor2; // original code - tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(16384 - inst->priorNonSpeechProb, - gainFactor1, 14); // Q13 16384 = Q14(1.0) - tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(inst->priorNonSpeechProb, - gainFactor2, 14); // Q13; - gainFactor = tmp16no1 + tmp16no2; // Q13 - } // out of flag_gain_map==1 - - // synthesis - for (i = 0; i < inst->anaLen; i++) - { - tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(inst->window[i], - inst->real[i], 14); // Q0, window in Q14 - tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16no1, gainFactor, 13); // Q0 - // Down shift with rounding - tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, tmp32no1, - WEBRTC_SPL_WORD16_MIN); // Q0 - inst->synthesisBuffer[i] = WEBRTC_SPL_ADD_SAT_W16(inst->synthesisBuffer[i], tmp16no2); // Q0 - } + WebRtc_Word16 realImag[ANAL_BLOCKL_MAX << 1]; + WebRtc_Word16 tmp16no1, tmp16no2; + WebRtc_Word16 energyRatio; + WebRtc_Word16 gainFactor, gainFactor1, gainFactor2; + + int i, j; + int outCIFFT; + int scaleEnergyOut = 0; + if (inst->zeroInputSignal) { + // synthesize the special case of zero input // read out fully processed segment - for (i = 0; i < inst->blockLen10ms; i++) - { - outFrame[i] = inst->synthesisBuffer[i]; // Q0 + for (i = 0; i < inst->blockLen10ms; i++) { + outFrame[i] = inst->synthesisBuffer[i]; // Q0 } // update synthesis buffer - WEBRTC_SPL_MEMCPY_W16(inst->synthesisBuffer, inst->synthesisBuffer + inst->blockLen10ms, + WEBRTC_SPL_MEMCPY_W16(inst->synthesisBuffer, + inst->synthesisBuffer + inst->blockLen10ms, inst->anaLen - inst->blockLen10ms); WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms, inst->blockLen10ms); + return; + } + // Filter the data in the frequency domain + for (i = 0; i < inst->magnLen; i++) { + inst->real[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + inst->real[i], (WebRtc_Word16)(inst->noiseSupFilter[i]), 14); // Q(normData-stages) + inst->imag[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + inst->imag[i], (WebRtc_Word16)(inst->noiseSupFilter[i]), 14); // Q(normData-stages) + } + // back to time domain + // Create spectrum + realImag[0] = inst->real[0]; + realImag[1] = -inst->imag[0]; + for (i = 1; i < inst->anaLen2; i++) { + j = WEBRTC_SPL_LSHIFT_W16(i, 1); + tmp16no1 = (inst->anaLen << 1) - j; + realImag[j] = inst->real[i]; + realImag[j + 1] = -inst->imag[i]; + realImag[tmp16no1] = inst->real[i]; + realImag[tmp16no1 + 1] = inst->imag[i]; + } + realImag[inst->anaLen] = inst->real[inst->anaLen2]; + realImag[inst->anaLen + 1] = -inst->imag[inst->anaLen2]; + + // bit-reverse position of elements in array and IFFT it + WebRtcSpl_ComplexBitReverse(realImag, inst->stages); + outCIFFT = WebRtcSpl_ComplexIFFT(realImag, inst->stages, 1); + + for (i = 0; i < inst->anaLen; i++) { + j = WEBRTC_SPL_LSHIFT_W16(i, 1); + tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)realImag[j], + outCIFFT - inst->normData); + inst->real[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, + tmp32no1, + WEBRTC_SPL_WORD16_MIN); + } + + //scale factor: only do it after END_STARTUP_LONG time + gainFactor = 8192; // 8192 = Q13(1.0) + if (inst->gainMap == 1 && + inst->blockIndex > END_STARTUP_LONG && + inst->energyIn > 0) { + energyOut = WebRtcSpl_Energy(inst->real, (int)inst->anaLen, &scaleEnergyOut); // Q(-scaleEnergyOut) + if (scaleEnergyOut == 0 && !(energyOut & 0x7f800000)) { + energyOut = WEBRTC_SPL_SHIFT_W32(energyOut, 8 + scaleEnergyOut + - inst->scaleEnergyIn); + } else { + inst->energyIn = WEBRTC_SPL_RSHIFT_W32(inst->energyIn, 8 + scaleEnergyOut + - inst->scaleEnergyIn); // Q(-8-scaleEnergyOut) + } + + assert(inst->energyIn > 0); + energyRatio = (WebRtc_Word16)WEBRTC_SPL_DIV(energyOut + + WEBRTC_SPL_RSHIFT_W32(inst->energyIn, 1), inst->energyIn); // Q8 + // Limit the ratio to [0, 1] in Q8, i.e., [0, 256] + energyRatio = WEBRTC_SPL_SAT(256, energyRatio, 0); + + // all done in lookup tables now + assert(energyRatio < 257); + gainFactor1 = kFactor1Table[energyRatio]; // Q8 + gainFactor2 = inst->factor2Table[energyRatio]; // Q8 + + //combine both scales with speech/noise prob: note prior (priorSpeechProb) is not frequency dependent + + // factor = inst->priorSpeechProb*factor1 + (1.0-inst->priorSpeechProb)*factor2; // original code + tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(16384 - inst->priorNonSpeechProb, + gainFactor1, 14); // Q13 16384 = Q14(1.0) + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(inst->priorNonSpeechProb, + gainFactor2, 14); // Q13; + gainFactor = tmp16no1 + tmp16no2; // Q13 + } // out of flag_gain_map==1 + + // synthesis + for (i = 0; i < inst->anaLen; i++) { + tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(inst->window[i], + inst->real[i], 14); // Q0, window in Q14 + tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16no1, gainFactor, 13); // Q0 + // Down shift with rounding + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, tmp32no1, + WEBRTC_SPL_WORD16_MIN); // Q0 + inst->synthesisBuffer[i] = WEBRTC_SPL_ADD_SAT_W16(inst->synthesisBuffer[i], tmp16no2); // Q0 + } + + // read out fully processed segment + for (i = 0; i < inst->blockLen10ms; i++) { + outFrame[i] = inst->synthesisBuffer[i]; // Q0 + } + // update synthesis buffer + WEBRTC_SPL_MEMCPY_W16(inst->synthesisBuffer, inst->synthesisBuffer + inst->blockLen10ms, + inst->anaLen - inst->blockLen10ms); + WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms, + inst->blockLen10ms); } -int WebRtcNsx_ProcessCore(NsxInst_t *inst, short *speechFrame, short *speechFrameHB, - short *outFrame, short *outFrameHB) -{ - // main routine for noise suppression - - WebRtc_UWord32 tmpU32no1, tmpU32no2, tmpU32no3; - WebRtc_UWord32 satMax, maxNoiseU32; - WebRtc_UWord32 tmpMagnU32, tmpNoiseU32; - WebRtc_UWord32 nearMagnEst; - WebRtc_UWord32 noiseUpdateU32; - WebRtc_UWord32 noiseU32[HALF_ANAL_BLOCKL]; - WebRtc_UWord32 postLocSnr[HALF_ANAL_BLOCKL]; - WebRtc_UWord32 priorLocSnr[HALF_ANAL_BLOCKL]; - WebRtc_UWord32 prevNearSnr[HALF_ANAL_BLOCKL]; - WebRtc_UWord32 curNearSnr; - WebRtc_UWord32 priorSnr; - WebRtc_UWord32 noise_estimate = 0; - WebRtc_UWord32 noise_estimate_avg = 0; - WebRtc_UWord32 numerator = 0; - - WebRtc_Word32 tmp32no1, tmp32no2; - WebRtc_Word32 pink_noise_num_avg = 0; - - WebRtc_UWord16 tmpU16no1; - WebRtc_UWord16 magnU16[HALF_ANAL_BLOCKL]; - WebRtc_UWord16 prevNoiseU16[HALF_ANAL_BLOCKL]; - WebRtc_UWord16 nonSpeechProbFinal[HALF_ANAL_BLOCKL]; - WebRtc_UWord16 gammaNoise, prevGammaNoise; - WebRtc_UWord16 noiseSupFilterTmp[HALF_ANAL_BLOCKL]; - - WebRtc_Word16 qMagn, qNoise; - WebRtc_Word16 avgProbSpeechHB, gainModHB, avgFilterGainHB, gainTimeDomainHB; - WebRtc_Word16 pink_noise_exp_avg = 0; - - int i; - int nShifts, postShifts; - int norm32no1, norm32no2; - int flag, sign; - int q_domain_to_use = 0; +int WebRtcNsx_ProcessCore(NsxInst_t* inst, short* speechFrame, short* speechFrameHB, + short* outFrame, short* outFrameHB) { + // main routine for noise suppression + + WebRtc_UWord32 tmpU32no1, tmpU32no2, tmpU32no3; + WebRtc_UWord32 satMax, maxNoiseU32; + WebRtc_UWord32 tmpMagnU32, tmpNoiseU32; + WebRtc_UWord32 nearMagnEst; + WebRtc_UWord32 noiseUpdateU32; + WebRtc_UWord32 noiseU32[HALF_ANAL_BLOCKL]; + WebRtc_UWord32 postLocSnr[HALF_ANAL_BLOCKL]; + WebRtc_UWord32 priorLocSnr[HALF_ANAL_BLOCKL]; + WebRtc_UWord32 prevNearSnr[HALF_ANAL_BLOCKL]; + WebRtc_UWord32 curNearSnr; + WebRtc_UWord32 priorSnr; + WebRtc_UWord32 noise_estimate = 0; + WebRtc_UWord32 noise_estimate_avg = 0; + WebRtc_UWord32 numerator = 0; + + WebRtc_Word32 tmp32no1, tmp32no2; + WebRtc_Word32 pink_noise_num_avg = 0; + + WebRtc_UWord16 tmpU16no1; + WebRtc_UWord16 magnU16[HALF_ANAL_BLOCKL]; + WebRtc_UWord16 prevNoiseU16[HALF_ANAL_BLOCKL]; + WebRtc_UWord16 nonSpeechProbFinal[HALF_ANAL_BLOCKL]; + WebRtc_UWord16 gammaNoise, prevGammaNoise; + WebRtc_UWord16 noiseSupFilterTmp[HALF_ANAL_BLOCKL]; + + WebRtc_Word16 qMagn, qNoise; + WebRtc_Word16 avgProbSpeechHB, gainModHB, avgFilterGainHB, gainTimeDomainHB; + WebRtc_Word16 pink_noise_exp_avg = 0; + + int i; + int nShifts, postShifts; + int norm32no1, norm32no2; + int flag, sign; + int q_domain_to_use = 0; #ifdef NS_FILEDEBUG - fwrite(spframe, sizeof(short), inst->blockLen10ms, inst->infile); + fwrite(spframe, sizeof(short), inst->blockLen10ms, inst->infile); #endif - // Check that initialization has been done - if (inst->initFlag != 1) - { - return -1; + // Check that initialization has been done + if (inst->initFlag != 1) { + return -1; + } + // Check for valid pointers based on sampling rate + if ((inst->fs == 32000) && (speechFrameHB == NULL)) { + return -1; + } + + // Store speechFrame and transform to frequency domain + WebRtcNsx_DataAnalysis(inst, speechFrame, magnU16); + + if (inst->zeroInputSignal) { + WebRtcNsx_DataSynthesis(inst, outFrame); + + if (inst->fs == 32000) { + // update analysis buffer for H band + // append new data to buffer FX + WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX, inst->dataBufHBFX + inst->blockLen10ms, + inst->anaLen - inst->blockLen10ms); + WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX + inst->anaLen - inst->blockLen10ms, + speechFrameHB, inst->blockLen10ms); + for (i = 0; i < inst->blockLen10ms; i++) { + outFrameHB[i] = inst->dataBufHBFX[i]; // Q0 + } + } // end of H band gain computation + return 0; + } + + // Update block index when we have something to process + inst->blockIndex++; + // + + // Norm of magn + qMagn = inst->normData - inst->stages; + + // Compute spectral flatness on input spectrum + WebRtcNsx_ComputeSpectralFlatness(inst, magnU16); + + // quantile noise estimate + WebRtcNsx_NoiseEstimation(inst, magnU16, noiseU32, &qNoise); + + //noise estimate from previous frame + for (i = 0; i < inst->magnLen; i++) { + prevNoiseU16[i] = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_U32(inst->prevNoiseU32[i], 11); // Q(prevQNoise) + } + + if (inst->blockIndex < END_STARTUP_SHORT) { + // Noise Q-domain to be used later; see description at end of section. + q_domain_to_use = WEBRTC_SPL_MIN((int)qNoise, inst->minNorm - inst->stages); + + // Calculate frequency independent parts in parametric noise estimate and calculate + // the estimate for the lower frequency band (same values for all frequency bins) + if (inst->pinkNoiseExp) { + pink_noise_exp_avg = (WebRtc_Word16)WebRtcSpl_DivW32W16(inst->pinkNoiseExp, + (WebRtc_Word16)(inst->blockIndex + 1)); // Q14 + pink_noise_num_avg = WebRtcSpl_DivW32W16(inst->pinkNoiseNumerator, + (WebRtc_Word16)(inst->blockIndex + 1)); // Q11 + WebRtcNsx_CalcParametricNoiseEstimate(inst, + pink_noise_exp_avg, + pink_noise_num_avg, + kStartBand, + &noise_estimate, + &noise_estimate_avg); + } else { + // Use white noise estimate if we have poor pink noise parameter estimates + noise_estimate = inst->whiteNoiseLevel; // Q(minNorm-stages) + noise_estimate_avg = noise_estimate / (inst->blockIndex + 1); // Q(minNorm-stages) } - // Check for valid pointers based on sampling rate - if ((inst->fs == 32000) && (speechFrameHB == NULL)) - { - return -1; + for (i = 0; i < inst->magnLen; i++) { + // Estimate the background noise using the pink noise parameters if permitted + if ((inst->pinkNoiseExp) && (i >= kStartBand)) { + // Reset noise_estimate + noise_estimate = 0; + noise_estimate_avg = 0; + // Calculate the parametric noise estimate for current frequency bin + WebRtcNsx_CalcParametricNoiseEstimate(inst, + pink_noise_exp_avg, + pink_noise_num_avg, + i, + &noise_estimate, + &noise_estimate_avg); + } + // Calculate parametric Wiener filter + noiseSupFilterTmp[i] = inst->denoiseBound; + if (inst->initMagnEst[i]) { + // numerator = (initMagnEst - noise_estimate * overdrive) + // Result in Q(8+minNorm-stages) + tmpU32no1 = WEBRTC_SPL_UMUL_32_16(noise_estimate, inst->overdrive); + numerator = WEBRTC_SPL_LSHIFT_U32(inst->initMagnEst[i], 8); + if (numerator > tmpU32no1) { + // Suppression filter coefficient larger than zero, so calculate. + numerator -= tmpU32no1; + + // Determine number of left shifts in numerator for best accuracy after + // division + nShifts = WebRtcSpl_NormU32(numerator); + nShifts = WEBRTC_SPL_SAT(6, nShifts, 0); + + // Shift numerator to Q(nShifts+8+minNorm-stages) + numerator = WEBRTC_SPL_LSHIFT_U32(numerator, nShifts); + + // Shift denominator to Q(nShifts-6+minNorm-stages) + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[i], 6 - nShifts); + if (tmpU32no1 == 0) { + // This is only possible if numerator = 0, in which case + // we don't need any division. + tmpU32no1 = 1; + } + tmpU32no2 = WEBRTC_SPL_UDIV(numerator, tmpU32no1); // Q14 + noiseSupFilterTmp[i] = (WebRtc_UWord16)WEBRTC_SPL_SAT(16384, tmpU32no2, + (WebRtc_UWord32)(inst->denoiseBound)); // Q14 + } + } + // Weight quantile noise 'noiseU32' with modeled noise 'noise_estimate_avg' + // 'noiseU32 is in Q(qNoise) and 'noise_estimate' in Q(minNorm-stages) + // To guarantee that we do not get wrap around when shifting to the same domain + // we use the lowest one. Furthermore, we need to save 6 bits for the weighting. + // 'noise_estimate_avg' can handle this operation by construction, but 'noiseU32' + // may not. + + // Shift 'noiseU32' to 'q_domain_to_use' + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], (int)qNoise - q_domain_to_use); + // Shift 'noise_estimate_avg' to 'q_domain_to_use' + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(noise_estimate_avg, inst->minNorm - inst->stages + - q_domain_to_use); + // Make a simple check to see if we have enough room for weighting 'tmpU32no1' + // without wrap around + nShifts = 0; + if (tmpU32no1 & 0xfc000000) { + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 6); + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 6); + nShifts = 6; + } + tmpU32no1 *= inst->blockIndex; + tmpU32no2 *= (END_STARTUP_SHORT - inst->blockIndex); + // Add them together and divide by startup length + noiseU32[i] = WebRtcSpl_DivU32U16(tmpU32no1 + tmpU32no2, END_STARTUP_SHORT); + // Shift back if necessary + noiseU32[i] = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], nShifts); + } + // Update new Q-domain for 'noiseU32' + qNoise = q_domain_to_use; + } + // compute average signal during END_STARTUP_LONG time: + // used to normalize spectral difference measure + if (inst->blockIndex < END_STARTUP_LONG) { + // substituting division with shift ending up in Q(-2*stages) + inst->timeAvgMagnEnergyTmp + += WEBRTC_SPL_RSHIFT_U32(inst->magnEnergy, + 2 * inst->normData + inst->stages - 1); + inst->timeAvgMagnEnergy = WebRtcSpl_DivU32U16(inst->timeAvgMagnEnergyTmp, + inst->blockIndex + 1); + } + + //start processing at frames == converged+1 + // STEP 1: compute prior and post SNR based on quantile noise estimates + + // compute direct decision (DD) estimate of prior SNR: needed for new method + satMax = (WebRtc_UWord32)1048575;// Largest possible value without getting overflow despite shifting 12 steps + postShifts = 6 + qMagn - qNoise; + nShifts = 5 - inst->prevQMagn + inst->prevQNoise; + for (i = 0; i < inst->magnLen; i++) { + // FLOAT: + // post SNR + // postLocSnr[i] = 0.0; + // if (magn[i] > noise[i]) + // { + // postLocSnr[i] = magn[i] / (noise[i] + 0.0001); + // } + // // previous post SNR + // // previous estimate: based on previous frame with gain filter (smooth is previous filter) + // + // prevNearSnr[i] = inst->prevMagnU16[i] / (inst->noisePrev[i] + 0.0001) * (inst->smooth[i]); + // + // // DD estimate is sum of two terms: current estimate and previous estimate + // // directed decision update of priorSnr (or we actually store [2*priorSnr+1]) + // + // priorLocSnr[i] = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * (postLocSnr[i] - 1.0); + + // calculate post SNR: output in Q11 + postLocSnr[i] = 2048; // 1.0 in Q11 + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)magnU16[i], 6); // Q(6+qMagn) + if (postShifts < 0) { + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], -postShifts); // Q(6+qMagn) + } else { + tmpU32no2 = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], postShifts); // Q(6+qMagn) + } + if (tmpU32no1 > tmpU32no2) { + // Current magnitude larger than noise + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, 11); // Q(17+qMagn) + if (tmpU32no2 > 0) { + tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q11 + postLocSnr[i] = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11 + } else { + postLocSnr[i] = satMax; + } } - // Store speechFrame and transform to frequency domain - WebRtcNsx_DataAnalysis(inst, speechFrame, magnU16); - - if (inst->zeroInputSignal) - { - WebRtcNsx_DataSynthesis(inst, outFrame); - - if (inst->fs == 32000) - { - // update analysis buffer for H band - // append new data to buffer FX - WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX, inst->dataBufHBFX + inst->blockLen10ms, - inst->anaLen - inst->blockLen10ms); - WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX + inst->anaLen - inst->blockLen10ms, - speechFrameHB, inst->blockLen10ms); - for (i = 0; i < inst->blockLen10ms; i++) - { - outFrameHB[i] = inst->dataBufHBFX[i]; // Q0 - } - } // end of H band gain computation - return 0; + // calculate prevNearSnr[i] and save for later instead of recalculating it later + nearMagnEst = WEBRTC_SPL_UMUL_16_16(inst->prevMagnU16[i], inst->noiseSupFilter[i]); // Q(prevQMagn+14) + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(nearMagnEst, 3); // Q(prevQMagn+17) + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(inst->prevNoiseU32[i], nShifts); // Q(prevQMagn+6) + + if (tmpU32no2 > 0) { + tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q11 + tmpU32no1 = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11 + } else { + tmpU32no1 = satMax; // Q11 + } + prevNearSnr[i] = tmpU32no1; // Q11 + + //directed decision update of priorSnr + tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22 + tmpU32no2 = WEBRTC_SPL_UMUL_32_16(postLocSnr[i] - 2048, ONE_MINUS_DD_PR_SNR_Q11); // Q22 + priorSnr = tmpU32no1 + tmpU32no2 + 512; // Q22 (added 512 for rounding) + // priorLocSnr = 1 + 2*priorSnr + priorLocSnr[i] = 2048 + WEBRTC_SPL_RSHIFT_U32(priorSnr, 10); // Q11 + } // end of loop over frequencies + // done with step 1: DD computation of prior and post SNR + + // STEP 2: compute speech/noise likelihood + + //compute difference of input spectrum with learned/estimated noise spectrum + WebRtcNsx_ComputeSpectralDifference(inst, magnU16); + //compute histograms for determination of parameters (thresholds and weights for features) + //parameters are extracted once every window time (=inst->modelUpdate) + //counter update + inst->cntThresUpdate++; + flag = (int)(inst->cntThresUpdate == inst->modelUpdate); + //update histogram + WebRtcNsx_FeatureParameterExtraction(inst, flag); + //compute model parameters + if (flag) { + inst->cntThresUpdate = 0; // Reset counter + //update every window: + // get normalization for spectral difference for next window estimate + + // Shift to Q(-2*stages) + inst->curAvgMagnEnergy = WEBRTC_SPL_RSHIFT_U32(inst->curAvgMagnEnergy, STAT_UPDATES); + + tmpU32no1 = (inst->curAvgMagnEnergy + inst->timeAvgMagnEnergy + 1) >> 1; //Q(-2*stages) + // Update featureSpecDiff + if ((tmpU32no1 != inst->timeAvgMagnEnergy) && (inst->featureSpecDiff) && + (inst->timeAvgMagnEnergy > 0)) { + norm32no1 = 0; + tmpU32no3 = tmpU32no1; + while (0xFFFF0000 & tmpU32no3) { + tmpU32no3 >>= 1; + norm32no1++; + } + tmpU32no2 = inst->featureSpecDiff; + while (0xFFFF0000 & tmpU32no2) { + tmpU32no2 >>= 1; + norm32no1++; + } + tmpU32no3 = WEBRTC_SPL_UMUL(tmpU32no3, tmpU32no2); + tmpU32no3 = WEBRTC_SPL_UDIV(tmpU32no3, inst->timeAvgMagnEnergy); + if (WebRtcSpl_NormU32(tmpU32no3) < norm32no1) { + inst->featureSpecDiff = 0x007FFFFF; + } else { + inst->featureSpecDiff = WEBRTC_SPL_MIN( + 0x007FFFFF, WEBRTC_SPL_LSHIFT_U32(tmpU32no3, norm32no1)); + } } - // Update block index when we have something to process - inst->blockIndex++; - // + inst->timeAvgMagnEnergy = tmpU32no1; // Q(-2*stages) + inst->curAvgMagnEnergy = 0; + } - // Norm of magn - qMagn = inst->normData - inst->stages; + //compute speech/noise probability + WebRtcNsx_SpeechNoiseProb(inst, nonSpeechProbFinal, priorLocSnr, postLocSnr); - // Compute spectral flatness on input spectrum - WebRtcNsx_ComputeSpectralFlatness(inst, magnU16); + //time-avg parameter for noise update + gammaNoise = NOISE_UPDATE_Q8; // Q8 - // quantile noise estimate - WebRtcNsx_NoiseEstimation(inst, magnU16, noiseU32, &qNoise); + maxNoiseU32 = 0; + postShifts = inst->prevQNoise - qMagn; + nShifts = inst->prevQMagn - qMagn; + for (i = 0; i < inst->magnLen; i++) { + // temporary noise update: use it for speech frames if update value is less than previous + // the formula has been rewritten into: + // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i]) - //noise estimate from previous frame - for (i = 0; i < inst->magnLen; i++) - { - prevNoiseU16[i] = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_U32(inst->prevNoiseU32[i], 11); // Q(prevQNoise) + if (postShifts < 0) { + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(magnU16[i], -postShifts); // Q(prevQNoise) + } else { + tmpU32no2 = WEBRTC_SPL_LSHIFT_U32(magnU16[i], postShifts); // Q(prevQNoise) } - - if (inst->blockIndex < END_STARTUP_SHORT) - { - // Noise Q-domain to be used later; see description at end of section. - q_domain_to_use = WEBRTC_SPL_MIN((int)qNoise, inst->minNorm - inst->stages); - - // Calculate frequency independent parts in parametric noise estimate and calculate - // the estimate for the lower frequency band (same values for all frequency bins) - if (inst->pinkNoiseExp) - { - pink_noise_exp_avg = (WebRtc_Word16)WebRtcSpl_DivW32W16(inst->pinkNoiseExp, - (WebRtc_Word16)(inst->blockIndex + 1)); // Q14 - pink_noise_num_avg = WebRtcSpl_DivW32W16(inst->pinkNoiseNumerator, - (WebRtc_Word16)(inst->blockIndex + 1)); // Q11 - WebRtcNsx_CalcParametricNoiseEstimate(inst, - pink_noise_exp_avg, - pink_noise_num_avg, - kStartBand, - &noise_estimate, - &noise_estimate_avg); - } - else - { - // Use white noise estimate if we have poor pink noise parameter estimates - noise_estimate = inst->whiteNoiseLevel; // Q(minNorm-stages) - noise_estimate_avg = noise_estimate / (inst->blockIndex + 1); // Q(minNorm-stages) - } - for (i = 0; i < inst->magnLen; i++) - { - // Estimate the background noise using the pink noise parameters if permitted - if ((inst->pinkNoiseExp) && (i >= kStartBand)) - { - // Reset noise_estimate - noise_estimate = 0; - noise_estimate_avg = 0; - // Calculate the parametric noise estimate for current frequency bin - WebRtcNsx_CalcParametricNoiseEstimate(inst, - pink_noise_exp_avg, - pink_noise_num_avg, - i, - &noise_estimate, - &noise_estimate_avg); - } - // Calculate parametric Wiener filter - noiseSupFilterTmp[i] = inst->denoiseBound; - if (inst->initMagnEst[i]) - { - // numerator = (initMagnEst - noise_estimate * overdrive) - // Result in Q(8+minNorm-stages) - tmpU32no1 = WEBRTC_SPL_UMUL_32_16(noise_estimate, inst->overdrive); - numerator = WEBRTC_SPL_LSHIFT_U32(inst->initMagnEst[i], 8); - if (numerator > tmpU32no1) - { - // Suppression filter coefficient larger than zero, so calculate. - numerator -= tmpU32no1; - - // Determine number of left shifts in numerator for best accuracy after - // division - nShifts = WebRtcSpl_NormU32(numerator); - nShifts = WEBRTC_SPL_SAT(6, nShifts, 0); - - // Shift numerator to Q(nShifts+8+minNorm-stages) - numerator = WEBRTC_SPL_LSHIFT_U32(numerator, nShifts); - - // Shift denominator to Q(nShifts-6+minNorm-stages) - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[i], 6 - nShifts); - tmpU32no2 = WEBRTC_SPL_UDIV(numerator, tmpU32no1); // Q14 - noiseSupFilterTmp[i] = (WebRtc_UWord16)WEBRTC_SPL_SAT(16384, tmpU32no2, - (WebRtc_UWord32)(inst->denoiseBound)); // Q14 - } - } - // Weight quantile noise 'noiseU32' with modeled noise 'noise_estimate_avg' - // 'noiseU32 is in Q(qNoise) and 'noise_estimate' in Q(minNorm-stages) - // To guarantee that we do not get wrap around when shifting to the same domain - // we use the lowest one. Furthermore, we need to save 6 bits for the weighting. - // 'noise_estimate_avg' can handle this operation by construction, but 'noiseU32' - // may not. - - // Shift 'noiseU32' to 'q_domain_to_use' - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], (int)qNoise - q_domain_to_use); - // Shift 'noise_estimate_avg' to 'q_domain_to_use' - tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(noise_estimate_avg, inst->minNorm - inst->stages - - q_domain_to_use); - // Make a simple check to see if we have enough room for weighting 'tmpU32no1' - // without wrap around - nShifts = 0; - if (tmpU32no1 & 0xfc000000) { - tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 6); - tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 6); - nShifts = 6; - } - // Add them together and divide by startup length - noiseU32[i] = WebRtcSpl_DivU32U16(tmpU32no1 + tmpU32no2, END_STARTUP_SHORT); - // Shift back if necessary - noiseU32[i] = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], nShifts); - } - // Update new Q-domain for 'noiseU32' - qNoise = q_domain_to_use; + if (prevNoiseU16[i] > tmpU32no2) { + sign = -1; + tmpU32no1 = prevNoiseU16[i] - tmpU32no2; + } else { + sign = 1; + tmpU32no1 = tmpU32no2 - prevNoiseU16[i]; } - // compute average signal during END_STARTUP_LONG time: - // used to normalize spectral difference measure - if (inst->blockIndex < END_STARTUP_LONG) - { - // substituting division with shift ending up in Q(-2*stages) - inst->timeAvgMagnEnergyTmp - += WEBRTC_SPL_RSHIFT_U32(inst->magnEnergy, - 2 * inst->normData + inst->stages - 1); - inst->timeAvgMagnEnergy = WebRtcSpl_DivU32U16(inst->timeAvgMagnEnergyTmp, - inst->blockIndex + 1); + noiseUpdateU32 = inst->prevNoiseU32[i]; // Q(prevQNoise+11) + tmpU32no3 = 0; + if ((tmpU32no1) && (nonSpeechProbFinal[i])) { + // This value will be used later, if gammaNoise changes + tmpU32no3 = WEBRTC_SPL_UMUL_32_16(tmpU32no1, nonSpeechProbFinal[i]); // Q(prevQNoise+8) + if (0x7c000000 & tmpU32no3) { + // Shifting required before multiplication + tmpU32no2 + = WEBRTC_SPL_UMUL_32_16(WEBRTC_SPL_RSHIFT_U32(tmpU32no3, 5), gammaNoise); // Q(prevQNoise+11) + } else { + // We can do shifting after multiplication + tmpU32no2 + = WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_UMUL_32_16(tmpU32no3, gammaNoise), 5); // Q(prevQNoise+11) + } + if (sign > 0) { + noiseUpdateU32 += tmpU32no2; // Q(prevQNoise+11) + } else { + // This operation is safe. We can never get wrap around, since worst + // case scenario means magnU16 = 0 + noiseUpdateU32 -= tmpU32no2; // Q(prevQNoise+11) + } } - //start processing at frames == converged+1 - // STEP 1: compute prior and post SNR based on quantile noise estimates - - // compute direct decision (DD) estimate of prior SNR: needed for new method - satMax = (WebRtc_UWord32)1048575;// Largest possible value without getting overflow despite shifting 12 steps - postShifts = 6 + qMagn - qNoise; - nShifts = 5 - inst->prevQMagn + inst->prevQNoise; - for (i = 0; i < inst->magnLen; i++) - { - // FLOAT: - // post SNR - // postLocSnr[i] = 0.0; - // if (magn[i] > noise[i]) - // { - // postLocSnr[i] = magn[i] / (noise[i] + 0.0001); - // } - // // previous post SNR - // // previous estimate: based on previous frame with gain filter (smooth is previous filter) - // - // prevNearSnr[i] = inst->prevMagnU16[i] / (inst->noisePrev[i] + 0.0001) * (inst->smooth[i]); - // - // // DD estimate is sum of two terms: current estimate and previous estimate - // // directed decision update of priorSnr (or we actually store [2*priorSnr+1]) - // - // priorLocSnr[i] = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * (postLocSnr[i] - 1.0); - - // calculate post SNR: output in Q11 - postLocSnr[i] = 2048; // 1.0 in Q11 - tmpU32no1 = WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)magnU16[i], 6); // Q(6+qMagn) - if (postShifts < 0) - { - tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], -postShifts); // Q(6+qMagn) - } else - { - tmpU32no2 = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], postShifts); // Q(6+qMagn) - } - if (tmpU32no1 > tmpU32no2) - { - // Current magnitude larger than noise - tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, 11); // Q(17+qMagn) - if (tmpU32no2) - { - tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q11 - postLocSnr[i] = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11 - } else - { - postLocSnr[i] = satMax; - } - } - - // calculate prevNearSnr[i] and save for later instead of recalculating it later - nearMagnEst = WEBRTC_SPL_UMUL_16_16(inst->prevMagnU16[i], inst->noiseSupFilter[i]); // Q(prevQMagn+14) - tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(nearMagnEst, 3); // Q(prevQMagn+17) - tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(inst->prevNoiseU32[i], nShifts); // Q(prevQMagn+6) - - if (tmpU32no2) - { - tmpU32no1 = WEBRTC_SPL_DIV(tmpU32no1, tmpU32no2); // Q11 - tmpU32no1 = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11 - } else - { - tmpU32no1 = satMax; // Q11 - } - prevNearSnr[i] = tmpU32no1; // Q11 - - //directed decision update of priorSnr - tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22 - tmpU32no2 = WEBRTC_SPL_UMUL_32_16(postLocSnr[i] - 2048, ONE_MINUS_DD_PR_SNR_Q11); // Q22 - priorSnr = tmpU32no1 + tmpU32no2 + 512; // Q22 (added 512 for rounding) - // priorLocSnr = 1 + 2*priorSnr - priorLocSnr[i] = 2048 + WEBRTC_SPL_RSHIFT_U32(priorSnr, 10); // Q11 - } // end of loop over frequencies - // done with step 1: DD computation of prior and post SNR - - // STEP 2: compute speech/noise likelihood - - //compute difference of input spectrum with learned/estimated noise spectrum - WebRtcNsx_ComputeSpectralDifference(inst, magnU16); - //compute histograms for determination of parameters (thresholds and weights for features) - //parameters are extracted once every window time (=inst->modelUpdate) - //counter update - inst->cntThresUpdate++; - flag = (int)(inst->cntThresUpdate == inst->modelUpdate); - //update histogram - WebRtcNsx_FeatureParameterExtraction(inst, flag); - //compute model parameters - if (flag) - { - inst->cntThresUpdate = 0; // Reset counter - //update every window: - // get normalization for spectral difference for next window estimate - - // Shift to Q(-2*stages) - inst->curAvgMagnEnergy = WEBRTC_SPL_RSHIFT_U32(inst->curAvgMagnEnergy, STAT_UPDATES); - - tmpU32no1 = (inst->curAvgMagnEnergy + inst->timeAvgMagnEnergy + 1) >> 1; //Q(-2*stages) - // Update featureSpecDiff - if ((tmpU32no1 != inst->timeAvgMagnEnergy) && (inst->featureSpecDiff)) - { - norm32no1 = 0; - tmpU32no3 = tmpU32no1; - while (0xFFFF0000 & tmpU32no3) - { - tmpU32no3 >>= 1; - norm32no1++; - } - tmpU32no2 = inst->featureSpecDiff; - while (0xFFFF0000 & tmpU32no2) - { - tmpU32no2 >>= 1; - norm32no1++; - } - tmpU32no3 = WEBRTC_SPL_UMUL(tmpU32no3, tmpU32no2); - tmpU32no3 = WEBRTC_SPL_UDIV(tmpU32no3, inst->timeAvgMagnEnergy); - if (WebRtcSpl_NormU32(tmpU32no3) < norm32no1) - { - inst->featureSpecDiff = 0x007FFFFF; - } else - { - inst->featureSpecDiff = WEBRTC_SPL_MIN(0x007FFFFF, - WEBRTC_SPL_LSHIFT_U32(tmpU32no3, norm32no1)); - } - } + //increase gamma (i.e., less noise update) for frame likely to be speech + prevGammaNoise = gammaNoise; + gammaNoise = NOISE_UPDATE_Q8; + //time-constant based on speech/noise state + //increase gamma (i.e., less noise update) for frames likely to be speech + if (nonSpeechProbFinal[i] < ONE_MINUS_PROB_RANGE_Q8) { + gammaNoise = GAMMA_NOISE_TRANS_AND_SPEECH_Q8; + } - inst->timeAvgMagnEnergy = tmpU32no1; // Q(-2*stages) - inst->curAvgMagnEnergy = 0; + if (prevGammaNoise != gammaNoise) { + // new noise update + // this line is the same as above, only that the result is stored in a different variable and the gammaNoise + // has changed + // + // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i]) + + if (0x7c000000 & tmpU32no3) { + // Shifting required before multiplication + tmpU32no2 + = WEBRTC_SPL_UMUL_32_16(WEBRTC_SPL_RSHIFT_U32(tmpU32no3, 5), gammaNoise); // Q(prevQNoise+11) + } else { + // We can do shifting after multiplication + tmpU32no2 + = WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_UMUL_32_16(tmpU32no3, gammaNoise), 5); // Q(prevQNoise+11) + } + if (sign > 0) { + tmpU32no1 = inst->prevNoiseU32[i] + tmpU32no2; // Q(prevQNoise+11) + } else { + tmpU32no1 = inst->prevNoiseU32[i] - tmpU32no2; // Q(prevQNoise+11) + } + if (noiseUpdateU32 > tmpU32no1) { + noiseUpdateU32 = tmpU32no1; // Q(prevQNoise+11) + } + } + noiseU32[i] = noiseUpdateU32; // Q(prevQNoise+11) + if (noiseUpdateU32 > maxNoiseU32) { + maxNoiseU32 = noiseUpdateU32; } - //compute speech/noise probability - WebRtcNsx_SpeechNoiseProb(inst, nonSpeechProbFinal, priorLocSnr, postLocSnr); - - //time-avg parameter for noise update - gammaNoise = NOISE_UPDATE_Q8; // Q8 - - maxNoiseU32 = 0; - postShifts = inst->prevQNoise - qMagn; - nShifts = inst->prevQMagn - qMagn; - for (i = 0; i < inst->magnLen; i++) - { - // temporary noise update: use it for speech frames if update value is less than previous - // the formula has been rewritten into: - // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i]) - - if (postShifts < 0) - { - tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(magnU16[i], -postShifts); // Q(prevQNoise) - } else - { - tmpU32no2 = WEBRTC_SPL_LSHIFT_U32(magnU16[i], postShifts); // Q(prevQNoise) - } - if (prevNoiseU16[i] > tmpU32no2) - { - sign = -1; - tmpU32no1 = prevNoiseU16[i] - tmpU32no2; - } else - { - sign = 1; - tmpU32no1 = tmpU32no2 - prevNoiseU16[i]; - } - noiseUpdateU32 = inst->prevNoiseU32[i]; // Q(prevQNoise+11) - tmpU32no3 = 0; - if ((tmpU32no1) && (nonSpeechProbFinal[i])) - { - // This value will be used later, if gammaNoise changes - tmpU32no3 = WEBRTC_SPL_UMUL_32_16(tmpU32no1, nonSpeechProbFinal[i]); // Q(prevQNoise+8) - if (0x7c000000 & tmpU32no3) - { - // Shifting required before multiplication - tmpU32no2 - = WEBRTC_SPL_UMUL_32_16(WEBRTC_SPL_RSHIFT_U32(tmpU32no3, 5), gammaNoise); // Q(prevQNoise+11) - } else - { - // We can do shifting after multiplication - tmpU32no2 - = WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_UMUL_32_16(tmpU32no3, gammaNoise), 5); // Q(prevQNoise+11) - } - if (sign > 0) - { - noiseUpdateU32 += tmpU32no2; // Q(prevQNoise+11) - } else - { - // This operation is safe. We can never get wrap around, since worst - // case scenario means magnU16 = 0 - noiseUpdateU32 -= tmpU32no2; // Q(prevQNoise+11) - } - } + // conservative noise update + // // original FLOAT code + // if (prob_speech < PROB_RANGE) { + // inst->avgMagnPause[i] = inst->avgMagnPause[i] + (1.0 - gamma_pause)*(magn[i] - inst->avgMagnPause[i]); + // } + + tmp32no2 = WEBRTC_SPL_SHIFT_W32(inst->avgMagnPause[i], -nShifts); + if (nonSpeechProbFinal[i] > ONE_MINUS_PROB_RANGE_Q8) { + if (nShifts < 0) { + tmp32no1 = (WebRtc_Word32)magnU16[i] - tmp32no2; // Q(qMagn) + tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no1, ONE_MINUS_GAMMA_PAUSE_Q8); // Q(8+prevQMagn+nShifts) + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1 + 128, 8); // Q(qMagn) + } else { + tmp32no1 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)magnU16[i], nShifts) + - inst->avgMagnPause[i]; // Q(qMagn+nShifts) + tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no1, ONE_MINUS_GAMMA_PAUSE_Q8); // Q(8+prevQMagn+nShifts) + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1 + (128 << nShifts), 8 + nShifts); // Q(qMagn) + } + tmp32no2 += tmp32no1; // Q(qMagn) + } + inst->avgMagnPause[i] = tmp32no2; + } // end of frequency loop - //increase gamma (i.e., less noise update) for frame likely to be speech - prevGammaNoise = gammaNoise; - gammaNoise = NOISE_UPDATE_Q8; - //time-constant based on speech/noise state - //increase gamma (i.e., less noise update) for frames likely to be speech - if (nonSpeechProbFinal[i] < ONE_MINUS_PROB_RANGE_Q8) - { - gammaNoise = GAMMA_NOISE_TRANS_AND_SPEECH_Q8; - } + norm32no1 = WebRtcSpl_NormU32(maxNoiseU32); + qNoise = inst->prevQNoise + norm32no1 - 5; + // done with step 2: noise update - if (prevGammaNoise != gammaNoise) - { - // new noise update - // this line is the same as above, only that the result is stored in a different variable and the gammaNoise - // has changed - // - // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i]) - - if (0x7c000000 & tmpU32no3) - { - // Shifting required before multiplication - tmpU32no2 - = WEBRTC_SPL_UMUL_32_16(WEBRTC_SPL_RSHIFT_U32(tmpU32no3, 5), gammaNoise); // Q(prevQNoise+11) - } else - { - // We can do shifting after multiplication - tmpU32no2 - = WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_UMUL_32_16(tmpU32no3, gammaNoise), 5); // Q(prevQNoise+11) - } - if (sign > 0) - { - tmpU32no1 = inst->prevNoiseU32[i] + tmpU32no2; // Q(prevQNoise+11) - } else - { - tmpU32no1 = inst->prevNoiseU32[i] - tmpU32no2; // Q(prevQNoise+11) - } - if (noiseUpdateU32 > tmpU32no1) - { - noiseUpdateU32 = tmpU32no1; // Q(prevQNoise+11) - } - } - noiseU32[i] = noiseUpdateU32; // Q(prevQNoise+11) - if (noiseUpdateU32 > maxNoiseU32) - { - maxNoiseU32 = noiseUpdateU32; - } - - // conservative noise update - // // original FLOAT code - // if (prob_speech < PROB_RANGE) { - // inst->avgMagnPause[i] = inst->avgMagnPause[i] + (1.0 - gamma_pause)*(magn[i] - inst->avgMagnPause[i]); - // } - - tmp32no2 = WEBRTC_SPL_SHIFT_W32(inst->avgMagnPause[i], -nShifts); - if (nonSpeechProbFinal[i] > ONE_MINUS_PROB_RANGE_Q8) - { - if (nShifts < 0) - { - tmp32no1 = (WebRtc_Word32)magnU16[i] - tmp32no2; // Q(qMagn) - tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no1, ONE_MINUS_GAMMA_PAUSE_Q8); // Q(8+prevQMagn+nShifts) - tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1 + 128, 8); // Q(qMagn) - } else - { - tmp32no1 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)magnU16[i], nShifts) - - inst->avgMagnPause[i]; // Q(qMagn+nShifts) - tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no1, ONE_MINUS_GAMMA_PAUSE_Q8); // Q(8+prevQMagn+nShifts) - tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1 + (128 << nShifts), 8 + nShifts); // Q(qMagn) - } - tmp32no2 += tmp32no1; // Q(qMagn) - } - inst->avgMagnPause[i] = tmp32no2; - } // end of frequency loop - - norm32no1 = WebRtcSpl_NormU32(maxNoiseU32); - qNoise = inst->prevQNoise + norm32no1 - 5; - // done with step 2: noise update - - // STEP 3: compute dd update of prior snr and post snr based on new noise estimate - nShifts = inst->prevQNoise + 11 - qMagn; - for (i = 0; i < inst->magnLen; i++) - { - // FLOAT code - // // post and prior SNR - // curNearSnr = 0.0; - // if (magn[i] > noise[i]) - // { - // curNearSnr = magn[i] / (noise[i] + 0.0001) - 1.0; - // } - // // DD estimate is sum of two terms: current estimate and previous estimate - // // directed decision update of snrPrior - // snrPrior = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * curNearSnr; - // // gain filter - // tmpFloat1 = inst->overdrive + snrPrior; - // tmpFloat2 = snrPrior / tmpFloat1; - // theFilter[i] = tmpFloat2; - - // calculate curNearSnr again, this is necessary because a new noise estimate has been made since then. for the original - curNearSnr = 0; // Q11 - if (nShifts < 0) - { - // This case is equivalent with magn < noise which implies curNearSnr = 0; - tmpMagnU32 = (WebRtc_UWord32)magnU16[i]; // Q(qMagn) - tmpNoiseU32 = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], -nShifts); // Q(qMagn) - } else if (nShifts > 17) - { - tmpMagnU32 = WEBRTC_SPL_LSHIFT_U32(magnU16[i], 17); // Q(qMagn+17) - tmpNoiseU32 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], nShifts - 17); // Q(qMagn+17) - } else - { - tmpMagnU32 = WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)magnU16[i], nShifts); // Q(qNoise_prev+11) - tmpNoiseU32 = noiseU32[i]; // Q(qNoise_prev+11) - } - if (tmpMagnU32 > tmpNoiseU32) - { - tmpU32no1 = tmpMagnU32 - tmpNoiseU32; // Q(qCur) - norm32no2 = WEBRTC_SPL_MIN(11, WebRtcSpl_NormU32(tmpU32no1)); - tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, norm32no2); // Q(qCur+norm32no2) - tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpNoiseU32, 11 - norm32no2); // Q(qCur+norm32no2-11) - if (tmpU32no2) - { - tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q11 - } - curNearSnr = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11 - } + // STEP 3: compute dd update of prior snr and post snr based on new noise estimate + nShifts = inst->prevQNoise + 11 - qMagn; + for (i = 0; i < inst->magnLen; i++) { + // FLOAT code + // // post and prior SNR + // curNearSnr = 0.0; + // if (magn[i] > noise[i]) + // { + // curNearSnr = magn[i] / (noise[i] + 0.0001) - 1.0; + // } + // // DD estimate is sum of two terms: current estimate and previous estimate + // // directed decision update of snrPrior + // snrPrior = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * curNearSnr; + // // gain filter + // tmpFloat1 = inst->overdrive + snrPrior; + // tmpFloat2 = snrPrior / tmpFloat1; + // theFilter[i] = tmpFloat2; + + // calculate curNearSnr again, this is necessary because a new noise estimate has been made since then. for the original + curNearSnr = 0; // Q11 + if (nShifts < 0) { + // This case is equivalent with magn < noise which implies curNearSnr = 0; + tmpMagnU32 = (WebRtc_UWord32)magnU16[i]; // Q(qMagn) + tmpNoiseU32 = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], -nShifts); // Q(qMagn) + } else if (nShifts > 17) { + tmpMagnU32 = WEBRTC_SPL_LSHIFT_U32(magnU16[i], 17); // Q(qMagn+17) + tmpNoiseU32 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], nShifts - 17); // Q(qMagn+17) + } else { + tmpMagnU32 = WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)magnU16[i], nShifts); // Q(qNoise_prev+11) + tmpNoiseU32 = noiseU32[i]; // Q(qNoise_prev+11) + } + if (tmpMagnU32 > tmpNoiseU32) { + tmpU32no1 = tmpMagnU32 - tmpNoiseU32; // Q(qCur) + norm32no2 = WEBRTC_SPL_MIN(11, WebRtcSpl_NormU32(tmpU32no1)); + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, norm32no2); // Q(qCur+norm32no2) + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpNoiseU32, 11 - norm32no2); // Q(qCur+norm32no2-11) + if (tmpU32no2 > 0) { + tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q11 + } + curNearSnr = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11 + } - //directed decision update of priorSnr - // FLOAT - // priorSnr = DD_PR_SNR * prevNearSnr + (1.0-DD_PR_SNR) * curNearSnr; + //directed decision update of priorSnr + // FLOAT + // priorSnr = DD_PR_SNR * prevNearSnr + (1.0-DD_PR_SNR) * curNearSnr; - tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22 - tmpU32no2 = WEBRTC_SPL_UMUL_32_16(curNearSnr, ONE_MINUS_DD_PR_SNR_Q11); // Q22 - priorSnr = tmpU32no1 + tmpU32no2; // Q22 + tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22 + tmpU32no2 = WEBRTC_SPL_UMUL_32_16(curNearSnr, ONE_MINUS_DD_PR_SNR_Q11); // Q22 + priorSnr = tmpU32no1 + tmpU32no2; // Q22 - //gain filter - tmpU32no1 = (WebRtc_UWord32)(inst->overdrive) + //gain filter + tmpU32no1 = (WebRtc_UWord32)(inst->overdrive) + WEBRTC_SPL_RSHIFT_U32(priorSnr + 8192, 14); // Q8 - tmpU16no1 = (WebRtc_UWord16)WEBRTC_SPL_UDIV(priorSnr + (tmpU32no1 >> 1), tmpU32no1); // Q14 - inst->noiseSupFilter[i] = WEBRTC_SPL_SAT(16384, tmpU16no1, inst->denoiseBound); // 16384 = Q14(1.0) // Q14 - - // Weight in the parametric Wiener filter during startup - if (inst->blockIndex < END_STARTUP_SHORT) - { - // Weight the two suppression filters - tmpU32no1 = WEBRTC_SPL_UMUL_16_16(inst->noiseSupFilter[i], - (WebRtc_UWord16)inst->blockIndex); - tmpU32no2 = WEBRTC_SPL_UMUL_16_16(noiseSupFilterTmp[i], - (WebRtc_UWord16)(END_STARTUP_SHORT - - inst->blockIndex)); - tmpU32no1 += tmpU32no2; - inst->noiseSupFilter[i] = (WebRtc_UWord16)WebRtcSpl_DivU32U16(tmpU32no1, - END_STARTUP_SHORT); - } - } // end of loop over frequencies - //done with step3 - - // save noise and magnitude spectrum for next frame - inst->prevQNoise = qNoise; - inst->prevQMagn = qMagn; - if (norm32no1 > 5) - { - for (i = 0; i < inst->magnLen; i++) - { - inst->prevNoiseU32[i] = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], norm32no1 - 5); // Q(qNoise+11) - inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn) - } - } else - { - for (i = 0; i < inst->magnLen; i++) - { - inst->prevNoiseU32[i] = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], 5 - norm32no1); // Q(qNoise+11) - inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn) - } + assert(inst->overdrive > 0); + tmpU16no1 = (WebRtc_UWord16)WEBRTC_SPL_UDIV(priorSnr + (tmpU32no1 >> 1), tmpU32no1); // Q14 + inst->noiseSupFilter[i] = WEBRTC_SPL_SAT(16384, tmpU16no1, inst->denoiseBound); // 16384 = Q14(1.0) // Q14 + + // Weight in the parametric Wiener filter during startup + if (inst->blockIndex < END_STARTUP_SHORT) { + // Weight the two suppression filters + tmpU32no1 = WEBRTC_SPL_UMUL_16_16(inst->noiseSupFilter[i], + (WebRtc_UWord16)inst->blockIndex); + tmpU32no2 = WEBRTC_SPL_UMUL_16_16(noiseSupFilterTmp[i], + (WebRtc_UWord16)(END_STARTUP_SHORT + - inst->blockIndex)); + tmpU32no1 += tmpU32no2; + inst->noiseSupFilter[i] = (WebRtc_UWord16)WebRtcSpl_DivU32U16(tmpU32no1, + END_STARTUP_SHORT); } + } // end of loop over frequencies + //done with step3 + + // save noise and magnitude spectrum for next frame + inst->prevQNoise = qNoise; + inst->prevQMagn = qMagn; + if (norm32no1 > 5) { + for (i = 0; i < inst->magnLen; i++) { + inst->prevNoiseU32[i] = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], norm32no1 - 5); // Q(qNoise+11) + inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn) + } + } else { + for (i = 0; i < inst->magnLen; i++) { + inst->prevNoiseU32[i] = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], 5 - norm32no1); // Q(qNoise+11) + inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn) + } + } - WebRtcNsx_DataSynthesis(inst, outFrame); + WebRtcNsx_DataSynthesis(inst, outFrame); #ifdef NS_FILEDEBUG - fwrite(outframe, sizeof(short), inst->blockLen10ms, inst->outfile); + fwrite(outframe, sizeof(short), inst->blockLen10ms, inst->outfile); #endif - //for H band: - // only update data buffer, then apply time-domain gain is applied derived from L band - if (inst->fs == 32000) - { - // update analysis buffer for H band - // append new data to buffer FX - WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX, inst->dataBufHBFX + inst->blockLen10ms, inst->anaLen - inst->blockLen10ms); - WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX + inst->anaLen - inst->blockLen10ms, speechFrameHB, inst->blockLen10ms); - // range for averaging low band quantities for H band gain - - gainTimeDomainHB = 16384; // 16384 = Q14(1.0) - //average speech prob from low band - //average filter gain from low band - //avg over second half (i.e., 4->8kHz) of freq. spectrum - tmpU32no1 = 0; // Q12 - tmpU16no1 = 0; // Q8 - for (i = inst->anaLen2 - (inst->anaLen2 >> 2); i < inst->anaLen2; i++) - { - tmpU16no1 += nonSpeechProbFinal[i]; // Q8 - tmpU32no1 += (WebRtc_UWord32)(inst->noiseSupFilter[i]); // Q14 - } - avgProbSpeechHB = (WebRtc_Word16)(4096 - - WEBRTC_SPL_RSHIFT_U16(tmpU16no1, inst->stages - 7)); // Q12 - avgFilterGainHB = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, inst->stages - 3); // Q14 - - // // original FLOAT code - // // gain based on speech probability: - // avg_prob_speech_tt=(float)2.0*avg_prob_speech-(float)1.0; - // gain_mod=(float)0.5*((float)1.0+(float)tanh(avg_prob_speech_tt)); // between 0 and 1 - - // gain based on speech probability: - // original expression: "0.5 * (1 + tanh(2x-1))" - // avgProbSpeechHB has been anyway saturated to a value between 0 and 1 so the other cases don't have to be dealt with - // avgProbSpeechHB and gainModHB are in Q12, 3607 = Q12(0.880615234375) which is a zero point of - // |0.5 * (1 + tanh(2x-1)) - x| - |0.5 * (1 + tanh(2x-1)) - 0.880615234375| meaning that from that point the error of approximating - // the expression with f(x) = x would be greater than the error of approximating the expression with f(x) = 0.880615234375 - // error: "|0.5 * (1 + tanh(2x-1)) - x| from x=0 to 0.880615234375" -> http://www.wolframalpha.com/input/?i=|0.5+*+(1+%2B+tanh(2x-1))+-+x|+from+x%3D0+to+0.880615234375 - // and: "|0.5 * (1 + tanh(2x-1)) - 0.880615234375| from x=0.880615234375 to 1" -> http://www.wolframalpha.com/input/?i=+|0.5+*+(1+%2B+tanh(2x-1))+-+0.880615234375|+from+x%3D0.880615234375+to+1 - gainModHB = WEBRTC_SPL_MIN(avgProbSpeechHB, 3607); - - // // original FLOAT code - // //combine gain with low band gain - // if (avg_prob_speech < (float)0.5) { - // gain_time_domain_HB=(float)0.5*gain_mod+(float)0.5*avg_filter_gain; - // } - // else { - // gain_time_domain_HB=(float)0.25*gain_mod+(float)0.75*avg_filter_gain; - // } - - - //combine gain with low band gain - if (avgProbSpeechHB < 2048) - { // 2048 = Q12(0.5) - // the next two lines in float are "gain_time_domain = 0.5 * gain_mod + 0.5 * avg_filter_gain"; Q2(0.5) = 2 equals one left shift - gainTimeDomainHB = (gainModHB << 1) + (avgFilterGainHB >> 1); // Q14 - } else - { - // "gain_time_domain = 0.25 * gain_mod + 0.75 * agv_filter_gain;" - gainTimeDomainHB = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(3, avgFilterGainHB, 2); // 3 = Q2(0.75); Q14 - gainTimeDomainHB += gainModHB; // Q14 - } - //make sure gain is within flooring range - gainTimeDomainHB - = WEBRTC_SPL_SAT(16384, gainTimeDomainHB, (WebRtc_Word16)(inst->denoiseBound)); // 16384 = Q14(1.0) + //for H band: + // only update data buffer, then apply time-domain gain is applied derived from L band + if (inst->fs == 32000) { + // update analysis buffer for H band + // append new data to buffer FX + WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX, inst->dataBufHBFX + inst->blockLen10ms, inst->anaLen - inst->blockLen10ms); + WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX + inst->anaLen - inst->blockLen10ms, speechFrameHB, inst->blockLen10ms); + // range for averaging low band quantities for H band gain + + gainTimeDomainHB = 16384; // 16384 = Q14(1.0) + //average speech prob from low band + //average filter gain from low band + //avg over second half (i.e., 4->8kHz) of freq. spectrum + tmpU32no1 = 0; // Q12 + tmpU16no1 = 0; // Q8 + for (i = inst->anaLen2 - (inst->anaLen2 >> 2); i < inst->anaLen2; i++) { + tmpU16no1 += nonSpeechProbFinal[i]; // Q8 + tmpU32no1 += (WebRtc_UWord32)(inst->noiseSupFilter[i]); // Q14 + } + avgProbSpeechHB = (WebRtc_Word16)(4096 + - WEBRTC_SPL_RSHIFT_U16(tmpU16no1, inst->stages - 7)); // Q12 + avgFilterGainHB = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, inst->stages - 3); // Q14 + + // // original FLOAT code + // // gain based on speech probability: + // avg_prob_speech_tt=(float)2.0*avg_prob_speech-(float)1.0; + // gain_mod=(float)0.5*((float)1.0+(float)tanh(avg_prob_speech_tt)); // between 0 and 1 + + // gain based on speech probability: + // original expression: "0.5 * (1 + tanh(2x-1))" + // avgProbSpeechHB has been anyway saturated to a value between 0 and 1 so the other cases don't have to be dealt with + // avgProbSpeechHB and gainModHB are in Q12, 3607 = Q12(0.880615234375) which is a zero point of + // |0.5 * (1 + tanh(2x-1)) - x| - |0.5 * (1 + tanh(2x-1)) - 0.880615234375| meaning that from that point the error of approximating + // the expression with f(x) = x would be greater than the error of approximating the expression with f(x) = 0.880615234375 + // error: "|0.5 * (1 + tanh(2x-1)) - x| from x=0 to 0.880615234375" -> http://www.wolframalpha.com/input/?i=|0.5+*+(1+%2B+tanh(2x-1))+-+x|+from+x%3D0+to+0.880615234375 + // and: "|0.5 * (1 + tanh(2x-1)) - 0.880615234375| from x=0.880615234375 to 1" -> http://www.wolframalpha.com/input/?i=+|0.5+*+(1+%2B+tanh(2x-1))+-+0.880615234375|+from+x%3D0.880615234375+to+1 + gainModHB = WEBRTC_SPL_MIN(avgProbSpeechHB, 3607); + + // // original FLOAT code + // //combine gain with low band gain + // if (avg_prob_speech < (float)0.5) { + // gain_time_domain_HB=(float)0.5*gain_mod+(float)0.5*avg_filter_gain; + // } + // else { + // gain_time_domain_HB=(float)0.25*gain_mod+(float)0.75*avg_filter_gain; + // } + + + //combine gain with low band gain + if (avgProbSpeechHB < 2048) { + // 2048 = Q12(0.5) + // the next two lines in float are "gain_time_domain = 0.5 * gain_mod + 0.5 * avg_filter_gain"; Q2(0.5) = 2 equals one left shift + gainTimeDomainHB = (gainModHB << 1) + (avgFilterGainHB >> 1); // Q14 + } else { + // "gain_time_domain = 0.25 * gain_mod + 0.75 * agv_filter_gain;" + gainTimeDomainHB = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(3, avgFilterGainHB, 2); // 3 = Q2(0.75); Q14 + gainTimeDomainHB += gainModHB; // Q14 + } + //make sure gain is within flooring range + gainTimeDomainHB + = WEBRTC_SPL_SAT(16384, gainTimeDomainHB, (WebRtc_Word16)(inst->denoiseBound)); // 16384 = Q14(1.0) - //apply gain - for (i = 0; i < inst->blockLen10ms; i++) - { - outFrameHB[i] - = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(gainTimeDomainHB, inst->dataBufHBFX[i], 14); // Q0 - } - } // end of H band gain computation + //apply gain + for (i = 0; i < inst->blockLen10ms; i++) { + outFrameHB[i] + = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(gainTimeDomainHB, inst->dataBufHBFX[i], 14); // Q0 + } + } // end of H band gain computation - return 0; + return 0; } diff --git a/src/modules/audio_processing/ns/main/source/nsx_core.h b/src/modules/audio_processing/ns/main/source/nsx_core.h index 54a236f..d5766ab 100644 --- a/src/modules/audio_processing/ns/main/source/nsx_core.h +++ b/src/modules/audio_processing/ns/main/source/nsx_core.h @@ -20,85 +20,84 @@ #include <stdio.h> #endif -typedef struct NsxInst_t_ -{ - WebRtc_UWord32 fs; - - const WebRtc_Word16* window; - WebRtc_Word16 analysisBuffer[ANAL_BLOCKL_MAX]; - WebRtc_Word16 synthesisBuffer[ANAL_BLOCKL_MAX]; - WebRtc_UWord16 noiseSupFilter[HALF_ANAL_BLOCKL]; - WebRtc_UWord16 overdrive; /* Q8 */ - WebRtc_UWord16 denoiseBound; /* Q14 */ - const WebRtc_Word16* factor2Table; - WebRtc_Word16 noiseEstLogQuantile[SIMULT * HALF_ANAL_BLOCKL]; - WebRtc_Word16 noiseEstDensity[SIMULT * HALF_ANAL_BLOCKL]; - WebRtc_Word16 noiseEstCounter[SIMULT]; - WebRtc_Word16 noiseEstQuantile[HALF_ANAL_BLOCKL]; - - WebRtc_Word16 anaLen; - int anaLen2; - int magnLen; - int aggrMode; - int stages; - int initFlag; - int gainMap; - - WebRtc_Word32 maxLrt; - WebRtc_Word32 minLrt; - WebRtc_Word32 logLrtTimeAvgW32[HALF_ANAL_BLOCKL]; //log lrt factor with time-smoothing in Q8 - WebRtc_Word32 featureLogLrt; - WebRtc_Word32 thresholdLogLrt; - WebRtc_Word16 weightLogLrt; - - WebRtc_UWord32 featureSpecDiff; - WebRtc_UWord32 thresholdSpecDiff; - WebRtc_Word16 weightSpecDiff; - - WebRtc_UWord32 featureSpecFlat; - WebRtc_UWord32 thresholdSpecFlat; - WebRtc_Word16 weightSpecFlat; - - WebRtc_Word32 avgMagnPause[HALF_ANAL_BLOCKL]; //conservative estimate of noise spectrum - WebRtc_UWord32 magnEnergy; - WebRtc_UWord32 sumMagn; - WebRtc_UWord32 curAvgMagnEnergy; - WebRtc_UWord32 timeAvgMagnEnergy; - WebRtc_UWord32 timeAvgMagnEnergyTmp; - - WebRtc_UWord32 whiteNoiseLevel; //initial noise estimate - WebRtc_UWord32 initMagnEst[HALF_ANAL_BLOCKL];//initial magnitude spectrum estimate - WebRtc_Word32 pinkNoiseNumerator; //pink noise parameter: numerator - WebRtc_Word32 pinkNoiseExp; //pink noise parameter: power of freq - int minNorm; //smallest normalization factor - int zeroInputSignal; //zero input signal flag - - WebRtc_UWord32 prevNoiseU32[HALF_ANAL_BLOCKL]; //noise spectrum from previous frame - WebRtc_UWord16 prevMagnU16[HALF_ANAL_BLOCKL]; //magnitude spectrum from previous frame - WebRtc_Word16 priorNonSpeechProb; //prior speech/noise probability // Q14 - - int blockIndex; //frame index counter - int modelUpdate; //parameter for updating or estimating thresholds/weights for prior model - int cntThresUpdate; - - //histograms for parameter estimation - WebRtc_Word16 histLrt[HIST_PAR_EST]; - WebRtc_Word16 histSpecFlat[HIST_PAR_EST]; - WebRtc_Word16 histSpecDiff[HIST_PAR_EST]; - - //quantities for high band estimate - WebRtc_Word16 dataBufHBFX[ANAL_BLOCKL_MAX]; /* Q0 */ - - int qNoise; - int prevQNoise; - int prevQMagn; - int blockLen10ms; - - WebRtc_Word16 real[ANAL_BLOCKL_MAX]; - WebRtc_Word16 imag[ANAL_BLOCKL_MAX]; - WebRtc_Word32 energyIn; - int scaleEnergyIn; - int normData; +typedef struct NsxInst_t_ { + WebRtc_UWord32 fs; + + const WebRtc_Word16* window; + WebRtc_Word16 analysisBuffer[ANAL_BLOCKL_MAX]; + WebRtc_Word16 synthesisBuffer[ANAL_BLOCKL_MAX]; + WebRtc_UWord16 noiseSupFilter[HALF_ANAL_BLOCKL]; + WebRtc_UWord16 overdrive; /* Q8 */ + WebRtc_UWord16 denoiseBound; /* Q14 */ + const WebRtc_Word16* factor2Table; + WebRtc_Word16 noiseEstLogQuantile[SIMULT* HALF_ANAL_BLOCKL]; + WebRtc_Word16 noiseEstDensity[SIMULT* HALF_ANAL_BLOCKL]; + WebRtc_Word16 noiseEstCounter[SIMULT]; + WebRtc_Word16 noiseEstQuantile[HALF_ANAL_BLOCKL]; + + WebRtc_Word16 anaLen; + int anaLen2; + int magnLen; + int aggrMode; + int stages; + int initFlag; + int gainMap; + + WebRtc_Word32 maxLrt; + WebRtc_Word32 minLrt; + WebRtc_Word32 logLrtTimeAvgW32[HALF_ANAL_BLOCKL]; //log lrt factor with time-smoothing in Q8 + WebRtc_Word32 featureLogLrt; + WebRtc_Word32 thresholdLogLrt; + WebRtc_Word16 weightLogLrt; + + WebRtc_UWord32 featureSpecDiff; + WebRtc_UWord32 thresholdSpecDiff; + WebRtc_Word16 weightSpecDiff; + + WebRtc_UWord32 featureSpecFlat; + WebRtc_UWord32 thresholdSpecFlat; + WebRtc_Word16 weightSpecFlat; + + WebRtc_Word32 avgMagnPause[HALF_ANAL_BLOCKL]; //conservative estimate of noise spectrum + WebRtc_UWord32 magnEnergy; + WebRtc_UWord32 sumMagn; + WebRtc_UWord32 curAvgMagnEnergy; + WebRtc_UWord32 timeAvgMagnEnergy; + WebRtc_UWord32 timeAvgMagnEnergyTmp; + + WebRtc_UWord32 whiteNoiseLevel; //initial noise estimate + WebRtc_UWord32 initMagnEst[HALF_ANAL_BLOCKL];//initial magnitude spectrum estimate + WebRtc_Word32 pinkNoiseNumerator; //pink noise parameter: numerator + WebRtc_Word32 pinkNoiseExp; //pink noise parameter: power of freq + int minNorm; //smallest normalization factor + int zeroInputSignal; //zero input signal flag + + WebRtc_UWord32 prevNoiseU32[HALF_ANAL_BLOCKL]; //noise spectrum from previous frame + WebRtc_UWord16 prevMagnU16[HALF_ANAL_BLOCKL]; //magnitude spectrum from previous frame + WebRtc_Word16 priorNonSpeechProb; //prior speech/noise probability // Q14 + + int blockIndex; //frame index counter + int modelUpdate; //parameter for updating or estimating thresholds/weights for prior model + int cntThresUpdate; + + //histograms for parameter estimation + WebRtc_Word16 histLrt[HIST_PAR_EST]; + WebRtc_Word16 histSpecFlat[HIST_PAR_EST]; + WebRtc_Word16 histSpecDiff[HIST_PAR_EST]; + + //quantities for high band estimate + WebRtc_Word16 dataBufHBFX[ANAL_BLOCKL_MAX]; /* Q0 */ + + int qNoise; + int prevQNoise; + int prevQMagn; + int blockLen10ms; + + WebRtc_Word16 real[ANAL_BLOCKL_MAX]; + WebRtc_Word16 imag[ANAL_BLOCKL_MAX]; + WebRtc_Word32 energyIn; + int scaleEnergyIn; + int normData; } NsxInst_t; @@ -122,7 +121,7 @@ extern "C" * Return value : 0 - Ok * -1 - Error */ -WebRtc_Word32 WebRtcNsx_InitCore(NsxInst_t *inst, WebRtc_UWord32 fs); +WebRtc_Word32 WebRtcNsx_InitCore(NsxInst_t* inst, WebRtc_UWord32 fs); /**************************************************************************** * WebRtcNsx_set_policy_core(...) @@ -139,7 +138,7 @@ WebRtc_Word32 WebRtcNsx_InitCore(NsxInst_t *inst, WebRtc_UWord32 fs); * Return value : 0 - Ok * -1 - Error */ -int WebRtcNsx_set_policy_core(NsxInst_t *inst, int mode); +int WebRtcNsx_set_policy_core(NsxInst_t* inst, int mode); /**************************************************************************** * WebRtcNsx_ProcessCore @@ -159,16 +158,16 @@ int WebRtcNsx_set_policy_core(NsxInst_t *inst, int mode); * Return value : 0 - OK * -1 - Error */ -int WebRtcNsx_ProcessCore(NsxInst_t *inst, short *inFrameLow, short *inFrameHigh, - short *outFrameLow, short *outFrameHigh); +int WebRtcNsx_ProcessCore(NsxInst_t* inst, short* inFrameLow, short* inFrameHigh, + short* outFrameLow, short* outFrameHigh); /**************************************************************************** * Internal functions and variable declarations shared with optimized code. */ -void WebRtcNsx_UpdateNoiseEstimate(NsxInst_t *inst, int offset); +void WebRtcNsx_UpdateNoiseEstimate(NsxInst_t* inst, int offset); -void WebRtcNsx_NoiseEstimation(NsxInst_t *inst, WebRtc_UWord16 *magn, WebRtc_UWord32 *noise, - WebRtc_Word16 *qNoise); +void WebRtcNsx_NoiseEstimation(NsxInst_t* inst, WebRtc_UWord16* magn, WebRtc_UWord32* noise, + WebRtc_Word16* qNoise); extern const WebRtc_Word16 WebRtcNsx_kLogTable[9]; extern const WebRtc_Word16 WebRtcNsx_kLogTableFrac[256]; diff --git a/src/modules/audio_processing/ns/main/source/nsx_core_neon.c b/src/modules/audio_processing/ns/main/source/nsx_core_neon.c index e0da82c..82f02ae 100644 --- a/src/modules/audio_processing/ns/main/source/nsx_core_neon.c +++ b/src/modules/audio_processing/ns/main/source/nsx_core_neon.c @@ -11,215 +11,230 @@ #if defined(WEBRTC_ARCH_ARM_NEON) && defined(WEBRTC_ANDROID) #include "nsx_core.h" -#include <arm_neon.h> - -void WebRtcNsx_NoiseEstimation(NsxInst_t *inst, WebRtc_UWord16 *magn, WebRtc_UWord32 *noise, - WebRtc_Word16 *qNoise) -{ - WebRtc_Word32 numerator; - - WebRtc_Word16 lmagn[HALF_ANAL_BLOCKL], counter, countDiv, countProd, delta, zeros, frac; - WebRtc_Word16 log2, tabind, logval, tmp16, tmp16no1, tmp16no2; - WebRtc_Word16 log2Const = 22713; - WebRtc_Word16 widthFactor = 21845; - - int i, s, offset; - numerator = FACTOR_Q16; - - tabind = inst->stages - inst->normData; - if (tabind < 0) - { - logval = -WebRtcNsx_kLogTable[-tabind]; - } else - { - logval = WebRtcNsx_kLogTable[tabind]; +#include <arm_neon.h> +#include <assert.h> + +void WebRtcNsx_NoiseEstimation(NsxInst_t* inst, WebRtc_UWord16* magn, WebRtc_UWord32* noise, + WebRtc_Word16* qNoise) { + WebRtc_Word32 numerator; + + WebRtc_Word16 lmagn[HALF_ANAL_BLOCKL], counter, countDiv, countProd, delta, zeros, frac; + WebRtc_Word16 log2, tabind, logval, tmp16, tmp16no1, tmp16no2; + WebRtc_Word16 log2Const = 22713; + WebRtc_Word16 widthFactor = 21845; + + int i, s, offset; + + numerator = FACTOR_Q16; + + tabind = inst->stages - inst->normData; + assert(tabind < 9); + assert(tabind > -9); + if (tabind < 0) { + logval = -WebRtcNsx_kLogTable[-tabind]; + } else { + logval = WebRtcNsx_kLogTable[tabind]; + } + + int16x8_t logval_16x8 = vdupq_n_s16(logval); + + // lmagn(i)=log(magn(i))=log(2)*log2(magn(i)) + // magn is in Q(-stages), and the real lmagn values are: + // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages) + // lmagn in Q8 + for (i = 0; i < inst->magnLen; i++) { + if (magn[i]) { + zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magn[i]); + frac = (WebRtc_Word16)((((WebRtc_UWord32)magn[i] << zeros) & 0x7FFFFFFF) >> 23); + assert(frac < 256); + // log2(magn(i)) + log2 = (WebRtc_Word16)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); + // log2(magn(i))*log(2) + lmagn[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(log2, log2Const, 15); + // + log(2^stages) + lmagn[i] += logval; + } else { + lmagn[i] = logval; } - - // lmagn(i)=log(magn(i))=log(2)*log2(magn(i)) - // magn is in Q(-stages), and the real lmagn values are: - // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages) - // lmagn in Q8 - for (i = 0; i < inst->magnLen; i++) - { - if (magn[i]) - { - zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magn[i]); - frac = (WebRtc_Word16)((((WebRtc_UWord32)magn[i] << zeros) & 0x7FFFFFFF) >> 23); - // log2(magn(i)) - log2 = (WebRtc_Word16)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); - // log2(magn(i))*log(2) - lmagn[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(log2, log2Const, 15); - // + log(2^stages) - lmagn[i] += logval; - } else - { - lmagn[i] = logval; + } + + int16x4_t Q3_16x4 = vdup_n_s16(3); + int16x8_t WIDTHQ8_16x8 = vdupq_n_s16(WIDTH_Q8); + int16x8_t WIDTHFACTOR_16x8 = vdupq_n_s16(widthFactor); + + WebRtc_Word16 factor = FACTOR_Q7; + if (inst->blockIndex < END_STARTUP_LONG) + factor = FACTOR_Q7_STARTUP; + + // Loop over simultaneous estimates + for (s = 0; s < SIMULT; s++) { + offset = s * inst->magnLen; + + // Get counter values from state + counter = inst->noiseEstCounter[s]; + assert(counter < 201); + countDiv = WebRtcNsx_kCounterDiv[counter]; + countProd = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(counter, countDiv); + + // quant_est(...) + WebRtc_Word16 deltaBuff[8]; + int16x4_t tmp16x4_0; + int16x4_t tmp16x4_1; + int16x4_t countDiv_16x4 = vdup_n_s16(countDiv); + int16x8_t countProd_16x8 = vdupq_n_s16(countProd); + int16x8_t tmp16x8_0 = vdupq_n_s16(countDiv); + int16x8_t prod16x8 = vqrdmulhq_s16(WIDTHFACTOR_16x8, tmp16x8_0); + int16x8_t tmp16x8_1; + int16x8_t tmp16x8_2; + int16x8_t tmp16x8_3; + int16x8_t tmp16x8_4; + int16x8_t tmp16x8_5; + int32x4_t tmp32x4; + + for (i = 0; i < inst->magnLen - 7; i += 8) { + // Compute delta. + // Smaller step size during startup. This prevents from using + // unrealistic values causing overflow. + tmp16x8_0 = vdupq_n_s16(factor); + vst1q_s16(deltaBuff, tmp16x8_0); + + int j; + for (j = 0; j < 8; j++) { + if (inst->noiseEstDensity[offset + i + j] > 512) { + deltaBuff[j] = WebRtcSpl_DivW32W16ResW16( + numerator, inst->noiseEstDensity[offset + i + j]); } - } - - int16x4_t Q3_16x4 = vdup_n_s16(3); - int16x8_t WIDTHQ8_16x8 = vdupq_n_s16(WIDTH_Q8); - int16x8_t WIDTHFACTOR_16x8 = vdupq_n_s16(widthFactor); - - // Loop over simultaneous estimates - for (s = 0; s < SIMULT; s++) - { - offset = s * inst->magnLen; - - // Get counter values from state - counter = inst->noiseEstCounter[s]; - countDiv = WebRtcNsx_kCounterDiv[counter]; - countProd = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(counter, countDiv); - - // quant_est(...) - WebRtc_Word16 delta_[8]; - int16x4_t tmp16x4_0; - int16x4_t tmp16x4_1; - int16x4_t countDiv_16x4 = vdup_n_s16(countDiv); - int16x8_t countProd_16x8 = vdupq_n_s16(countProd); - int16x8_t tmp16x8_0 = vdupq_n_s16(countDiv); - int16x8_t prod16x8 = vqrdmulhq_s16(WIDTHFACTOR_16x8, tmp16x8_0); - int16x8_t tmp16x8_1; - int16x8_t tmp16x8_2; - int16x8_t tmp16x8_3; - int16x8_t tmp16x8_4; - int16x8_t tmp16x8_5; - int32x4_t tmp32x4; - - for (i = 0; i < inst->magnLen - 7; i += 8) { - // compute delta - tmp16x8_0 = vdupq_n_s16(FACTOR_Q7); - vst1q_s16(delta_, tmp16x8_0); - int j; - for (j = 0; j < 8; j++) { - if (inst->noiseEstDensity[offset + i + j] > 512) - delta_[j] = WebRtcSpl_DivW32W16ResW16(numerator, - inst->noiseEstDensity[offset + i + j]); - } - - // Update log quantile estimate - - // tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(delta, countDiv, 14); - tmp32x4 = vmull_s16(vld1_s16(&delta_[0]), countDiv_16x4); - tmp16x4_1 = vshrn_n_s32(tmp32x4, 14); - tmp32x4 = vmull_s16(vld1_s16(&delta_[4]), countDiv_16x4); - tmp16x4_0 = vshrn_n_s32(tmp32x4, 14); - tmp16x8_0 = vcombine_s16(tmp16x4_1, tmp16x4_0); // Keep for several lines. - - // prepare for the "if" branch - // tmp16 += 2; - // tmp16_1 = (Word16)(tmp16>>2); - tmp16x8_1 = vrshrq_n_s16(tmp16x8_0, 2); - - // inst->noiseEstLogQuantile[offset+i] + tmp16_1; - tmp16x8_2 = vld1q_s16(&inst->noiseEstLogQuantile[offset + i]); // Keep - tmp16x8_1 = vaddq_s16(tmp16x8_2, tmp16x8_1); // Keep for several lines - - // Prepare for the "else" branch - // tmp16 += 1; - // tmp16_1 = (Word16)(tmp16>>1); - tmp16x8_0 = vrshrq_n_s16(tmp16x8_0, 1); - - // tmp16_2 = (Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16_1,3,1); - tmp32x4 = vmull_s16(vget_low_s16(tmp16x8_0), Q3_16x4); - tmp16x4_1 = vshrn_n_s32(tmp32x4, 1); - - // tmp16_2 = (Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16_1,3,1); - tmp32x4 = vmull_s16(vget_high_s16(tmp16x8_0), Q3_16x4); - tmp16x4_0 = vshrn_n_s32(tmp32x4, 1); - - // inst->noiseEstLogQuantile[offset + i] - tmp16_2; - tmp16x8_0 = vcombine_s16(tmp16x4_1, tmp16x4_0); // keep - tmp16x8_0 = vsubq_s16(tmp16x8_2, tmp16x8_0); - - // Do the if-else branches: - tmp16x8_3 = vld1q_s16(&lmagn[i]); // keep for several lines - tmp16x8_5 = vsubq_s16(tmp16x8_3, tmp16x8_2); - __asm__("vcgt.s16 %q0, %q1, #0"::"w"(tmp16x8_4), "w"(tmp16x8_5)); - __asm__("vbit %q0, %q1, %q2"::"w"(tmp16x8_2), "w"(tmp16x8_1), "w"(tmp16x8_4)); - __asm__("vbif %q0, %q1, %q2"::"w"(tmp16x8_2), "w"(tmp16x8_0), "w"(tmp16x8_4)); - vst1q_s16(&inst->noiseEstLogQuantile[offset + i], tmp16x8_2); - - // Update density estimate - // tmp16_1 + tmp16_2 - tmp16x8_1 = vld1q_s16(&inst->noiseEstDensity[offset + i]); - tmp16x8_0 = vqrdmulhq_s16(tmp16x8_1, countProd_16x8); - tmp16x8_0 = vaddq_s16(tmp16x8_0, prod16x8); - - // lmagn[i] - inst->noiseEstLogQuantile[offset + i] - tmp16x8_3 = vsubq_s16(tmp16x8_3, tmp16x8_2); - tmp16x8_3 = vabsq_s16(tmp16x8_3); - tmp16x8_4 = vcgtq_s16(WIDTHQ8_16x8, tmp16x8_3); - __asm__("vbit %q0, %q1, %q2"::"w"(tmp16x8_1), "w"(tmp16x8_0), "w"(tmp16x8_4)); - vst1q_s16(&inst->noiseEstDensity[offset + i], tmp16x8_1); - } // End loop over magnitude spectrum - - for (; i < inst->magnLen; i++) - { - // compute delta - if (inst->noiseEstDensity[offset + i] > 512) - { - delta = WebRtcSpl_DivW32W16ResW16(numerator, - inst->noiseEstDensity[offset + i]); - } else - { - delta = FACTOR_Q7; - } - - // update log quantile estimate - tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(delta, countDiv, 14); - if (lmagn[i] > inst->noiseEstLogQuantile[offset + i]) - { - // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2 - // CounterDiv=1/inst->counter[s] in Q15 - tmp16 += 2; - tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 2); - inst->noiseEstLogQuantile[offset + i] += tmp16no1; - } else - { - tmp16 += 1; - tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 1); - // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2 - tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, 3, 1); - inst->noiseEstLogQuantile[offset + i] -= tmp16no2; - } - - // update density estimate - if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i]) - < WIDTH_Q8) - { - tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( - inst->noiseEstDensity[offset + i], countProd, 15); - tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(widthFactor, - countDiv, 15); - inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2; - } - } // end loop over magnitude spectrum - - if (counter >= END_STARTUP_LONG) - { - inst->noiseEstCounter[s] = 0; - if (inst->blockIndex >= END_STARTUP_LONG) - { - WebRtcNsx_UpdateNoiseEstimate(inst, offset); - } + } + + // Update log quantile estimate + + // tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(delta, countDiv, 14); + tmp32x4 = vmull_s16(vld1_s16(&deltaBuff[0]), countDiv_16x4); + tmp16x4_1 = vshrn_n_s32(tmp32x4, 14); + tmp32x4 = vmull_s16(vld1_s16(&deltaBuff[4]), countDiv_16x4); + tmp16x4_0 = vshrn_n_s32(tmp32x4, 14); + tmp16x8_0 = vcombine_s16(tmp16x4_1, tmp16x4_0); // Keep for several lines. + + // prepare for the "if" branch + // tmp16 += 2; + // tmp16_1 = (Word16)(tmp16>>2); + tmp16x8_1 = vrshrq_n_s16(tmp16x8_0, 2); + + // inst->noiseEstLogQuantile[offset+i] + tmp16_1; + tmp16x8_2 = vld1q_s16(&inst->noiseEstLogQuantile[offset + i]); // Keep + tmp16x8_1 = vaddq_s16(tmp16x8_2, tmp16x8_1); // Keep for several lines + + // Prepare for the "else" branch + // tmp16 += 1; + // tmp16_1 = (Word16)(tmp16>>1); + tmp16x8_0 = vrshrq_n_s16(tmp16x8_0, 1); + + // tmp16_2 = (Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16_1,3,1); + tmp32x4 = vmull_s16(vget_low_s16(tmp16x8_0), Q3_16x4); + tmp16x4_1 = vshrn_n_s32(tmp32x4, 1); + + // tmp16_2 = (Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16_1,3,1); + tmp32x4 = vmull_s16(vget_high_s16(tmp16x8_0), Q3_16x4); + tmp16x4_0 = vshrn_n_s32(tmp32x4, 1); + + // inst->noiseEstLogQuantile[offset + i] - tmp16_2; + tmp16x8_0 = vcombine_s16(tmp16x4_1, tmp16x4_0); // keep + tmp16x8_0 = vsubq_s16(tmp16x8_2, tmp16x8_0); + + // logval is the smallest fixed point representation we can have. Values below + // that will correspond to values in the interval [0, 1], which can't possibly + // occur. + tmp16x8_0 = vmaxq_s16(tmp16x8_0, logval_16x8); + + // Do the if-else branches: + tmp16x8_3 = vld1q_s16(&lmagn[i]); // keep for several lines + tmp16x8_5 = vsubq_s16(tmp16x8_3, tmp16x8_2); + __asm__("vcgt.s16 %q0, %q1, #0"::"w"(tmp16x8_4), "w"(tmp16x8_5)); + __asm__("vbit %q0, %q1, %q2"::"w"(tmp16x8_2), "w"(tmp16x8_1), "w"(tmp16x8_4)); + __asm__("vbif %q0, %q1, %q2"::"w"(tmp16x8_2), "w"(tmp16x8_0), "w"(tmp16x8_4)); + vst1q_s16(&inst->noiseEstLogQuantile[offset + i], tmp16x8_2); + + // Update density estimate + // tmp16_1 + tmp16_2 + tmp16x8_1 = vld1q_s16(&inst->noiseEstDensity[offset + i]); + tmp16x8_0 = vqrdmulhq_s16(tmp16x8_1, countProd_16x8); + tmp16x8_0 = vaddq_s16(tmp16x8_0, prod16x8); + + // lmagn[i] - inst->noiseEstLogQuantile[offset + i] + tmp16x8_3 = vsubq_s16(tmp16x8_3, tmp16x8_2); + tmp16x8_3 = vabsq_s16(tmp16x8_3); + tmp16x8_4 = vcgtq_s16(WIDTHQ8_16x8, tmp16x8_3); + __asm__("vbit %q0, %q1, %q2"::"w"(tmp16x8_1), "w"(tmp16x8_0), "w"(tmp16x8_4)); + vst1q_s16(&inst->noiseEstDensity[offset + i], tmp16x8_1); + } // End loop over magnitude spectrum + + for (; i < inst->magnLen; i++) { + // compute delta + if (inst->noiseEstDensity[offset + i] > 512) { + delta = WebRtcSpl_DivW32W16ResW16(numerator, + inst->noiseEstDensity[offset + i]); + } else { + delta = FACTOR_Q7; + if (inst->blockIndex < END_STARTUP_LONG) { + // Smaller step size during startup. This prevents from using + // unrealistic values causing overflow. + delta = FACTOR_Q7_STARTUP; } - inst->noiseEstCounter[s]++; - - } // end loop over simultaneous estimates - - // Sequentially update the noise during startup - if (inst->blockIndex < END_STARTUP_LONG) - { + } + + // update log quantile estimate + tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(delta, countDiv, 14); + if (lmagn[i] > inst->noiseEstLogQuantile[offset + i]) { + // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2 + // CounterDiv=1/(inst->counter[s]+1) in Q15 + tmp16 += 2; + tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 2); + inst->noiseEstLogQuantile[offset + i] += tmp16no1; + } else { + tmp16 += 1; + tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 1); + // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2 + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, 3, 1); + inst->noiseEstLogQuantile[offset + i] -= tmp16no2; + if (inst->noiseEstLogQuantile[offset + i] < logval) { + // logval is the smallest fixed point representation we can have. + // Values below that will correspond to values in the interval + // [0, 1], which can't possibly occur. + inst->noiseEstLogQuantile[offset + i] = logval; + } + } + + // update density estimate + if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i]) + < WIDTH_Q8) { + tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + inst->noiseEstDensity[offset + i], countProd, 15); + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + widthFactor, countDiv, 15); + inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2; + } + } // end loop over magnitude spectrum + + if (counter >= END_STARTUP_LONG) { + inst->noiseEstCounter[s] = 0; + if (inst->blockIndex >= END_STARTUP_LONG) { WebRtcNsx_UpdateNoiseEstimate(inst, offset); + } } + inst->noiseEstCounter[s]++; - for (i = 0; i < inst->magnLen; i++) - { - noise[i] = (WebRtc_UWord32)(inst->noiseEstQuantile[i]); // Q(qNoise) - } - (*qNoise) = (WebRtc_Word16)inst->qNoise; + } // end loop over simultaneous estimates + + // Sequentially update the noise during startup + if (inst->blockIndex < END_STARTUP_LONG) { + WebRtcNsx_UpdateNoiseEstimate(inst, offset); + } + + for (i = 0; i < inst->magnLen; i++) { + noise[i] = (WebRtc_UWord32)(inst->noiseEstQuantile[i]); // Q(qNoise) + } + (*qNoise) = (WebRtc_Word16)inst->qNoise; } #endif // defined(WEBRTC_ARCH_ARM_NEON) && defined(WEBRTC_ANDROID) diff --git a/src/modules/audio_processing/ns/main/source/nsx_defines.h b/src/modules/audio_processing/ns/main/source/nsx_defines.h index 58796b9..cd1e3bf 100644 --- a/src/modules/audio_processing/ns/main/source/nsx_defines.h +++ b/src/modules/audio_processing/ns/main/source/nsx_defines.h @@ -18,6 +18,7 @@ #define END_STARTUP_SHORT 50 #define FACTOR_Q16 (WebRtc_Word32)2621440 // 40 in Q16 #define FACTOR_Q7 (WebRtc_Word16)5120 // 40 in Q7 +#define FACTOR_Q7_STARTUP (WebRtc_Word16)1024 // 8 in Q7 #define WIDTH_Q8 3 // 0.01 in Q8 (or 25 ) //PARAMETERS FOR NEW METHOD #define DD_PR_SNR_Q11 2007 // ~= Q11(0.98) DD update of prior SNR diff --git a/src/modules/audio_processing/ns/main/source/windows_private.h b/src/modules/audio_processing/ns/main/source/windows_private.h index 8f9006e..44c2e84 100644 --- a/src/modules/audio_processing/ns/main/source/windows_private.h +++ b/src/modules/audio_processing/ns/main/source/windows_private.h @@ -13,561 +13,562 @@ // Hanning window for 4ms 16kHz static const float kHanning64w128[128] = { -0.00000000000000f, 0.02454122852291f, 0.04906767432742f, -0.07356456359967f, 0.09801714032956f, 0.12241067519922f, -0.14673047445536f, 0.17096188876030f, 0.19509032201613f, -0.21910124015687f, 0.24298017990326f, 0.26671275747490f, -0.29028467725446f, 0.31368174039889f, 0.33688985339222f, -0.35989503653499f, 0.38268343236509f, 0.40524131400499f, -0.42755509343028f, 0.44961132965461f, 0.47139673682600f, -0.49289819222978f, 0.51410274419322f, 0.53499761988710f, -0.55557023301960f, 0.57580819141785f, 0.59569930449243f, -0.61523159058063f, 0.63439328416365f, 0.65317284295378f, -0.67155895484702f, 0.68954054473707f, 0.70710678118655f, -0.72424708295147f, 0.74095112535496f, 0.75720884650648f, -0.77301045336274f, 0.78834642762661f, 0.80320753148064f, -0.81758481315158f, 0.83146961230255f, 0.84485356524971f, -0.85772861000027f, 0.87008699110871f, 0.88192126434835f, -0.89322430119552f, 0.90398929312344f, 0.91420975570353f, -0.92387953251129f, 0.93299279883474f, 0.94154406518302f, -0.94952818059304f, 0.95694033573221f, 0.96377606579544f, -0.97003125319454f, 0.97570213003853f, 0.98078528040323f, -0.98527764238894f, 0.98917650996478f, 0.99247953459871f, -0.99518472667220f, 0.99729045667869f, 0.99879545620517f, -0.99969881869620f, 1.00000000000000f, -0.99969881869620f, 0.99879545620517f, 0.99729045667869f, -0.99518472667220f, 0.99247953459871f, 0.98917650996478f, -0.98527764238894f, 0.98078528040323f, 0.97570213003853f, -0.97003125319454f, 0.96377606579544f, 0.95694033573221f, -0.94952818059304f, 0.94154406518302f, 0.93299279883474f, -0.92387953251129f, 0.91420975570353f, 0.90398929312344f, -0.89322430119552f, 0.88192126434835f, 0.87008699110871f, -0.85772861000027f, 0.84485356524971f, 0.83146961230255f, -0.81758481315158f, 0.80320753148064f, 0.78834642762661f, -0.77301045336274f, 0.75720884650648f, 0.74095112535496f, -0.72424708295147f, 0.70710678118655f, 0.68954054473707f, -0.67155895484702f, 0.65317284295378f, 0.63439328416365f, -0.61523159058063f, 0.59569930449243f, 0.57580819141785f, -0.55557023301960f, 0.53499761988710f, 0.51410274419322f, -0.49289819222978f, 0.47139673682600f, 0.44961132965461f, -0.42755509343028f, 0.40524131400499f, 0.38268343236509f, -0.35989503653499f, 0.33688985339222f, 0.31368174039889f, -0.29028467725446f, 0.26671275747490f, 0.24298017990326f, -0.21910124015687f, 0.19509032201613f, 0.17096188876030f, -0.14673047445536f, 0.12241067519922f, 0.09801714032956f, -0.07356456359967f, 0.04906767432742f, 0.02454122852291f + 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, + 0.07356456359967f, 0.09801714032956f, 0.12241067519922f, + 0.14673047445536f, 0.17096188876030f, 0.19509032201613f, + 0.21910124015687f, 0.24298017990326f, 0.26671275747490f, + 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, + 0.35989503653499f, 0.38268343236509f, 0.40524131400499f, + 0.42755509343028f, 0.44961132965461f, 0.47139673682600f, + 0.49289819222978f, 0.51410274419322f, 0.53499761988710f, + 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, + 0.61523159058063f, 0.63439328416365f, 0.65317284295378f, + 0.67155895484702f, 0.68954054473707f, 0.70710678118655f, + 0.72424708295147f, 0.74095112535496f, 0.75720884650648f, + 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, + 0.81758481315158f, 0.83146961230255f, 0.84485356524971f, + 0.85772861000027f, 0.87008699110871f, 0.88192126434835f, + 0.89322430119552f, 0.90398929312344f, 0.91420975570353f, + 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, + 0.94952818059304f, 0.95694033573221f, 0.96377606579544f, + 0.97003125319454f, 0.97570213003853f, 0.98078528040323f, + 0.98527764238894f, 0.98917650996478f, 0.99247953459871f, + 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, + 0.99969881869620f, 1.00000000000000f, + 0.99969881869620f, 0.99879545620517f, 0.99729045667869f, + 0.99518472667220f, 0.99247953459871f, 0.98917650996478f, + 0.98527764238894f, 0.98078528040323f, 0.97570213003853f, + 0.97003125319454f, 0.96377606579544f, 0.95694033573221f, + 0.94952818059304f, 0.94154406518302f, 0.93299279883474f, + 0.92387953251129f, 0.91420975570353f, 0.90398929312344f, + 0.89322430119552f, 0.88192126434835f, 0.87008699110871f, + 0.85772861000027f, 0.84485356524971f, 0.83146961230255f, + 0.81758481315158f, 0.80320753148064f, 0.78834642762661f, + 0.77301045336274f, 0.75720884650648f, 0.74095112535496f, + 0.72424708295147f, 0.70710678118655f, 0.68954054473707f, + 0.67155895484702f, 0.65317284295378f, 0.63439328416365f, + 0.61523159058063f, 0.59569930449243f, 0.57580819141785f, + 0.55557023301960f, 0.53499761988710f, 0.51410274419322f, + 0.49289819222978f, 0.47139673682600f, 0.44961132965461f, + 0.42755509343028f, 0.40524131400499f, 0.38268343236509f, + 0.35989503653499f, 0.33688985339222f, 0.31368174039889f, + 0.29028467725446f, 0.26671275747490f, 0.24298017990326f, + 0.21910124015687f, 0.19509032201613f, 0.17096188876030f, + 0.14673047445536f, 0.12241067519922f, 0.09801714032956f, + 0.07356456359967f, 0.04906767432742f, 0.02454122852291f }; // hybrib Hanning & flat window static const float kBlocks80w128[128] = { -(float)0.00000000, (float)0.03271908, (float)0.06540313, (float)0.09801714, (float)0.13052619, -(float)0.16289547, (float)0.19509032, (float)0.22707626, (float)0.25881905, (float)0.29028468, -(float)0.32143947, (float)0.35225005, (float)0.38268343, (float)0.41270703, (float)0.44228869, -(float)0.47139674, (float)0.50000000, (float)0.52806785, (float)0.55557023, (float)0.58247770, -(float)0.60876143, (float)0.63439328, (float)0.65934582, (float)0.68359230, (float)0.70710678, -(float)0.72986407, (float)0.75183981, (float)0.77301045, (float)0.79335334, (float)0.81284668, -(float)0.83146961, (float)0.84920218, (float)0.86602540, (float)0.88192126, (float)0.89687274, -(float)0.91086382, (float)0.92387953, (float)0.93590593, (float)0.94693013, (float)0.95694034, -(float)0.96592583, (float)0.97387698, (float)0.98078528, (float)0.98664333, (float)0.99144486, -(float)0.99518473, (float)0.99785892, (float)0.99946459, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)0.99946459, (float)0.99785892, (float)0.99518473, (float)0.99144486, -(float)0.98664333, (float)0.98078528, (float)0.97387698, (float)0.96592583, (float)0.95694034, -(float)0.94693013, (float)0.93590593, (float)0.92387953, (float)0.91086382, (float)0.89687274, -(float)0.88192126, (float)0.86602540, (float)0.84920218, (float)0.83146961, (float)0.81284668, -(float)0.79335334, (float)0.77301045, (float)0.75183981, (float)0.72986407, (float)0.70710678, -(float)0.68359230, (float)0.65934582, (float)0.63439328, (float)0.60876143, (float)0.58247770, -(float)0.55557023, (float)0.52806785, (float)0.50000000, (float)0.47139674, (float)0.44228869, -(float)0.41270703, (float)0.38268343, (float)0.35225005, (float)0.32143947, (float)0.29028468, -(float)0.25881905, (float)0.22707626, (float)0.19509032, (float)0.16289547, (float)0.13052619, -(float)0.09801714, (float)0.06540313, (float)0.03271908 + (float)0.00000000, (float)0.03271908, (float)0.06540313, (float)0.09801714, (float)0.13052619, + (float)0.16289547, (float)0.19509032, (float)0.22707626, (float)0.25881905, (float)0.29028468, + (float)0.32143947, (float)0.35225005, (float)0.38268343, (float)0.41270703, (float)0.44228869, + (float)0.47139674, (float)0.50000000, (float)0.52806785, (float)0.55557023, (float)0.58247770, + (float)0.60876143, (float)0.63439328, (float)0.65934582, (float)0.68359230, (float)0.70710678, + (float)0.72986407, (float)0.75183981, (float)0.77301045, (float)0.79335334, (float)0.81284668, + (float)0.83146961, (float)0.84920218, (float)0.86602540, (float)0.88192126, (float)0.89687274, + (float)0.91086382, (float)0.92387953, (float)0.93590593, (float)0.94693013, (float)0.95694034, + (float)0.96592583, (float)0.97387698, (float)0.98078528, (float)0.98664333, (float)0.99144486, + (float)0.99518473, (float)0.99785892, (float)0.99946459, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)0.99946459, (float)0.99785892, (float)0.99518473, (float)0.99144486, + (float)0.98664333, (float)0.98078528, (float)0.97387698, (float)0.96592583, (float)0.95694034, + (float)0.94693013, (float)0.93590593, (float)0.92387953, (float)0.91086382, (float)0.89687274, + (float)0.88192126, (float)0.86602540, (float)0.84920218, (float)0.83146961, (float)0.81284668, + (float)0.79335334, (float)0.77301045, (float)0.75183981, (float)0.72986407, (float)0.70710678, + (float)0.68359230, (float)0.65934582, (float)0.63439328, (float)0.60876143, (float)0.58247770, + (float)0.55557023, (float)0.52806785, (float)0.50000000, (float)0.47139674, (float)0.44228869, + (float)0.41270703, (float)0.38268343, (float)0.35225005, (float)0.32143947, (float)0.29028468, + (float)0.25881905, (float)0.22707626, (float)0.19509032, (float)0.16289547, (float)0.13052619, + (float)0.09801714, (float)0.06540313, (float)0.03271908 }; // hybrib Hanning & flat window static const float kBlocks160w256[256] = { -(float)0.00000000, (float)0.01636173, (float)0.03271908, (float)0.04906767, (float)0.06540313, -(float)0.08172107, (float)0.09801714, (float)0.11428696, (float)0.13052619, (float)0.14673047, -(float)0.16289547, (float)0.17901686, (float)0.19509032, (float)0.21111155, (float)0.22707626, -(float)0.24298018, (float)0.25881905, (float)0.27458862, (float)0.29028468, (float)0.30590302, -(float)0.32143947, (float)0.33688985, (float)0.35225005, (float)0.36751594, (float)0.38268343, -(float)0.39774847, (float)0.41270703, (float)0.42755509, (float)0.44228869, (float)0.45690388, -(float)0.47139674, (float)0.48576339, (float)0.50000000, (float)0.51410274, (float)0.52806785, -(float)0.54189158, (float)0.55557023, (float)0.56910015, (float)0.58247770, (float)0.59569930, -(float)0.60876143, (float)0.62166057, (float)0.63439328, (float)0.64695615, (float)0.65934582, -(float)0.67155895, (float)0.68359230, (float)0.69544264, (float)0.70710678, (float)0.71858162, -(float)0.72986407, (float)0.74095113, (float)0.75183981, (float)0.76252720, (float)0.77301045, -(float)0.78328675, (float)0.79335334, (float)0.80320753, (float)0.81284668, (float)0.82226822, -(float)0.83146961, (float)0.84044840, (float)0.84920218, (float)0.85772861, (float)0.86602540, -(float)0.87409034, (float)0.88192126, (float)0.88951608, (float)0.89687274, (float)0.90398929, -(float)0.91086382, (float)0.91749450, (float)0.92387953, (float)0.93001722, (float)0.93590593, -(float)0.94154407, (float)0.94693013, (float)0.95206268, (float)0.95694034, (float)0.96156180, -(float)0.96592583, (float)0.97003125, (float)0.97387698, (float)0.97746197, (float)0.98078528, -(float)0.98384601, (float)0.98664333, (float)0.98917651, (float)0.99144486, (float)0.99344778, -(float)0.99518473, (float)0.99665524, (float)0.99785892, (float)0.99879546, (float)0.99946459, -(float)0.99986614, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)0.99986614, (float)0.99946459, (float)0.99879546, (float)0.99785892, -(float)0.99665524, (float)0.99518473, (float)0.99344778, (float)0.99144486, (float)0.98917651, -(float)0.98664333, (float)0.98384601, (float)0.98078528, (float)0.97746197, (float)0.97387698, -(float)0.97003125, (float)0.96592583, (float)0.96156180, (float)0.95694034, (float)0.95206268, -(float)0.94693013, (float)0.94154407, (float)0.93590593, (float)0.93001722, (float)0.92387953, -(float)0.91749450, (float)0.91086382, (float)0.90398929, (float)0.89687274, (float)0.88951608, -(float)0.88192126, (float)0.87409034, (float)0.86602540, (float)0.85772861, (float)0.84920218, -(float)0.84044840, (float)0.83146961, (float)0.82226822, (float)0.81284668, (float)0.80320753, -(float)0.79335334, (float)0.78328675, (float)0.77301045, (float)0.76252720, (float)0.75183981, -(float)0.74095113, (float)0.72986407, (float)0.71858162, (float)0.70710678, (float)0.69544264, -(float)0.68359230, (float)0.67155895, (float)0.65934582, (float)0.64695615, (float)0.63439328, -(float)0.62166057, (float)0.60876143, (float)0.59569930, (float)0.58247770, (float)0.56910015, -(float)0.55557023, (float)0.54189158, (float)0.52806785, (float)0.51410274, (float)0.50000000, -(float)0.48576339, (float)0.47139674, (float)0.45690388, (float)0.44228869, (float)0.42755509, -(float)0.41270703, (float)0.39774847, (float)0.38268343, (float)0.36751594, (float)0.35225005, -(float)0.33688985, (float)0.32143947, (float)0.30590302, (float)0.29028468, (float)0.27458862, -(float)0.25881905, (float)0.24298018, (float)0.22707626, (float)0.21111155, (float)0.19509032, -(float)0.17901686, (float)0.16289547, (float)0.14673047, (float)0.13052619, (float)0.11428696, -(float)0.09801714, (float)0.08172107, (float)0.06540313, (float)0.04906767, (float)0.03271908, -(float)0.01636173 + (float)0.00000000, (float)0.01636173, (float)0.03271908, (float)0.04906767, (float)0.06540313, + (float)0.08172107, (float)0.09801714, (float)0.11428696, (float)0.13052619, (float)0.14673047, + (float)0.16289547, (float)0.17901686, (float)0.19509032, (float)0.21111155, (float)0.22707626, + (float)0.24298018, (float)0.25881905, (float)0.27458862, (float)0.29028468, (float)0.30590302, + (float)0.32143947, (float)0.33688985, (float)0.35225005, (float)0.36751594, (float)0.38268343, + (float)0.39774847, (float)0.41270703, (float)0.42755509, (float)0.44228869, (float)0.45690388, + (float)0.47139674, (float)0.48576339, (float)0.50000000, (float)0.51410274, (float)0.52806785, + (float)0.54189158, (float)0.55557023, (float)0.56910015, (float)0.58247770, (float)0.59569930, + (float)0.60876143, (float)0.62166057, (float)0.63439328, (float)0.64695615, (float)0.65934582, + (float)0.67155895, (float)0.68359230, (float)0.69544264, (float)0.70710678, (float)0.71858162, + (float)0.72986407, (float)0.74095113, (float)0.75183981, (float)0.76252720, (float)0.77301045, + (float)0.78328675, (float)0.79335334, (float)0.80320753, (float)0.81284668, (float)0.82226822, + (float)0.83146961, (float)0.84044840, (float)0.84920218, (float)0.85772861, (float)0.86602540, + (float)0.87409034, (float)0.88192126, (float)0.88951608, (float)0.89687274, (float)0.90398929, + (float)0.91086382, (float)0.91749450, (float)0.92387953, (float)0.93001722, (float)0.93590593, + (float)0.94154407, (float)0.94693013, (float)0.95206268, (float)0.95694034, (float)0.96156180, + (float)0.96592583, (float)0.97003125, (float)0.97387698, (float)0.97746197, (float)0.98078528, + (float)0.98384601, (float)0.98664333, (float)0.98917651, (float)0.99144486, (float)0.99344778, + (float)0.99518473, (float)0.99665524, (float)0.99785892, (float)0.99879546, (float)0.99946459, + (float)0.99986614, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)0.99986614, (float)0.99946459, (float)0.99879546, (float)0.99785892, + (float)0.99665524, (float)0.99518473, (float)0.99344778, (float)0.99144486, (float)0.98917651, + (float)0.98664333, (float)0.98384601, (float)0.98078528, (float)0.97746197, (float)0.97387698, + (float)0.97003125, (float)0.96592583, (float)0.96156180, (float)0.95694034, (float)0.95206268, + (float)0.94693013, (float)0.94154407, (float)0.93590593, (float)0.93001722, (float)0.92387953, + (float)0.91749450, (float)0.91086382, (float)0.90398929, (float)0.89687274, (float)0.88951608, + (float)0.88192126, (float)0.87409034, (float)0.86602540, (float)0.85772861, (float)0.84920218, + (float)0.84044840, (float)0.83146961, (float)0.82226822, (float)0.81284668, (float)0.80320753, + (float)0.79335334, (float)0.78328675, (float)0.77301045, (float)0.76252720, (float)0.75183981, + (float)0.74095113, (float)0.72986407, (float)0.71858162, (float)0.70710678, (float)0.69544264, + (float)0.68359230, (float)0.67155895, (float)0.65934582, (float)0.64695615, (float)0.63439328, + (float)0.62166057, (float)0.60876143, (float)0.59569930, (float)0.58247770, (float)0.56910015, + (float)0.55557023, (float)0.54189158, (float)0.52806785, (float)0.51410274, (float)0.50000000, + (float)0.48576339, (float)0.47139674, (float)0.45690388, (float)0.44228869, (float)0.42755509, + (float)0.41270703, (float)0.39774847, (float)0.38268343, (float)0.36751594, (float)0.35225005, + (float)0.33688985, (float)0.32143947, (float)0.30590302, (float)0.29028468, (float)0.27458862, + (float)0.25881905, (float)0.24298018, (float)0.22707626, (float)0.21111155, (float)0.19509032, + (float)0.17901686, (float)0.16289547, (float)0.14673047, (float)0.13052619, (float)0.11428696, + (float)0.09801714, (float)0.08172107, (float)0.06540313, (float)0.04906767, (float)0.03271908, + (float)0.01636173 }; // hybrib Hanning & flat window: for 20ms static const float kBlocks320w512[512] = { -(float)0.00000000, (float)0.00818114, (float)0.01636173, (float)0.02454123, (float)0.03271908, -(float)0.04089475, (float)0.04906767, (float)0.05723732, (float)0.06540313, (float)0.07356456, -(float)0.08172107, (float)0.08987211, (float)0.09801714, (float)0.10615561, (float)0.11428696, -(float)0.12241068, (float)0.13052619, (float)0.13863297, (float)0.14673047, (float)0.15481816, -(float)0.16289547, (float)0.17096189, (float)0.17901686, (float)0.18705985, (float)0.19509032, -(float)0.20310773, (float)0.21111155, (float)0.21910124, (float)0.22707626, (float)0.23503609, -(float)0.24298018, (float)0.25090801, (float)0.25881905, (float)0.26671276, (float)0.27458862, -(float)0.28244610, (float)0.29028468, (float)0.29810383, (float)0.30590302, (float)0.31368174, -(float)0.32143947, (float)0.32917568, (float)0.33688985, (float)0.34458148, (float)0.35225005, -(float)0.35989504, (float)0.36751594, (float)0.37511224, (float)0.38268343, (float)0.39022901, -(float)0.39774847, (float)0.40524131, (float)0.41270703, (float)0.42014512, (float)0.42755509, -(float)0.43493645, (float)0.44228869, (float)0.44961133, (float)0.45690388, (float)0.46416584, -(float)0.47139674, (float)0.47859608, (float)0.48576339, (float)0.49289819, (float)0.50000000, -(float)0.50706834, (float)0.51410274, (float)0.52110274, (float)0.52806785, (float)0.53499762, -(float)0.54189158, (float)0.54874927, (float)0.55557023, (float)0.56235401, (float)0.56910015, -(float)0.57580819, (float)0.58247770, (float)0.58910822, (float)0.59569930, (float)0.60225052, -(float)0.60876143, (float)0.61523159, (float)0.62166057, (float)0.62804795, (float)0.63439328, -(float)0.64069616, (float)0.64695615, (float)0.65317284, (float)0.65934582, (float)0.66547466, -(float)0.67155895, (float)0.67759830, (float)0.68359230, (float)0.68954054, (float)0.69544264, -(float)0.70129818, (float)0.70710678, (float)0.71286806, (float)0.71858162, (float)0.72424708, -(float)0.72986407, (float)0.73543221, (float)0.74095113, (float)0.74642045, (float)0.75183981, -(float)0.75720885, (float)0.76252720, (float)0.76779452, (float)0.77301045, (float)0.77817464, -(float)0.78328675, (float)0.78834643, (float)0.79335334, (float)0.79830715, (float)0.80320753, -(float)0.80805415, (float)0.81284668, (float)0.81758481, (float)0.82226822, (float)0.82689659, -(float)0.83146961, (float)0.83598698, (float)0.84044840, (float)0.84485357, (float)0.84920218, -(float)0.85349396, (float)0.85772861, (float)0.86190585, (float)0.86602540, (float)0.87008699, -(float)0.87409034, (float)0.87803519, (float)0.88192126, (float)0.88574831, (float)0.88951608, -(float)0.89322430, (float)0.89687274, (float)0.90046115, (float)0.90398929, (float)0.90745693, -(float)0.91086382, (float)0.91420976, (float)0.91749450, (float)0.92071783, (float)0.92387953, -(float)0.92697940, (float)0.93001722, (float)0.93299280, (float)0.93590593, (float)0.93875641, -(float)0.94154407, (float)0.94426870, (float)0.94693013, (float)0.94952818, (float)0.95206268, -(float)0.95453345, (float)0.95694034, (float)0.95928317, (float)0.96156180, (float)0.96377607, -(float)0.96592583, (float)0.96801094, (float)0.97003125, (float)0.97198664, (float)0.97387698, -(float)0.97570213, (float)0.97746197, (float)0.97915640, (float)0.98078528, (float)0.98234852, -(float)0.98384601, (float)0.98527764, (float)0.98664333, (float)0.98794298, (float)0.98917651, -(float)0.99034383, (float)0.99144486, (float)0.99247953, (float)0.99344778, (float)0.99434953, -(float)0.99518473, (float)0.99595331, (float)0.99665524, (float)0.99729046, (float)0.99785892, -(float)0.99836060, (float)0.99879546, (float)0.99916346, (float)0.99946459, (float)0.99969882, -(float)0.99986614, (float)0.99996653, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, -(float)1.00000000, (float)0.99996653, (float)0.99986614, (float)0.99969882, (float)0.99946459, -(float)0.99916346, (float)0.99879546, (float)0.99836060, (float)0.99785892, (float)0.99729046, -(float)0.99665524, (float)0.99595331, (float)0.99518473, (float)0.99434953, (float)0.99344778, -(float)0.99247953, (float)0.99144486, (float)0.99034383, (float)0.98917651, (float)0.98794298, -(float)0.98664333, (float)0.98527764, (float)0.98384601, (float)0.98234852, (float)0.98078528, -(float)0.97915640, (float)0.97746197, (float)0.97570213, (float)0.97387698, (float)0.97198664, -(float)0.97003125, (float)0.96801094, (float)0.96592583, (float)0.96377607, (float)0.96156180, -(float)0.95928317, (float)0.95694034, (float)0.95453345, (float)0.95206268, (float)0.94952818, -(float)0.94693013, (float)0.94426870, (float)0.94154407, (float)0.93875641, (float)0.93590593, -(float)0.93299280, (float)0.93001722, (float)0.92697940, (float)0.92387953, (float)0.92071783, -(float)0.91749450, (float)0.91420976, (float)0.91086382, (float)0.90745693, (float)0.90398929, -(float)0.90046115, (float)0.89687274, (float)0.89322430, (float)0.88951608, (float)0.88574831, -(float)0.88192126, (float)0.87803519, (float)0.87409034, (float)0.87008699, (float)0.86602540, -(float)0.86190585, (float)0.85772861, (float)0.85349396, (float)0.84920218, (float)0.84485357, -(float)0.84044840, (float)0.83598698, (float)0.83146961, (float)0.82689659, (float)0.82226822, -(float)0.81758481, (float)0.81284668, (float)0.80805415, (float)0.80320753, (float)0.79830715, -(float)0.79335334, (float)0.78834643, (float)0.78328675, (float)0.77817464, (float)0.77301045, -(float)0.76779452, (float)0.76252720, (float)0.75720885, (float)0.75183981, (float)0.74642045, -(float)0.74095113, (float)0.73543221, (float)0.72986407, (float)0.72424708, (float)0.71858162, -(float)0.71286806, (float)0.70710678, (float)0.70129818, (float)0.69544264, (float)0.68954054, -(float)0.68359230, (float)0.67759830, (float)0.67155895, (float)0.66547466, (float)0.65934582, -(float)0.65317284, (float)0.64695615, (float)0.64069616, (float)0.63439328, (float)0.62804795, -(float)0.62166057, (float)0.61523159, (float)0.60876143, (float)0.60225052, (float)0.59569930, -(float)0.58910822, (float)0.58247770, (float)0.57580819, (float)0.56910015, (float)0.56235401, -(float)0.55557023, (float)0.54874927, (float)0.54189158, (float)0.53499762, (float)0.52806785, -(float)0.52110274, (float)0.51410274, (float)0.50706834, (float)0.50000000, (float)0.49289819, -(float)0.48576339, (float)0.47859608, (float)0.47139674, (float)0.46416584, (float)0.45690388, -(float)0.44961133, (float)0.44228869, (float)0.43493645, (float)0.42755509, (float)0.42014512, -(float)0.41270703, (float)0.40524131, (float)0.39774847, (float)0.39022901, (float)0.38268343, -(float)0.37511224, (float)0.36751594, (float)0.35989504, (float)0.35225005, (float)0.34458148, -(float)0.33688985, (float)0.32917568, (float)0.32143947, (float)0.31368174, (float)0.30590302, -(float)0.29810383, (float)0.29028468, (float)0.28244610, (float)0.27458862, (float)0.26671276, -(float)0.25881905, (float)0.25090801, (float)0.24298018, (float)0.23503609, (float)0.22707626, -(float)0.21910124, (float)0.21111155, (float)0.20310773, (float)0.19509032, (float)0.18705985, -(float)0.17901686, (float)0.17096189, (float)0.16289547, (float)0.15481816, (float)0.14673047, -(float)0.13863297, (float)0.13052619, (float)0.12241068, (float)0.11428696, (float)0.10615561, -(float)0.09801714, (float)0.08987211, (float)0.08172107, (float)0.07356456, (float)0.06540313, -(float)0.05723732, (float)0.04906767, (float)0.04089475, (float)0.03271908, (float)0.02454123, -(float)0.01636173, (float)0.00818114 + (float)0.00000000, (float)0.00818114, (float)0.01636173, (float)0.02454123, (float)0.03271908, + (float)0.04089475, (float)0.04906767, (float)0.05723732, (float)0.06540313, (float)0.07356456, + (float)0.08172107, (float)0.08987211, (float)0.09801714, (float)0.10615561, (float)0.11428696, + (float)0.12241068, (float)0.13052619, (float)0.13863297, (float)0.14673047, (float)0.15481816, + (float)0.16289547, (float)0.17096189, (float)0.17901686, (float)0.18705985, (float)0.19509032, + (float)0.20310773, (float)0.21111155, (float)0.21910124, (float)0.22707626, (float)0.23503609, + (float)0.24298018, (float)0.25090801, (float)0.25881905, (float)0.26671276, (float)0.27458862, + (float)0.28244610, (float)0.29028468, (float)0.29810383, (float)0.30590302, (float)0.31368174, + (float)0.32143947, (float)0.32917568, (float)0.33688985, (float)0.34458148, (float)0.35225005, + (float)0.35989504, (float)0.36751594, (float)0.37511224, (float)0.38268343, (float)0.39022901, + (float)0.39774847, (float)0.40524131, (float)0.41270703, (float)0.42014512, (float)0.42755509, + (float)0.43493645, (float)0.44228869, (float)0.44961133, (float)0.45690388, (float)0.46416584, + (float)0.47139674, (float)0.47859608, (float)0.48576339, (float)0.49289819, (float)0.50000000, + (float)0.50706834, (float)0.51410274, (float)0.52110274, (float)0.52806785, (float)0.53499762, + (float)0.54189158, (float)0.54874927, (float)0.55557023, (float)0.56235401, (float)0.56910015, + (float)0.57580819, (float)0.58247770, (float)0.58910822, (float)0.59569930, (float)0.60225052, + (float)0.60876143, (float)0.61523159, (float)0.62166057, (float)0.62804795, (float)0.63439328, + (float)0.64069616, (float)0.64695615, (float)0.65317284, (float)0.65934582, (float)0.66547466, + (float)0.67155895, (float)0.67759830, (float)0.68359230, (float)0.68954054, (float)0.69544264, + (float)0.70129818, (float)0.70710678, (float)0.71286806, (float)0.71858162, (float)0.72424708, + (float)0.72986407, (float)0.73543221, (float)0.74095113, (float)0.74642045, (float)0.75183981, + (float)0.75720885, (float)0.76252720, (float)0.76779452, (float)0.77301045, (float)0.77817464, + (float)0.78328675, (float)0.78834643, (float)0.79335334, (float)0.79830715, (float)0.80320753, + (float)0.80805415, (float)0.81284668, (float)0.81758481, (float)0.82226822, (float)0.82689659, + (float)0.83146961, (float)0.83598698, (float)0.84044840, (float)0.84485357, (float)0.84920218, + (float)0.85349396, (float)0.85772861, (float)0.86190585, (float)0.86602540, (float)0.87008699, + (float)0.87409034, (float)0.87803519, (float)0.88192126, (float)0.88574831, (float)0.88951608, + (float)0.89322430, (float)0.89687274, (float)0.90046115, (float)0.90398929, (float)0.90745693, + (float)0.91086382, (float)0.91420976, (float)0.91749450, (float)0.92071783, (float)0.92387953, + (float)0.92697940, (float)0.93001722, (float)0.93299280, (float)0.93590593, (float)0.93875641, + (float)0.94154407, (float)0.94426870, (float)0.94693013, (float)0.94952818, (float)0.95206268, + (float)0.95453345, (float)0.95694034, (float)0.95928317, (float)0.96156180, (float)0.96377607, + (float)0.96592583, (float)0.96801094, (float)0.97003125, (float)0.97198664, (float)0.97387698, + (float)0.97570213, (float)0.97746197, (float)0.97915640, (float)0.98078528, (float)0.98234852, + (float)0.98384601, (float)0.98527764, (float)0.98664333, (float)0.98794298, (float)0.98917651, + (float)0.99034383, (float)0.99144486, (float)0.99247953, (float)0.99344778, (float)0.99434953, + (float)0.99518473, (float)0.99595331, (float)0.99665524, (float)0.99729046, (float)0.99785892, + (float)0.99836060, (float)0.99879546, (float)0.99916346, (float)0.99946459, (float)0.99969882, + (float)0.99986614, (float)0.99996653, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)0.99996653, (float)0.99986614, (float)0.99969882, (float)0.99946459, + (float)0.99916346, (float)0.99879546, (float)0.99836060, (float)0.99785892, (float)0.99729046, + (float)0.99665524, (float)0.99595331, (float)0.99518473, (float)0.99434953, (float)0.99344778, + (float)0.99247953, (float)0.99144486, (float)0.99034383, (float)0.98917651, (float)0.98794298, + (float)0.98664333, (float)0.98527764, (float)0.98384601, (float)0.98234852, (float)0.98078528, + (float)0.97915640, (float)0.97746197, (float)0.97570213, (float)0.97387698, (float)0.97198664, + (float)0.97003125, (float)0.96801094, (float)0.96592583, (float)0.96377607, (float)0.96156180, + (float)0.95928317, (float)0.95694034, (float)0.95453345, (float)0.95206268, (float)0.94952818, + (float)0.94693013, (float)0.94426870, (float)0.94154407, (float)0.93875641, (float)0.93590593, + (float)0.93299280, (float)0.93001722, (float)0.92697940, (float)0.92387953, (float)0.92071783, + (float)0.91749450, (float)0.91420976, (float)0.91086382, (float)0.90745693, (float)0.90398929, + (float)0.90046115, (float)0.89687274, (float)0.89322430, (float)0.88951608, (float)0.88574831, + (float)0.88192126, (float)0.87803519, (float)0.87409034, (float)0.87008699, (float)0.86602540, + (float)0.86190585, (float)0.85772861, (float)0.85349396, (float)0.84920218, (float)0.84485357, + (float)0.84044840, (float)0.83598698, (float)0.83146961, (float)0.82689659, (float)0.82226822, + (float)0.81758481, (float)0.81284668, (float)0.80805415, (float)0.80320753, (float)0.79830715, + (float)0.79335334, (float)0.78834643, (float)0.78328675, (float)0.77817464, (float)0.77301045, + (float)0.76779452, (float)0.76252720, (float)0.75720885, (float)0.75183981, (float)0.74642045, + (float)0.74095113, (float)0.73543221, (float)0.72986407, (float)0.72424708, (float)0.71858162, + (float)0.71286806, (float)0.70710678, (float)0.70129818, (float)0.69544264, (float)0.68954054, + (float)0.68359230, (float)0.67759830, (float)0.67155895, (float)0.66547466, (float)0.65934582, + (float)0.65317284, (float)0.64695615, (float)0.64069616, (float)0.63439328, (float)0.62804795, + (float)0.62166057, (float)0.61523159, (float)0.60876143, (float)0.60225052, (float)0.59569930, + (float)0.58910822, (float)0.58247770, (float)0.57580819, (float)0.56910015, (float)0.56235401, + (float)0.55557023, (float)0.54874927, (float)0.54189158, (float)0.53499762, (float)0.52806785, + (float)0.52110274, (float)0.51410274, (float)0.50706834, (float)0.50000000, (float)0.49289819, + (float)0.48576339, (float)0.47859608, (float)0.47139674, (float)0.46416584, (float)0.45690388, + (float)0.44961133, (float)0.44228869, (float)0.43493645, (float)0.42755509, (float)0.42014512, + (float)0.41270703, (float)0.40524131, (float)0.39774847, (float)0.39022901, (float)0.38268343, + (float)0.37511224, (float)0.36751594, (float)0.35989504, (float)0.35225005, (float)0.34458148, + (float)0.33688985, (float)0.32917568, (float)0.32143947, (float)0.31368174, (float)0.30590302, + (float)0.29810383, (float)0.29028468, (float)0.28244610, (float)0.27458862, (float)0.26671276, + (float)0.25881905, (float)0.25090801, (float)0.24298018, (float)0.23503609, (float)0.22707626, + (float)0.21910124, (float)0.21111155, (float)0.20310773, (float)0.19509032, (float)0.18705985, + (float)0.17901686, (float)0.17096189, (float)0.16289547, (float)0.15481816, (float)0.14673047, + (float)0.13863297, (float)0.13052619, (float)0.12241068, (float)0.11428696, (float)0.10615561, + (float)0.09801714, (float)0.08987211, (float)0.08172107, (float)0.07356456, (float)0.06540313, + (float)0.05723732, (float)0.04906767, (float)0.04089475, (float)0.03271908, (float)0.02454123, + (float)0.01636173, (float)0.00818114 }; // Hanning window: for 15ms at 16kHz with symmetric zeros static const float kBlocks240w512[512] = { -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00654494, (float)0.01308960, (float)0.01963369, -(float)0.02617695, (float)0.03271908, (float)0.03925982, (float)0.04579887, (float)0.05233596, -(float)0.05887080, (float)0.06540313, (float)0.07193266, (float)0.07845910, (float)0.08498218, -(float)0.09150162, (float)0.09801714, (float)0.10452846, (float)0.11103531, (float)0.11753740, -(float)0.12403446, (float)0.13052620, (float)0.13701233, (float)0.14349262, (float)0.14996676, -(float)0.15643448, (float)0.16289547, (float)0.16934951, (float)0.17579629, (float)0.18223552, -(float)0.18866697, (float)0.19509032, (float)0.20150533, (float)0.20791170, (float)0.21430916, -(float)0.22069745, (float)0.22707628, (float)0.23344538, (float)0.23980446, (float)0.24615330, -(float)0.25249159, (float)0.25881904, (float)0.26513544, (float)0.27144045, (float)0.27773386, -(float)0.28401536, (float)0.29028466, (float)0.29654160, (float)0.30278578, (float)0.30901700, -(float)0.31523499, (float)0.32143945, (float)0.32763019, (float)0.33380687, (float)0.33996925, -(float)0.34611708, (float)0.35225007, (float)0.35836795, (float)0.36447051, (float)0.37055743, -(float)0.37662852, (float)0.38268346, (float)0.38872197, (float)0.39474389, (float)0.40074885, -(float)0.40673664, (float)0.41270703, (float)0.41865975, (float)0.42459452, (float)0.43051112, -(float)0.43640924, (float)0.44228873, (float)0.44814920, (float)0.45399052, (float)0.45981237, -(float)0.46561453, (float)0.47139674, (float)0.47715878, (float)0.48290035, (float)0.48862126, -(float)0.49432120, (float)0.50000000, (float)0.50565743, (float)0.51129311, (float)0.51690692, -(float)0.52249855, (float)0.52806789, (float)0.53361452, (float)0.53913832, (float)0.54463905, -(float)0.55011642, (float)0.55557024, (float)0.56100029, (float)0.56640625, (float)0.57178795, -(float)0.57714522, (float)0.58247769, (float)0.58778524, (float)0.59306765, (float)0.59832460, -(float)0.60355598, (float)0.60876143, (float)0.61394083, (float)0.61909395, (float)0.62422055, -(float)0.62932038, (float)0.63439333, (float)0.63943899, (float)0.64445734, (float)0.64944810, -(float)0.65441096, (float)0.65934587, (float)0.66425246, (float)0.66913062, (float)0.67398012, -(float)0.67880076, (float)0.68359232, (float)0.68835455, (float)0.69308740, (float)0.69779050, -(float)0.70246369, (float)0.70710677, (float)0.71171963, (float)0.71630198, (float)0.72085363, -(float)0.72537440, (float)0.72986406, (float)0.73432255, (float)0.73874950, (float)0.74314487, -(float)0.74750835, (float)0.75183982, (float)0.75613910, (float)0.76040596, (float)0.76464027, -(float)0.76884186, (float)0.77301043, (float)0.77714598, (float)0.78124821, (float)0.78531694, -(float)0.78935206, (float)0.79335338, (float)0.79732066, (float)0.80125386, (float)0.80515265, -(float)0.80901700, (float)0.81284672, (float)0.81664157, (float)0.82040149, (float)0.82412618, -(float)0.82781565, (float)0.83146966, (float)0.83508795, (float)0.83867061, (float)0.84221727, -(float)0.84572780, (float)0.84920216, (float)0.85264021, (float)0.85604161, (float)0.85940641, -(float)0.86273444, (float)0.86602545, (float)0.86927933, (float)0.87249607, (float)0.87567532, -(float)0.87881714, (float)0.88192129, (float)0.88498765, (float)0.88801610, (float)0.89100653, -(float)0.89395881, (float)0.89687276, (float)0.89974827, (float)0.90258533, (float)0.90538365, -(float)0.90814316, (float)0.91086388, (float)0.91354549, (float)0.91618794, (float)0.91879123, -(float)0.92135513, (float)0.92387950, (float)0.92636442, (float)0.92880958, (float)0.93121493, -(float)0.93358046, (float)0.93590593, (float)0.93819135, (float)0.94043654, (float)0.94264150, -(float)0.94480604, (float)0.94693011, (float)0.94901365, (float)0.95105654, (float)0.95305866, -(float)0.95501995, (float)0.95694035, (float)0.95881975, (float)0.96065807, (float)0.96245527, -(float)0.96421117, (float)0.96592581, (float)0.96759909, (float)0.96923089, (float)0.97082120, -(float)0.97236991, (float)0.97387701, (float)0.97534233, (float)0.97676587, (float)0.97814763, -(float)0.97948742, (float)0.98078531, (float)0.98204112, (float)0.98325491, (float)0.98442656, -(float)0.98555607, (float)0.98664331, (float)0.98768836, (float)0.98869103, (float)0.98965138, -(float)0.99056935, (float)0.99144489, (float)0.99227792, (float)0.99306846, (float)0.99381649, -(float)0.99452192, (float)0.99518472, (float)0.99580491, (float)0.99638247, (float)0.99691731, -(float)0.99740952, (float)0.99785894, (float)0.99826562, (float)0.99862951, (float)0.99895066, -(float)0.99922901, (float)0.99946457, (float)0.99965733, (float)0.99980724, (float)0.99991435, -(float)0.99997860, (float)1.00000000, (float)0.99997860, (float)0.99991435, (float)0.99980724, -(float)0.99965733, (float)0.99946457, (float)0.99922901, (float)0.99895066, (float)0.99862951, -(float)0.99826562, (float)0.99785894, (float)0.99740946, (float)0.99691731, (float)0.99638247, -(float)0.99580491, (float)0.99518472, (float)0.99452192, (float)0.99381644, (float)0.99306846, -(float)0.99227792, (float)0.99144489, (float)0.99056935, (float)0.98965138, (float)0.98869103, -(float)0.98768836, (float)0.98664331, (float)0.98555607, (float)0.98442656, (float)0.98325491, -(float)0.98204112, (float)0.98078525, (float)0.97948742, (float)0.97814757, (float)0.97676587, -(float)0.97534227, (float)0.97387695, (float)0.97236991, (float)0.97082120, (float)0.96923089, -(float)0.96759909, (float)0.96592581, (float)0.96421117, (float)0.96245521, (float)0.96065807, -(float)0.95881969, (float)0.95694029, (float)0.95501995, (float)0.95305860, (float)0.95105648, -(float)0.94901365, (float)0.94693011, (float)0.94480604, (float)0.94264150, (float)0.94043654, -(float)0.93819129, (float)0.93590593, (float)0.93358046, (float)0.93121493, (float)0.92880952, -(float)0.92636436, (float)0.92387950, (float)0.92135507, (float)0.91879123, (float)0.91618794, -(float)0.91354543, (float)0.91086382, (float)0.90814310, (float)0.90538365, (float)0.90258527, -(float)0.89974827, (float)0.89687276, (float)0.89395875, (float)0.89100647, (float)0.88801610, -(float)0.88498759, (float)0.88192123, (float)0.87881714, (float)0.87567532, (float)0.87249595, -(float)0.86927933, (float)0.86602539, (float)0.86273432, (float)0.85940641, (float)0.85604161, -(float)0.85264009, (float)0.84920216, (float)0.84572780, (float)0.84221715, (float)0.83867055, -(float)0.83508795, (float)0.83146954, (float)0.82781565, (float)0.82412612, (float)0.82040137, -(float)0.81664157, (float)0.81284660, (float)0.80901700, (float)0.80515265, (float)0.80125374, -(float)0.79732066, (float)0.79335332, (float)0.78935200, (float)0.78531694, (float)0.78124815, -(float)0.77714586, (float)0.77301049, (float)0.76884180, (float)0.76464021, (float)0.76040596, -(float)0.75613904, (float)0.75183970, (float)0.74750835, (float)0.74314481, (float)0.73874938, -(float)0.73432249, (float)0.72986400, (float)0.72537428, (float)0.72085363, (float)0.71630186, -(float)0.71171951, (float)0.70710677, (float)0.70246363, (float)0.69779032, (float)0.69308734, -(float)0.68835449, (float)0.68359220, (float)0.67880070, (float)0.67398006, (float)0.66913044, -(float)0.66425240, (float)0.65934575, (float)0.65441096, (float)0.64944804, (float)0.64445722, -(float)0.63943905, (float)0.63439327, (float)0.62932026, (float)0.62422055, (float)0.61909389, -(float)0.61394072, (float)0.60876143, (float)0.60355592, (float)0.59832448, (float)0.59306765, -(float)0.58778518, (float)0.58247757, (float)0.57714522, (float)0.57178789, (float)0.56640613, -(float)0.56100023, (float)0.55557019, (float)0.55011630, (float)0.54463905, (float)0.53913826, -(float)0.53361434, (float)0.52806783, (float)0.52249849, (float)0.51690674, (float)0.51129305, -(float)0.50565726, (float)0.50000006, (float)0.49432117, (float)0.48862115, (float)0.48290038, -(float)0.47715873, (float)0.47139663, (float)0.46561456, (float)0.45981231, (float)0.45399037, -(float)0.44814920, (float)0.44228864, (float)0.43640912, (float)0.43051112, (float)0.42459446, -(float)0.41865960, (float)0.41270703, (float)0.40673658, (float)0.40074870, (float)0.39474386, -(float)0.38872188, (float)0.38268328, (float)0.37662849, (float)0.37055734, (float)0.36447033, -(float)0.35836792, (float)0.35224995, (float)0.34611690, (float)0.33996922, (float)0.33380675, -(float)0.32763001, (float)0.32143945, (float)0.31523487, (float)0.30901679, (float)0.30278572, -(float)0.29654145, (float)0.29028472, (float)0.28401530, (float)0.27773371, (float)0.27144048, -(float)0.26513538, (float)0.25881892, (float)0.25249159, (float)0.24615324, (float)0.23980433, -(float)0.23344538, (float)0.22707619, (float)0.22069728, (float)0.21430916, (float)0.20791161, -(float)0.20150517, (float)0.19509031, (float)0.18866688, (float)0.18223536, (float)0.17579627, -(float)0.16934940, (float)0.16289529, (float)0.15643445, (float)0.14996666, (float)0.14349243, -(float)0.13701232, (float)0.13052608, (float)0.12403426, (float)0.11753736, (float)0.11103519, -(float)0.10452849, (float)0.09801710, (float)0.09150149, (float)0.08498220, (float)0.07845904, -(float)0.07193252, (float)0.06540315, (float)0.05887074, (float)0.05233581, (float)0.04579888, -(float)0.03925974, (float)0.03271893, (float)0.02617695, (float)0.01963361, (float)0.01308943, -(float)0.00654493, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000 + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00654494, (float)0.01308960, (float)0.01963369, + (float)0.02617695, (float)0.03271908, (float)0.03925982, (float)0.04579887, (float)0.05233596, + (float)0.05887080, (float)0.06540313, (float)0.07193266, (float)0.07845910, (float)0.08498218, + (float)0.09150162, (float)0.09801714, (float)0.10452846, (float)0.11103531, (float)0.11753740, + (float)0.12403446, (float)0.13052620, (float)0.13701233, (float)0.14349262, (float)0.14996676, + (float)0.15643448, (float)0.16289547, (float)0.16934951, (float)0.17579629, (float)0.18223552, + (float)0.18866697, (float)0.19509032, (float)0.20150533, (float)0.20791170, (float)0.21430916, + (float)0.22069745, (float)0.22707628, (float)0.23344538, (float)0.23980446, (float)0.24615330, + (float)0.25249159, (float)0.25881904, (float)0.26513544, (float)0.27144045, (float)0.27773386, + (float)0.28401536, (float)0.29028466, (float)0.29654160, (float)0.30278578, (float)0.30901700, + (float)0.31523499, (float)0.32143945, (float)0.32763019, (float)0.33380687, (float)0.33996925, + (float)0.34611708, (float)0.35225007, (float)0.35836795, (float)0.36447051, (float)0.37055743, + (float)0.37662852, (float)0.38268346, (float)0.38872197, (float)0.39474389, (float)0.40074885, + (float)0.40673664, (float)0.41270703, (float)0.41865975, (float)0.42459452, (float)0.43051112, + (float)0.43640924, (float)0.44228873, (float)0.44814920, (float)0.45399052, (float)0.45981237, + (float)0.46561453, (float)0.47139674, (float)0.47715878, (float)0.48290035, (float)0.48862126, + (float)0.49432120, (float)0.50000000, (float)0.50565743, (float)0.51129311, (float)0.51690692, + (float)0.52249855, (float)0.52806789, (float)0.53361452, (float)0.53913832, (float)0.54463905, + (float)0.55011642, (float)0.55557024, (float)0.56100029, (float)0.56640625, (float)0.57178795, + (float)0.57714522, (float)0.58247769, (float)0.58778524, (float)0.59306765, (float)0.59832460, + (float)0.60355598, (float)0.60876143, (float)0.61394083, (float)0.61909395, (float)0.62422055, + (float)0.62932038, (float)0.63439333, (float)0.63943899, (float)0.64445734, (float)0.64944810, + (float)0.65441096, (float)0.65934587, (float)0.66425246, (float)0.66913062, (float)0.67398012, + (float)0.67880076, (float)0.68359232, (float)0.68835455, (float)0.69308740, (float)0.69779050, + (float)0.70246369, (float)0.70710677, (float)0.71171963, (float)0.71630198, (float)0.72085363, + (float)0.72537440, (float)0.72986406, (float)0.73432255, (float)0.73874950, (float)0.74314487, + (float)0.74750835, (float)0.75183982, (float)0.75613910, (float)0.76040596, (float)0.76464027, + (float)0.76884186, (float)0.77301043, (float)0.77714598, (float)0.78124821, (float)0.78531694, + (float)0.78935206, (float)0.79335338, (float)0.79732066, (float)0.80125386, (float)0.80515265, + (float)0.80901700, (float)0.81284672, (float)0.81664157, (float)0.82040149, (float)0.82412618, + (float)0.82781565, (float)0.83146966, (float)0.83508795, (float)0.83867061, (float)0.84221727, + (float)0.84572780, (float)0.84920216, (float)0.85264021, (float)0.85604161, (float)0.85940641, + (float)0.86273444, (float)0.86602545, (float)0.86927933, (float)0.87249607, (float)0.87567532, + (float)0.87881714, (float)0.88192129, (float)0.88498765, (float)0.88801610, (float)0.89100653, + (float)0.89395881, (float)0.89687276, (float)0.89974827, (float)0.90258533, (float)0.90538365, + (float)0.90814316, (float)0.91086388, (float)0.91354549, (float)0.91618794, (float)0.91879123, + (float)0.92135513, (float)0.92387950, (float)0.92636442, (float)0.92880958, (float)0.93121493, + (float)0.93358046, (float)0.93590593, (float)0.93819135, (float)0.94043654, (float)0.94264150, + (float)0.94480604, (float)0.94693011, (float)0.94901365, (float)0.95105654, (float)0.95305866, + (float)0.95501995, (float)0.95694035, (float)0.95881975, (float)0.96065807, (float)0.96245527, + (float)0.96421117, (float)0.96592581, (float)0.96759909, (float)0.96923089, (float)0.97082120, + (float)0.97236991, (float)0.97387701, (float)0.97534233, (float)0.97676587, (float)0.97814763, + (float)0.97948742, (float)0.98078531, (float)0.98204112, (float)0.98325491, (float)0.98442656, + (float)0.98555607, (float)0.98664331, (float)0.98768836, (float)0.98869103, (float)0.98965138, + (float)0.99056935, (float)0.99144489, (float)0.99227792, (float)0.99306846, (float)0.99381649, + (float)0.99452192, (float)0.99518472, (float)0.99580491, (float)0.99638247, (float)0.99691731, + (float)0.99740952, (float)0.99785894, (float)0.99826562, (float)0.99862951, (float)0.99895066, + (float)0.99922901, (float)0.99946457, (float)0.99965733, (float)0.99980724, (float)0.99991435, + (float)0.99997860, (float)1.00000000, (float)0.99997860, (float)0.99991435, (float)0.99980724, + (float)0.99965733, (float)0.99946457, (float)0.99922901, (float)0.99895066, (float)0.99862951, + (float)0.99826562, (float)0.99785894, (float)0.99740946, (float)0.99691731, (float)0.99638247, + (float)0.99580491, (float)0.99518472, (float)0.99452192, (float)0.99381644, (float)0.99306846, + (float)0.99227792, (float)0.99144489, (float)0.99056935, (float)0.98965138, (float)0.98869103, + (float)0.98768836, (float)0.98664331, (float)0.98555607, (float)0.98442656, (float)0.98325491, + (float)0.98204112, (float)0.98078525, (float)0.97948742, (float)0.97814757, (float)0.97676587, + (float)0.97534227, (float)0.97387695, (float)0.97236991, (float)0.97082120, (float)0.96923089, + (float)0.96759909, (float)0.96592581, (float)0.96421117, (float)0.96245521, (float)0.96065807, + (float)0.95881969, (float)0.95694029, (float)0.95501995, (float)0.95305860, (float)0.95105648, + (float)0.94901365, (float)0.94693011, (float)0.94480604, (float)0.94264150, (float)0.94043654, + (float)0.93819129, (float)0.93590593, (float)0.93358046, (float)0.93121493, (float)0.92880952, + (float)0.92636436, (float)0.92387950, (float)0.92135507, (float)0.91879123, (float)0.91618794, + (float)0.91354543, (float)0.91086382, (float)0.90814310, (float)0.90538365, (float)0.90258527, + (float)0.89974827, (float)0.89687276, (float)0.89395875, (float)0.89100647, (float)0.88801610, + (float)0.88498759, (float)0.88192123, (float)0.87881714, (float)0.87567532, (float)0.87249595, + (float)0.86927933, (float)0.86602539, (float)0.86273432, (float)0.85940641, (float)0.85604161, + (float)0.85264009, (float)0.84920216, (float)0.84572780, (float)0.84221715, (float)0.83867055, + (float)0.83508795, (float)0.83146954, (float)0.82781565, (float)0.82412612, (float)0.82040137, + (float)0.81664157, (float)0.81284660, (float)0.80901700, (float)0.80515265, (float)0.80125374, + (float)0.79732066, (float)0.79335332, (float)0.78935200, (float)0.78531694, (float)0.78124815, + (float)0.77714586, (float)0.77301049, (float)0.76884180, (float)0.76464021, (float)0.76040596, + (float)0.75613904, (float)0.75183970, (float)0.74750835, (float)0.74314481, (float)0.73874938, + (float)0.73432249, (float)0.72986400, (float)0.72537428, (float)0.72085363, (float)0.71630186, + (float)0.71171951, (float)0.70710677, (float)0.70246363, (float)0.69779032, (float)0.69308734, + (float)0.68835449, (float)0.68359220, (float)0.67880070, (float)0.67398006, (float)0.66913044, + (float)0.66425240, (float)0.65934575, (float)0.65441096, (float)0.64944804, (float)0.64445722, + (float)0.63943905, (float)0.63439327, (float)0.62932026, (float)0.62422055, (float)0.61909389, + (float)0.61394072, (float)0.60876143, (float)0.60355592, (float)0.59832448, (float)0.59306765, + (float)0.58778518, (float)0.58247757, (float)0.57714522, (float)0.57178789, (float)0.56640613, + (float)0.56100023, (float)0.55557019, (float)0.55011630, (float)0.54463905, (float)0.53913826, + (float)0.53361434, (float)0.52806783, (float)0.52249849, (float)0.51690674, (float)0.51129305, + (float)0.50565726, (float)0.50000006, (float)0.49432117, (float)0.48862115, (float)0.48290038, + (float)0.47715873, (float)0.47139663, (float)0.46561456, (float)0.45981231, (float)0.45399037, + (float)0.44814920, (float)0.44228864, (float)0.43640912, (float)0.43051112, (float)0.42459446, + (float)0.41865960, (float)0.41270703, (float)0.40673658, (float)0.40074870, (float)0.39474386, + (float)0.38872188, (float)0.38268328, (float)0.37662849, (float)0.37055734, (float)0.36447033, + (float)0.35836792, (float)0.35224995, (float)0.34611690, (float)0.33996922, (float)0.33380675, + (float)0.32763001, (float)0.32143945, (float)0.31523487, (float)0.30901679, (float)0.30278572, + (float)0.29654145, (float)0.29028472, (float)0.28401530, (float)0.27773371, (float)0.27144048, + (float)0.26513538, (float)0.25881892, (float)0.25249159, (float)0.24615324, (float)0.23980433, + (float)0.23344538, (float)0.22707619, (float)0.22069728, (float)0.21430916, (float)0.20791161, + (float)0.20150517, (float)0.19509031, (float)0.18866688, (float)0.18223536, (float)0.17579627, + (float)0.16934940, (float)0.16289529, (float)0.15643445, (float)0.14996666, (float)0.14349243, + (float)0.13701232, (float)0.13052608, (float)0.12403426, (float)0.11753736, (float)0.11103519, + (float)0.10452849, (float)0.09801710, (float)0.09150149, (float)0.08498220, (float)0.07845904, + (float)0.07193252, (float)0.06540315, (float)0.05887074, (float)0.05233581, (float)0.04579888, + (float)0.03925974, (float)0.03271893, (float)0.02617695, (float)0.01963361, (float)0.01308943, + (float)0.00654493, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000 }; // Hanning window: for 30ms with 1024 fft with symmetric zeros at 16kHz static const float kBlocks480w1024[1024] = { -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00327249, (float)0.00654494, -(float)0.00981732, (float)0.01308960, (float)0.01636173, (float)0.01963369, (float)0.02290544, -(float)0.02617695, (float)0.02944817, (float)0.03271908, (float)0.03598964, (float)0.03925982, -(float)0.04252957, (float)0.04579887, (float)0.04906768, (float)0.05233596, (float)0.05560368, -(float)0.05887080, (float)0.06213730, (float)0.06540313, (float)0.06866825, (float)0.07193266, -(float)0.07519628, (float)0.07845910, (float)0.08172107, (float)0.08498218, (float)0.08824237, -(float)0.09150162, (float)0.09475989, (float)0.09801714, (float)0.10127335, (float)0.10452846, -(float)0.10778246, (float)0.11103531, (float)0.11428697, (float)0.11753740, (float)0.12078657, -(float)0.12403446, (float)0.12728101, (float)0.13052620, (float)0.13376999, (float)0.13701233, -(float)0.14025325, (float)0.14349262, (float)0.14673047, (float)0.14996676, (float)0.15320145, -(float)0.15643448, (float)0.15966582, (float)0.16289547, (float)0.16612339, (float)0.16934951, -(float)0.17257382, (float)0.17579629, (float)0.17901687, (float)0.18223552, (float)0.18545224, -(float)0.18866697, (float)0.19187967, (float)0.19509032, (float)0.19829889, (float)0.20150533, -(float)0.20470962, (float)0.20791170, (float)0.21111156, (float)0.21430916, (float)0.21750447, -(float)0.22069745, (float)0.22388805, (float)0.22707628, (float)0.23026206, (float)0.23344538, -(float)0.23662618, (float)0.23980446, (float)0.24298020, (float)0.24615330, (float)0.24932377, -(float)0.25249159, (float)0.25565669, (float)0.25881904, (float)0.26197866, (float)0.26513544, -(float)0.26828939, (float)0.27144045, (float)0.27458861, (float)0.27773386, (float)0.28087610, -(float)0.28401536, (float)0.28715158, (float)0.29028466, (float)0.29341471, (float)0.29654160, -(float)0.29966527, (float)0.30278578, (float)0.30590302, (float)0.30901700, (float)0.31212768, -(float)0.31523499, (float)0.31833893, (float)0.32143945, (float)0.32453656, (float)0.32763019, -(float)0.33072028, (float)0.33380687, (float)0.33688986, (float)0.33996925, (float)0.34304500, -(float)0.34611708, (float)0.34918544, (float)0.35225007, (float)0.35531089, (float)0.35836795, -(float)0.36142117, (float)0.36447051, (float)0.36751595, (float)0.37055743, (float)0.37359497, -(float)0.37662852, (float)0.37965801, (float)0.38268346, (float)0.38570479, (float)0.38872197, -(float)0.39173502, (float)0.39474389, (float)0.39774847, (float)0.40074885, (float)0.40374491, -(float)0.40673664, (float)0.40972406, (float)0.41270703, (float)0.41568562, (float)0.41865975, -(float)0.42162940, (float)0.42459452, (float)0.42755508, (float)0.43051112, (float)0.43346250, -(float)0.43640924, (float)0.43935132, (float)0.44228873, (float)0.44522133, (float)0.44814920, -(float)0.45107228, (float)0.45399052, (float)0.45690390, (float)0.45981237, (float)0.46271592, -(float)0.46561453, (float)0.46850815, (float)0.47139674, (float)0.47428030, (float)0.47715878, -(float)0.48003215, (float)0.48290035, (float)0.48576337, (float)0.48862126, (float)0.49147385, -(float)0.49432120, (float)0.49716330, (float)0.50000000, (float)0.50283140, (float)0.50565743, -(float)0.50847799, (float)0.51129311, (float)0.51410276, (float)0.51690692, (float)0.51970553, -(float)0.52249855, (float)0.52528602, (float)0.52806789, (float)0.53084403, (float)0.53361452, -(float)0.53637928, (float)0.53913832, (float)0.54189163, (float)0.54463905, (float)0.54738063, -(float)0.55011642, (float)0.55284631, (float)0.55557024, (float)0.55828828, (float)0.56100029, -(float)0.56370628, (float)0.56640625, (float)0.56910014, (float)0.57178795, (float)0.57446963, -(float)0.57714522, (float)0.57981455, (float)0.58247769, (float)0.58513463, (float)0.58778524, -(float)0.59042960, (float)0.59306765, (float)0.59569931, (float)0.59832460, (float)0.60094351, -(float)0.60355598, (float)0.60616195, (float)0.60876143, (float)0.61135441, (float)0.61394083, -(float)0.61652070, (float)0.61909395, (float)0.62166059, (float)0.62422055, (float)0.62677383, -(float)0.62932038, (float)0.63186020, (float)0.63439333, (float)0.63691956, (float)0.63943899, -(float)0.64195162, (float)0.64445734, (float)0.64695615, (float)0.64944810, (float)0.65193301, -(float)0.65441096, (float)0.65688187, (float)0.65934587, (float)0.66180271, (float)0.66425246, -(float)0.66669512, (float)0.66913062, (float)0.67155898, (float)0.67398012, (float)0.67639405, -(float)0.67880076, (float)0.68120021, (float)0.68359232, (float)0.68597710, (float)0.68835455, -(float)0.69072467, (float)0.69308740, (float)0.69544262, (float)0.69779050, (float)0.70013082, -(float)0.70246369, (float)0.70478904, (float)0.70710677, (float)0.70941699, (float)0.71171963, -(float)0.71401459, (float)0.71630198, (float)0.71858168, (float)0.72085363, (float)0.72311789, -(float)0.72537440, (float)0.72762316, (float)0.72986406, (float)0.73209721, (float)0.73432255, -(float)0.73653996, (float)0.73874950, (float)0.74095118, (float)0.74314487, (float)0.74533057, -(float)0.74750835, (float)0.74967808, (float)0.75183982, (float)0.75399351, (float)0.75613910, -(float)0.75827658, (float)0.76040596, (float)0.76252723, (float)0.76464027, (float)0.76674515, -(float)0.76884186, (float)0.77093029, (float)0.77301043, (float)0.77508241, (float)0.77714598, -(float)0.77920127, (float)0.78124821, (float)0.78328675, (float)0.78531694, (float)0.78733873, -(float)0.78935206, (float)0.79135692, (float)0.79335338, (float)0.79534125, (float)0.79732066, -(float)0.79929149, (float)0.80125386, (float)0.80320752, (float)0.80515265, (float)0.80708915, -(float)0.80901700, (float)0.81093621, (float)0.81284672, (float)0.81474853, (float)0.81664157, -(float)0.81852591, (float)0.82040149, (float)0.82226825, (float)0.82412618, (float)0.82597536, -(float)0.82781565, (float)0.82964706, (float)0.83146966, (float)0.83328325, (float)0.83508795, -(float)0.83688378, (float)0.83867061, (float)0.84044838, (float)0.84221727, (float)0.84397703, -(float)0.84572780, (float)0.84746957, (float)0.84920216, (float)0.85092574, (float)0.85264021, -(float)0.85434544, (float)0.85604161, (float)0.85772866, (float)0.85940641, (float)0.86107504, -(float)0.86273444, (float)0.86438453, (float)0.86602545, (float)0.86765707, (float)0.86927933, -(float)0.87089235, (float)0.87249607, (float)0.87409031, (float)0.87567532, (float)0.87725097, -(float)0.87881714, (float)0.88037390, (float)0.88192129, (float)0.88345921, (float)0.88498765, -(float)0.88650668, (float)0.88801610, (float)0.88951612, (float)0.89100653, (float)0.89248741, -(float)0.89395881, (float)0.89542055, (float)0.89687276, (float)0.89831537, (float)0.89974827, -(float)0.90117162, (float)0.90258533, (float)0.90398932, (float)0.90538365, (float)0.90676826, -(float)0.90814316, (float)0.90950841, (float)0.91086388, (float)0.91220951, (float)0.91354549, -(float)0.91487163, (float)0.91618794, (float)0.91749454, (float)0.91879123, (float)0.92007810, -(float)0.92135513, (float)0.92262226, (float)0.92387950, (float)0.92512691, (float)0.92636442, -(float)0.92759192, (float)0.92880958, (float)0.93001723, (float)0.93121493, (float)0.93240267, -(float)0.93358046, (float)0.93474817, (float)0.93590593, (float)0.93705362, (float)0.93819135, -(float)0.93931901, (float)0.94043654, (float)0.94154406, (float)0.94264150, (float)0.94372880, -(float)0.94480604, (float)0.94587320, (float)0.94693011, (float)0.94797695, (float)0.94901365, -(float)0.95004016, (float)0.95105654, (float)0.95206273, (float)0.95305866, (float)0.95404440, -(float)0.95501995, (float)0.95598525, (float)0.95694035, (float)0.95788521, (float)0.95881975, -(float)0.95974404, (float)0.96065807, (float)0.96156180, (float)0.96245527, (float)0.96333838, -(float)0.96421117, (float)0.96507370, (float)0.96592581, (float)0.96676767, (float)0.96759909, -(float)0.96842021, (float)0.96923089, (float)0.97003126, (float)0.97082120, (float)0.97160077, -(float)0.97236991, (float)0.97312868, (float)0.97387701, (float)0.97461486, (float)0.97534233, -(float)0.97605932, (float)0.97676587, (float)0.97746199, (float)0.97814763, (float)0.97882277, -(float)0.97948742, (float)0.98014158, (float)0.98078531, (float)0.98141843, (float)0.98204112, -(float)0.98265332, (float)0.98325491, (float)0.98384601, (float)0.98442656, (float)0.98499662, -(float)0.98555607, (float)0.98610497, (float)0.98664331, (float)0.98717111, (float)0.98768836, -(float)0.98819500, (float)0.98869103, (float)0.98917651, (float)0.98965138, (float)0.99011570, -(float)0.99056935, (float)0.99101239, (float)0.99144489, (float)0.99186671, (float)0.99227792, -(float)0.99267852, (float)0.99306846, (float)0.99344778, (float)0.99381649, (float)0.99417448, -(float)0.99452192, (float)0.99485862, (float)0.99518472, (float)0.99550015, (float)0.99580491, -(float)0.99609905, (float)0.99638247, (float)0.99665523, (float)0.99691731, (float)0.99716878, -(float)0.99740952, (float)0.99763954, (float)0.99785894, (float)0.99806762, (float)0.99826562, -(float)0.99845290, (float)0.99862951, (float)0.99879545, (float)0.99895066, (float)0.99909520, -(float)0.99922901, (float)0.99935216, (float)0.99946457, (float)0.99956632, (float)0.99965733, -(float)0.99973762, (float)0.99980724, (float)0.99986613, (float)0.99991435, (float)0.99995178, -(float)0.99997860, (float)0.99999464, (float)1.00000000, (float)0.99999464, (float)0.99997860, -(float)0.99995178, (float)0.99991435, (float)0.99986613, (float)0.99980724, (float)0.99973762, -(float)0.99965733, (float)0.99956632, (float)0.99946457, (float)0.99935216, (float)0.99922901, -(float)0.99909520, (float)0.99895066, (float)0.99879545, (float)0.99862951, (float)0.99845290, -(float)0.99826562, (float)0.99806762, (float)0.99785894, (float)0.99763954, (float)0.99740946, -(float)0.99716872, (float)0.99691731, (float)0.99665523, (float)0.99638247, (float)0.99609905, -(float)0.99580491, (float)0.99550015, (float)0.99518472, (float)0.99485862, (float)0.99452192, -(float)0.99417448, (float)0.99381644, (float)0.99344778, (float)0.99306846, (float)0.99267852, -(float)0.99227792, (float)0.99186671, (float)0.99144489, (float)0.99101239, (float)0.99056935, -(float)0.99011564, (float)0.98965138, (float)0.98917651, (float)0.98869103, (float)0.98819494, -(float)0.98768836, (float)0.98717111, (float)0.98664331, (float)0.98610497, (float)0.98555607, -(float)0.98499656, (float)0.98442656, (float)0.98384601, (float)0.98325491, (float)0.98265326, -(float)0.98204112, (float)0.98141843, (float)0.98078525, (float)0.98014158, (float)0.97948742, -(float)0.97882277, (float)0.97814757, (float)0.97746193, (float)0.97676587, (float)0.97605932, -(float)0.97534227, (float)0.97461486, (float)0.97387695, (float)0.97312862, (float)0.97236991, -(float)0.97160077, (float)0.97082120, (float)0.97003126, (float)0.96923089, (float)0.96842015, -(float)0.96759909, (float)0.96676761, (float)0.96592581, (float)0.96507365, (float)0.96421117, -(float)0.96333838, (float)0.96245521, (float)0.96156180, (float)0.96065807, (float)0.95974404, -(float)0.95881969, (float)0.95788515, (float)0.95694029, (float)0.95598525, (float)0.95501995, -(float)0.95404440, (float)0.95305860, (float)0.95206267, (float)0.95105648, (float)0.95004016, -(float)0.94901365, (float)0.94797695, (float)0.94693011, (float)0.94587314, (float)0.94480604, -(float)0.94372880, (float)0.94264150, (float)0.94154406, (float)0.94043654, (float)0.93931895, -(float)0.93819129, (float)0.93705362, (float)0.93590593, (float)0.93474817, (float)0.93358046, -(float)0.93240267, (float)0.93121493, (float)0.93001723, (float)0.92880952, (float)0.92759192, -(float)0.92636436, (float)0.92512691, (float)0.92387950, (float)0.92262226, (float)0.92135507, -(float)0.92007804, (float)0.91879123, (float)0.91749448, (float)0.91618794, (float)0.91487157, -(float)0.91354543, (float)0.91220951, (float)0.91086382, (float)0.90950835, (float)0.90814310, -(float)0.90676820, (float)0.90538365, (float)0.90398932, (float)0.90258527, (float)0.90117157, -(float)0.89974827, (float)0.89831525, (float)0.89687276, (float)0.89542055, (float)0.89395875, -(float)0.89248741, (float)0.89100647, (float)0.88951600, (float)0.88801610, (float)0.88650662, -(float)0.88498759, (float)0.88345915, (float)0.88192123, (float)0.88037384, (float)0.87881714, -(float)0.87725091, (float)0.87567532, (float)0.87409031, (float)0.87249595, (float)0.87089223, -(float)0.86927933, (float)0.86765701, (float)0.86602539, (float)0.86438447, (float)0.86273432, -(float)0.86107504, (float)0.85940641, (float)0.85772860, (float)0.85604161, (float)0.85434544, -(float)0.85264009, (float)0.85092574, (float)0.84920216, (float)0.84746951, (float)0.84572780, -(float)0.84397697, (float)0.84221715, (float)0.84044844, (float)0.83867055, (float)0.83688372, -(float)0.83508795, (float)0.83328319, (float)0.83146954, (float)0.82964706, (float)0.82781565, -(float)0.82597530, (float)0.82412612, (float)0.82226813, (float)0.82040137, (float)0.81852591, -(float)0.81664157, (float)0.81474847, (float)0.81284660, (float)0.81093609, (float)0.80901700, -(float)0.80708915, (float)0.80515265, (float)0.80320752, (float)0.80125374, (float)0.79929143, -(float)0.79732066, (float)0.79534125, (float)0.79335332, (float)0.79135686, (float)0.78935200, -(float)0.78733861, (float)0.78531694, (float)0.78328675, (float)0.78124815, (float)0.77920121, -(float)0.77714586, (float)0.77508223, (float)0.77301049, (float)0.77093029, (float)0.76884180, -(float)0.76674509, (float)0.76464021, (float)0.76252711, (float)0.76040596, (float)0.75827658, -(float)0.75613904, (float)0.75399339, (float)0.75183970, (float)0.74967796, (float)0.74750835, -(float)0.74533057, (float)0.74314481, (float)0.74095106, (float)0.73874938, (float)0.73653996, -(float)0.73432249, (float)0.73209721, (float)0.72986400, (float)0.72762305, (float)0.72537428, -(float)0.72311789, (float)0.72085363, (float)0.71858162, (float)0.71630186, (float)0.71401453, -(float)0.71171951, (float)0.70941705, (float)0.70710677, (float)0.70478898, (float)0.70246363, -(float)0.70013070, (float)0.69779032, (float)0.69544268, (float)0.69308734, (float)0.69072461, -(float)0.68835449, (float)0.68597704, (float)0.68359220, (float)0.68120021, (float)0.67880070, -(float)0.67639399, (float)0.67398006, (float)0.67155886, (float)0.66913044, (float)0.66669512, -(float)0.66425240, (float)0.66180259, (float)0.65934575, (float)0.65688181, (float)0.65441096, -(float)0.65193301, (float)0.64944804, (float)0.64695609, (float)0.64445722, (float)0.64195150, -(float)0.63943905, (float)0.63691956, (float)0.63439327, (float)0.63186014, (float)0.62932026, -(float)0.62677372, (float)0.62422055, (float)0.62166059, (float)0.61909389, (float)0.61652064, -(float)0.61394072, (float)0.61135429, (float)0.60876143, (float)0.60616189, (float)0.60355592, -(float)0.60094339, (float)0.59832448, (float)0.59569913, (float)0.59306765, (float)0.59042960, -(float)0.58778518, (float)0.58513451, (float)0.58247757, (float)0.57981461, (float)0.57714522, -(float)0.57446963, (float)0.57178789, (float)0.56910002, (float)0.56640613, (float)0.56370628, -(float)0.56100023, (float)0.55828822, (float)0.55557019, (float)0.55284619, (float)0.55011630, -(float)0.54738069, (float)0.54463905, (float)0.54189152, (float)0.53913826, (float)0.53637916, -(float)0.53361434, (float)0.53084403, (float)0.52806783, (float)0.52528596, (float)0.52249849, -(float)0.51970541, (float)0.51690674, (float)0.51410276, (float)0.51129305, (float)0.50847787, -(float)0.50565726, (float)0.50283122, (float)0.50000006, (float)0.49716327, (float)0.49432117, -(float)0.49147379, (float)0.48862115, (float)0.48576325, (float)0.48290038, (float)0.48003212, -(float)0.47715873, (float)0.47428021, (float)0.47139663, (float)0.46850798, (float)0.46561456, -(float)0.46271589, (float)0.45981231, (float)0.45690379, (float)0.45399037, (float)0.45107210, -(float)0.44814920, (float)0.44522130, (float)0.44228864, (float)0.43935123, (float)0.43640912, -(float)0.43346232, (float)0.43051112, (float)0.42755505, (float)0.42459446, (float)0.42162928, -(float)0.41865960, (float)0.41568545, (float)0.41270703, (float)0.40972400, (float)0.40673658, -(float)0.40374479, (float)0.40074870, (float)0.39774850, (float)0.39474386, (float)0.39173496, -(float)0.38872188, (float)0.38570464, (float)0.38268328, (float)0.37965804, (float)0.37662849, -(float)0.37359491, (float)0.37055734, (float)0.36751580, (float)0.36447033, (float)0.36142117, -(float)0.35836792, (float)0.35531086, (float)0.35224995, (float)0.34918529, (float)0.34611690, -(float)0.34304500, (float)0.33996922, (float)0.33688980, (float)0.33380675, (float)0.33072016, -(float)0.32763001, (float)0.32453656, (float)0.32143945, (float)0.31833887, (float)0.31523487, -(float)0.31212750, (float)0.30901679, (float)0.30590302, (float)0.30278572, (float)0.29966521, -(float)0.29654145, (float)0.29341453, (float)0.29028472, (float)0.28715155, (float)0.28401530, -(float)0.28087601, (float)0.27773371, (float)0.27458847, (float)0.27144048, (float)0.26828936, -(float)0.26513538, (float)0.26197854, (float)0.25881892, (float)0.25565651, (float)0.25249159, -(float)0.24932374, (float)0.24615324, (float)0.24298008, (float)0.23980433, (float)0.23662600, -(float)0.23344538, (float)0.23026201, (float)0.22707619, (float)0.22388794, (float)0.22069728, -(float)0.21750426, (float)0.21430916, (float)0.21111152, (float)0.20791161, (float)0.20470949, -(float)0.20150517, (float)0.19829892, (float)0.19509031, (float)0.19187963, (float)0.18866688, -(float)0.18545210, (float)0.18223536, (float)0.17901689, (float)0.17579627, (float)0.17257376, -(float)0.16934940, (float)0.16612324, (float)0.16289529, (float)0.15966584, (float)0.15643445, -(float)0.15320137, (float)0.14996666, (float)0.14673033, (float)0.14349243, (float)0.14025325, -(float)0.13701232, (float)0.13376991, (float)0.13052608, (float)0.12728085, (float)0.12403426, -(float)0.12078657, (float)0.11753736, (float)0.11428688, (float)0.11103519, (float)0.10778230, -(float)0.10452849, (float)0.10127334, (float)0.09801710, (float)0.09475980, (float)0.09150149, -(float)0.08824220, (float)0.08498220, (float)0.08172106, (float)0.07845904, (float)0.07519618, -(float)0.07193252, (float)0.06866808, (float)0.06540315, (float)0.06213728, (float)0.05887074, -(float)0.05560357, (float)0.05233581, (float)0.04906749, (float)0.04579888, (float)0.04252954, -(float)0.03925974, (float)0.03598953, (float)0.03271893, (float)0.02944798, (float)0.02617695, -(float)0.02290541, (float)0.01963361, (float)0.01636161, (float)0.01308943, (float)0.00981712, -(float)0.00654493, (float)0.00327244, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, -(float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000}; + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00327249, (float)0.00654494, + (float)0.00981732, (float)0.01308960, (float)0.01636173, (float)0.01963369, (float)0.02290544, + (float)0.02617695, (float)0.02944817, (float)0.03271908, (float)0.03598964, (float)0.03925982, + (float)0.04252957, (float)0.04579887, (float)0.04906768, (float)0.05233596, (float)0.05560368, + (float)0.05887080, (float)0.06213730, (float)0.06540313, (float)0.06866825, (float)0.07193266, + (float)0.07519628, (float)0.07845910, (float)0.08172107, (float)0.08498218, (float)0.08824237, + (float)0.09150162, (float)0.09475989, (float)0.09801714, (float)0.10127335, (float)0.10452846, + (float)0.10778246, (float)0.11103531, (float)0.11428697, (float)0.11753740, (float)0.12078657, + (float)0.12403446, (float)0.12728101, (float)0.13052620, (float)0.13376999, (float)0.13701233, + (float)0.14025325, (float)0.14349262, (float)0.14673047, (float)0.14996676, (float)0.15320145, + (float)0.15643448, (float)0.15966582, (float)0.16289547, (float)0.16612339, (float)0.16934951, + (float)0.17257382, (float)0.17579629, (float)0.17901687, (float)0.18223552, (float)0.18545224, + (float)0.18866697, (float)0.19187967, (float)0.19509032, (float)0.19829889, (float)0.20150533, + (float)0.20470962, (float)0.20791170, (float)0.21111156, (float)0.21430916, (float)0.21750447, + (float)0.22069745, (float)0.22388805, (float)0.22707628, (float)0.23026206, (float)0.23344538, + (float)0.23662618, (float)0.23980446, (float)0.24298020, (float)0.24615330, (float)0.24932377, + (float)0.25249159, (float)0.25565669, (float)0.25881904, (float)0.26197866, (float)0.26513544, + (float)0.26828939, (float)0.27144045, (float)0.27458861, (float)0.27773386, (float)0.28087610, + (float)0.28401536, (float)0.28715158, (float)0.29028466, (float)0.29341471, (float)0.29654160, + (float)0.29966527, (float)0.30278578, (float)0.30590302, (float)0.30901700, (float)0.31212768, + (float)0.31523499, (float)0.31833893, (float)0.32143945, (float)0.32453656, (float)0.32763019, + (float)0.33072028, (float)0.33380687, (float)0.33688986, (float)0.33996925, (float)0.34304500, + (float)0.34611708, (float)0.34918544, (float)0.35225007, (float)0.35531089, (float)0.35836795, + (float)0.36142117, (float)0.36447051, (float)0.36751595, (float)0.37055743, (float)0.37359497, + (float)0.37662852, (float)0.37965801, (float)0.38268346, (float)0.38570479, (float)0.38872197, + (float)0.39173502, (float)0.39474389, (float)0.39774847, (float)0.40074885, (float)0.40374491, + (float)0.40673664, (float)0.40972406, (float)0.41270703, (float)0.41568562, (float)0.41865975, + (float)0.42162940, (float)0.42459452, (float)0.42755508, (float)0.43051112, (float)0.43346250, + (float)0.43640924, (float)0.43935132, (float)0.44228873, (float)0.44522133, (float)0.44814920, + (float)0.45107228, (float)0.45399052, (float)0.45690390, (float)0.45981237, (float)0.46271592, + (float)0.46561453, (float)0.46850815, (float)0.47139674, (float)0.47428030, (float)0.47715878, + (float)0.48003215, (float)0.48290035, (float)0.48576337, (float)0.48862126, (float)0.49147385, + (float)0.49432120, (float)0.49716330, (float)0.50000000, (float)0.50283140, (float)0.50565743, + (float)0.50847799, (float)0.51129311, (float)0.51410276, (float)0.51690692, (float)0.51970553, + (float)0.52249855, (float)0.52528602, (float)0.52806789, (float)0.53084403, (float)0.53361452, + (float)0.53637928, (float)0.53913832, (float)0.54189163, (float)0.54463905, (float)0.54738063, + (float)0.55011642, (float)0.55284631, (float)0.55557024, (float)0.55828828, (float)0.56100029, + (float)0.56370628, (float)0.56640625, (float)0.56910014, (float)0.57178795, (float)0.57446963, + (float)0.57714522, (float)0.57981455, (float)0.58247769, (float)0.58513463, (float)0.58778524, + (float)0.59042960, (float)0.59306765, (float)0.59569931, (float)0.59832460, (float)0.60094351, + (float)0.60355598, (float)0.60616195, (float)0.60876143, (float)0.61135441, (float)0.61394083, + (float)0.61652070, (float)0.61909395, (float)0.62166059, (float)0.62422055, (float)0.62677383, + (float)0.62932038, (float)0.63186020, (float)0.63439333, (float)0.63691956, (float)0.63943899, + (float)0.64195162, (float)0.64445734, (float)0.64695615, (float)0.64944810, (float)0.65193301, + (float)0.65441096, (float)0.65688187, (float)0.65934587, (float)0.66180271, (float)0.66425246, + (float)0.66669512, (float)0.66913062, (float)0.67155898, (float)0.67398012, (float)0.67639405, + (float)0.67880076, (float)0.68120021, (float)0.68359232, (float)0.68597710, (float)0.68835455, + (float)0.69072467, (float)0.69308740, (float)0.69544262, (float)0.69779050, (float)0.70013082, + (float)0.70246369, (float)0.70478904, (float)0.70710677, (float)0.70941699, (float)0.71171963, + (float)0.71401459, (float)0.71630198, (float)0.71858168, (float)0.72085363, (float)0.72311789, + (float)0.72537440, (float)0.72762316, (float)0.72986406, (float)0.73209721, (float)0.73432255, + (float)0.73653996, (float)0.73874950, (float)0.74095118, (float)0.74314487, (float)0.74533057, + (float)0.74750835, (float)0.74967808, (float)0.75183982, (float)0.75399351, (float)0.75613910, + (float)0.75827658, (float)0.76040596, (float)0.76252723, (float)0.76464027, (float)0.76674515, + (float)0.76884186, (float)0.77093029, (float)0.77301043, (float)0.77508241, (float)0.77714598, + (float)0.77920127, (float)0.78124821, (float)0.78328675, (float)0.78531694, (float)0.78733873, + (float)0.78935206, (float)0.79135692, (float)0.79335338, (float)0.79534125, (float)0.79732066, + (float)0.79929149, (float)0.80125386, (float)0.80320752, (float)0.80515265, (float)0.80708915, + (float)0.80901700, (float)0.81093621, (float)0.81284672, (float)0.81474853, (float)0.81664157, + (float)0.81852591, (float)0.82040149, (float)0.82226825, (float)0.82412618, (float)0.82597536, + (float)0.82781565, (float)0.82964706, (float)0.83146966, (float)0.83328325, (float)0.83508795, + (float)0.83688378, (float)0.83867061, (float)0.84044838, (float)0.84221727, (float)0.84397703, + (float)0.84572780, (float)0.84746957, (float)0.84920216, (float)0.85092574, (float)0.85264021, + (float)0.85434544, (float)0.85604161, (float)0.85772866, (float)0.85940641, (float)0.86107504, + (float)0.86273444, (float)0.86438453, (float)0.86602545, (float)0.86765707, (float)0.86927933, + (float)0.87089235, (float)0.87249607, (float)0.87409031, (float)0.87567532, (float)0.87725097, + (float)0.87881714, (float)0.88037390, (float)0.88192129, (float)0.88345921, (float)0.88498765, + (float)0.88650668, (float)0.88801610, (float)0.88951612, (float)0.89100653, (float)0.89248741, + (float)0.89395881, (float)0.89542055, (float)0.89687276, (float)0.89831537, (float)0.89974827, + (float)0.90117162, (float)0.90258533, (float)0.90398932, (float)0.90538365, (float)0.90676826, + (float)0.90814316, (float)0.90950841, (float)0.91086388, (float)0.91220951, (float)0.91354549, + (float)0.91487163, (float)0.91618794, (float)0.91749454, (float)0.91879123, (float)0.92007810, + (float)0.92135513, (float)0.92262226, (float)0.92387950, (float)0.92512691, (float)0.92636442, + (float)0.92759192, (float)0.92880958, (float)0.93001723, (float)0.93121493, (float)0.93240267, + (float)0.93358046, (float)0.93474817, (float)0.93590593, (float)0.93705362, (float)0.93819135, + (float)0.93931901, (float)0.94043654, (float)0.94154406, (float)0.94264150, (float)0.94372880, + (float)0.94480604, (float)0.94587320, (float)0.94693011, (float)0.94797695, (float)0.94901365, + (float)0.95004016, (float)0.95105654, (float)0.95206273, (float)0.95305866, (float)0.95404440, + (float)0.95501995, (float)0.95598525, (float)0.95694035, (float)0.95788521, (float)0.95881975, + (float)0.95974404, (float)0.96065807, (float)0.96156180, (float)0.96245527, (float)0.96333838, + (float)0.96421117, (float)0.96507370, (float)0.96592581, (float)0.96676767, (float)0.96759909, + (float)0.96842021, (float)0.96923089, (float)0.97003126, (float)0.97082120, (float)0.97160077, + (float)0.97236991, (float)0.97312868, (float)0.97387701, (float)0.97461486, (float)0.97534233, + (float)0.97605932, (float)0.97676587, (float)0.97746199, (float)0.97814763, (float)0.97882277, + (float)0.97948742, (float)0.98014158, (float)0.98078531, (float)0.98141843, (float)0.98204112, + (float)0.98265332, (float)0.98325491, (float)0.98384601, (float)0.98442656, (float)0.98499662, + (float)0.98555607, (float)0.98610497, (float)0.98664331, (float)0.98717111, (float)0.98768836, + (float)0.98819500, (float)0.98869103, (float)0.98917651, (float)0.98965138, (float)0.99011570, + (float)0.99056935, (float)0.99101239, (float)0.99144489, (float)0.99186671, (float)0.99227792, + (float)0.99267852, (float)0.99306846, (float)0.99344778, (float)0.99381649, (float)0.99417448, + (float)0.99452192, (float)0.99485862, (float)0.99518472, (float)0.99550015, (float)0.99580491, + (float)0.99609905, (float)0.99638247, (float)0.99665523, (float)0.99691731, (float)0.99716878, + (float)0.99740952, (float)0.99763954, (float)0.99785894, (float)0.99806762, (float)0.99826562, + (float)0.99845290, (float)0.99862951, (float)0.99879545, (float)0.99895066, (float)0.99909520, + (float)0.99922901, (float)0.99935216, (float)0.99946457, (float)0.99956632, (float)0.99965733, + (float)0.99973762, (float)0.99980724, (float)0.99986613, (float)0.99991435, (float)0.99995178, + (float)0.99997860, (float)0.99999464, (float)1.00000000, (float)0.99999464, (float)0.99997860, + (float)0.99995178, (float)0.99991435, (float)0.99986613, (float)0.99980724, (float)0.99973762, + (float)0.99965733, (float)0.99956632, (float)0.99946457, (float)0.99935216, (float)0.99922901, + (float)0.99909520, (float)0.99895066, (float)0.99879545, (float)0.99862951, (float)0.99845290, + (float)0.99826562, (float)0.99806762, (float)0.99785894, (float)0.99763954, (float)0.99740946, + (float)0.99716872, (float)0.99691731, (float)0.99665523, (float)0.99638247, (float)0.99609905, + (float)0.99580491, (float)0.99550015, (float)0.99518472, (float)0.99485862, (float)0.99452192, + (float)0.99417448, (float)0.99381644, (float)0.99344778, (float)0.99306846, (float)0.99267852, + (float)0.99227792, (float)0.99186671, (float)0.99144489, (float)0.99101239, (float)0.99056935, + (float)0.99011564, (float)0.98965138, (float)0.98917651, (float)0.98869103, (float)0.98819494, + (float)0.98768836, (float)0.98717111, (float)0.98664331, (float)0.98610497, (float)0.98555607, + (float)0.98499656, (float)0.98442656, (float)0.98384601, (float)0.98325491, (float)0.98265326, + (float)0.98204112, (float)0.98141843, (float)0.98078525, (float)0.98014158, (float)0.97948742, + (float)0.97882277, (float)0.97814757, (float)0.97746193, (float)0.97676587, (float)0.97605932, + (float)0.97534227, (float)0.97461486, (float)0.97387695, (float)0.97312862, (float)0.97236991, + (float)0.97160077, (float)0.97082120, (float)0.97003126, (float)0.96923089, (float)0.96842015, + (float)0.96759909, (float)0.96676761, (float)0.96592581, (float)0.96507365, (float)0.96421117, + (float)0.96333838, (float)0.96245521, (float)0.96156180, (float)0.96065807, (float)0.95974404, + (float)0.95881969, (float)0.95788515, (float)0.95694029, (float)0.95598525, (float)0.95501995, + (float)0.95404440, (float)0.95305860, (float)0.95206267, (float)0.95105648, (float)0.95004016, + (float)0.94901365, (float)0.94797695, (float)0.94693011, (float)0.94587314, (float)0.94480604, + (float)0.94372880, (float)0.94264150, (float)0.94154406, (float)0.94043654, (float)0.93931895, + (float)0.93819129, (float)0.93705362, (float)0.93590593, (float)0.93474817, (float)0.93358046, + (float)0.93240267, (float)0.93121493, (float)0.93001723, (float)0.92880952, (float)0.92759192, + (float)0.92636436, (float)0.92512691, (float)0.92387950, (float)0.92262226, (float)0.92135507, + (float)0.92007804, (float)0.91879123, (float)0.91749448, (float)0.91618794, (float)0.91487157, + (float)0.91354543, (float)0.91220951, (float)0.91086382, (float)0.90950835, (float)0.90814310, + (float)0.90676820, (float)0.90538365, (float)0.90398932, (float)0.90258527, (float)0.90117157, + (float)0.89974827, (float)0.89831525, (float)0.89687276, (float)0.89542055, (float)0.89395875, + (float)0.89248741, (float)0.89100647, (float)0.88951600, (float)0.88801610, (float)0.88650662, + (float)0.88498759, (float)0.88345915, (float)0.88192123, (float)0.88037384, (float)0.87881714, + (float)0.87725091, (float)0.87567532, (float)0.87409031, (float)0.87249595, (float)0.87089223, + (float)0.86927933, (float)0.86765701, (float)0.86602539, (float)0.86438447, (float)0.86273432, + (float)0.86107504, (float)0.85940641, (float)0.85772860, (float)0.85604161, (float)0.85434544, + (float)0.85264009, (float)0.85092574, (float)0.84920216, (float)0.84746951, (float)0.84572780, + (float)0.84397697, (float)0.84221715, (float)0.84044844, (float)0.83867055, (float)0.83688372, + (float)0.83508795, (float)0.83328319, (float)0.83146954, (float)0.82964706, (float)0.82781565, + (float)0.82597530, (float)0.82412612, (float)0.82226813, (float)0.82040137, (float)0.81852591, + (float)0.81664157, (float)0.81474847, (float)0.81284660, (float)0.81093609, (float)0.80901700, + (float)0.80708915, (float)0.80515265, (float)0.80320752, (float)0.80125374, (float)0.79929143, + (float)0.79732066, (float)0.79534125, (float)0.79335332, (float)0.79135686, (float)0.78935200, + (float)0.78733861, (float)0.78531694, (float)0.78328675, (float)0.78124815, (float)0.77920121, + (float)0.77714586, (float)0.77508223, (float)0.77301049, (float)0.77093029, (float)0.76884180, + (float)0.76674509, (float)0.76464021, (float)0.76252711, (float)0.76040596, (float)0.75827658, + (float)0.75613904, (float)0.75399339, (float)0.75183970, (float)0.74967796, (float)0.74750835, + (float)0.74533057, (float)0.74314481, (float)0.74095106, (float)0.73874938, (float)0.73653996, + (float)0.73432249, (float)0.73209721, (float)0.72986400, (float)0.72762305, (float)0.72537428, + (float)0.72311789, (float)0.72085363, (float)0.71858162, (float)0.71630186, (float)0.71401453, + (float)0.71171951, (float)0.70941705, (float)0.70710677, (float)0.70478898, (float)0.70246363, + (float)0.70013070, (float)0.69779032, (float)0.69544268, (float)0.69308734, (float)0.69072461, + (float)0.68835449, (float)0.68597704, (float)0.68359220, (float)0.68120021, (float)0.67880070, + (float)0.67639399, (float)0.67398006, (float)0.67155886, (float)0.66913044, (float)0.66669512, + (float)0.66425240, (float)0.66180259, (float)0.65934575, (float)0.65688181, (float)0.65441096, + (float)0.65193301, (float)0.64944804, (float)0.64695609, (float)0.64445722, (float)0.64195150, + (float)0.63943905, (float)0.63691956, (float)0.63439327, (float)0.63186014, (float)0.62932026, + (float)0.62677372, (float)0.62422055, (float)0.62166059, (float)0.61909389, (float)0.61652064, + (float)0.61394072, (float)0.61135429, (float)0.60876143, (float)0.60616189, (float)0.60355592, + (float)0.60094339, (float)0.59832448, (float)0.59569913, (float)0.59306765, (float)0.59042960, + (float)0.58778518, (float)0.58513451, (float)0.58247757, (float)0.57981461, (float)0.57714522, + (float)0.57446963, (float)0.57178789, (float)0.56910002, (float)0.56640613, (float)0.56370628, + (float)0.56100023, (float)0.55828822, (float)0.55557019, (float)0.55284619, (float)0.55011630, + (float)0.54738069, (float)0.54463905, (float)0.54189152, (float)0.53913826, (float)0.53637916, + (float)0.53361434, (float)0.53084403, (float)0.52806783, (float)0.52528596, (float)0.52249849, + (float)0.51970541, (float)0.51690674, (float)0.51410276, (float)0.51129305, (float)0.50847787, + (float)0.50565726, (float)0.50283122, (float)0.50000006, (float)0.49716327, (float)0.49432117, + (float)0.49147379, (float)0.48862115, (float)0.48576325, (float)0.48290038, (float)0.48003212, + (float)0.47715873, (float)0.47428021, (float)0.47139663, (float)0.46850798, (float)0.46561456, + (float)0.46271589, (float)0.45981231, (float)0.45690379, (float)0.45399037, (float)0.45107210, + (float)0.44814920, (float)0.44522130, (float)0.44228864, (float)0.43935123, (float)0.43640912, + (float)0.43346232, (float)0.43051112, (float)0.42755505, (float)0.42459446, (float)0.42162928, + (float)0.41865960, (float)0.41568545, (float)0.41270703, (float)0.40972400, (float)0.40673658, + (float)0.40374479, (float)0.40074870, (float)0.39774850, (float)0.39474386, (float)0.39173496, + (float)0.38872188, (float)0.38570464, (float)0.38268328, (float)0.37965804, (float)0.37662849, + (float)0.37359491, (float)0.37055734, (float)0.36751580, (float)0.36447033, (float)0.36142117, + (float)0.35836792, (float)0.35531086, (float)0.35224995, (float)0.34918529, (float)0.34611690, + (float)0.34304500, (float)0.33996922, (float)0.33688980, (float)0.33380675, (float)0.33072016, + (float)0.32763001, (float)0.32453656, (float)0.32143945, (float)0.31833887, (float)0.31523487, + (float)0.31212750, (float)0.30901679, (float)0.30590302, (float)0.30278572, (float)0.29966521, + (float)0.29654145, (float)0.29341453, (float)0.29028472, (float)0.28715155, (float)0.28401530, + (float)0.28087601, (float)0.27773371, (float)0.27458847, (float)0.27144048, (float)0.26828936, + (float)0.26513538, (float)0.26197854, (float)0.25881892, (float)0.25565651, (float)0.25249159, + (float)0.24932374, (float)0.24615324, (float)0.24298008, (float)0.23980433, (float)0.23662600, + (float)0.23344538, (float)0.23026201, (float)0.22707619, (float)0.22388794, (float)0.22069728, + (float)0.21750426, (float)0.21430916, (float)0.21111152, (float)0.20791161, (float)0.20470949, + (float)0.20150517, (float)0.19829892, (float)0.19509031, (float)0.19187963, (float)0.18866688, + (float)0.18545210, (float)0.18223536, (float)0.17901689, (float)0.17579627, (float)0.17257376, + (float)0.16934940, (float)0.16612324, (float)0.16289529, (float)0.15966584, (float)0.15643445, + (float)0.15320137, (float)0.14996666, (float)0.14673033, (float)0.14349243, (float)0.14025325, + (float)0.13701232, (float)0.13376991, (float)0.13052608, (float)0.12728085, (float)0.12403426, + (float)0.12078657, (float)0.11753736, (float)0.11428688, (float)0.11103519, (float)0.10778230, + (float)0.10452849, (float)0.10127334, (float)0.09801710, (float)0.09475980, (float)0.09150149, + (float)0.08824220, (float)0.08498220, (float)0.08172106, (float)0.07845904, (float)0.07519618, + (float)0.07193252, (float)0.06866808, (float)0.06540315, (float)0.06213728, (float)0.05887074, + (float)0.05560357, (float)0.05233581, (float)0.04906749, (float)0.04579888, (float)0.04252954, + (float)0.03925974, (float)0.03598953, (float)0.03271893, (float)0.02944798, (float)0.02617695, + (float)0.02290541, (float)0.01963361, (float)0.01636161, (float)0.01308943, (float)0.00981712, + (float)0.00654493, (float)0.00327244, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000 +}; #endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_ diff --git a/src/modules/audio_processing/utility/Makefile.am b/src/modules/audio_processing/utility/Makefile.am index 3d97b5b..b1376be 100644 --- a/src/modules/audio_processing/utility/Makefile.am +++ b/src/modules/audio_processing/utility/Makefile.am @@ -1,7 +1,12 @@ noinst_LTLIBRARIES = libapm_util.la -libapm_util_la_SOURCES = ring_buffer.c \ - ring_buffer.h \ +libapm_util_la_SOURCES = delay_estimator_float.c \ + delay_estimator_float.h \ + delay_estimator.c \ + delay_estimator.h \ fft4g.c \ - fft4g.h -libapm_util_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS) + fft4g.h \ + ring_buffer.c \ + ring_buffer.h +libapm_util_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS) \ + -I$(top_srcdir)/src/common_audio/signal_processing_library/main/interface diff --git a/src/modules/audio_processing/utility/delay_estimator.c b/src/modules/audio_processing/utility/delay_estimator.c new file mode 100644 index 0000000..044d545 --- /dev/null +++ b/src/modules/audio_processing/utility/delay_estimator.c @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "delay_estimator.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "signal_processing_library.h" + +typedef struct { + // Pointers to mean values of spectrum and bit counts + int32_t* mean_far_spectrum; + int32_t* mean_near_spectrum; + int32_t* mean_bit_counts; + + // Arrays only used locally in DelayEstimatorProcess() but whose size + // is determined at run-time. + int32_t* bit_counts; + int32_t* far_spectrum_32; + int32_t* near_spectrum_32; + + // Binary history variables + uint32_t* binary_far_history; + + // Far end history variables + uint16_t* far_history; + int far_history_pos; + int* far_q_domains; + + // Delay histogram variables + int* delay_histogram; + int vad_counter; + + // Delay memory + int last_delay; + + // Used to enable far end alignment. If it is disabled, only delay values are + // produced + int alignment_enabled; + + // Buffer size parameters + int history_size; + int spectrum_size; + +} DelayEstimator_t; + +// Only bit |kBandFirst| through bit |kBandLast| are processed +// |kBandFirst| - |kBandLast| must be < 32 +static const int kBandFirst = 12; +static const int kBandLast = 43; + +static __inline uint32_t SetBit(uint32_t in, int32_t pos) { + uint32_t mask = WEBRTC_SPL_LSHIFT_W32(1, pos); + uint32_t out = (in | mask); + + return out; +} + +// Compares the |binary_vector| with all rows of the |binary_matrix| and counts +// per row the number of times they have the same value. +// +// Inputs: +// - binary_vector : binary "vector" stored in a long +// - binary_matrix : binary "matrix" stored as a vector of long +// - matrix_size : size of binary "matrix" +// +// Output: +// - bit_counts : "Vector" stored as a long, containing for each +// row the number of times the matrix row and the +// input vector have the same value +// +static void BitCountComparison(uint32_t binary_vector, + const uint32_t* binary_matrix, + int matrix_size, + int32_t* bit_counts) { + int n = 0; + uint32_t a = binary_vector; + register uint32_t tmp; + + // compare |binary_vector| with all rows of the |binary_matrix| + for (; n < matrix_size; n++) { + a = (binary_vector ^ binary_matrix[n]); + // Returns bit counts in tmp + tmp = a - ((a >> 1) & 033333333333) - ((a >> 2) & 011111111111); + tmp = ((tmp + (tmp >> 3)) & 030707070707); + tmp = (tmp + (tmp >> 6)); + tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077; + + bit_counts[n] = (int32_t) tmp; + } +} + +// Computes the binary spectrum by comparing the input |spectrum| with a +// |threshold_spectrum|. +// +// Inputs: +// - spectrum : Spectrum of which the binary spectrum should be +// calculated. +// - threshold_spectrum : Threshold spectrum with which the input +// spectrum is compared. +// Return: +// - out : Binary spectrum +// +static uint32_t BinarySpectrum(int32_t* spectrum, int32_t* threshold_spectrum) { + int k = kBandFirst; + uint32_t out = 0; + + for (; k <= kBandLast; k++) { + if (spectrum[k] > threshold_spectrum[k]) { + out = SetBit(out, k - kBandFirst); + } + } + + return out; +} + +// Calculates the mean recursively. +// +// Inputs: +// - new_value : new additional value +// - factor : factor for smoothing +// +// Input/Output: +// - mean_value : pointer to the mean value that should be updated +// +static void MeanEstimator(const int32_t new_value, + int factor, + int32_t* mean_value) { + int32_t mean_new = *mean_value; + int32_t diff = new_value - mean_new; + + // mean_new = mean_value + ((new_value - mean_value) >> factor); + if (diff < 0) { + diff = -WEBRTC_SPL_RSHIFT_W32(-diff, factor); + } else { + diff = WEBRTC_SPL_RSHIFT_W32(diff, factor); + } + mean_new += diff; + + *mean_value = mean_new; +} + +// 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(DelayEstimator_t* self, + uint16_t* far_spectrum, + int far_q) { + // Get new buffer position + self->far_history_pos++; + if (self->far_history_pos >= self->history_size) { + 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 * self->spectrum_size]), + far_spectrum, + sizeof(uint16_t) * self->spectrum_size); +} + +int WebRtc_FreeDelayEstimator(void* handle) { + DelayEstimator_t* self = (DelayEstimator_t*) handle; + + if (self == NULL) { + return -1; + } + + if (self->mean_far_spectrum != NULL) { + free(self->mean_far_spectrum); + self->mean_far_spectrum = NULL; + } + if (self->mean_near_spectrum != NULL) { + free(self->mean_near_spectrum); + self->mean_near_spectrum = NULL; + } + if (self->mean_bit_counts != NULL) { + free(self->mean_bit_counts); + self->mean_bit_counts = NULL; + } + if (self->bit_counts != NULL) { + free(self->bit_counts); + self->bit_counts = NULL; + } + if (self->far_spectrum_32 != NULL) { + free(self->far_spectrum_32); + self->far_spectrum_32 = NULL; + } + if (self->near_spectrum_32 != NULL) { + free(self->near_spectrum_32); + self->near_spectrum_32 = NULL; + } + if (self->binary_far_history != NULL) { + free(self->binary_far_history); + self->binary_far_history = NULL; + } + if (self->far_history != NULL) { + free(self->far_history); + self->far_history = NULL; + } + if (self->far_q_domains != NULL) { + free(self->far_q_domains); + self->far_q_domains = NULL; + } + if (self->delay_histogram != NULL) { + free(self->delay_histogram); + self->delay_histogram = NULL; + } + + free(self); + + return 0; +} + +int WebRtc_CreateDelayEstimator(void** handle, + int spectrum_size, + int history_size, + int enable_alignment) { + DelayEstimator_t *self = NULL; + + // Check if the sub band used in the delay estimation is small enough to + // fit the binary spectra in a uint32. + assert(kBandLast - kBandFirst < 32); + + if (spectrum_size < kBandLast) { + return -1; + } + if (history_size < 0) { + return -1; + } + if ((enable_alignment != 0) && (enable_alignment != 1)) { + return -1; + } + + self = malloc(sizeof(DelayEstimator_t)); + *handle = self; + if (self == NULL) { + return -1; + } + + self->mean_far_spectrum = NULL; + self->mean_near_spectrum = NULL; + self->mean_bit_counts = NULL; + self->bit_counts = NULL; + self->far_spectrum_32 = NULL; + self->near_spectrum_32 = NULL; + self->binary_far_history = NULL; + self->far_history = NULL; + self->far_q_domains = NULL; + self->delay_histogram = NULL; + + // Allocate memory for spectrum buffers + self->mean_far_spectrum = malloc(spectrum_size * sizeof(int32_t)); + if (self->mean_far_spectrum == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + self->mean_near_spectrum = malloc(spectrum_size * sizeof(int32_t)); + if (self->mean_near_spectrum == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + self->mean_bit_counts = malloc(history_size * sizeof(int32_t)); + if (self->mean_bit_counts == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + self->bit_counts = malloc(history_size * sizeof(int32_t)); + if (self->bit_counts == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + self->far_spectrum_32 = malloc(spectrum_size * sizeof(int32_t)); + if (self->far_spectrum_32 == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + self->near_spectrum_32 = malloc(spectrum_size * sizeof(int32_t)); + if (self->near_spectrum_32 == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + // Allocate memory for history buffers + self->binary_far_history = malloc(history_size * sizeof(uint32_t)); + if (self->binary_far_history == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + if (enable_alignment) { + self->far_history = malloc(spectrum_size * history_size * sizeof(uint16_t)); + if (self->far_history == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + self->far_q_domains = malloc(history_size * sizeof(int)); + if (self->far_q_domains == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + } + self->delay_histogram = malloc(history_size * sizeof(int)); + if (self->delay_histogram == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + + self->spectrum_size = spectrum_size; + self->history_size = history_size; + self->alignment_enabled = enable_alignment; + + return 0; +} + +int WebRtc_InitDelayEstimator(void* handle) { + DelayEstimator_t* self = (DelayEstimator_t*) handle; + + if (self == NULL) { + return -1; + } + // Set averaged far and near end spectra to zero + memset(self->mean_far_spectrum, 0, sizeof(int32_t) * self->spectrum_size); + memset(self->mean_near_spectrum, 0, sizeof(int32_t) * self->spectrum_size); + // Set averaged bit counts to zero + memset(self->mean_bit_counts, 0, sizeof(int32_t) * self->history_size); + memset(self->bit_counts, 0, sizeof(int32_t) * self->history_size); + memset(self->far_spectrum_32, 0, sizeof(int32_t) * self->spectrum_size); + memset(self->near_spectrum_32, 0, sizeof(int32_t) * self->spectrum_size); + // Set far end histories to zero + memset(self->binary_far_history, 0, sizeof(uint32_t) * self->history_size); + if (self->alignment_enabled) { + memset(self->far_history, + 0, + sizeof(uint16_t) * self->spectrum_size * self->history_size); + memset(self->far_q_domains, 0, sizeof(int) * self->history_size); + self->far_history_pos = self->history_size; + } + // Set delay histogram to zero + memset(self->delay_histogram, 0, sizeof(int) * self->history_size); + // Set VAD counter to zero + self->vad_counter = 0; + // Set delay memory to zero + self->last_delay = 0; + + return 0; +} + +int WebRtc_DelayEstimatorProcess(void* handle, + uint16_t* far_spectrum, + uint16_t* near_spectrum, + int spectrum_size, + int far_q, + int vad_value) { + DelayEstimator_t* self = (DelayEstimator_t*) handle; + + const int kVadCountThreshold = 25; + const int kMaxHistogram = 600; + + int histogram_bin = 0; + int i = 0; + int max_histogram_level = 0; + int min_position = -1; + + uint32_t binary_far_spectrum = 0; + uint32_t binary_near_spectrum = 0; + + int32_t bit_counts_tmp = 0; + + if (self == NULL) { + return -1; + } + + if (spectrum_size != self->spectrum_size) { + // Data sizes don't match + return -1; + } + if (far_q > 15) { + // If |far_q| is larger than 15 we cannot guarantee no wrap around + return -1; + } + + if (self->alignment_enabled) { + // Update far end history + UpdateFarHistory(self, far_spectrum, far_q); + } // Update the far and near end means + for (i = 0; i < self->spectrum_size; i++) { + self->far_spectrum_32[i] = (int32_t) far_spectrum[i]; + MeanEstimator(self->far_spectrum_32[i], 6, &(self->mean_far_spectrum[i])); + + self->near_spectrum_32[i] = (int32_t) near_spectrum[i]; + MeanEstimator(self->near_spectrum_32[i], 6, &(self->mean_near_spectrum[i])); + } + + // Shift binary spectrum history + memmove(&(self->binary_far_history[1]), &(self->binary_far_history[0]), + (self->history_size - 1) * sizeof(uint32_t)); + + // Get binary spectra + binary_far_spectrum = BinarySpectrum(self->far_spectrum_32, + self->mean_far_spectrum); + binary_near_spectrum = BinarySpectrum(self->near_spectrum_32, + self->mean_near_spectrum); + // Insert new binary spectrum + self->binary_far_history[0] = binary_far_spectrum; + + // Compare with delayed spectra + BitCountComparison(binary_near_spectrum, + self->binary_far_history, + self->history_size, + self->bit_counts); + + // Smooth bit count curve + for (i = 0; i < self->history_size; i++) { + // Update sum + // |bit_counts| is constrained to [0, 32], meaning we can smooth with a + // factor up to 2^26. We use Q9. + bit_counts_tmp = WEBRTC_SPL_LSHIFT_W32(self->bit_counts[i], 9); // Q9 + MeanEstimator(bit_counts_tmp, 9, &(self->mean_bit_counts[i])); + } + + // Find minimum position of bit count curve + min_position = (int) WebRtcSpl_MinIndexW32(self->mean_bit_counts, + (int16_t) self->history_size); + + // If the far end has been active sufficiently long, begin accumulating a + // histogram of the minimum positions. Search for the maximum bin to + // determine the delay. + if (vad_value == 1) { + if (self->vad_counter >= kVadCountThreshold) { + // Increment the histogram at the current minimum position. + if (self->delay_histogram[min_position] < kMaxHistogram) { + self->delay_histogram[min_position] += 3; + } + + self->last_delay = 0; + for (i = 0; i < self->history_size; i++) { + histogram_bin = self->delay_histogram[i]; + + // Decrement the histogram bin. + if (histogram_bin > 0) { + histogram_bin--; + self->delay_histogram[i] = histogram_bin; + // Select the histogram index corresponding to the maximum bin as the + // delay. + if (histogram_bin > max_histogram_level) { + max_histogram_level = histogram_bin; + self->last_delay = i; + } + } + } + } else { + self->vad_counter++; + } + } else { + self->vad_counter = 0; + } + + return self->last_delay; +} + +const uint16_t* WebRtc_AlignedFarend(void* handle, + int far_spectrum_size, + int* far_q) { + DelayEstimator_t* self = (DelayEstimator_t*) handle; + int buffer_position = 0; + + if (self == NULL) { + return NULL; + } + if (far_spectrum_size != self->spectrum_size) { + return NULL; + } + if (self->alignment_enabled == 0) { + return NULL; + } + + // Get buffer position + buffer_position = self->far_history_pos - self->last_delay; + if (buffer_position < 0) { + buffer_position += self->history_size; + } + // Get Q-domain + *far_q = self->far_q_domains[buffer_position]; + // Return far end spectrum + return (self->far_history + (buffer_position * far_spectrum_size)); + +} + +int WebRtc_last_delay(void* handle) { + DelayEstimator_t* self = (DelayEstimator_t*) handle; + + if (self == NULL) { + return -1; + } + + return self->last_delay; +} + +int WebRtc_history_size(void* handle) { + DelayEstimator_t* self = (DelayEstimator_t*) handle; + + if (self == NULL) { + return -1; + } + + return self->history_size; +} + +int WebRtc_spectrum_size(void* handle) { + DelayEstimator_t* self = (DelayEstimator_t*) handle; + + if (self == NULL) { + return -1; + } + + return self->spectrum_size; +} + +int WebRtc_is_alignment_enabled(void* handle) { + DelayEstimator_t* self = (DelayEstimator_t*) handle; + + if (self == NULL) { + return -1; + } + + return self->alignment_enabled; +} diff --git a/src/modules/audio_processing/utility/delay_estimator.h b/src/modules/audio_processing/utility/delay_estimator.h new file mode 100644 index 0000000..9b77b55 --- /dev/null +++ b/src/modules/audio_processing/utility/delay_estimator.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Performs delay estimation on a block by block basis +// The return value is 0 - OK and -1 - Error, unless otherwise stated. + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ + +#include "typedefs.h" + +// Releases the memory allocated by WebRtc_CreateDelayEstimator(...) +// Input: +// - handle : Pointer to the delay estimation instance +// +int WebRtc_FreeDelayEstimator(void* handle); + +// Allocates the memory needed by the delay estimation. The memory needs to be +// initialized separately using the WebRtc_InitDelayEstimator(...) +// function. +// +// Inputs: +// - handle : Instance that should be created +// - spectrum_size : Size of the spectrum used both in far end and +// near end. Used to allocate memory for spectrum +// specific buffers. +// - history_size : Size of the far end history used to estimate the +// delay from. Used to allocate memory for history +// specific buffers. +// - enable_alignment : With this mode set to 1, a far end history is +// created, so that the user can retrieve aligned +// far end spectra using +// WebRtc_AlignedFarend(...). Otherwise, only delay +// values are calculated. +// +// Output: +// - handle : Created instance +// +int WebRtc_CreateDelayEstimator(void** handle, + int spectrum_size, + int history_size, + int enable_alignment); + +// Initializes the delay estimation instance created with +// 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. +// Inputs: +// - handle : Pointer to the delay estimation instance +// - far_spectrum : Pointer to the far end spectrum data +// - 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) +// - far_q : The Q-domain of the far end data +// - vad_value : The VAD decision of the current block +// +// Output: +// - handle : Updated instance +// +// Return value: +// - delay : >= 0 - Calculated delay value +// -1 - Error +// +int WebRtc_DelayEstimatorProcess(void* handle, + uint16_t* far_spectrum, + uint16_t* near_spectrum, + int spectrum_size, + int far_q, + int vad_value); + +// Returns a pointer to the far end spectrum aligned to current near end +// spectrum. The function WebRtc_DelayEstimatorProcess(...) should have been +// called before WebRtc_AlignedFarend(...). Otherwise, you get the pointer to +// the previous frame. The memory is only valid until the next call of +// WebRtc_DelayEstimatorProcess(...). +// +// Inputs: +// - handle : Pointer to the delay estimation instance +// - far_spectrum_size : Size of far_spectrum allocated by the caller +// +// Output: +// - far_q : The Q-domain of the aligned far end spectrum +// +// Return value: +// - far_spectrum : Pointer to the aligned far end spectrum +// NULL - Error +// +const uint16_t* WebRtc_AlignedFarend(void* handle, + int far_spectrum_size, + int* far_q); + +// 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 +// +int WebRtc_last_delay(void* handle); + +// Returns the history size used in the far end buffers to calculate the delay +// over. +// +// Input: +// - handle : Pointer to the delay estimation instance +// +// Return value: +// - history_size : > 0 - Far end history size +// -1 - Error +// +int WebRtc_history_size(void* handle); + +// Returns the fixed spectrum size used in the algorithm. +// +// Input: +// - handle : Pointer to the delay estimation instance +// +// Return value: +// - spectrum_size : > 0 - Spectrum size +// -1 - Error +// +int WebRtc_spectrum_size(void* handle); + +// Returns 1 if the far end alignment is enabled and 0 otherwise. +// +// Input: +// - handle : Pointer to the delay estimation instance +// +// Return value: +// - alignment_enabled : 1 - Enabled +// 0 - Disabled +// -1 - Error +// +int WebRtc_is_alignment_enabled(void* handle); + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ diff --git a/src/modules/audio_processing/utility/delay_estimator_float.c b/src/modules/audio_processing/utility/delay_estimator_float.c new file mode 100644 index 0000000..5633521 --- /dev/null +++ b/src/modules/audio_processing/utility/delay_estimator_float.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "delay_estimator_float.h" + +#include <assert.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#include "delay_estimator.h" +#include "signal_processing_library.h" + +typedef struct { + // Fixed point spectra + uint16_t* far_spectrum_u16; + uint16_t* near_spectrum_u16; + + // Far end history variables + float* far_history; + int far_history_pos; + + // Fixed point delay estimator + void* fixed_handle; + +} DelayEstimatorFloat_t; + +// Moves the pointer to the next buffer entry and inserts new far end spectrum. +// Only used when alignment is enabled. +// +// Inputs: +// - self : Pointer to the delay estimation instance +// - far_spectrum : Pointer to the far end spectrum +// +static void UpdateFarHistory(DelayEstimatorFloat_t* self, float* far_spectrum) { + int spectrum_size = WebRtc_spectrum_size(self->fixed_handle); + // Get new buffer position + self->far_history_pos++; + if (self->far_history_pos >= WebRtc_history_size(self->fixed_handle)) { + self->far_history_pos = 0; + } + // Update far end spectrum buffer + memcpy(&(self->far_history[self->far_history_pos * spectrum_size]), + far_spectrum, + sizeof(float) * spectrum_size); +} + +int WebRtc_FreeDelayEstimatorFloat(void* handle) { + DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle; + + if (self == NULL) { + return -1; + } + + if (self->far_history != NULL) { + free(self->far_history); + self->far_history = NULL; + } + if (self->far_spectrum_u16 != NULL) { + free(self->far_spectrum_u16); + self->far_spectrum_u16 = NULL; + } + if (self->near_spectrum_u16 != NULL) { + free(self->near_spectrum_u16); + self->near_spectrum_u16 = NULL; + } + + WebRtc_FreeDelayEstimator(self->fixed_handle); + free(self); + + return 0; +} + +int WebRtc_CreateDelayEstimatorFloat(void** handle, + int spectrum_size, + int history_size, + int enable_alignment) { + DelayEstimatorFloat_t *self = NULL; + if ((enable_alignment != 0) && (enable_alignment != 1)) { + return -1; + } + + self = malloc(sizeof(DelayEstimatorFloat_t)); + *handle = self; + if (self == NULL) { + return -1; + } + + self->far_history = NULL; + self->far_spectrum_u16 = NULL; + self->near_spectrum_u16 = NULL; + + // Create fixed point core delay estimator + if (WebRtc_CreateDelayEstimator(&self->fixed_handle, + spectrum_size, + history_size, + enable_alignment) != 0) { + WebRtc_FreeDelayEstimatorFloat(self); + self = NULL; + return -1; + } + + // Allocate memory for far history buffer + if (enable_alignment) { + self->far_history = malloc(spectrum_size * history_size * sizeof(float)); + if (self->far_history == NULL) { + WebRtc_FreeDelayEstimatorFloat(self); + self = NULL; + return -1; + } + } + // Allocate memory for fixed point spectra + self->far_spectrum_u16 = malloc(spectrum_size * sizeof(uint16_t)); + if (self->far_spectrum_u16 == NULL) { + WebRtc_FreeDelayEstimatorFloat(self); + self = NULL; + return -1; + } + self->near_spectrum_u16 = malloc(spectrum_size * sizeof(uint16_t)); + if (self->near_spectrum_u16 == NULL) { + WebRtc_FreeDelayEstimatorFloat(self); + self = NULL; + return -1; + } + + return 0; +} + +int WebRtc_InitDelayEstimatorFloat(void* handle) { + DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle; + + if (self == NULL) { + return -1; + } + + if (WebRtc_InitDelayEstimator(self->fixed_handle) != 0) { + return -1; + } + + { + int history_size = WebRtc_history_size(self->fixed_handle); + int spectrum_size = WebRtc_spectrum_size(self->fixed_handle); + if (WebRtc_is_alignment_enabled(self->fixed_handle) == 1) { + // Set far end histories to zero + memset(self->far_history, + 0, + sizeof(float) * spectrum_size * history_size); + self->far_history_pos = history_size; + } + // Set fixed point spectra to zero + memset(self->far_spectrum_u16, 0, sizeof(uint16_t) * spectrum_size); + memset(self->near_spectrum_u16, 0, sizeof(uint16_t) * spectrum_size); + } + + return 0; +} + +int WebRtc_DelayEstimatorProcessFloat(void* handle, + float* far_spectrum, + float* near_spectrum, + int spectrum_size, + int vad_value) { + DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle; + + const float kFftSize = (float) (2 * (spectrum_size - 1)); + const float kLogOf2Inverse = 1.4426950f; + float max_value = 0.0f; + float scaling = 0; + + int far_q = 0; + int scaling_log = 0; + int i = 0; + + if (self == NULL) { + return -1; + } + if (far_spectrum == NULL) { + // Empty far end spectrum + return -1; + } + if (near_spectrum == NULL) { + // Empty near end spectrum + return -1; + } + if (spectrum_size != WebRtc_spectrum_size(self->fixed_handle)) { + // Data sizes don't match + return -1; + } + + // Convert floating point spectrum to fixed point + // 1) Find largest value + // 2) Scale largest value to fit in Word16 + for (i = 0; i < spectrum_size; ++i) { + if (near_spectrum[i] > max_value) { + max_value = near_spectrum[i]; + } + } + // Find the largest possible scaling that is a multiple of two. + // With largest we mean to fit in a Word16. + // TODO(bjornv): I've taken the size of FFT into account, since there is a + // different scaling in float vs fixed point FFTs. I'm not completely sure + // this is necessary. + scaling_log = 14 - (int) (log(max_value / kFftSize + 1) * kLogOf2Inverse); + scaling = (float) (1 << scaling_log) / kFftSize; + for (i = 0; i < spectrum_size; ++i) { + self->near_spectrum_u16[i] = (uint16_t) (near_spectrum[i] * scaling); + } + + // Same for far end + max_value = 0.0f; + for (i = 0; i < spectrum_size; ++i) { + if (far_spectrum[i] > max_value) { + max_value = far_spectrum[i]; + } + } + // Find the largest possible scaling that is a multiple of two. + // With largest we mean to fit in a Word16. + scaling_log = 14 - (int) (log(max_value / kFftSize + 1) * kLogOf2Inverse); + scaling = (float) (1 << scaling_log) / kFftSize; + for (i = 0; i < spectrum_size; ++i) { + self->far_spectrum_u16[i] = (uint16_t) (far_spectrum[i] * scaling); + } + far_q = (int) scaling_log; + assert(far_q < 16); // Catch too large scaling, which should never be able to + // occur. + + if (WebRtc_is_alignment_enabled(self->fixed_handle) == 1) { + // Update far end history + UpdateFarHistory(self, far_spectrum); + } + + return WebRtc_DelayEstimatorProcess(self->fixed_handle, + self->far_spectrum_u16, + self->near_spectrum_u16, + spectrum_size, + far_q, + vad_value); +} + +const float* WebRtc_AlignedFarendFloat(void* handle, int far_spectrum_size) { + DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle; + int buffer_pos = 0; + + if (self == NULL) { + return NULL; + } + if (far_spectrum_size != WebRtc_spectrum_size(self->fixed_handle)) { + return NULL; + } + if (WebRtc_is_alignment_enabled(self->fixed_handle) != 1) { + return NULL; + } + + // Get buffer position + buffer_pos = self->far_history_pos - WebRtc_last_delay(self->fixed_handle); + if (buffer_pos < 0) { + buffer_pos += WebRtc_history_size(self->fixed_handle); + } + // Return pointer to far end spectrum + return (self->far_history + (buffer_pos * far_spectrum_size)); +} + +int WebRtc_last_delay_float(void* handle) { + DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle; + + if (self == NULL) { + return -1; + } + + return WebRtc_last_delay(self->fixed_handle); +} + +int WebRtc_is_alignment_enabled_float(void* handle) { + DelayEstimatorFloat_t* self = (DelayEstimatorFloat_t*) handle; + + if (self == NULL) { + return -1; + } + + return WebRtc_is_alignment_enabled(self->fixed_handle); +} diff --git a/src/modules/audio_processing/utility/delay_estimator_float.h b/src/modules/audio_processing/utility/delay_estimator_float.h new file mode 100644 index 0000000..3089965 --- /dev/null +++ b/src/modules/audio_processing/utility/delay_estimator_float.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Performs delay estimation on a block by block basis +// The return value is 0 - OK and -1 - Error, unless otherwise stated. + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_FLOAT_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_FLOAT_H_ + +// Releases the memory allocated by WebRtc_CreateDelayEstimatorFloat(...) +// Input: +// - handle : Pointer to the delay estimation instance +// +int WebRtc_FreeDelayEstimatorFloat(void* handle); + +// Allocates the memory needed by the delay estimation. The memory needs to be +// initialized separately using the WebRtc_InitDelayEstimatorFloat(...) +// function. +// +// Inputs: +// - handle : Instance that should be created +// - spectrum_size : Size of the spectrum used both in far end and +// near end. Used to allocate memory for spectrum +// specific buffers. +// - history_size : Size of the far end history used to estimate the +// delay from. Used to allocate memory for history +// specific buffers. +// - enable_alignment : With this mode set to 1, a far end history is +// created, so that the user can retrieve aligned +// far end spectra using +// WebRtc_AlignedFarendFloat(...). Otherwise, only +// delay values are calculated. +// +// Output: +// - handle : Created instance +// +int WebRtc_CreateDelayEstimatorFloat(void** handle, + int spectrum_size, + int history_size, + int enable_alignment); + +// Initializes the delay estimation instance created with +// WebRtc_CreateDelayEstimatorFloat(...) +// Input: +// - handle : Pointer to the delay estimation instance +// +// Output: +// - handle : Initialized instance +// +int WebRtc_InitDelayEstimatorFloat(void* handle); + +// Estimates and returns the delay between the far end and near end blocks. +// Inputs: +// - handle : Pointer to the delay estimation instance +// - far_spectrum : Pointer to the far end spectrum data +// - 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) +// - far_q : The Q-domain of the far end data +// - vad_value : The VAD decision of the current block +// +// Output: +// - handle : Updated instance +// +// Return value: +// - delay : >= 0 - Calculated delay value +// -1 - Error +// +int WebRtc_DelayEstimatorProcessFloat(void* handle, + float* far_spectrum, + float* near_spectrum, + int spectrum_size, + int vad_value); + +// Returns a pointer to the far end spectrum aligned to current near end +// spectrum. The function WebRtc_DelayEstimatorProcessFloat(...) should +// have been called before WebRtc_AlignedFarendFloat(...). Otherwise, you get +// the pointer to the previous frame. The memory is only valid until the +// next call of WebRtc_DelayEstimatorProcessFloat(...). +// +// Inputs: +// - handle : Pointer to the delay estimation instance +// - far_spectrum_size : Size of far_spectrum allocated by the caller +// +// Output: +// +// Return value: +// - far_spectrum : Pointer to the aligned far end spectrum +// NULL - Error +// +const float* WebRtc_AlignedFarendFloat(void* handle, int far_spectrum_size); + +// Returns the last calculated delay updated by the function +// WebRtcApm_DelayEstimatorProcessFloat(...) +// +// Inputs: +// - handle : Pointer to the delay estimation instance +// +// Return value: +// - delay : >= 0 - Last calculated delay value +// -1 - Error +// +int WebRtc_last_delay_float(void* handle); + +// Returns 1 if the far end alignment is enabled and 0 otherwise. +// +// Input: +// - handle : Pointer to the delay estimation instance +// +// Return value: +// - alignment_enabled : 1 - Enabled +// 0 - Disabled +// -1 - Error +// +int WebRtc_is_alignment_enabled_float(void* handle); + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_FLOAT_H_ diff --git a/src/modules/audio_processing/utility/util.gypi b/src/modules/audio_processing/utility/util.gypi index 331de4b..c088e98 100644 --- a/src/modules/audio_processing/utility/util.gypi +++ b/src/modules/audio_processing/utility/util.gypi @@ -11,16 +11,23 @@ { 'target_name': 'apm_util', 'type': '<(library)', + 'dependencies': [ + '<(webrtc_root)/common_audio/common_audio.gyp:spl', + ], 'direct_dependent_settings': { 'include_dirs': [ '.', ], }, 'sources': [ - 'ring_buffer.c', - 'ring_buffer.h', + 'delay_estimator_float.c', + 'delay_estimator_float.h', + 'delay_estimator.c', + 'delay_estimator.h', 'fft4g.c', 'fft4g.h', + 'ring_buffer.c', + 'ring_buffer.h', ], }, ], diff --git a/src/modules/interface/module_common_types.h b/src/modules/interface/module_common_types.h index 6e35a9d..99e1b68 100644 --- a/src/modules/interface/module_common_types.h +++ b/src/modules/interface/module_common_types.h @@ -42,9 +42,12 @@ struct RTPVideoHeaderH263 bool bits; // H.263 mode B, Xor the lasy byte of previus packet with the // first byte of this packet }; + enum {kNoPictureId = -1}; enum {kNoTl0PicIdx = -1}; enum {kNoTemporalIdx = -1}; +enum {kNoSimulcastIdx = 0}; + struct RTPVideoHeaderVP8 { void InitRTPVideoHeaderVP8() @@ -89,6 +92,8 @@ struct RTPVideoHeader WebRtc_UWord16 height; bool isFirstPacket; // first packet in frame + WebRtc_UWord8 simulcastIdx; // Index if the simulcast encoder creating + // this frame, 0 if not using simulcast. RTPVideoCodecTypes codec; RTPVideoTypeHeader codecHeader; }; diff --git a/src/system_wrappers/source/system_wrappers.gyp b/src/system_wrappers/source/system_wrappers.gyp index c3e98ea..02221df 100644 --- a/src/system_wrappers/source/system_wrappers.gyp +++ b/src/system_wrappers/source/system_wrappers.gyp @@ -33,6 +33,7 @@ '../interface/cpu_features_wrapper.h', '../interface/critical_section_wrapper.h', '../interface/data_log.h', + '../interface/data_log_c.h', '../interface/data_log_impl.h', '../interface/event_wrapper.h', '../interface/file_wrapper.h', @@ -63,6 +64,7 @@ 'critical_section.cc', 'critical_section_posix.h', 'critical_section_windows.h', + 'data_log_c.cc', 'event.cc', 'event_posix.h', 'event_windows.h', diff --git a/src/typedefs.h b/src/typedefs.h index 6620550..ca3b509 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -14,12 +14,14 @@ #define WEBRTC_TYPEDEFS_H_ // Reserved words definitions +// TODO(andrew): Look at removing these. #define WEBRTC_EXTERN extern #define G_CONST const #define WEBRTC_INLINE extern __inline // Define WebRTC preprocessor identifiers based on the current build platform. -// TODO(ajm): Clean these up. We can probably remove everything in this block. +// TODO(andrew): Clean these up. We can probably remove everything in this +// block. // - TARGET_MAC_INTEL and TARGET_MAC aren't used anywhere. // - In the few places where TARGET_PC is used, it should be replaced by // something more specific. @@ -32,7 +34,7 @@ #endif #elif defined(__APPLE__) // Mac OS X - #if defined(__LITTLE_ENDIAN__ ) //TODO: is this used? + #if defined(__LITTLE_ENDIAN__ ) #if !defined(WEBRTC_TARGET_MAC_INTEL) #define WEBRTC_TARGET_MAC_INTEL #endif @@ -53,7 +55,7 @@ // 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(ajm): replace WEBRTC_LITTLE_ENDIAN with WEBRTC_ARCH_LITTLE_ENDIAN? +// TODO(andrew): replace WEBRTC_LITTLE_ENDIAN with WEBRTC_ARCH_LITTLE_ENDIAN? #if defined(_M_X64) || defined(__x86_64__) #define WEBRTC_ARCH_X86_FAMILY #define WEBRTC_ARCH_X86_64 @@ -65,8 +67,11 @@ #define WEBRTC_ARCH_32_BITS #define WEBRTC_ARCH_LITTLE_ENDIAN #elif defined(__ARMEL__) -// TODO(ajm): Chromium uses the two commented defines. Should we switch? -#define WEBRTC_ARCH_ARM +// TODO(andrew): We'd prefer to control platform defines here, but this is +// currently provided by the Android makefiles. Commented to avoid duplicate +// definition warnings. +//#define WEBRTC_ARCH_ARM +// TODO(andrew): Chromium uses the following two defines. Should we switch? //#define WEBRTC_ARCH_ARM_FAMILY //#define WEBRTC_ARCH_ARMEL #define WEBRTC_ARCH_32_BITS @@ -75,10 +80,7 @@ #error Please add support for your architecture in typedefs.h #endif -// TODO(ajm): SSE2 is disabled on Windows for the moment, because AEC -// optimization is broken. Enable it as soon as AEC is fixed. -//#if defined(__SSE2__) || defined(_MSC_VER) -#if defined(__SSE2__) +#if defined(__SSE2__) || defined(_MSC_VER) #define WEBRTC_USE_SSE2 #endif |