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

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

Issue 2886733002: Transparency increasing tuning for AEC3 (Closed)
Patch Set: Created 3 years, 7 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/base/checks.h" 22 #include "webrtc/base/checks.h"
23 #include "webrtc/modules/audio_processing/aec3/vector_math.h" 23 #include "webrtc/modules/audio_processing/aec3/vector_math.h"
24 24
25 namespace webrtc { 25 namespace webrtc {
26 namespace { 26 namespace {
27 27
28 void GainPostProcessing(std::array<float, kFftLengthBy2Plus1>* gain_squared) { 28 // Adjust the gains according to the presense of known external filters.
ivoc 2017/05/22 14:58:00 I think it should be "presence".
peah-webrtc 2017/05/22 21:52:47 Done.
29 void AdjustForExternalFilters(std::array<float, kFftLengthBy2Plus1>* gain) {
29 // Limit the low frequency gains to avoid the impact of the high-pass filter 30 // Limit the low frequency gains to avoid the impact of the high-pass filter
30 // on the lower-frequency gain influencing the overall achieved gain. 31 // on the lower-frequency gain influencing the overall achieved gain.
31 (*gain_squared)[1] = std::min((*gain_squared)[1], (*gain_squared)[2]); 32 (*gain)[0] = (*gain)[1] = std::min((*gain)[1], (*gain)[2]);
32 (*gain_squared)[0] = (*gain_squared)[1];
33 33
34 // Limit the high frequency gains to avoid the impact of the anti-aliasing 34 // Limit the high frequency gains to avoid the impact of the anti-aliasing
35 // filter on the upper-frequency gains influencing the overall achieved 35 // filter on the upper-frequency gains influencing the overall achieved
36 // gain. TODO(peah): Update this when new anti-aliasing filters are 36 // gain. TODO(peah): Update this when new anti-aliasing filters are
37 // implemented. 37 // implemented.
38 constexpr size_t kAntiAliasingImpactLimit = (64 * 2000) / 8000; 38 constexpr size_t kAntiAliasingImpactLimit = (64 * 2000) / 8000;
39 std::for_each(gain_squared->begin() + kAntiAliasingImpactLimit, 39 const float min_upper_gain = (*gain)[kAntiAliasingImpactLimit];
40 gain_squared->end() - 1, 40 std::for_each(
41 [gain_squared, kAntiAliasingImpactLimit](float& a) { 41 gain->begin() + kAntiAliasingImpactLimit, gain->end() - 1,
42 a = std::min(a, (*gain_squared)[kAntiAliasingImpactLimit]); 42 [min_upper_gain](float& a) { a = std::min(a, min_upper_gain); });
43 }); 43 (*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2Minus1];
44 (*gain_squared)[kFftLengthBy2] = (*gain_squared)[kFftLengthBy2Minus1]; 44 }
45 } 45
46 46 // Computes the gain to apply for the bands beyond the first band.
47 constexpr int kNumIterations = 2; 47 float UpperBandsGain(
48 constexpr float kEchoMaskingMargin = 1.f / 20.f; 48 bool saturated_echo,
49 constexpr float kBandMaskingFactor = 1.f / 10.f; 49 const std::vector<std::vector<float>>& render,
50 constexpr float kTimeMaskingFactor = 1.f / 10.f; 50 const std::array<float, kFftLengthBy2Plus1>& low_band_gain) {
51
52 // TODO(peah): Add further optimizations, in particular for the divisions.
53 void ComputeGains(
54 Aec3Optimization optimization,
55 const std::array<float, kFftLengthBy2Plus1>& nearend_power,
56 const std::array<float, kFftLengthBy2Plus1>& residual_echo_power,
57 const std::array<float, kFftLengthBy2Plus1>& comfort_noise_power,
58 float strong_nearend_margin,
59 std::array<float, kFftLengthBy2Minus1>* previous_gain_squared,
60 std::array<float, kFftLengthBy2Minus1>* previous_masker,
61 std::array<float, kFftLengthBy2Plus1>* gain) {
62 std::array<float, kFftLengthBy2Minus1> masker;
63 std::array<float, kFftLengthBy2Minus1> same_band_masker;
64 std::array<float, kFftLengthBy2Minus1> one_by_residual_echo_power;
65 std::array<bool, kFftLengthBy2Minus1> strong_nearend;
66 std::array<float, kFftLengthBy2Plus1> neighboring_bands_masker;
67 std::array<float, kFftLengthBy2Plus1>* gain_squared = gain;
68 aec3::VectorMath math(optimization);
69
70 // Precompute 1/residual_echo_power.
71 std::transform(residual_echo_power.begin() + 1, residual_echo_power.end() - 1,
72 one_by_residual_echo_power.begin(),
73 [](float a) { return a > 0.f ? 1.f / a : -1.f; });
74
75 // Precompute indicators for bands with strong nearend.
76 std::transform(
77 residual_echo_power.begin() + 1, residual_echo_power.end() - 1,
78 nearend_power.begin() + 1, strong_nearend.begin(),
79 [&](float a, float b) { return a <= strong_nearend_margin * b; });
80
81 // Precompute masker for the same band.
82 std::transform(comfort_noise_power.begin() + 1, comfort_noise_power.end() - 1,
83 previous_masker->begin(), same_band_masker.begin(),
84 [&](float a, float b) { return a + kTimeMaskingFactor * b; });
85
86 for (int k = 0; k < kNumIterations; ++k) {
87 if (k == 0) {
88 // Add masker from the same band.
89 std::copy(same_band_masker.begin(), same_band_masker.end(),
90 masker.begin());
91 } else {
92 // Add masker for neighboring bands.
93 math.Multiply(nearend_power, *gain_squared, neighboring_bands_masker);
94 math.Accumulate(comfort_noise_power, neighboring_bands_masker);
95 std::transform(
96 neighboring_bands_masker.begin(), neighboring_bands_masker.end() - 2,
97 neighboring_bands_masker.begin() + 2, masker.begin(),
98 [&](float a, float b) { return kBandMaskingFactor * (a + b); });
99
100 // Add masker from the same band.
101 math.Accumulate(same_band_masker, masker);
102 }
103
104 // Compute new gain as:
105 // G2(t,f) = (comfort_noise_power(t,f) + G2(t-1)*nearend_power(t-1)) *
106 // kTimeMaskingFactor
107 // * kEchoMaskingMargin / residual_echo_power(t,f).
108 // or
109 // G2(t,f) = ((comfort_noise_power(t,f) + G2(t-1) *
110 // nearend_power(t-1)) * kTimeMaskingFactor +
111 // (comfort_noise_power(t, f-1) + comfort_noise_power(t, f+1) +
112 // (G2(t,f-1)*nearend_power(t, f-1) +
113 // G2(t,f+1)*nearend_power(t, f+1)) *
114 // kTimeMaskingFactor) * kBandMaskingFactor)
115 // * kEchoMaskingMargin / residual_echo_power(t,f).
116 std::transform(
117 masker.begin(), masker.end(), one_by_residual_echo_power.begin(),
118 gain_squared->begin() + 1, [&](float a, float b) {
119 return b >= 0 ? std::min(kEchoMaskingMargin * a * b, 1.f) : 1.f;
120 });
121
122 // Limit gain for bands with strong nearend.
123 std::transform(gain_squared->begin() + 1, gain_squared->end() - 1,
124 strong_nearend.begin(), gain_squared->begin() + 1,
125 [](float a, bool b) { return b ? 1.f : a; });
126
127 // Limit the allowed gain update over time.
128 std::transform(gain_squared->begin() + 1, gain_squared->end() - 1,
129 previous_gain_squared->begin(), gain_squared->begin() + 1,
130 [](float a, float b) {
131 return b < 0.001f ? std::min(a, 0.001f)
132 : std::min(a, b * 2.f);
133 });
134
135 // Process the gains to avoid artefacts caused by gain realization in the
136 // filterbank and impact of external pre-processing of the signal.
137 GainPostProcessing(gain_squared);
138 }
139
140 std::copy(gain_squared->begin() + 1, gain_squared->end() - 1,
141 previous_gain_squared->begin());
142
143 math.Multiply(
144 rtc::ArrayView<const float>(&(*gain_squared)[1], previous_masker->size()),
145 rtc::ArrayView<const float>(&nearend_power[1], previous_masker->size()),
146 *previous_masker);
147 math.Accumulate(rtc::ArrayView<const float>(&comfort_noise_power[1],
148 previous_masker->size()),
149 *previous_masker);
150 math.Sqrt(*gain);
151 }
152
153 } // namespace
154
155 // Computes an upper bound on the gain to apply for high frequencies.
156 float HighFrequencyGainBound(bool saturated_echo,
157 const std::vector<std::vector<float>>& render) {
158 if (render.size() == 1) { 51 if (render.size() == 1) {
ivoc 2017/05/22 14:58:00 Should there be a DHECK for render.size() > 0?
peah-webrtc 2017/05/22 21:52:47 Good point! Done.
159 return 1.f; 52 return 1.f;
160 } 53 }
161 54
55 const float gain_below_8_khz =
56 *std::min_element(low_band_gain.begin() + 32, low_band_gain.end());
ivoc 2017/05/22 14:58:00 I think the constant (32) should be derived from k
peah-webrtc 2017/05/22 21:52:47 Done.
57
162 // Always attenuate the upper bands when there is saturated echo. 58 // Always attenuate the upper bands when there is saturated echo.
163 if (saturated_echo) { 59 if (saturated_echo) {
164 return 0.001f; 60 return std::min(0.001f, gain_below_8_khz);
165 } 61 }
166 62
167 // Compute the upper and lower band energies. 63 // Compute the upper and lower band energies.
168 float low_band_energy = 64 auto sum_of_squares = [](float a, float b) { return a + b * b; };
aleloi 2017/05/22 20:41:45 const auto
peah-webrtc 2017/05/22 21:52:47 Done.
169 std::accumulate(render[0].begin(), render[0].end(), 0.f, 65 const float low_band_energy =
170 [](float a, float b) -> float { return a + b * b; }); 66 std::accumulate(render[0].begin(), render[0].end(), 0.f, sum_of_squares);
171 float high_band_energies = 0.f; 67 float high_band_energy = 0.f;
172 for (size_t k = 1; k < render.size(); ++k) { 68 for (size_t k = 1; k < render.size(); ++k) {
173 high_band_energies = std::max( 69 const float energy = std::accumulate(render[k].begin(), render[k].end(),
174 high_band_energies, 70 0.f, sum_of_squares);
175 std::accumulate(render[k].begin(), render[k].end(), 0.f, 71 high_band_energy = std::max(high_band_energy, energy);
176 [](float a, float b) -> float { return a + b * b; }));
177 } 72 }
178 73
179 // If there is more power in the lower frequencies than the upper frequencies, 74 // If there is more power in the lower frequencies than the upper frequencies,
180 // or if the power in upper frequencies is low, do not bound the gain in the 75 // or if the power in upper frequencies is low, do not bound the gain in the
181 // upper bands. 76 // upper bands.
182 if (high_band_energies < low_band_energy || 77 float anti_howling_gain;
183 high_band_energies < kSubBlockSize * 10.f * 10.f) { 78 constexpr float kThreshold = kSubBlockSize * 10.f * 10.f;
184 return 1.f; 79 if (high_band_energy < std::max(low_band_energy, kThreshold)) {
185 } 80 anti_howling_gain = 1.f;
186 81 } else {
187 // In all other cases, bound the gain for upper frequencies. 82 // In all other cases, bound the gain for upper frequencies.
188 RTC_DCHECK_LE(low_band_energy, high_band_energies); 83 RTC_DCHECK_LE(low_band_energy, high_band_energy);
189 return 0.01f * sqrtf(low_band_energy / high_band_energies); 84 RTC_DCHECK_NE(0.f, high_band_energy);
85 anti_howling_gain = 0.01f * sqrtf(low_band_energy / high_band_energy);
86 }
87
88 // Choose the gain as the minimum of the lower and upper gains.
89 return std::min(gain_below_8_khz, anti_howling_gain);
90 }
91
92 // Limits the gain increase.
93 void UpdateMaxGainIncrease(
94 size_t no_saturation_counter,
95 bool low_noise_render,
96 const std::array<float, kFftLengthBy2Plus1>& last_echo,
97 const std::array<float, kFftLengthBy2Plus1>& echo,
98 const std::array<float, kFftLengthBy2Plus1>& last_gain,
99 const std::array<float, kFftLengthBy2Plus1>& new_gain,
100 std::array<float, kFftLengthBy2Plus1>* gain_increase) {
101 float max_increasing;
102 float max_decreasing;
103 float rate_increasing;
104 float rate_decreasing;
105 float min_increasing;
106 float min_decreasing;
107
108 if (low_noise_render) {
109 max_increasing = 8.f;
110 max_decreasing = 8.f;
111 rate_increasing = 2.f;
112 rate_decreasing = 2.f;
113 min_increasing = 4.f;
114 min_decreasing = 4.f;
115 } else if (no_saturation_counter > 10) {
116 max_increasing = 4.f;
117 max_decreasing = 4.f;
118 rate_increasing = 2.f;
119 rate_decreasing = 2.f;
120 min_increasing = 1.2f;
121 min_decreasing = 2.f;
ivoc 2017/05/22 14:58:00 Just checking, is this 2.f correct or a typo? (it'
peah-webrtc 2017/05/22 21:52:47 No, it should be correct. The idea when there is s
122 } else {
123 max_increasing = 1.2f;
124 max_decreasing = 1.2f;
125 rate_increasing = 1.5f;
126 rate_decreasing = 1.5f;
127 min_increasing = 1.f;
128 min_decreasing = 1.f;
129 }
130
131 for (size_t k = 0; k < new_gain.size(); ++k) {
132 if (echo[k] > last_echo[k]) {
133 (*gain_increase)[k] =
134 new_gain[k] > last_gain[k]
135 ? std::min(max_increasing, (*gain_increase)[k] * rate_increasing)
136 : min_increasing;
137 } else {
138 (*gain_increase)[k] =
139 new_gain[k] > last_gain[k]
140 ? std::min(max_decreasing, (*gain_increase)[k] * rate_decreasing)
141 : min_decreasing;
142 }
143 }
144 }
145
146 // Computes the gain to reduce the echo to a non audible level.
147 void GainToNoAudibleEcho(
148 bool low_noise_render,
149 bool saturated_echo,
150 const std::array<float, kFftLengthBy2Plus1>& nearend,
151 const std::array<float, kFftLengthBy2Plus1>& echo,
152 const std::array<float, kFftLengthBy2Plus1>& masker,
153 const std::array<float, kFftLengthBy2Plus1>& min_gain,
154 const std::array<float, kFftLengthBy2Plus1>& max_gain,
155 const std::array<float, kFftLengthBy2Plus1>& one_by_echo,
156 std::array<float, kFftLengthBy2Plus1>* gain) {
157 constexpr float kEchoMaskingMargin = 1.f / 100.f;
158 const float echo_masking_margin =
159 low_noise_render ? 0.01f : kEchoMaskingMargin;
ivoc 2017/05/22 14:58:00 This seems to have no effect, kEchoMaskingMargin i
peah-webrtc 2017/05/22 21:52:47 Oups! Good find! Removed that. Done.
160 const float nearend_masking_margin =
161 low_noise_render ? 2.f : (saturated_echo ? 0.001f : 0.01f);
162
163 for (size_t k = 0; k < gain->size(); ++k) {
164 RTC_DCHECK_LE(0.f, nearend_masking_margin * nearend[k]);
165 if (echo[k] <= nearend_masking_margin * nearend[k]) {
166 (*gain)[k] = 1.f;
167 } else {
168 (*gain)[k] = echo_masking_margin * masker[k] * one_by_echo[k];
169 }
170
171 (*gain)[k] = std::min(std::max((*gain)[k], min_gain[k]), max_gain[k]);
172 }
173 }
174
175 // Computes the signal output power that masks the echo signal.
176 void MaskingPower(const std::array<float, kFftLengthBy2Plus1>& nearend,
177 const std::array<float, kFftLengthBy2Plus1>& comfort_noise,
178 const std::array<float, kFftLengthBy2Plus1>& last_masker,
179 const std::array<float, kFftLengthBy2Plus1>& gain,
180 std::array<float, kFftLengthBy2Plus1>* masker) {
181 std::array<float, kFftLengthBy2Plus1> side_band_masker;
182 for (size_t k = 0; k < gain.size(); ++k) {
183 side_band_masker[k] = nearend[k] * gain[k] + comfort_noise[k];
184 (*masker)[k] = comfort_noise[k] + 0.1f * last_masker[k];
185 }
186 for (size_t k = 1; k < gain.size() - 1; ++k) {
ivoc 2017/05/22 14:58:00 It's possible to merge this loop with the previous
peah-webrtc 2017/05/22 21:52:47 I considered that, but it makes the code somewhat
187 (*masker)[k] += 0.1f * (side_band_masker[k - 1] + side_band_masker[k + 1]);
188 }
189 }
190
191 } // namespace
192
193 // TODO(peah): Add further optimizations, in particular for the divisions.
194 void SuppressionGain::LowerBandGain(
195 bool low_noise_render,
196 bool saturated_echo,
197 const std::array<float, kFftLengthBy2Plus1>& nearend,
198 const std::array<float, kFftLengthBy2Plus1>& echo,
199 const std::array<float, kFftLengthBy2Plus1>& comfort_noise,
200 std::array<float, kFftLengthBy2Plus1>* gain) {
201 // Count the number of blocks since saturation.
202 no_saturation_counter_ = saturated_echo ? 0 : no_saturation_counter_ + 1;
203
204 // Precompute 1/echo.
205 std::array<float, kFftLengthBy2Plus1> one_by_echo;
206 std::transform(echo.begin(), echo.end(), one_by_echo.begin(),
207 [](float a) { return a > 0.f ? 1.f / a : 1.f; });
ivoc 2017/05/22 14:58:00 Why is the default value 1.f? Doesn't that introdu
aleloi 2017/05/22 20:41:45 Another related issue: perhaps we should avoid div
peah-webrtc 2017/05/22 21:52:47 This is not as big a problem as it may seem. If 1/
peah-webrtc 2017/05/22 21:52:47 To avoid that we should have one_by_echo=inf if a
208
209 // Compute the minimum gain as the attenuating gain to put the signal just
210 // above the zero sample values.
211 std::array<float, kFftLengthBy2Plus1> min_gain;
212 const float min_echo_power = low_noise_render ? 192.f : 64.f;
213 if (no_saturation_counter_ > 10) {
214 for (size_t k = 0; k < nearend.size(); ++k) {
215 const float denom = std::min(nearend[k], echo[k]);
216 min_gain[k] = denom > 0.f ? min_echo_power / denom : 1.f;
217 min_gain[k] = std::min(min_gain[k], 1.f);
218 }
219 } else {
220 min_gain.fill(0.f);
221 }
222
223 // Compute the maximum gain by limiting the gain increase from the previous
224 // gain.
225 std::array<float, kFftLengthBy2Plus1> max_gain;
226 for (size_t k = 0; k < gain->size(); ++k) {
227 max_gain[k] =
228 std::min(std::max(last_gain_[k] * gain_increase_[k], 0.001f), 1.f);
229 }
230
231 // Iteratively compute the gain required to attenuate the echo to a non
232 // noticeable level.
233 gain->fill(0.f);
234 for (int k = 0; k < 2; ++k) {
235 std::array<float, kFftLengthBy2Plus1> masker;
236 MaskingPower(nearend, comfort_noise, last_masker_, *gain, &masker);
237 GainToNoAudibleEcho(low_noise_render, saturated_echo, nearend, echo, masker,
238 min_gain, max_gain, one_by_echo, gain);
239 AdjustForExternalFilters(gain);
240 }
241
242 // Update the allowed maximum gain increase.
243 UpdateMaxGainIncrease(no_saturation_counter_, low_noise_render, last_echo_,
244 echo, last_gain_, *gain, &gain_increase_);
245
246 // Store data required for the gain computation of the next block.
247 std::copy(echo.begin(), echo.end(), last_echo_.begin());
248 std::copy(gain->begin(), gain->end(), last_gain_.begin());
249 MaskingPower(nearend, comfort_noise, last_masker_, *gain, &last_masker_);
250 aec3::VectorMath(optimization_).Sqrt(*gain);
190 } 251 }
191 252
192 SuppressionGain::SuppressionGain(Aec3Optimization optimization) 253 SuppressionGain::SuppressionGain(Aec3Optimization optimization)
193 : optimization_(optimization) { 254 : optimization_(optimization) {
194 previous_gain_squared_.fill(1.f); 255 last_gain_.fill(1.f);
195 previous_masker_.fill(0.f); 256 last_masker_.fill(0.f);
257 gain_increase_.fill(1.f);
196 } 258 }
197 259
198 void SuppressionGain::GetGain( 260 void SuppressionGain::GetGain(
199 const std::array<float, kFftLengthBy2Plus1>& nearend_power, 261 const std::array<float, kFftLengthBy2Plus1>& nearend,
200 const std::array<float, kFftLengthBy2Plus1>& residual_echo_power, 262 const std::array<float, kFftLengthBy2Plus1>& echo,
201 const std::array<float, kFftLengthBy2Plus1>& comfort_noise_power, 263 const std::array<float, kFftLengthBy2Plus1>& comfort_noise,
202 bool saturated_echo, 264 bool saturated_echo,
203 const std::vector<std::vector<float>>& render, 265 const std::vector<std::vector<float>>& render,
204 size_t num_capture_bands,
205 bool force_zero_gain, 266 bool force_zero_gain,
206 float* high_bands_gain, 267 float* high_bands_gain,
207 std::array<float, kFftLengthBy2Plus1>* low_band_gain) { 268 std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
208 RTC_DCHECK(high_bands_gain); 269 RTC_DCHECK(high_bands_gain);
209 RTC_DCHECK(low_band_gain); 270 RTC_DCHECK(low_band_gain);
210 271
211 if (force_zero_gain) { 272 if (force_zero_gain) {
212 previous_gain_squared_.fill(0.f); 273 last_gain_.fill(0.f);
213 std::copy(comfort_noise_power.begin() + 1, comfort_noise_power.end() - 1, 274 std::copy(comfort_noise.begin(), comfort_noise.end(),
214 previous_masker_.begin()); 275 last_masker_.begin() + 1);
215 low_band_gain->fill(0.f); 276 low_band_gain->fill(0.f);
277 gain_increase_.fill(1.f);
216 *high_bands_gain = 0.f; 278 *high_bands_gain = 0.f;
217 return; 279 return;
218 } 280 }
219 281
220 // Choose margin to use. 282 bool low_noise_render = low_render_detector_.Detect(render);
221 const float margin = saturated_echo ? 0.001f : 0.01f;
222 ComputeGains(optimization_, nearend_power, residual_echo_power,
223 comfort_noise_power, margin, &previous_gain_squared_,
224 &previous_masker_, low_band_gain);
225 283
226 if (num_capture_bands > 1) { 284 // Compute gain for the lower band.
227 // Compute the gain for upper frequencies. 285 LowerBandGain(low_noise_render, saturated_echo, nearend, echo, comfort_noise,
228 const float min_high_band_gain = 286 low_band_gain);
229 HighFrequencyGainBound(saturated_echo, render);
230 *high_bands_gain =
231 *std::min_element(low_band_gain->begin() + 32, low_band_gain->end());
232 287
233 *high_bands_gain = std::min(*high_bands_gain, min_high_band_gain); 288 // Compute the gain for the upper bands.
289 *high_bands_gain = UpperBandsGain(saturated_echo, render, *low_band_gain);
290 }
234 291
235 } else { 292 // Detects when the render signal can be considered to have low power and
236 *high_bands_gain = 1.f; 293 // consist of stationary noise.
294 bool SuppressionGain::LowNoiseRenderDetector::Detect(
295 const std::vector<std::vector<float>>& render) {
296 float x2_sum = 0.f;
297 float x2_max = 0.f;
298 for (auto x_k : render[0]) {
299 const float x2 = x_k * x_k;
300 x2_sum += x2;
301 x2_max = std::max(x2_max, x2);
237 } 302 }
303
304 constexpr float kThreshold = 50.f * 50.f * 64.f;
305 const bool low_noise_render =
306 average_power_ < kThreshold && x2_max < 3 * average_power_;
307 average_power_ = average_power_ * 0.9f + x2_sum * 0.1f;
308 return low_noise_render;
238 } 309 }
239 310
240 } // namespace webrtc 311 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698