Chromium Code Reviews| Index: webrtc/modules/audio_processing/aec3/comfort_noise_generator.cc |
| diff --git a/webrtc/modules/audio_processing/aec3/comfort_noise_generator.cc b/webrtc/modules/audio_processing/aec3/comfort_noise_generator.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2f605209417db73eabbbd08d4506a27383650d0e |
| --- /dev/null |
| +++ b/webrtc/modules/audio_processing/aec3/comfort_noise_generator.cc |
| @@ -0,0 +1,116 @@ |
| +/* |
| + * Copyright (c) 2017 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 "webrtc/modules/audio_processing/aec3/comfort_noise_generator.h" |
| + |
| +#include <math.h> |
| +#include <algorithm> |
| +#include <array> |
| +#include <functional> |
| +#include <numeric> |
| + |
| +#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" |
| + |
| +namespace webrtc { |
| + |
| +ComfortNoiseGenerator::ComfortNoiseGenerator() |
| + : seed_(42), N2_initial_(new std::array<float, kFftLengthBy2Plus1>()) { |
| + N2_initial_->fill(0.f); |
| + Y2_smoothed_.fill(0.f); |
| + N2_.fill(1.0e6f); |
| +} |
| + |
| +ComfortNoiseGenerator::~ComfortNoiseGenerator() = default; |
| + |
| +void ComfortNoiseGenerator::Compute( |
| + const std::array<float, kFftLengthBy2Plus1>& capture_spectrum, |
| + FftData* lower_band_noise, |
| + FftData* upper_band_noise) { |
| + RTC_DCHECK(lower_band_noise); |
| + RTC_DCHECK(upper_band_noise); |
| + const std::array<float, kFftLengthBy2Plus1>& Y2 = capture_spectrum; |
|
ivoc
2017/02/10 13:52:33
I would prefer const auto&
peah-webrtc
2017/02/20 07:37:15
Nice!
Done.
|
| + FftData* N_low = lower_band_noise; |
| + FftData* N_high = upper_band_noise; |
| + |
| + // Smooth Y2. |
| + std::transform(Y2_smoothed_.begin(), Y2_smoothed_.end(), Y2.begin(), |
| + Y2_smoothed_.begin(), |
| + [](float a, float b) { return a + 0.1f * (b - a); }); |
|
ivoc
2017/02/10 13:52:33
Out of curiousity, what kind of filter is this?
peah-webrtc
2017/02/20 07:37:15
This is a low-pass filter: Y2_smoothed(t)=0.9f*Y2_
ivoc
2017/02/21 17:26:00
ah, I should have seen that :)
peah-webrtc
2017/02/22 23:51:35
No worries! Good question!
|
| + |
| + if (N2_counter_ > 50) { |
| + // Update N2 from Y2_smoothed. |
| + std::transform(N2_.begin(), N2_.end(), Y2_smoothed_.begin(), N2_.begin(), |
| + [](float a, float b) { |
| + return b < a ? (0.9f * b + 0.1f * a) * 1.0002f |
| + : a * 1.0002f; |
| + }); |
| + } |
| + |
| + if (N2_initial_) { |
| + if (++N2_counter_ == 1000) { |
| + N2_initial_.reset(); |
| + } else { |
| + // Compute initial N2 from N2. |
|
ivoc
2017/02/10 13:52:33
This is a bit confusing. I would rephrase as "Comp
peah-webrtc
2017/02/20 07:37:15
Done.
|
| + std::transform( |
| + N2_.begin(), N2_.end(), N2_initial_->begin(), N2_initial_->begin(), |
| + [](float a, float b) { return a > b ? b + 0.001f * (a - b) : a; }); |
| + } |
| + } |
| + |
| + // Choose N2 estimate to use. |
| + const std::array<float, kFftLengthBy2Plus1>& N2 = |
| + N2_initial_ ? *N2_initial_ : N2_; |
| + |
| + // Compute square root spectrum. |
| + std::array<float, kFftLengthBy2Plus1> N; |
| + std::transform(N2.begin(), N2.end(), N.begin(), |
| + [](float a) { return sqrtf(a); }); |
| + |
| + // Compute the noise level for the upper bands. |
| + const float high_band_noise_level = |
| + std::accumulate(N.begin() + kFftLengthBy2Plus1 / 2, N.end(), 0.f, |
| + [](float a, float b) { return a + b; }) / |
|
ivoc
2017/02/10 13:52:33
The last argument (the lambda) is not needed, accu
peah-webrtc
2017/02/20 07:37:15
Done.
|
| + (kFftLengthBy2Plus1 / 2 + 1); |
| + |
| + // Generate complex noise. |
| + std::array<int16_t, kFftLengthBy2 - 1> random_values_int; |
| + WebRtcSpl_RandUArray(random_values_int.data(), random_values_int.size(), |
| + &seed_); |
| + |
| + std::array<float, kFftLengthBy2 - 1> sin; |
| + std::array<float, kFftLengthBy2 - 1> cos; |
| + const float kScale = 6.28318530717959f * 1.f / 32768.0f; |
|
ivoc
2017/02/10 13:52:33
The "* 1.f" can be removed, right? Also, this can
peah-webrtc
2017/02/20 07:37:15
Done.
|
| + 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<float>()); |
| + std::transform(sin.begin(), sin.end(), N.begin() + 1, N_low->im.begin() + 1, |
| + std::multiplies<float>()); |
| + |
| + // 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; }); |
| + |
| + // TODO(peah): Remove when landing. |
|
ivoc
2017/02/10 13:52:33
Is that now?
peah-webrtc
2017/02/20 07:37:15
Should be :-) Thanks!
Done-
|
| + std::array<float, kFftLength> noiseP; |
| + std::array<float, kFftLength> noise_high_bandP; |
| + N_low->CopyToPackedArray(&noiseP); |
| + N_high->CopyToPackedArray(&noise_high_bandP); |
| +} |
| + |
| +} // namespace webrtc |