quantile_noise_estimator.cc (3029B)
1 /* 2 * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/audio_processing/ns/quantile_noise_estimator.h" 12 13 #include <algorithm> 14 #include <array> 15 #include <cmath> 16 #include <cstddef> 17 18 #include "api/array_view.h" 19 #include "modules/audio_processing/ns/fast_math.h" 20 #include "modules/audio_processing/ns/ns_common.h" 21 22 namespace webrtc { 23 24 QuantileNoiseEstimator::QuantileNoiseEstimator() { 25 quantile_.fill(0.f); 26 density_.fill(0.3f); 27 log_quantile_.fill(8.f); 28 29 constexpr float kOneBySimult = 1.f / kSimult; 30 for (size_t i = 0; i < kSimult; ++i) { 31 counter_[i] = floor(kLongStartupPhaseBlocks * (i + 1.f) * kOneBySimult); 32 } 33 } 34 35 void QuantileNoiseEstimator::Estimate( 36 ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum, 37 ArrayView<float, kFftSizeBy2Plus1> noise_spectrum) { 38 std::array<float, kFftSizeBy2Plus1> log_spectrum; 39 LogApproximation(signal_spectrum, log_spectrum); 40 41 int quantile_index_to_return = -1; 42 // Loop over simultaneous estimates. 43 for (int s = 0, k = 0; s < kSimult; 44 ++s, k += static_cast<int>(kFftSizeBy2Plus1)) { 45 const float one_by_counter_plus_1 = 1.f / (counter_[s] + 1.f); 46 for (int i = 0, j = k; i < static_cast<int>(kFftSizeBy2Plus1); ++i, ++j) { 47 // Update log quantile estimate. 48 const float delta = density_[j] > 1.f ? 40.f / density_[j] : 40.f; 49 50 const float multiplier = delta * one_by_counter_plus_1; 51 if (log_spectrum[i] > log_quantile_[j]) { 52 log_quantile_[j] += 0.25f * multiplier; 53 } else { 54 log_quantile_[j] -= 0.75f * multiplier; 55 } 56 57 // Update density estimate. 58 constexpr float kWidth = 0.01f; 59 constexpr float kOneByWidthPlus2 = 1.f / (2.f * kWidth); 60 if (fabs(log_spectrum[i] - log_quantile_[j]) < kWidth) { 61 density_[j] = (counter_[s] * density_[j] + kOneByWidthPlus2) * 62 one_by_counter_plus_1; 63 } 64 } 65 66 if (counter_[s] >= kLongStartupPhaseBlocks) { 67 counter_[s] = 0; 68 if (num_updates_ >= kLongStartupPhaseBlocks) { 69 quantile_index_to_return = k; 70 } 71 } 72 73 ++counter_[s]; 74 } 75 76 // Sequentially update the noise during startup. 77 if (num_updates_ < kLongStartupPhaseBlocks) { 78 // Use the last "s" to get noise during startup that differ from zero. 79 quantile_index_to_return = kFftSizeBy2Plus1 * (kSimult - 1); 80 ++num_updates_; 81 } 82 83 if (quantile_index_to_return >= 0) { 84 ExpApproximation( 85 ArrayView<const float>(&log_quantile_[quantile_index_to_return], 86 kFftSizeBy2Plus1), 87 quantile_); 88 } 89 90 std::copy(quantile_.begin(), quantile_.end(), noise_spectrum.begin()); 91 } 92 93 } // namespace webrtc