• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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