OLD | NEW |
---|---|
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 |
OLD | NEW |