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