Chromium Code Reviews| 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 |