1 /*
2 * Copyright (c) 2017 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/aec3/comfort_noise_generator.h"
12
13 // Defines WEBRTC_ARCH_X86_FAMILY, used below.
14 #include "rtc_base/system/arch.h"
15
16 #if defined(WEBRTC_ARCH_X86_FAMILY)
17 #include <emmintrin.h>
18 #endif
19 #include <algorithm>
20 #include <array>
21 #include <cmath>
22 #include <cstdint>
23 #include <functional>
24 #include <numeric>
25
26 #include "common_audio/signal_processing/include/signal_processing_library.h"
27 #include "modules/audio_processing/aec3/vector_math.h"
28 #include "rtc_base/checks.h"
29
30 namespace webrtc {
31
32 namespace {
33
34 // Computes the noise floor value that matches a WGN input of noise_floor_dbfs.
GetNoiseFloorFactor(float noise_floor_dbfs)35 float GetNoiseFloorFactor(float noise_floor_dbfs) {
36 // kdBfsNormalization = 20.f*log10(32768.f).
37 constexpr float kdBfsNormalization = 90.30899869919436f;
38 return 64.f * powf(10.f, (kdBfsNormalization + noise_floor_dbfs) * 0.1f);
39 }
40
41 // Table of sqrt(2) * sin(2*pi*i/32).
42 constexpr float kSqrt2Sin[32] = {
43 +0.0000000f, +0.2758994f, +0.5411961f, +0.7856950f, +1.0000000f,
44 +1.1758756f, +1.3065630f, +1.3870398f, +1.4142136f, +1.3870398f,
45 +1.3065630f, +1.1758756f, +1.0000000f, +0.7856950f, +0.5411961f,
46 +0.2758994f, +0.0000000f, -0.2758994f, -0.5411961f, -0.7856950f,
47 -1.0000000f, -1.1758756f, -1.3065630f, -1.3870398f, -1.4142136f,
48 -1.3870398f, -1.3065630f, -1.1758756f, -1.0000000f, -0.7856950f,
49 -0.5411961f, -0.2758994f};
50
GenerateComfortNoise(Aec3Optimization optimization,const std::array<float,kFftLengthBy2Plus1> & N2,uint32_t * seed,FftData * lower_band_noise,FftData * upper_band_noise)51 void GenerateComfortNoise(Aec3Optimization optimization,
52 const std::array<float, kFftLengthBy2Plus1>& N2,
53 uint32_t* seed,
54 FftData* lower_band_noise,
55 FftData* upper_band_noise) {
56 FftData* N_low = lower_band_noise;
57 FftData* N_high = upper_band_noise;
58
59 // Compute square root spectrum.
60 std::array<float, kFftLengthBy2Plus1> N;
61 std::copy(N2.begin(), N2.end(), N.begin());
62 aec3::VectorMath(optimization).Sqrt(N);
63
64 // Compute the noise level for the upper bands.
65 constexpr float kOneByNumBands = 1.f / (kFftLengthBy2Plus1 / 2 + 1);
66 constexpr int kFftLengthBy2Plus1By2 = kFftLengthBy2Plus1 / 2;
67 const float high_band_noise_level =
68 std::accumulate(N.begin() + kFftLengthBy2Plus1By2, N.end(), 0.f) *
69 kOneByNumBands;
70
71 // The analysis and synthesis windowing cause loss of power when
72 // cross-fading the noise where frames are completely uncorrelated
73 // (generated with random phase), hence the factor sqrt(2).
74 // This is not the case for the speech signal where the input is overlapping
75 // (strong correlation).
76 N_low->re[0] = N_low->re[kFftLengthBy2] = N_high->re[0] =
77 N_high->re[kFftLengthBy2] = 0.f;
78 for (size_t k = 1; k < kFftLengthBy2; k++) {
79 constexpr int kIndexMask = 32 - 1;
80 // Generate a random 31-bit integer.
81 seed[0] = (seed[0] * 69069 + 1) & (0x80000000 - 1);
82 // Convert to a 5-bit index.
83 int i = seed[0] >> 26;
84
85 // y = sqrt(2) * sin(a)
86 const float x = kSqrt2Sin[i];
87 // x = sqrt(2) * cos(a) = sqrt(2) * sin(a + pi/2)
88 const float y = kSqrt2Sin[(i + 8) & kIndexMask];
89
90 // Form low-frequency noise via spectral shaping.
91 N_low->re[k] = N[k] * x;
92 N_low->im[k] = N[k] * y;
93
94 // Form the high-frequency noise via simple levelling.
95 N_high->re[k] = high_band_noise_level * x;
96 N_high->im[k] = high_band_noise_level * y;
97 }
98 }
99
100 } // namespace
101
ComfortNoiseGenerator(const EchoCanceller3Config & config,Aec3Optimization optimization,size_t num_capture_channels)102 ComfortNoiseGenerator::ComfortNoiseGenerator(const EchoCanceller3Config& config,
103 Aec3Optimization optimization,
104 size_t num_capture_channels)
105 : optimization_(optimization),
106 seed_(42),
107 num_capture_channels_(num_capture_channels),
108 noise_floor_(GetNoiseFloorFactor(config.comfort_noise.noise_floor_dbfs)),
109 N2_initial_(
110 std::make_unique<std::vector<std::array<float, kFftLengthBy2Plus1>>>(
111 num_capture_channels_)),
112 Y2_smoothed_(num_capture_channels_),
113 N2_(num_capture_channels_) {
114 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
115 (*N2_initial_)[ch].fill(0.f);
116 Y2_smoothed_[ch].fill(0.f);
117 N2_[ch].fill(1.0e6f);
118 }
119 }
120
121 ComfortNoiseGenerator::~ComfortNoiseGenerator() = default;
122
Compute(bool saturated_capture,rtc::ArrayView<const std::array<float,kFftLengthBy2Plus1>> capture_spectrum,rtc::ArrayView<FftData> lower_band_noise,rtc::ArrayView<FftData> upper_band_noise)123 void ComfortNoiseGenerator::Compute(
124 bool saturated_capture,
125 rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
126 capture_spectrum,
127 rtc::ArrayView<FftData> lower_band_noise,
128 rtc::ArrayView<FftData> upper_band_noise) {
129 const auto& Y2 = capture_spectrum;
130
131 if (!saturated_capture) {
132 // Smooth Y2.
133 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
134 std::transform(Y2_smoothed_[ch].begin(), Y2_smoothed_[ch].end(),
135 Y2[ch].begin(), Y2_smoothed_[ch].begin(),
136 [](float a, float b) { return a + 0.1f * (b - a); });
137 }
138
139 if (N2_counter_ > 50) {
140 // Update N2 from Y2_smoothed.
141 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
142 std::transform(N2_[ch].begin(), N2_[ch].end(), Y2_smoothed_[ch].begin(),
143 N2_[ch].begin(), [](float a, float b) {
144 return b < a ? (0.9f * b + 0.1f * a) * 1.0002f
145 : a * 1.0002f;
146 });
147 }
148 }
149
150 if (N2_initial_) {
151 if (++N2_counter_ == 1000) {
152 N2_initial_.reset();
153 } else {
154 // Compute the N2_initial from N2.
155 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
156 std::transform(N2_[ch].begin(), N2_[ch].end(),
157 (*N2_initial_)[ch].begin(), (*N2_initial_)[ch].begin(),
158 [](float a, float b) {
159 return a > b ? b + 0.001f * (a - b) : a;
160 });
161 }
162 }
163 }
164
165 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
166 for (auto& n : N2_[ch]) {
167 n = std::max(n, noise_floor_);
168 }
169 if (N2_initial_) {
170 for (auto& n : (*N2_initial_)[ch]) {
171 n = std::max(n, noise_floor_);
172 }
173 }
174 }
175 }
176
177 // Choose N2 estimate to use.
178 const auto& N2 = N2_initial_ ? (*N2_initial_) : N2_;
179
180 for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
181 GenerateComfortNoise(optimization_, N2[ch], &seed_, &lower_band_noise[ch],
182 &upper_band_noise[ch]);
183 }
184 }
185
186 } // namespace webrtc
187