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

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

Issue 2678423005: Finalization of the first version of EchoCanceller 3 (Closed)
Patch Set: Fixed failing unittest Created 3 years, 10 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
(Empty)
1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/modules/audio_processing/aec3/suppression_gain.h"
12
13 #include "webrtc/typedefs.h"
14 #if defined(WEBRTC_ARCH_X86_FAMILY)
15 #include <emmintrin.h>
16 #endif
17 #include <math.h>
18 #include <algorithm>
19 #include <functional>
20
21 namespace webrtc {
22 namespace {
23
24 constexpr int kNumIterations = 2;
25 constexpr float kEchoMaskingMargin = 1.f / 10.f;
26 constexpr float kBandMaskingFactor = 1.f / 3.f;
27 constexpr float kTimeMaskingFactor = 1.f / 10.f;
28
29 } // namespace
30
31 #if defined(WEBRTC_ARCH_X86_FAMILY)
32
33 // Optimized SSE2 code for the gain computation.
34 // TODO(peah): Add further optimizations, in particular for the divisions.
35 void ComputeGains_SSE2(
36 const std::array<float, kFftLengthBy2Plus1>& nearend_power,
37 const std::array<float, kFftLengthBy2Plus1>& residual_echo_power,
38 const std::array<float, kFftLengthBy2Plus1>& comfort_noise_power,
39 float strong_nearend_margin,
40 std::array<float, kFftLengthBy2 - 1>* previous_gain_squared,
hlundin-webrtc 2017/02/21 16:34:03 You already have kFftLengthBy2Plus1 defined. Why n
peah-webrtc 2017/02/21 23:00:41 Nice! Done.
41 std::array<float, kFftLengthBy2 - 1>* previous_masker,
42 std::array<float, kFftLengthBy2Plus1>* gain) {
43 std::array<float, kFftLengthBy2 - 1> masker;
44 std::array<float, kFftLengthBy2 - 1> same_band_masker;
45 std::array<float, kFftLengthBy2 - 1> one_by_residual_echo_power;
46 std::array<bool, kFftLengthBy2 - 1> strong_nearend;
47 std::array<float, kFftLengthBy2Plus1> neighboring_bands_masker;
48
49 // Precompute 1/residual_echo_power.
50 std::transform(residual_echo_power.begin() + 1, residual_echo_power.end() - 1,
51 one_by_residual_echo_power.begin(),
52 [](float a) { return a > 0.f ? 1.f / a : -1.f; });
53
54 // Precompute indicators for bands with strong nearend.
55 std::transform(
56 residual_echo_power.begin() + 1, residual_echo_power.end() - 1,
57 nearend_power.begin() + 1, strong_nearend.begin(),
58 [&](float a, float b) { return a <= strong_nearend_margin * b; });
59
60 // Precompute masker for the same band.
61 std::transform(comfort_noise_power.begin() + 1, comfort_noise_power.end() - 1,
62 previous_masker->begin(), same_band_masker.begin(),
63 [&](float a, float b) { return a + kTimeMaskingFactor * b; });
64
65 for (int k = 0; k < kNumIterations; ++k) {
66 if (k == 0) {
67 // Add masker from the same band.
68 std::copy(same_band_masker.begin(), same_band_masker.end(),
69 masker.begin());
70 } else {
71 // Add masker for neightboring bands.
72 std::transform(nearend_power.begin(), nearend_power.end(), gain->begin(),
73 neighboring_bands_masker.begin(),
74 std::multiplies<float>());
75 std::transform(neighboring_bands_masker.begin(),
76 neighboring_bands_masker.end(),
77 comfort_noise_power.begin(),
78 neighboring_bands_masker.begin(), std::plus<float>());
79 std::transform(
80 neighboring_bands_masker.begin(), neighboring_bands_masker.end() - 2,
81 neighboring_bands_masker.begin() + 2, masker.begin(),
82 [&](float a, float b) { return kBandMaskingFactor * (a + b); });
83
84 // Add masker from the same band.
85 std::transform(same_band_masker.begin(), same_band_masker.end(),
86 masker.begin(), masker.begin(), std::plus<float>());
87 }
88
89 // Compute new gain as:
90 // G2(t,f) = (comfort_noise_power(t,f) + G2(t-1)*nearend_power(t-1)) *
91 // kTimeMaskingFactor
92 // * kEchoMaskingMargin / residual_echo_power(t,f).
93 // or
94 // G2(t,f) = ((comfort_noise_power(t,f) + G2(t-1) *
95 // nearend_power(t-1)) * kTimeMaskingFactor +
96 // (comfort_noise_power(t, f-1) + comfort_noise_power(t, f+1) +
97 // (G2(t,f-1)*nearend_power(t, f-1) +
98 // G2(t,f+1)*nearend_power(t, f+1)) *
99 // kTimeMaskingFactor) * kBandMaskingFactor)
100 // * kEchoMaskingMargin / residual_echo_power(t,f).
101 std::transform(
102 masker.begin(), masker.end(), one_by_residual_echo_power.begin(),
103 gain->begin() + 1, [&](float a, float b) {
104 return b >= 0 ? std::min(kEchoMaskingMargin * a * b, 1.f) : 1.f;
105 });
106
107 // Limit gain for bands with strong nearend.
108 std::transform(gain->begin() + 1, gain->end() - 1, strong_nearend.begin(),
109 gain->begin() + 1,
110 [](float a, bool b) { return b ? 1.f : a; });
111
112 // Limit the allowed gain update over time.
113 std::transform(
114 gain->begin() + 1, gain->end() - 1, previous_gain_squared->begin(),
115 gain->begin() + 1, [](float a, float b) {
116 return b < 0.0001f ? std::min(a, 0.0001f) : std::min(a, b * 2.f);
117 });
118
119 (*gain)[0] = (*gain)[1];
120 (*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2 - 1];
121 }
122
123 std::copy(gain->begin() + 1, gain->end() - 1, previous_gain_squared->begin());
124
125 std::transform(gain->begin() + 1, gain->end() - 1, nearend_power.begin() + 1,
126 previous_masker->begin(), std::multiplies<float>());
127 std::transform(previous_masker->begin(), previous_masker->end(),
128 comfort_noise_power.begin() + 1, previous_masker->begin(),
129 std::plus<float>());
130
131 for (size_t k = 0; k < kFftLengthBy2; k += 4) {
132 __m128 g = _mm_loadu_ps(&(*gain)[k]);
133 g = _mm_sqrt_ps(g);
134 _mm_storeu_ps(&(*gain)[k], g);
135 }
136
137 (*gain)[kFftLengthBy2] = sqrtf((*gain)[kFftLengthBy2]);
138 }
139
140 #endif
141
142 void ComputeGains(
143 const std::array<float, kFftLengthBy2Plus1>& nearend_power,
144 const std::array<float, kFftLengthBy2Plus1>& residual_echo_power,
145 const std::array<float, kFftLengthBy2Plus1>& comfort_noise_power,
146 float strong_nearend_margin,
147 std::array<float, kFftLengthBy2 - 1>* previous_gain_squared,
148 std::array<float, kFftLengthBy2 - 1>* previous_masker,
149 std::array<float, kFftLengthBy2Plus1>* gain) {
150 std::array<float, kFftLengthBy2 - 1> masker;
151 std::array<float, kFftLengthBy2 - 1> same_band_masker;
152 std::array<float, kFftLengthBy2 - 1> one_by_residual_echo_power;
153 std::array<bool, kFftLengthBy2 - 1> strong_nearend;
154 std::array<float, kFftLengthBy2Plus1> neighboring_bands_masker;
155
156 // Precompute 1/residual_echo_power.
157 std::transform(residual_echo_power.begin() + 1, residual_echo_power.end() - 1,
158 one_by_residual_echo_power.begin(),
159 [](float a) { return a > 0.f ? 1.f / a : -1.f; });
hlundin-webrtc 2017/02/21 16:34:03 Is there any risk that we get _really_ large resul
peah-webrtc 2017/02/21 23:00:41 Yes, the division should actually be done as it is
160
161 // Precompute indicators for bands with strong nearend.
162 std::transform(
163 residual_echo_power.begin() + 1, residual_echo_power.end() - 1,
164 nearend_power.begin() + 1, strong_nearend.begin(),
165 [&](float a, float b) { return a <= strong_nearend_margin * b; });
166
167 // Precompute masker for the same band.
168 std::transform(comfort_noise_power.begin() + 1, comfort_noise_power.end() - 1,
169 previous_masker->begin(), same_band_masker.begin(),
170 [&](float a, float b) { return a + kTimeMaskingFactor * b; });
171
172 for (int k = 0; k < kNumIterations; ++k) {
173 if (k == 0) {
174 // Add masker from the same band.
175 std::copy(same_band_masker.begin(), same_band_masker.end(),
176 masker.begin());
177 } else {
178 // Add masker for neightboring bands.
hlundin-webrtc 2017/02/21 16:34:03 neighboring
peah-webrtc 2017/02/21 23:00:41 Done.
179 std::transform(nearend_power.begin(), nearend_power.end(), gain->begin(),
180 neighboring_bands_masker.begin(),
181 std::multiplies<float>());
182 std::transform(neighboring_bands_masker.begin(),
183 neighboring_bands_masker.end(),
184 comfort_noise_power.begin(),
185 neighboring_bands_masker.begin(), std::plus<float>());
186 std::transform(
187 neighboring_bands_masker.begin(), neighboring_bands_masker.end() - 2,
188 neighboring_bands_masker.begin() + 2, masker.begin(),
189 [&](float a, float b) { return kBandMaskingFactor * (a + b); });
190
191 // Add masker from the same band.
192 std::transform(same_band_masker.begin(), same_band_masker.end(),
193 masker.begin(), masker.begin(), std::plus<float>());
194 }
195
196 // Compute new gain as:
197 // G2(t,f) = (comfort_noise_power(t,f) + G2(t-1)*nearend_power(t-1)) *
198 // kTimeMaskingFactor
199 // * kEchoMaskingMargin / residual_echo_power(t,f).
200 // or
201 // G2(t,f) = ((comfort_noise_power(t,f) + G2(t-1) *
202 // nearend_power(t-1)) * kTimeMaskingFactor +
203 // (comfort_noise_power(t, f-1) + comfort_noise_power(t, f+1) +
204 // (G2(t,f-1)*nearend_power(t, f-1) +
205 // G2(t,f+1)*nearend_power(t, f+1)) *
206 // kTimeMaskingFactor) * kBandMaskingFactor)
207 // * kEchoMaskingMargin / residual_echo_power(t,f).
208 std::transform(
209 masker.begin(), masker.end(), one_by_residual_echo_power.begin(),
210 gain->begin() + 1, [&](float a, float b) {
211 return b >= 0 ? std::min(kEchoMaskingMargin * a * b, 1.f) : 1.f;
212 });
213
214 // Limit gain for bands with strong nearend.
215 std::transform(gain->begin() + 1, gain->end() - 1, strong_nearend.begin(),
216 gain->begin() + 1,
217 [](float a, bool b) { return b ? 1.f : a; });
218
219 // Limit the allowed gain update over time.
220 std::transform(
221 gain->begin() + 1, gain->end() - 1, previous_gain_squared->begin(),
222 gain->begin() + 1, [](float a, float b) {
223 return b < 0.0001f ? std::min(a, 0.0001f) : std::min(a, b * 2.f);
224 });
225
226 (*gain)[0] = (*gain)[1];
227 (*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2 - 1];
228 }
229
230 std::copy(gain->begin() + 1, gain->end() - 1, previous_gain_squared->begin());
hlundin-webrtc 2017/02/21 16:34:03 It's a bit confusing that you copy to "previous_ga
peah-webrtc 2017/02/21 23:00:41 I simplified this with an alias. PTAL.
hlundin-webrtc 2017/02/22 15:24:05 Better.
peah-webrtc 2017/02/22 23:51:36 Acknowledged.
231
232 std::transform(gain->begin() + 1, gain->end() - 1, nearend_power.begin() + 1,
233 previous_masker->begin(), std::multiplies<float>());
234 std::transform(previous_masker->begin(), previous_masker->end(),
235 comfort_noise_power.begin() + 1, previous_masker->begin(),
236 std::plus<float>());
237
238 std::transform(gain->begin(), gain->end(), gain->begin(),
239 [](float a) { return sqrtf(a); });
240 }
241
242 SuppressionGain::SuppressionGain(Aec3Optimization optimization)
243 : optimization_(optimization) {
244 previous_gain_squared_.fill(1.f);
245 previous_masker_.fill(0.f);
246 }
247
248 void SuppressionGain::GetGain(
249 const std::array<float, kFftLengthBy2Plus1>& nearend_power,
250 const std::array<float, kFftLengthBy2Plus1>& residual_echo_power,
251 const std::array<float, kFftLengthBy2Plus1>& comfort_noise_power,
252 float strong_nearend_margin,
253 std::array<float, kFftLengthBy2Plus1>* gain) {
254 RTC_DCHECK(gain);
255 if (optimization_ == Aec3Optimization::kNone) {
hlundin-webrtc 2017/02/21 16:34:03 I think you should use switch instead: switch (opt
peah-webrtc 2017/02/21 23:00:41 Great one! I also changed to this in the other pla
hlundin-webrtc 2017/02/22 15:24:05 That was the way I hoped it would pan out. :)
peah-webrtc 2017/02/23 11:18:32 :-) Acknowledged.
256 ComputeGains(nearend_power, residual_echo_power, comfort_noise_power,
257 strong_nearend_margin, &previous_gain_squared_,
258 &previous_masker_, gain);
259 }
260 #if defined(WEBRTC_ARCH_X86_FAMILY)
261 if (optimization_ == Aec3Optimization::kSse2) {
262 ComputeGains_SSE2(nearend_power, residual_echo_power, comfort_noise_power,
263 strong_nearend_margin, &previous_gain_squared_,
264 &previous_masker_, gain);
265 }
266 #endif
267 }
268
269 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698