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 "modules/audio_processing/aec3/suppression_filter.h"
12
13 #include <math.h>
14 #include <algorithm>
15 #include <numeric>
16
17 #include "test/gtest.h"
18
19 namespace webrtc {
20 namespace {
21
22 constexpr float kPi = 3.141592f;
23
ProduceSinusoid(int sample_rate_hz,float sinusoidal_frequency_hz,size_t * sample_counter,rtc::ArrayView<float> x)24 void ProduceSinusoid(int sample_rate_hz,
25 float sinusoidal_frequency_hz,
26 size_t* sample_counter,
27 rtc::ArrayView<float> x) {
28 // Produce a sinusoid of the specified frequency.
29 for (size_t k = *sample_counter, j = 0; k < (*sample_counter + kBlockSize);
30 ++k, ++j) {
31 x[j] =
32 32767.f * sin(2.f * kPi * sinusoidal_frequency_hz * k / sample_rate_hz);
33 }
34 *sample_counter = *sample_counter + kBlockSize;
35 }
36
37 } // namespace
38
39 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
40
41 // Verifies the check for null suppressor output.
TEST(SuppressionFilter,NullOutput)42 TEST(SuppressionFilter, NullOutput) {
43 FftData cn;
44 FftData cn_high_bands;
45 std::array<float, kFftLengthBy2Plus1> gain;
46
47 EXPECT_DEATH(SuppressionFilter(16000).ApplyGain(cn, cn_high_bands, gain, 1.0f,
48 nullptr),
49 "");
50 }
51
52 // Verifies the check for allowed sample rate.
TEST(SuppressionFilter,ProperSampleRate)53 TEST(SuppressionFilter, ProperSampleRate) {
54 EXPECT_DEATH(SuppressionFilter(16001), "");
55 }
56
57 #endif
58
59 // Verifies that no comfort noise is added when the gain is 1.
TEST(SuppressionFilter,ComfortNoiseInUnityGain)60 TEST(SuppressionFilter, ComfortNoiseInUnityGain) {
61 SuppressionFilter filter(48000);
62 FftData cn;
63 FftData cn_high_bands;
64 std::array<float, kFftLengthBy2Plus1> gain;
65
66 gain.fill(1.f);
67 cn.re.fill(1.f);
68 cn.im.fill(1.f);
69 cn_high_bands.re.fill(1.f);
70 cn_high_bands.im.fill(1.f);
71
72 std::vector<std::vector<float>> e(3, std::vector<float>(kBlockSize, 0.f));
73 std::vector<std::vector<float>> e_ref = e;
74 filter.ApplyGain(cn, cn_high_bands, gain, 1.f, &e);
75
76 for (size_t k = 0; k < e.size(); ++k) {
77 EXPECT_EQ(e_ref[k], e[k]);
78 }
79 }
80
81 // Verifies that the suppressor is able to suppress a signal.
TEST(SuppressionFilter,SignalSuppression)82 TEST(SuppressionFilter, SignalSuppression) {
83 SuppressionFilter filter(48000);
84 FftData cn;
85 FftData cn_high_bands;
86 std::array<float, kFftLengthBy2Plus1> gain;
87 std::vector<std::vector<float>> e(3, std::vector<float>(kBlockSize, 0.f));
88
89 gain.fill(1.f);
90 std::for_each(gain.begin() + 10, gain.end(), [](float& a) { a = 0.f; });
91
92 cn.re.fill(0.f);
93 cn.im.fill(0.f);
94 cn_high_bands.re.fill(0.f);
95 cn_high_bands.im.fill(0.f);
96
97 size_t sample_counter = 0;
98
99 float e0_input = 0.f;
100 float e0_output = 0.f;
101 for (size_t k = 0; k < 100; ++k) {
102 ProduceSinusoid(16000, 16000 * 40 / kFftLengthBy2 / 2, &sample_counter,
103 e[0]);
104 e0_input =
105 std::inner_product(e[0].begin(), e[0].end(), e[0].begin(), e0_input);
106 filter.ApplyGain(cn, cn_high_bands, gain, 1.f, &e);
107 e0_output =
108 std::inner_product(e[0].begin(), e[0].end(), e[0].begin(), e0_output);
109 }
110
111 EXPECT_LT(e0_output, e0_input / 1000.f);
112 }
113
114 // Verifies that the suppressor is able to pass through a desired signal while
115 // applying suppressing for some frequencies.
TEST(SuppressionFilter,SignalTransparency)116 TEST(SuppressionFilter, SignalTransparency) {
117 SuppressionFilter filter(48000);
118 FftData cn;
119 FftData cn_high_bands;
120 std::array<float, kFftLengthBy2Plus1> gain;
121 std::vector<std::vector<float>> e(3, std::vector<float>(kBlockSize, 0.f));
122
123 gain.fill(1.f);
124 std::for_each(gain.begin() + 30, gain.end(), [](float& a) { a = 0.f; });
125
126 cn.re.fill(0.f);
127 cn.im.fill(0.f);
128 cn_high_bands.re.fill(0.f);
129 cn_high_bands.im.fill(0.f);
130
131 size_t sample_counter = 0;
132
133 float e0_input = 0.f;
134 float e0_output = 0.f;
135 for (size_t k = 0; k < 100; ++k) {
136 ProduceSinusoid(16000, 16000 * 10 / kFftLengthBy2 / 2, &sample_counter,
137 e[0]);
138 e0_input =
139 std::inner_product(e[0].begin(), e[0].end(), e[0].begin(), e0_input);
140 filter.ApplyGain(cn, cn_high_bands, gain, 1.f, &e);
141 e0_output =
142 std::inner_product(e[0].begin(), e[0].end(), e[0].begin(), e0_output);
143 }
144
145 EXPECT_LT(0.9f * e0_input, e0_output);
146 }
147
148 // Verifies that the suppressor delay.
TEST(SuppressionFilter,Delay)149 TEST(SuppressionFilter, Delay) {
150 SuppressionFilter filter(48000);
151 FftData cn;
152 FftData cn_high_bands;
153 std::array<float, kFftLengthBy2Plus1> gain;
154 std::vector<std::vector<float>> e(3, std::vector<float>(kBlockSize, 0.f));
155
156 gain.fill(1.f);
157
158 cn.re.fill(0.f);
159 cn.im.fill(0.f);
160 cn_high_bands.re.fill(0.f);
161 cn_high_bands.im.fill(0.f);
162
163 for (size_t k = 0; k < 100; ++k) {
164 for (size_t j = 0; j < 3; ++j) {
165 for (size_t i = 0; i < kBlockSize; ++i) {
166 e[j][i] = k * kBlockSize + i;
167 }
168 }
169
170 filter.ApplyGain(cn, cn_high_bands, gain, 1.f, &e);
171 if (k > 2) {
172 for (size_t j = 0; j < 2; ++j) {
173 for (size_t i = 0; i < kBlockSize; ++i) {
174 EXPECT_NEAR(k * kBlockSize + i - kBlockSize, e[j][i], 0.01);
175 }
176 }
177 }
178 }
179 }
180
181 } // namespace webrtc
182