From 83b00f020e2feb9360d74db65573f5442e1b6494 Mon Sep 17 00:00:00 2001 From: Gustaf Ullberg Date: Tue, 6 Nov 2018 16:25:37 +0100 Subject: [PATCH] AEC3: Computation of comfort noise gains from suppression gains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change corrects the computation of the comfort noise gains. Previously the comfort noise gain of band k, CG_k, was computed from suppression gain of band k, SG_k, as: CG_k = 1 - SG_k But since the two signals are uncorrelated (the comfort noise is randomly generated), the correct gain to maintain power is: CG_k = sqrt(1 - SG_k^2). Bug: webrtc:9967,chromium:902262 Change-Id: I393495742163d5e658bca4ab2f7a5067ab15af01 Reviewed-on: https://webrtc-review.googlesource.com/c/109580 Commit-Queue: Gustaf Ullberg Reviewed-by: Per Ã…hgren Cr-Commit-Position: refs/heads/master@{#25525} --- modules/audio_processing/aec3/echo_remover.cc | 2 +- .../aec3/suppression_filter.cc | 31 ++++++++++--------- .../aec3/suppression_filter.h | 3 +- .../aec3/suppression_filter_unittest.cc | 14 ++++----- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc index 5b3740f6bb..cfb7395199 100644 --- a/modules/audio_processing/aec3/echo_remover.cc +++ b/modules/audio_processing/aec3/echo_remover.cc @@ -178,7 +178,7 @@ EchoRemoverImpl::EchoRemoverImpl(const EchoCanceller3Config& config, subtractor_(config, data_dumper_.get(), optimization_), suppression_gain_(config_, optimization_, sample_rate_hz), cng_(optimization_), - suppression_filter_(sample_rate_hz_), + suppression_filter_(optimization_, sample_rate_hz_), render_signal_analyzer_(config_), residual_echo_estimator_(config_), aec_state_(config_) { diff --git a/modules/audio_processing/aec3/suppression_filter.cc b/modules/audio_processing/aec3/suppression_filter.cc index 4af9327dcc..6fe296c219 100644 --- a/modules/audio_processing/aec3/suppression_filter.cc +++ b/modules/audio_processing/aec3/suppression_filter.cc @@ -11,10 +11,12 @@ #include "modules/audio_processing/aec3/suppression_filter.h" #include +#include #include #include #include +#include "modules/audio_processing/aec3/vector_math.h" #include "rtc_base/checks.h" #include "rtc_base/numerics/safe_minmax.h" @@ -58,8 +60,10 @@ const float kSqrtHanning[kFftLength] = { } // namespace -SuppressionFilter::SuppressionFilter(int sample_rate_hz) - : sample_rate_hz_(sample_rate_hz), +SuppressionFilter::SuppressionFilter(Aec3Optimization optimization, + int sample_rate_hz) + : optimization_(optimization), + sample_rate_hz_(sample_rate_hz), fft_(), e_output_old_(NumBandsForRate(sample_rate_hz_)) { RTC_DCHECK(ValidFullBandRate(sample_rate_hz_)); @@ -89,18 +93,17 @@ void SuppressionFilter::ApplyGain( std::transform(suppression_gain.begin(), suppression_gain.end(), E.im.begin(), E.im.begin(), std::multiplies()); - // Compute and add the comfort noise. - std::array scaled_comfort_noise; + // Comfort noise gain is sqrt(1-g^2), where g is the suppression gain. + std::array noise_gain; std::transform(suppression_gain.begin(), suppression_gain.end(), - comfort_noise.re.begin(), scaled_comfort_noise.begin(), - [](float a, float b) { return std::max(1.f - a, 0.f) * b; }); - std::transform(scaled_comfort_noise.begin(), scaled_comfort_noise.end(), - E.re.begin(), E.re.begin(), std::plus()); - std::transform(suppression_gain.begin(), suppression_gain.end(), - comfort_noise.im.begin(), scaled_comfort_noise.begin(), - [](float a, float b) { return std::max(1.f - a, 0.f) * b; }); - std::transform(scaled_comfort_noise.begin(), scaled_comfort_noise.end(), - E.im.begin(), E.im.begin(), std::plus()); + noise_gain.begin(), [](float g) { return 1.f - g * g; }); + aec3::VectorMath(optimization_).Sqrt(noise_gain); + + // Scale and add the comfort noise. + for (size_t k = 0; k < kFftLengthBy2Plus1; k++) { + E.re[k] += noise_gain[k] * comfort_noise.re[k]; + E.im[k] += noise_gain[k] * comfort_noise.im[k]; + } // Synthesis filterbank. std::array e_extended; @@ -134,7 +137,7 @@ void SuppressionFilter::ApplyGain( // Scale and apply the noise to the signals. const float high_bands_noise_scaling = - 0.4f * std::max(1.f - high_bands_gain, 0.f); + 0.4f * std::sqrt(1.f - high_bands_gain * high_bands_gain); std::transform( (*e)[1].begin(), (*e)[1].end(), time_domain_high_band_noise.begin(), diff --git a/modules/audio_processing/aec3/suppression_filter.h b/modules/audio_processing/aec3/suppression_filter.h index df03156f08..edd1290014 100644 --- a/modules/audio_processing/aec3/suppression_filter.h +++ b/modules/audio_processing/aec3/suppression_filter.h @@ -24,7 +24,7 @@ namespace webrtc { class SuppressionFilter { public: - explicit SuppressionFilter(int sample_rate_hz); + SuppressionFilter(Aec3Optimization optimization, int sample_rate_hz); ~SuppressionFilter(); void ApplyGain(const FftData& comfort_noise, const FftData& comfort_noise_high_bands, @@ -34,6 +34,7 @@ class SuppressionFilter { std::vector>* e); private: + const Aec3Optimization optimization_; const int sample_rate_hz_; const OouraFft ooura_fft_; const Aec3Fft fft_; diff --git a/modules/audio_processing/aec3/suppression_filter_unittest.cc b/modules/audio_processing/aec3/suppression_filter_unittest.cc index eaa608eed5..9e4ff7c28b 100644 --- a/modules/audio_processing/aec3/suppression_filter_unittest.cc +++ b/modules/audio_processing/aec3/suppression_filter_unittest.cc @@ -45,21 +45,21 @@ TEST(SuppressionFilter, NullOutput) { FftData E; std::array gain; - EXPECT_DEATH(SuppressionFilter(16000).ApplyGain(cn, cn_high_bands, gain, 1.0f, - E, nullptr), + EXPECT_DEATH(SuppressionFilter(Aec3Optimization::kNone, 16000) + .ApplyGain(cn, cn_high_bands, gain, 1.0f, E, nullptr), ""); } // Verifies the check for allowed sample rate. TEST(SuppressionFilter, ProperSampleRate) { - EXPECT_DEATH(SuppressionFilter(16001), ""); + EXPECT_DEATH(SuppressionFilter(Aec3Optimization::kNone, 16001), ""); } #endif // Verifies that no comfort noise is added when the gain is 1. TEST(SuppressionFilter, ComfortNoiseInUnityGain) { - SuppressionFilter filter(48000); + SuppressionFilter filter(Aec3Optimization::kNone, 48000); FftData cn; FftData cn_high_bands; std::array gain; @@ -89,7 +89,7 @@ TEST(SuppressionFilter, ComfortNoiseInUnityGain) { // Verifies that the suppressor is able to suppress a signal. TEST(SuppressionFilter, SignalSuppression) { - SuppressionFilter filter(48000); + SuppressionFilter filter(Aec3Optimization::kNone, 48000); FftData cn; FftData cn_high_bands; std::array e_old_; @@ -131,7 +131,7 @@ TEST(SuppressionFilter, SignalSuppression) { // Verifies that the suppressor is able to pass through a desired signal while // applying suppressing for some frequencies. TEST(SuppressionFilter, SignalTransparency) { - SuppressionFilter filter(48000); + SuppressionFilter filter(Aec3Optimization::kNone, 48000); FftData cn; std::array e_old_; Aec3Fft fft; @@ -171,7 +171,7 @@ TEST(SuppressionFilter, SignalTransparency) { // Verifies that the suppressor delay. TEST(SuppressionFilter, Delay) { - SuppressionFilter filter(48000); + SuppressionFilter filter(Aec3Optimization::kNone, 48000); FftData cn; FftData cn_high_bands; std::array e_old_;