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/aec3_fft.h"
12
13 #include <algorithm>
14
15 #include "test/gmock.h"
16 #include "test/gtest.h"
17
18 namespace webrtc {
19
20 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
21
22 // Verifies that the check for non-null input in Fft works.
TEST(Aec3FftDeathTest,NullFftInput)23 TEST(Aec3FftDeathTest, NullFftInput) {
24 Aec3Fft fft;
25 FftData X;
26 EXPECT_DEATH(fft.Fft(nullptr, &X), "");
27 }
28
29 // Verifies that the check for non-null input in Fft works.
TEST(Aec3FftDeathTest,NullFftOutput)30 TEST(Aec3FftDeathTest, NullFftOutput) {
31 Aec3Fft fft;
32 std::array<float, kFftLength> x;
33 EXPECT_DEATH(fft.Fft(&x, nullptr), "");
34 }
35
36 // Verifies that the check for non-null output in Ifft works.
TEST(Aec3FftDeathTest,NullIfftOutput)37 TEST(Aec3FftDeathTest, NullIfftOutput) {
38 Aec3Fft fft;
39 FftData X;
40 EXPECT_DEATH(fft.Ifft(X, nullptr), "");
41 }
42
43 // Verifies that the check for non-null output in ZeroPaddedFft works.
TEST(Aec3FftDeathTest,NullZeroPaddedFftOutput)44 TEST(Aec3FftDeathTest, NullZeroPaddedFftOutput) {
45 Aec3Fft fft;
46 std::array<float, kFftLengthBy2> x;
47 EXPECT_DEATH(fft.ZeroPaddedFft(x, Aec3Fft::Window::kRectangular, nullptr),
48 "");
49 }
50
51 // Verifies that the check for input length in ZeroPaddedFft works.
TEST(Aec3FftDeathTest,ZeroPaddedFftWrongInputLength)52 TEST(Aec3FftDeathTest, ZeroPaddedFftWrongInputLength) {
53 Aec3Fft fft;
54 FftData X;
55 std::array<float, kFftLengthBy2 - 1> x;
56 EXPECT_DEATH(fft.ZeroPaddedFft(x, Aec3Fft::Window::kRectangular, &X), "");
57 }
58
59 // Verifies that the check for non-null output in PaddedFft works.
TEST(Aec3FftDeathTest,NullPaddedFftOutput)60 TEST(Aec3FftDeathTest, NullPaddedFftOutput) {
61 Aec3Fft fft;
62 std::array<float, kFftLengthBy2> x;
63 std::array<float, kFftLengthBy2> x_old;
64 EXPECT_DEATH(fft.PaddedFft(x, x_old, nullptr), "");
65 }
66
67 // Verifies that the check for input length in PaddedFft works.
TEST(Aec3FftDeathTest,PaddedFftWrongInputLength)68 TEST(Aec3FftDeathTest, PaddedFftWrongInputLength) {
69 Aec3Fft fft;
70 FftData X;
71 std::array<float, kFftLengthBy2 - 1> x;
72 std::array<float, kFftLengthBy2> x_old;
73 EXPECT_DEATH(fft.PaddedFft(x, x_old, &X), "");
74 }
75
76 // Verifies that the check for length in the old value in PaddedFft works.
TEST(Aec3FftDeathTest,PaddedFftWrongOldValuesLength)77 TEST(Aec3FftDeathTest, PaddedFftWrongOldValuesLength) {
78 Aec3Fft fft;
79 FftData X;
80 std::array<float, kFftLengthBy2> x;
81 std::array<float, kFftLengthBy2 - 1> x_old;
82 EXPECT_DEATH(fft.PaddedFft(x, x_old, &X), "");
83 }
84
85 #endif
86
87 // Verifies that Fft works as intended.
TEST(Aec3Fft,Fft)88 TEST(Aec3Fft, Fft) {
89 Aec3Fft fft;
90 FftData X;
91 std::array<float, kFftLength> x;
92 x.fill(0.f);
93 fft.Fft(&x, &X);
94 EXPECT_THAT(X.re, ::testing::Each(0.f));
95 EXPECT_THAT(X.im, ::testing::Each(0.f));
96
97 x.fill(0.f);
98 x[0] = 1.f;
99 fft.Fft(&x, &X);
100 EXPECT_THAT(X.re, ::testing::Each(1.f));
101 EXPECT_THAT(X.im, ::testing::Each(0.f));
102
103 x.fill(1.f);
104 fft.Fft(&x, &X);
105 EXPECT_EQ(128.f, X.re[0]);
106 std::for_each(X.re.begin() + 1, X.re.end(),
107 [](float a) { EXPECT_EQ(0.f, a); });
108 EXPECT_THAT(X.im, ::testing::Each(0.f));
109 }
110
111 // Verifies that InverseFft works as intended.
TEST(Aec3Fft,Ifft)112 TEST(Aec3Fft, Ifft) {
113 Aec3Fft fft;
114 FftData X;
115 std::array<float, kFftLength> x;
116
117 X.re.fill(0.f);
118 X.im.fill(0.f);
119 fft.Ifft(X, &x);
120 EXPECT_THAT(x, ::testing::Each(0.f));
121
122 X.re.fill(1.f);
123 X.im.fill(0.f);
124 fft.Ifft(X, &x);
125 EXPECT_EQ(64.f, x[0]);
126 std::for_each(x.begin() + 1, x.end(), [](float a) { EXPECT_EQ(0.f, a); });
127
128 X.re.fill(0.f);
129 X.re[0] = 128;
130 X.im.fill(0.f);
131 fft.Ifft(X, &x);
132 EXPECT_THAT(x, ::testing::Each(64.f));
133 }
134
135 // Verifies that InverseFft and Fft work as intended.
TEST(Aec3Fft,FftAndIfft)136 TEST(Aec3Fft, FftAndIfft) {
137 Aec3Fft fft;
138 FftData X;
139 std::array<float, kFftLength> x;
140 std::array<float, kFftLength> x_ref;
141
142 int v = 0;
143 for (int k = 0; k < 20; ++k) {
144 for (size_t j = 0; j < x.size(); ++j) {
145 x[j] = v++;
146 x_ref[j] = x[j] * 64.f;
147 }
148 fft.Fft(&x, &X);
149 fft.Ifft(X, &x);
150 for (size_t j = 0; j < x.size(); ++j) {
151 EXPECT_NEAR(x_ref[j], x[j], 0.001f);
152 }
153 }
154 }
155
156 // Verifies that ZeroPaddedFft work as intended.
TEST(Aec3Fft,ZeroPaddedFft)157 TEST(Aec3Fft, ZeroPaddedFft) {
158 Aec3Fft fft;
159 FftData X;
160 std::array<float, kFftLengthBy2> x_in;
161 std::array<float, kFftLength> x_ref;
162 std::array<float, kFftLength> x_out;
163
164 int v = 0;
165 x_ref.fill(0.f);
166 for (int k = 0; k < 20; ++k) {
167 for (size_t j = 0; j < x_in.size(); ++j) {
168 x_in[j] = v++;
169 x_ref[j + kFftLengthBy2] = x_in[j] * 64.f;
170 }
171 fft.ZeroPaddedFft(x_in, Aec3Fft::Window::kRectangular, &X);
172 fft.Ifft(X, &x_out);
173 for (size_t j = 0; j < x_out.size(); ++j) {
174 EXPECT_NEAR(x_ref[j], x_out[j], 0.1f);
175 }
176 }
177 }
178
179 // Verifies that ZeroPaddedFft work as intended.
TEST(Aec3Fft,PaddedFft)180 TEST(Aec3Fft, PaddedFft) {
181 Aec3Fft fft;
182 FftData X;
183 std::array<float, kFftLengthBy2> x_in;
184 std::array<float, kFftLength> x_out;
185 std::array<float, kFftLengthBy2> x_old;
186 std::array<float, kFftLengthBy2> x_old_ref;
187 std::array<float, kFftLength> x_ref;
188
189 int v = 0;
190 x_old.fill(0.f);
191 for (int k = 0; k < 20; ++k) {
192 for (size_t j = 0; j < x_in.size(); ++j) {
193 x_in[j] = v++;
194 }
195
196 std::copy(x_old.begin(), x_old.end(), x_ref.begin());
197 std::copy(x_in.begin(), x_in.end(), x_ref.begin() + kFftLengthBy2);
198 std::copy(x_in.begin(), x_in.end(), x_old_ref.begin());
199 std::for_each(x_ref.begin(), x_ref.end(), [](float& a) { a *= 64.f; });
200
201 fft.PaddedFft(x_in, x_old, &X);
202 std::copy(x_in.begin(), x_in.end(), x_old.begin());
203 fft.Ifft(X, &x_out);
204
205 for (size_t j = 0; j < x_out.size(); ++j) {
206 EXPECT_NEAR(x_ref[j], x_out[j], 0.1f);
207 }
208
209 EXPECT_EQ(x_old_ref, x_old);
210 }
211 }
212
213 } // namespace webrtc
214