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 #include "typedefs.h"  // NOLINT(build/include)
14 #if defined(WEBRTC_ARCH_X86_FAMILY)
15 #include <emmintrin.h>
16 #endif
17 #include <math.h>
18 #include <algorithm>
19 #include <array>
20 #include <functional>
21 #include <numeric>
22 
23 #include "common_audio/signal_processing/include/signal_processing_library.h"
24 
25 namespace webrtc {
26 
27 namespace {
28 
29 // Creates an array of uniformly distributed variables.
TableRandomValue(int16_t * vector,int16_t vector_length,uint32_t * seed)30 void TableRandomValue(int16_t* vector, int16_t vector_length, uint32_t* seed) {
31   for (int i = 0; i < vector_length; i++) {
32     seed[0] = (seed[0] * ((int32_t)69069) + 1) & (0x80000000 - 1);
33     vector[i] = (int16_t)(seed[0] >> 16);
34   }
35 }
36 
37 }  // namespace
38 
39 namespace aec3 {
40 
41 #if defined(WEBRTC_ARCH_X86_FAMILY)
42 
EstimateComfortNoise_SSE2(const std::array<float,kFftLengthBy2Plus1> & N2,uint32_t * seed,FftData * lower_band_noise,FftData * upper_band_noise)43 void EstimateComfortNoise_SSE2(const std::array<float, kFftLengthBy2Plus1>& N2,
44                                uint32_t* seed,
45                                FftData* lower_band_noise,
46                                FftData* upper_band_noise) {
47   FftData* N_low = lower_band_noise;
48   FftData* N_high = upper_band_noise;
49 
50   // Compute square root spectrum.
51   std::array<float, kFftLengthBy2Plus1> N;
52   for (size_t k = 0; k < kFftLengthBy2; k += 4) {
53     __m128 v = _mm_loadu_ps(&N2[k]);
54     v = _mm_sqrt_ps(v);
55     _mm_storeu_ps(&N[k], v);
56   }
57 
58   N[kFftLengthBy2] = sqrtf(N2[kFftLengthBy2]);
59 
60   // Compute the noise level for the upper bands.
61   constexpr float kOneByNumBands = 1.f / (kFftLengthBy2Plus1 / 2 + 1);
62   constexpr int kFftLengthBy2Plus1By2 = kFftLengthBy2Plus1 / 2;
63   const float high_band_noise_level =
64       std::accumulate(N.begin() + kFftLengthBy2Plus1By2, N.end(), 0.f) *
65       kOneByNumBands;
66 
67   // Generate complex noise.
68   std::array<int16_t, kFftLengthBy2 - 1> random_values_int;
69   TableRandomValue(random_values_int.data(), random_values_int.size(), seed);
70 
71   std::array<float, kFftLengthBy2 - 1> sin;
72   std::array<float, kFftLengthBy2 - 1> cos;
73   constexpr float kScale = 6.28318530717959f / 32768.0f;
74   std::transform(random_values_int.begin(), random_values_int.end(),
75                  sin.begin(), [&](int16_t a) { return -sinf(kScale * a); });
76   std::transform(random_values_int.begin(), random_values_int.end(),
77                  cos.begin(), [&](int16_t a) { return cosf(kScale * a); });
78 
79   // Form low-frequency noise via spectral shaping.
80   N_low->re[0] = N_low->re[kFftLengthBy2] = N_high->re[0] =
81       N_high->re[kFftLengthBy2] = 0.f;
82   std::transform(cos.begin(), cos.end(), N.begin() + 1, N_low->re.begin() + 1,
83                  std::multiplies<float>());
84   std::transform(sin.begin(), sin.end(), N.begin() + 1, N_low->im.begin() + 1,
85                  std::multiplies<float>());
86 
87   // Form the high-frequency noise via simple levelling.
88   std::transform(cos.begin(), cos.end(), N_high->re.begin() + 1,
89                  [&](float a) { return high_band_noise_level * a; });
90   std::transform(sin.begin(), sin.end(), N_high->im.begin() + 1,
91                  [&](float a) { return high_band_noise_level * a; });
92 }
93 
94 #endif
95 
EstimateComfortNoise(const std::array<float,kFftLengthBy2Plus1> & N2,uint32_t * seed,FftData * lower_band_noise,FftData * upper_band_noise)96 void EstimateComfortNoise(const std::array<float, kFftLengthBy2Plus1>& N2,
97                           uint32_t* seed,
98                           FftData* lower_band_noise,
99                           FftData* upper_band_noise) {
100   FftData* N_low = lower_band_noise;
101   FftData* N_high = upper_band_noise;
102 
103   // Compute square root spectrum.
104   std::array<float, kFftLengthBy2Plus1> N;
105   std::transform(N2.begin(), N2.end(), N.begin(),
106                  [](float a) { return sqrtf(a); });
107 
108   // Compute the noise level for the upper bands.
109   constexpr float kOneByNumBands = 1.f / (kFftLengthBy2Plus1 / 2 + 1);
110   constexpr int kFftLengthBy2Plus1By2 = kFftLengthBy2Plus1 / 2;
111   const float high_band_noise_level =
112       std::accumulate(N.begin() + kFftLengthBy2Plus1By2, N.end(), 0.f) *
113       kOneByNumBands;
114 
115   // Generate complex noise.
116   std::array<int16_t, kFftLengthBy2 - 1> random_values_int;
117   TableRandomValue(random_values_int.data(), random_values_int.size(), seed);
118 
119   std::array<float, kFftLengthBy2 - 1> sin;
120   std::array<float, kFftLengthBy2 - 1> cos;
121   constexpr float kScale = 6.28318530717959f / 32768.0f;
122   std::transform(random_values_int.begin(), random_values_int.end(),
123                  sin.begin(), [&](int16_t a) { return -sinf(kScale * a); });
124   std::transform(random_values_int.begin(), random_values_int.end(),
125                  cos.begin(), [&](int16_t a) { return cosf(kScale * a); });
126 
127   // Form low-frequency noise via spectral shaping.
128   N_low->re[0] = N_low->re[kFftLengthBy2] = N_high->re[0] =
129       N_high->re[kFftLengthBy2] = 0.f;
130   std::transform(cos.begin(), cos.end(), N.begin() + 1, N_low->re.begin() + 1,
131                  std::multiplies<float>());
132   std::transform(sin.begin(), sin.end(), N.begin() + 1, N_low->im.begin() + 1,
133                  std::multiplies<float>());
134 
135   // Form the high-frequency noise via simple levelling.
136   std::transform(cos.begin(), cos.end(), N_high->re.begin() + 1,
137                  [&](float a) { return high_band_noise_level * a; });
138   std::transform(sin.begin(), sin.end(), N_high->im.begin() + 1,
139                  [&](float a) { return high_band_noise_level * a; });
140 }
141 
142 }  // namespace aec3
143 
ComfortNoiseGenerator(Aec3Optimization optimization)144 ComfortNoiseGenerator::ComfortNoiseGenerator(Aec3Optimization optimization)
145     : optimization_(optimization),
146       seed_(42),
147       N2_initial_(new std::array<float, kFftLengthBy2Plus1>()) {
148   N2_initial_->fill(0.f);
149   Y2_smoothed_.fill(0.f);
150   N2_.fill(1.0e6f);
151 }
152 
153 ComfortNoiseGenerator::~ComfortNoiseGenerator() = default;
154 
Compute(const AecState & aec_state,const std::array<float,kFftLengthBy2Plus1> & capture_spectrum,FftData * lower_band_noise,FftData * upper_band_noise)155 void ComfortNoiseGenerator::Compute(
156     const AecState& aec_state,
157     const std::array<float, kFftLengthBy2Plus1>& capture_spectrum,
158     FftData* lower_band_noise,
159     FftData* upper_band_noise) {
160   RTC_DCHECK(lower_band_noise);
161   RTC_DCHECK(upper_band_noise);
162   const auto& Y2 = capture_spectrum;
163 
164   if (!aec_state.SaturatedCapture()) {
165     // Smooth Y2.
166     std::transform(Y2_smoothed_.begin(), Y2_smoothed_.end(), Y2.begin(),
167                    Y2_smoothed_.begin(),
168                    [](float a, float b) { return a + 0.1f * (b - a); });
169 
170     if (N2_counter_ > 50) {
171       // Update N2 from Y2_smoothed.
172       std::transform(N2_.begin(), N2_.end(), Y2_smoothed_.begin(), N2_.begin(),
173                      [](float a, float b) {
174                        return b < a ? (0.9f * b + 0.1f * a) * 1.0002f
175                                     : a * 1.0002f;
176                      });
177     }
178 
179     if (N2_initial_) {
180       if (++N2_counter_ == 1000) {
181         N2_initial_.reset();
182       } else {
183         // Compute the N2_initial from N2.
184         std::transform(
185             N2_.begin(), N2_.end(), N2_initial_->begin(), N2_initial_->begin(),
186             [](float a, float b) { return a > b ? b + 0.001f * (a - b) : a; });
187       }
188     }
189   }
190 
191   // Limit the noise to a floor of -96 dBFS.
192   constexpr float kNoiseFloor = 440.f;
193   for (auto& n : N2_) {
194     n = std::max(n, kNoiseFloor);
195   }
196   if (N2_initial_) {
197     for (auto& n : *N2_initial_) {
198       n = std::max(n, kNoiseFloor);
199     }
200   }
201 
202   // Choose N2 estimate to use.
203   const std::array<float, kFftLengthBy2Plus1>& N2 =
204       N2_initial_ ? *N2_initial_ : N2_;
205 
206   switch (optimization_) {
207 #if defined(WEBRTC_ARCH_X86_FAMILY)
208     case Aec3Optimization::kSse2:
209       aec3::EstimateComfortNoise_SSE2(N2, &seed_, lower_band_noise,
210                                       upper_band_noise);
211       break;
212 #endif
213     default:
214       aec3::EstimateComfortNoise(N2, &seed_, lower_band_noise,
215                                  upper_band_noise);
216   }
217 }
218 
219 }  // namespace webrtc
220