Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: webrtc/modules/audio_processing/aec3/suppression_gain.cc

Issue 2980493002: Add adaptive notch filter to remove narrowband echo components in AEC3 (Closed)
Patch Set: Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/modules/audio_processing/aec3/suppression_gain.h" 11 #include "webrtc/modules/audio_processing/aec3/suppression_gain.h"
12 12
13 #include "webrtc/typedefs.h" 13 #include "webrtc/typedefs.h"
14 #if defined(WEBRTC_ARCH_X86_FAMILY) 14 #if defined(WEBRTC_ARCH_X86_FAMILY)
15 #include <emmintrin.h> 15 #include <emmintrin.h>
16 #endif 16 #endif
17 #include <math.h> 17 #include <math.h>
18 #include <algorithm> 18 #include <algorithm>
19 #include <functional> 19 #include <functional>
20 #include <numeric> 20 #include <numeric>
21 21
22 #include "webrtc/modules/audio_processing/aec3/vector_math.h" 22 #include "webrtc/modules/audio_processing/aec3/vector_math.h"
23 #include "webrtc/rtc_base/checks.h" 23 #include "webrtc/rtc_base/checks.h"
24 24
25 namespace webrtc { 25 namespace webrtc {
26 namespace { 26 namespace {
27 27
28 // Reduce gain to avoid narrow band echo leakage.
29 void NarrowBandAttenuation(int narrow_bin,
30 std::array<float, kFftLengthBy2Plus1>* gain) {
31 const int upper_bin =
32 std::min(narrow_bin + 6, static_cast<int>(kFftLengthBy2Plus1 - 1));
33 for (int k = std::max(0, narrow_bin - 6); k <= upper_bin; ++k) {
34 (*gain)[k] = std::min((*gain)[k], 0.001f);
35 }
36 }
37
28 // Adjust the gains according to the presence of known external filters. 38 // Adjust the gains according to the presence of known external filters.
29 void AdjustForExternalFilters(std::array<float, kFftLengthBy2Plus1>* gain) { 39 void AdjustForExternalFilters(std::array<float, kFftLengthBy2Plus1>* gain) {
30 // Limit the low frequency gains to avoid the impact of the high-pass filter 40 // Limit the low frequency gains to avoid the impact of the high-pass filter
31 // on the lower-frequency gain influencing the overall achieved gain. 41 // on the lower-frequency gain influencing the overall achieved gain.
32 (*gain)[0] = (*gain)[1] = std::min((*gain)[1], (*gain)[2]); 42 (*gain)[0] = (*gain)[1] = std::min((*gain)[1], (*gain)[2]);
33 43
34 // Limit the high frequency gains to avoid the impact of the anti-aliasing 44 // Limit the high frequency gains to avoid the impact of the anti-aliasing
35 // filter on the upper-frequency gains influencing the overall achieved 45 // filter on the upper-frequency gains influencing the overall achieved
36 // gain. TODO(peah): Update this when new anti-aliasing filters are 46 // gain. TODO(peah): Update this when new anti-aliasing filters are
37 // implemented. 47 // implemented.
38 constexpr size_t kAntiAliasingImpactLimit = (64 * 2000) / 8000; 48 constexpr size_t kAntiAliasingImpactLimit = (64 * 2000) / 8000;
39 const float min_upper_gain = (*gain)[kAntiAliasingImpactLimit]; 49 const float min_upper_gain = (*gain)[kAntiAliasingImpactLimit];
40 std::for_each( 50 std::for_each(
41 gain->begin() + kAntiAliasingImpactLimit, gain->end() - 1, 51 gain->begin() + kAntiAliasingImpactLimit, gain->end() - 1,
42 [min_upper_gain](float& a) { a = std::min(a, min_upper_gain); }); 52 [min_upper_gain](float& a) { a = std::min(a, min_upper_gain); });
43 (*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2Minus1]; 53 (*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2Minus1];
44 } 54 }
45 55
46 // Computes the gain to apply for the bands beyond the first band. 56 // Computes the gain to apply for the bands beyond the first band.
47 float UpperBandsGain( 57 float UpperBandsGain(
58 const RenderSignalAnalyzer& render_signal_analyzer,
48 bool saturated_echo, 59 bool saturated_echo,
49 const std::vector<std::vector<float>>& render, 60 const std::vector<std::vector<float>>& render,
50 const std::array<float, kFftLengthBy2Plus1>& low_band_gain) { 61 const std::array<float, kFftLengthBy2Plus1>& low_band_gain) {
51 RTC_DCHECK_LT(0, render.size()); 62 RTC_DCHECK_LT(0, render.size());
52 if (render.size() == 1) { 63 if (render.size() == 1) {
53 return 1.f; 64 return 1.f;
54 } 65 }
55 66
67 if (render_signal_analyzer.NarrowPeakBand() &&
ivoc 2017/07/11 11:06:50 I think it makes sense to store this in a temporar
peah-webrtc 2017/07/11 11:54:18 I changed it to a separate input argument. Unfortu
68 (*render_signal_analyzer.NarrowPeakBand() >
69 static_cast<int>(kFftLengthBy2Plus1 - 10))) {
70 return 0.001f;
71 }
72
56 constexpr size_t kLowBandGainLimit = kFftLengthBy2 / 2; 73 constexpr size_t kLowBandGainLimit = kFftLengthBy2 / 2;
57 const float gain_below_8_khz = *std::min_element( 74 const float gain_below_8_khz = *std::min_element(
58 low_band_gain.begin() + kLowBandGainLimit, low_band_gain.end()); 75 low_band_gain.begin() + kLowBandGainLimit, low_band_gain.end());
59 76
60 // Always attenuate the upper bands when there is saturated echo. 77 // Always attenuate the upper bands when there is saturated echo.
61 if (saturated_echo) { 78 if (saturated_echo) {
62 return std::min(0.001f, gain_below_8_khz); 79 return std::min(0.001f, gain_below_8_khz);
63 } 80 }
64 81
65 // Compute the upper and lower band energies. 82 // Compute the upper and lower band energies.
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 for (size_t k = 1; k < gain.size() - 1; ++k) { 203 for (size_t k = 1; k < gain.size() - 1; ++k) {
187 (*masker)[k] += 0.1f * (side_band_masker[k - 1] + side_band_masker[k + 1]); 204 (*masker)[k] += 0.1f * (side_band_masker[k - 1] + side_band_masker[k + 1]);
188 } 205 }
189 } 206 }
190 207
191 } // namespace 208 } // namespace
192 209
193 // TODO(peah): Add further optimizations, in particular for the divisions. 210 // TODO(peah): Add further optimizations, in particular for the divisions.
194 void SuppressionGain::LowerBandGain( 211 void SuppressionGain::LowerBandGain(
195 bool low_noise_render, 212 bool low_noise_render,
213 const RenderSignalAnalyzer& render_signal_analyzer,
196 bool saturated_echo, 214 bool saturated_echo,
197 const std::array<float, kFftLengthBy2Plus1>& nearend, 215 const std::array<float, kFftLengthBy2Plus1>& nearend,
198 const std::array<float, kFftLengthBy2Plus1>& echo, 216 const std::array<float, kFftLengthBy2Plus1>& echo,
199 const std::array<float, kFftLengthBy2Plus1>& comfort_noise, 217 const std::array<float, kFftLengthBy2Plus1>& comfort_noise,
200 std::array<float, kFftLengthBy2Plus1>* gain) { 218 std::array<float, kFftLengthBy2Plus1>* gain) {
201 // Count the number of blocks since saturation. 219 // Count the number of blocks since saturation.
202 no_saturation_counter_ = saturated_echo ? 0 : no_saturation_counter_ + 1; 220 no_saturation_counter_ = saturated_echo ? 0 : no_saturation_counter_ + 1;
203 221
204 // Precompute 1/echo (note that when the echo is zero, the precomputed value 222 // Precompute 1/echo (note that when the echo is zero, the precomputed value
205 // is never used). 223 // is never used).
(...skipping 25 matching lines...) Expand all
231 249
232 // Iteratively compute the gain required to attenuate the echo to a non 250 // Iteratively compute the gain required to attenuate the echo to a non
233 // noticeable level. 251 // noticeable level.
234 gain->fill(0.f); 252 gain->fill(0.f);
235 for (int k = 0; k < 2; ++k) { 253 for (int k = 0; k < 2; ++k) {
236 std::array<float, kFftLengthBy2Plus1> masker; 254 std::array<float, kFftLengthBy2Plus1> masker;
237 MaskingPower(nearend, comfort_noise, last_masker_, *gain, &masker); 255 MaskingPower(nearend, comfort_noise, last_masker_, *gain, &masker);
238 GainToNoAudibleEcho(low_noise_render, saturated_echo, nearend, echo, masker, 256 GainToNoAudibleEcho(low_noise_render, saturated_echo, nearend, echo, masker,
239 min_gain, max_gain, one_by_echo, gain); 257 min_gain, max_gain, one_by_echo, gain);
240 AdjustForExternalFilters(gain); 258 AdjustForExternalFilters(gain);
259 if (render_signal_analyzer.NarrowPeakBand()) {
260 NarrowBandAttenuation(*render_signal_analyzer.NarrowPeakBand(), gain);
261 }
241 } 262 }
242 263
243 // Update the allowed maximum gain increase. 264 // Update the allowed maximum gain increase.
244 UpdateMaxGainIncrease(no_saturation_counter_, low_noise_render, last_echo_, 265 UpdateMaxGainIncrease(no_saturation_counter_, low_noise_render, last_echo_,
245 echo, last_gain_, *gain, &gain_increase_); 266 echo, last_gain_, *gain, &gain_increase_);
246 267
247 // Store data required for the gain computation of the next block. 268 // Store data required for the gain computation of the next block.
248 std::copy(echo.begin(), echo.end(), last_echo_.begin()); 269 std::copy(echo.begin(), echo.end(), last_echo_.begin());
249 std::copy(gain->begin(), gain->end(), last_gain_.begin()); 270 std::copy(gain->begin(), gain->end(), last_gain_.begin());
250 MaskingPower(nearend, comfort_noise, last_masker_, *gain, &last_masker_); 271 MaskingPower(nearend, comfort_noise, last_masker_, *gain, &last_masker_);
251 aec3::VectorMath(optimization_).Sqrt(*gain); 272 aec3::VectorMath(optimization_).Sqrt(*gain);
252 } 273 }
253 274
254 SuppressionGain::SuppressionGain(Aec3Optimization optimization) 275 SuppressionGain::SuppressionGain(Aec3Optimization optimization)
255 : optimization_(optimization) { 276 : optimization_(optimization) {
256 last_gain_.fill(1.f); 277 last_gain_.fill(1.f);
257 last_masker_.fill(0.f); 278 last_masker_.fill(0.f);
258 gain_increase_.fill(1.f); 279 gain_increase_.fill(1.f);
259 last_echo_.fill(0.f); 280 last_echo_.fill(0.f);
260 } 281 }
261 282
262 void SuppressionGain::GetGain( 283 void SuppressionGain::GetGain(
263 const std::array<float, kFftLengthBy2Plus1>& nearend, 284 const std::array<float, kFftLengthBy2Plus1>& nearend,
264 const std::array<float, kFftLengthBy2Plus1>& echo, 285 const std::array<float, kFftLengthBy2Plus1>& echo,
265 const std::array<float, kFftLengthBy2Plus1>& comfort_noise, 286 const std::array<float, kFftLengthBy2Plus1>& comfort_noise,
287 const RenderSignalAnalyzer& render_signal_analyzer,
ivoc 2017/07/11 11:06:50 This object is passed around a lot, but it seems l
peah-webrtc 2017/07/11 11:54:18 Good point! I changed the code along that, but as
266 bool saturated_echo, 288 bool saturated_echo,
267 const std::vector<std::vector<float>>& render, 289 const std::vector<std::vector<float>>& render,
268 bool force_zero_gain, 290 bool force_zero_gain,
269 float* high_bands_gain, 291 float* high_bands_gain,
270 std::array<float, kFftLengthBy2Plus1>* low_band_gain) { 292 std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
271 RTC_DCHECK(high_bands_gain); 293 RTC_DCHECK(high_bands_gain);
272 RTC_DCHECK(low_band_gain); 294 RTC_DCHECK(low_band_gain);
273 295
274 if (force_zero_gain) { 296 if (force_zero_gain) {
275 last_gain_.fill(0.f); 297 last_gain_.fill(0.f);
276 std::copy(comfort_noise.begin(), comfort_noise.end(), last_masker_.begin()); 298 std::copy(comfort_noise.begin(), comfort_noise.end(), last_masker_.begin());
277 low_band_gain->fill(0.f); 299 low_band_gain->fill(0.f);
278 gain_increase_.fill(1.f); 300 gain_increase_.fill(1.f);
279 *high_bands_gain = 0.f; 301 *high_bands_gain = 0.f;
280 return; 302 return;
281 } 303 }
282 304
283 bool low_noise_render = low_render_detector_.Detect(render); 305 bool low_noise_render = low_render_detector_.Detect(render);
284 306
285 // Compute gain for the lower band. 307 // Compute gain for the lower band.
286 LowerBandGain(low_noise_render, saturated_echo, nearend, echo, comfort_noise, 308 LowerBandGain(low_noise_render, render_signal_analyzer, saturated_echo,
287 low_band_gain); 309 nearend, echo, comfort_noise, low_band_gain);
288 310
289 // Compute the gain for the upper bands. 311 // Compute the gain for the upper bands.
290 *high_bands_gain = UpperBandsGain(saturated_echo, render, *low_band_gain); 312 *high_bands_gain = UpperBandsGain(render_signal_analyzer, saturated_echo,
313 render, *low_band_gain);
291 } 314 }
292 315
293 // Detects when the render signal can be considered to have low power and 316 // Detects when the render signal can be considered to have low power and
294 // consist of stationary noise. 317 // consist of stationary noise.
295 bool SuppressionGain::LowNoiseRenderDetector::Detect( 318 bool SuppressionGain::LowNoiseRenderDetector::Detect(
296 const std::vector<std::vector<float>>& render) { 319 const std::vector<std::vector<float>>& render) {
297 float x2_sum = 0.f; 320 float x2_sum = 0.f;
298 float x2_max = 0.f; 321 float x2_max = 0.f;
299 for (auto x_k : render[0]) { 322 for (auto x_k : render[0]) {
300 const float x2 = x_k * x_k; 323 const float x2 = x_k * x_k;
301 x2_sum += x2; 324 x2_sum += x2;
302 x2_max = std::max(x2_max, x2); 325 x2_max = std::max(x2_max, x2);
303 } 326 }
304 327
305 constexpr float kThreshold = 50.f * 50.f * 64.f; 328 constexpr float kThreshold = 50.f * 50.f * 64.f;
306 const bool low_noise_render = 329 const bool low_noise_render =
307 average_power_ < kThreshold && x2_max < 3 * average_power_; 330 average_power_ < kThreshold && x2_max < 3 * average_power_;
308 average_power_ = average_power_ * 0.9f + x2_sum * 0.1f; 331 average_power_ = average_power_ * 0.9f + x2_sum * 0.1f;
309 return low_noise_render; 332 return low_noise_render;
310 } 333 }
311 334
312 } // namespace webrtc 335 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698