diff --git a/modules/audio_processing/aec3/comfort_noise_generator.cc b/modules/audio_processing/aec3/comfort_noise_generator.cc index f55d9d4fda..766e658639 100644 --- a/modules/audio_processing/aec3/comfort_noise_generator.cc +++ b/modules/audio_processing/aec3/comfort_noise_generator.cc @@ -24,6 +24,7 @@ #include #include "common_audio/signal_processing/include/signal_processing_library.h" +#include "modules/audio_processing/aec3/vector_math.h" #include "rtc_base/checks.h" namespace webrtc { @@ -40,64 +41,10 @@ void TableRandomValue(int16_t* vector, int16_t vector_length, uint32_t* seed) { } // namespace -namespace aec3 { +namespace { -#if defined(WEBRTC_ARCH_X86_FAMILY) - -void EstimateComfortNoise_SSE2(const std::array& N2, - uint32_t* seed, - FftData* lower_band_noise, - FftData* upper_band_noise) { - FftData* N_low = lower_band_noise; - FftData* N_high = upper_band_noise; - - // Compute square root spectrum. - std::array N; - for (size_t k = 0; k < kFftLengthBy2; k += 4) { - __m128 v = _mm_loadu_ps(&N2[k]); - v = _mm_sqrt_ps(v); - _mm_storeu_ps(&N[k], v); - } - - N[kFftLengthBy2] = sqrtf(N2[kFftLengthBy2]); - - // Compute the noise level for the upper bands. - constexpr float kOneByNumBands = 1.f / (kFftLengthBy2Plus1 / 2 + 1); - constexpr int kFftLengthBy2Plus1By2 = kFftLengthBy2Plus1 / 2; - const float high_band_noise_level = - std::accumulate(N.begin() + kFftLengthBy2Plus1By2, N.end(), 0.f) * - kOneByNumBands; - - // Generate complex noise. - std::array random_values_int; - TableRandomValue(random_values_int.data(), random_values_int.size(), seed); - - std::array sin; - std::array cos; - constexpr float kScale = 6.28318530717959f / 32768.0f; - std::transform(random_values_int.begin(), random_values_int.end(), - sin.begin(), [&](int16_t a) { return -sinf(kScale * a); }); - std::transform(random_values_int.begin(), random_values_int.end(), - cos.begin(), [&](int16_t a) { return cosf(kScale * a); }); - - // Form low-frequency noise via spectral shaping. - N_low->re[0] = N_low->re[kFftLengthBy2] = N_high->re[0] = - N_high->re[kFftLengthBy2] = 0.f; - std::transform(cos.begin(), cos.end(), N.begin() + 1, N_low->re.begin() + 1, - std::multiplies()); - std::transform(sin.begin(), sin.end(), N.begin() + 1, N_low->im.begin() + 1, - std::multiplies()); - - // Form the high-frequency noise via simple levelling. - std::transform(cos.begin(), cos.end(), N_high->re.begin() + 1, - [&](float a) { return high_band_noise_level * a; }); - std::transform(sin.begin(), sin.end(), N_high->im.begin() + 1, - [&](float a) { return high_band_noise_level * a; }); -} - -#endif - -void EstimateComfortNoise(const std::array& N2, +void GenerateComfortNoise(Aec3Optimization optimization, + const std::array& N2, uint32_t* seed, FftData* lower_band_noise, FftData* upper_band_noise) { @@ -106,8 +53,8 @@ void EstimateComfortNoise(const std::array& N2, // Compute square root spectrum. std::array N; - std::transform(N2.begin(), N2.end(), N.begin(), - [](float a) { return sqrtf(a); }); + std::copy(N2.begin(), N2.end(), N.begin()); + aec3::VectorMath(optimization).Sqrt(N); // Compute the noise level for the upper bands. constexpr float kOneByNumBands = 1.f / (kFftLengthBy2Plus1 / 2 + 1); @@ -120,13 +67,21 @@ void EstimateComfortNoise(const std::array& N2, std::array random_values_int; TableRandomValue(random_values_int.data(), random_values_int.size(), seed); + // The analysis and synthesis windowing cause loss of power when + // cross-fading the noise where frames are completely uncorrelated + // (generated with random phase), hence the factor sqrt(2). + // This is not the case for the speech signal where the input is overlapping + // (strong correlation). std::array sin; std::array cos; constexpr float kScale = 6.28318530717959f / 32768.0f; + constexpr float kSqrt2 = 1.4142135623f; std::transform(random_values_int.begin(), random_values_int.end(), - sin.begin(), [&](int16_t a) { return -sinf(kScale * a); }); + sin.begin(), + [&](int16_t a) { return -sinf(kScale * a) * kSqrt2; }); std::transform(random_values_int.begin(), random_values_int.end(), - cos.begin(), [&](int16_t a) { return cosf(kScale * a); }); + cos.begin(), + [&](int16_t a) { return cosf(kScale * a) * kSqrt2; }); // Form low-frequency noise via spectral shaping. N_low->re[0] = N_low->re[kFftLengthBy2] = N_high->re[0] = @@ -143,7 +98,7 @@ void EstimateComfortNoise(const std::array& N2, [&](float a) { return high_band_noise_level * a; }); } -} // namespace aec3 +} // namespace ComfortNoiseGenerator::ComfortNoiseGenerator(Aec3Optimization optimization) : optimization_(optimization), @@ -207,17 +162,8 @@ void ComfortNoiseGenerator::Compute( const std::array& N2 = N2_initial_ ? *N2_initial_ : N2_; - switch (optimization_) { -#if defined(WEBRTC_ARCH_X86_FAMILY) - case Aec3Optimization::kSse2: - aec3::EstimateComfortNoise_SSE2(N2, &seed_, lower_band_noise, - upper_band_noise); - break; -#endif - default: - aec3::EstimateComfortNoise(N2, &seed_, lower_band_noise, - upper_band_noise); - } + GenerateComfortNoise(optimization_, N2, &seed_, lower_band_noise, + upper_band_noise); } } // namespace webrtc diff --git a/modules/audio_processing/aec3/comfort_noise_generator_unittest.cc b/modules/audio_processing/aec3/comfort_noise_generator_unittest.cc index 77a09edcd6..10ba696036 100644 --- a/modules/audio_processing/aec3/comfort_noise_generator_unittest.cc +++ b/modules/audio_processing/aec3/comfort_noise_generator_unittest.cc @@ -52,45 +52,6 @@ TEST(ComfortNoiseGenerator, NullUpperBandNoise) { #endif -#if defined(WEBRTC_ARCH_X86_FAMILY) -// Verifies that the optimized methods are bitexact to their reference -// counterparts. -TEST(ComfortNoiseGenerator, TestOptimizations) { - if (WebRtc_GetCPUInfo(kSSE2) != 0) { - Random random_generator(42U); - uint32_t seed = 42; - uint32_t seed_SSE2 = 42; - std::array N2; - FftData lower_band_noise; - FftData upper_band_noise; - FftData lower_band_noise_SSE2; - FftData upper_band_noise_SSE2; - for (int k = 0; k < 10; ++k) { - for (size_t j = 0; j < N2.size(); ++j) { - N2[j] = random_generator.Rand() * 1000.f; - } - - EstimateComfortNoise(N2, &seed, &lower_band_noise, &upper_band_noise); - EstimateComfortNoise_SSE2(N2, &seed_SSE2, &lower_band_noise_SSE2, - &upper_band_noise_SSE2); - for (size_t j = 0; j < lower_band_noise.re.size(); ++j) { - EXPECT_NEAR(lower_band_noise.re[j], lower_band_noise_SSE2.re[j], - 0.00001f); - EXPECT_NEAR(upper_band_noise.re[j], upper_band_noise_SSE2.re[j], - 0.00001f); - } - for (size_t j = 1; j < lower_band_noise.re.size() - 1; ++j) { - EXPECT_NEAR(lower_band_noise.im[j], lower_band_noise_SSE2.im[j], - 0.00001f); - EXPECT_NEAR(upper_band_noise.im[j], upper_band_noise_SSE2.im[j], - 0.00001f); - } - } - } -} - -#endif - TEST(ComfortNoiseGenerator, CorrectLevel) { ComfortNoiseGenerator cng(DetectOptimization()); AecState aec_state(EchoCanceller3Config{}); @@ -113,8 +74,8 @@ TEST(ComfortNoiseGenerator, CorrectLevel) { for (int k = 0; k < 10000; ++k) { cng.Compute(aec_state, N2, &n_lower, &n_upper); } - EXPECT_NEAR(N2[0], Power(n_lower), N2[0] / 10.f); - EXPECT_NEAR(N2[0], Power(n_upper), N2[0] / 10.f); + EXPECT_NEAR(2.f * N2[0], Power(n_lower), N2[0] / 10.f); + EXPECT_NEAR(2.f * N2[0], Power(n_upper), N2[0] / 10.f); } } // namespace aec3