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 presence of known external filters. |
| 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 | 51 RTC_DCHECK_LT(0, render.size()); |
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) { | 52 if (render.size() == 1) { |
159 return 1.f; | 53 return 1.f; |
160 } | 54 } |
161 | 55 |
| 56 constexpr size_t kLowBandGainLimit = kFftLengthBy2 / 2; |
| 57 const float gain_below_8_khz = *std::min_element( |
| 58 low_band_gain.begin() + kLowBandGainLimit, low_band_gain.end()); |
| 59 |
162 // Always attenuate the upper bands when there is saturated echo. | 60 // Always attenuate the upper bands when there is saturated echo. |
163 if (saturated_echo) { | 61 if (saturated_echo) { |
164 return 0.001f; | 62 return std::min(0.001f, gain_below_8_khz); |
165 } | 63 } |
166 | 64 |
167 // Compute the upper and lower band energies. | 65 // Compute the upper and lower band energies. |
168 float low_band_energy = | 66 const auto sum_of_squares = [](float a, float b) { return a + b * b; }; |
169 std::accumulate(render[0].begin(), render[0].end(), 0.f, | 67 const float low_band_energy = |
170 [](float a, float b) -> float { return a + b * b; }); | 68 std::accumulate(render[0].begin(), render[0].end(), 0.f, sum_of_squares); |
171 float high_band_energies = 0.f; | 69 float high_band_energy = 0.f; |
172 for (size_t k = 1; k < render.size(); ++k) { | 70 for (size_t k = 1; k < render.size(); ++k) { |
173 high_band_energies = std::max( | 71 const float energy = std::accumulate(render[k].begin(), render[k].end(), |
174 high_band_energies, | 72 0.f, sum_of_squares); |
175 std::accumulate(render[k].begin(), render[k].end(), 0.f, | 73 high_band_energy = std::max(high_band_energy, energy); |
176 [](float a, float b) -> float { return a + b * b; })); | |
177 } | 74 } |
178 | 75 |
179 // If there is more power in the lower frequencies than the upper frequencies, | 76 // 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 | 77 // or if the power in upper frequencies is low, do not bound the gain in the |
181 // upper bands. | 78 // upper bands. |
182 if (high_band_energies < low_band_energy || | 79 float anti_howling_gain; |
183 high_band_energies < kSubBlockSize * 10.f * 10.f) { | 80 constexpr float kThreshold = kSubBlockSize * 10.f * 10.f; |
184 return 1.f; | 81 if (high_band_energy < std::max(low_band_energy, kThreshold)) { |
185 } | 82 anti_howling_gain = 1.f; |
186 | 83 } else { |
187 // In all other cases, bound the gain for upper frequencies. | 84 // In all other cases, bound the gain for upper frequencies. |
188 RTC_DCHECK_LE(low_band_energy, high_band_energies); | 85 RTC_DCHECK_LE(low_band_energy, high_band_energy); |
189 return 0.01f * sqrtf(low_band_energy / high_band_energies); | 86 RTC_DCHECK_NE(0.f, high_band_energy); |
| 87 anti_howling_gain = 0.01f * sqrtf(low_band_energy / high_band_energy); |
| 88 } |
| 89 |
| 90 // Choose the gain as the minimum of the lower and upper gains. |
| 91 return std::min(gain_below_8_khz, anti_howling_gain); |
| 92 } |
| 93 |
| 94 // Limits the gain increase. |
| 95 void UpdateMaxGainIncrease( |
| 96 size_t no_saturation_counter, |
| 97 bool low_noise_render, |
| 98 const std::array<float, kFftLengthBy2Plus1>& last_echo, |
| 99 const std::array<float, kFftLengthBy2Plus1>& echo, |
| 100 const std::array<float, kFftLengthBy2Plus1>& last_gain, |
| 101 const std::array<float, kFftLengthBy2Plus1>& new_gain, |
| 102 std::array<float, kFftLengthBy2Plus1>* gain_increase) { |
| 103 float max_increasing; |
| 104 float max_decreasing; |
| 105 float rate_increasing; |
| 106 float rate_decreasing; |
| 107 float min_increasing; |
| 108 float min_decreasing; |
| 109 |
| 110 if (low_noise_render) { |
| 111 max_increasing = 8.f; |
| 112 max_decreasing = 8.f; |
| 113 rate_increasing = 2.f; |
| 114 rate_decreasing = 2.f; |
| 115 min_increasing = 4.f; |
| 116 min_decreasing = 4.f; |
| 117 } else if (no_saturation_counter > 10) { |
| 118 max_increasing = 4.f; |
| 119 max_decreasing = 4.f; |
| 120 rate_increasing = 2.f; |
| 121 rate_decreasing = 2.f; |
| 122 min_increasing = 1.2f; |
| 123 min_decreasing = 2.f; |
| 124 } else { |
| 125 max_increasing = 1.2f; |
| 126 max_decreasing = 1.2f; |
| 127 rate_increasing = 1.5f; |
| 128 rate_decreasing = 1.5f; |
| 129 min_increasing = 1.f; |
| 130 min_decreasing = 1.f; |
| 131 } |
| 132 |
| 133 for (size_t k = 0; k < new_gain.size(); ++k) { |
| 134 if (echo[k] > last_echo[k]) { |
| 135 (*gain_increase)[k] = |
| 136 new_gain[k] > last_gain[k] |
| 137 ? std::min(max_increasing, (*gain_increase)[k] * rate_increasing) |
| 138 : min_increasing; |
| 139 } else { |
| 140 (*gain_increase)[k] = |
| 141 new_gain[k] > last_gain[k] |
| 142 ? std::min(max_decreasing, (*gain_increase)[k] * rate_decreasing) |
| 143 : min_decreasing; |
| 144 } |
| 145 } |
| 146 } |
| 147 |
| 148 // Computes the gain to reduce the echo to a non audible level. |
| 149 void GainToNoAudibleEcho( |
| 150 bool low_noise_render, |
| 151 bool saturated_echo, |
| 152 const std::array<float, kFftLengthBy2Plus1>& nearend, |
| 153 const std::array<float, kFftLengthBy2Plus1>& echo, |
| 154 const std::array<float, kFftLengthBy2Plus1>& masker, |
| 155 const std::array<float, kFftLengthBy2Plus1>& min_gain, |
| 156 const std::array<float, kFftLengthBy2Plus1>& max_gain, |
| 157 const std::array<float, kFftLengthBy2Plus1>& one_by_echo, |
| 158 std::array<float, kFftLengthBy2Plus1>* gain) { |
| 159 constexpr float kEchoMaskingMargin = 1.f / 100.f; |
| 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] = kEchoMaskingMargin * 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) { |
| 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 (note that when the echo is zero, the precomputed value |
| 205 // is never used). |
| 206 std::array<float, kFftLengthBy2Plus1> one_by_echo; |
| 207 std::transform(echo.begin(), echo.end(), one_by_echo.begin(), |
| 208 [](float a) { return a > 0.f ? 1.f / a : 1.f; }); |
| 209 |
| 210 // Compute the minimum gain as the attenuating gain to put the signal just |
| 211 // above the zero sample values. |
| 212 std::array<float, kFftLengthBy2Plus1> min_gain; |
| 213 const float min_echo_power = low_noise_render ? 192.f : 64.f; |
| 214 if (no_saturation_counter_ > 10) { |
| 215 for (size_t k = 0; k < nearend.size(); ++k) { |
| 216 const float denom = std::min(nearend[k], echo[k]); |
| 217 min_gain[k] = denom > 0.f ? min_echo_power / denom : 1.f; |
| 218 min_gain[k] = std::min(min_gain[k], 1.f); |
| 219 } |
| 220 } else { |
| 221 min_gain.fill(0.f); |
| 222 } |
| 223 |
| 224 // Compute the maximum gain by limiting the gain increase from the previous |
| 225 // gain. |
| 226 std::array<float, kFftLengthBy2Plus1> max_gain; |
| 227 for (size_t k = 0; k < gain->size(); ++k) { |
| 228 max_gain[k] = |
| 229 std::min(std::max(last_gain_[k] * gain_increase_[k], 0.001f), 1.f); |
| 230 } |
| 231 |
| 232 // Iteratively compute the gain required to attenuate the echo to a non |
| 233 // noticeable level. |
| 234 gain->fill(0.f); |
| 235 for (int k = 0; k < 2; ++k) { |
| 236 std::array<float, kFftLengthBy2Plus1> masker; |
| 237 MaskingPower(nearend, comfort_noise, last_masker_, *gain, &masker); |
| 238 GainToNoAudibleEcho(low_noise_render, saturated_echo, nearend, echo, masker, |
| 239 min_gain, max_gain, one_by_echo, gain); |
| 240 AdjustForExternalFilters(gain); |
| 241 } |
| 242 |
| 243 // Update the allowed maximum gain increase. |
| 244 UpdateMaxGainIncrease(no_saturation_counter_, low_noise_render, last_echo_, |
| 245 echo, last_gain_, *gain, &gain_increase_); |
| 246 |
| 247 // Store data required for the gain computation of the next block. |
| 248 std::copy(echo.begin(), echo.end(), last_echo_.begin()); |
| 249 std::copy(gain->begin(), gain->end(), last_gain_.begin()); |
| 250 MaskingPower(nearend, comfort_noise, last_masker_, *gain, &last_masker_); |
| 251 aec3::VectorMath(optimization_).Sqrt(*gain); |
190 } | 252 } |
191 | 253 |
192 SuppressionGain::SuppressionGain(Aec3Optimization optimization) | 254 SuppressionGain::SuppressionGain(Aec3Optimization optimization) |
193 : optimization_(optimization) { | 255 : optimization_(optimization) { |
194 previous_gain_squared_.fill(1.f); | 256 last_gain_.fill(1.f); |
195 previous_masker_.fill(0.f); | 257 last_masker_.fill(0.f); |
| 258 gain_increase_.fill(1.f); |
| 259 last_echo_.fill(0.f); |
196 } | 260 } |
197 | 261 |
198 void SuppressionGain::GetGain( | 262 void SuppressionGain::GetGain( |
199 const std::array<float, kFftLengthBy2Plus1>& nearend_power, | 263 const std::array<float, kFftLengthBy2Plus1>& nearend, |
200 const std::array<float, kFftLengthBy2Plus1>& residual_echo_power, | 264 const std::array<float, kFftLengthBy2Plus1>& echo, |
201 const std::array<float, kFftLengthBy2Plus1>& comfort_noise_power, | 265 const std::array<float, kFftLengthBy2Plus1>& comfort_noise, |
202 bool saturated_echo, | 266 bool saturated_echo, |
203 const std::vector<std::vector<float>>& render, | 267 const std::vector<std::vector<float>>& render, |
204 size_t num_capture_bands, | |
205 bool force_zero_gain, | 268 bool force_zero_gain, |
206 float* high_bands_gain, | 269 float* high_bands_gain, |
207 std::array<float, kFftLengthBy2Plus1>* low_band_gain) { | 270 std::array<float, kFftLengthBy2Plus1>* low_band_gain) { |
208 RTC_DCHECK(high_bands_gain); | 271 RTC_DCHECK(high_bands_gain); |
209 RTC_DCHECK(low_band_gain); | 272 RTC_DCHECK(low_band_gain); |
210 | 273 |
211 if (force_zero_gain) { | 274 if (force_zero_gain) { |
212 previous_gain_squared_.fill(0.f); | 275 last_gain_.fill(0.f); |
213 std::copy(comfort_noise_power.begin() + 1, comfort_noise_power.end() - 1, | 276 std::copy(comfort_noise.begin(), comfort_noise.end(), last_masker_.begin()); |
214 previous_masker_.begin()); | |
215 low_band_gain->fill(0.f); | 277 low_band_gain->fill(0.f); |
| 278 gain_increase_.fill(1.f); |
216 *high_bands_gain = 0.f; | 279 *high_bands_gain = 0.f; |
217 return; | 280 return; |
218 } | 281 } |
219 | 282 |
220 // Choose margin to use. | 283 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 | 284 |
226 if (num_capture_bands > 1) { | 285 // Compute gain for the lower band. |
227 // Compute the gain for upper frequencies. | 286 LowerBandGain(low_noise_render, saturated_echo, nearend, echo, comfort_noise, |
228 const float min_high_band_gain = | 287 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 | 288 |
233 *high_bands_gain = std::min(*high_bands_gain, min_high_band_gain); | 289 // Compute the gain for the upper bands. |
| 290 *high_bands_gain = UpperBandsGain(saturated_echo, render, *low_band_gain); |
| 291 } |
234 | 292 |
235 } else { | 293 // Detects when the render signal can be considered to have low power and |
236 *high_bands_gain = 1.f; | 294 // consist of stationary noise. |
| 295 bool SuppressionGain::LowNoiseRenderDetector::Detect( |
| 296 const std::vector<std::vector<float>>& render) { |
| 297 float x2_sum = 0.f; |
| 298 float x2_max = 0.f; |
| 299 for (auto x_k : render[0]) { |
| 300 const float x2 = x_k * x_k; |
| 301 x2_sum += x2; |
| 302 x2_max = std::max(x2_max, x2); |
237 } | 303 } |
| 304 |
| 305 constexpr float kThreshold = 50.f * 50.f * 64.f; |
| 306 const bool low_noise_render = |
| 307 average_power_ < kThreshold && x2_max < 3 * average_power_; |
| 308 average_power_ = average_power_ * 0.9f + x2_sum * 0.1f; |
| 309 return low_noise_render; |
238 } | 310 } |
239 | 311 |
240 } // namespace webrtc | 312 } // namespace webrtc |
OLD | NEW |