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/fft_data.h"
12
13 #include "rtc_base/system/arch.h"
14 #include "system_wrappers/include/cpu_features_wrapper.h"
15 #include "test/gtest.h"
16
17 namespace webrtc {
18
19 #if defined(WEBRTC_ARCH_X86_FAMILY)
20 // Verifies that the optimized methods are bitexact to their reference
21 // counterparts.
TEST(FftData,TestSse2Optimizations)22 TEST(FftData, TestSse2Optimizations) {
23 if (GetCPUInfo(kSSE2) != 0) {
24 FftData x;
25
26 for (size_t k = 0; k < x.re.size(); ++k) {
27 x.re[k] = k + 1;
28 }
29
30 x.im[0] = x.im[x.im.size() - 1] = 0.f;
31 for (size_t k = 1; k < x.im.size() - 1; ++k) {
32 x.im[k] = 2.f * (k + 1);
33 }
34
35 std::array<float, kFftLengthBy2Plus1> spectrum;
36 std::array<float, kFftLengthBy2Plus1> spectrum_sse2;
37 x.Spectrum(Aec3Optimization::kNone, spectrum);
38 x.Spectrum(Aec3Optimization::kSse2, spectrum_sse2);
39 EXPECT_EQ(spectrum, spectrum_sse2);
40 }
41 }
42
43 // Verifies that the optimized methods are bitexact to their reference
44 // counterparts.
TEST(FftData,TestAvx2Optimizations)45 TEST(FftData, TestAvx2Optimizations) {
46 if (GetCPUInfo(kAVX2) != 0) {
47 FftData x;
48
49 for (size_t k = 0; k < x.re.size(); ++k) {
50 x.re[k] = k + 1;
51 }
52
53 x.im[0] = x.im[x.im.size() - 1] = 0.f;
54 for (size_t k = 1; k < x.im.size() - 1; ++k) {
55 x.im[k] = 2.f * (k + 1);
56 }
57
58 std::array<float, kFftLengthBy2Plus1> spectrum;
59 std::array<float, kFftLengthBy2Plus1> spectrum_avx2;
60 x.Spectrum(Aec3Optimization::kNone, spectrum);
61 x.Spectrum(Aec3Optimization::kAvx2, spectrum_avx2);
62 EXPECT_EQ(spectrum, spectrum_avx2);
63 }
64 }
65 #endif
66
67 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
68
69 // Verifies the check for null output in CopyToPackedArray.
TEST(FftDataDeathTest,NonNullCopyToPackedArrayOutput)70 TEST(FftDataDeathTest, NonNullCopyToPackedArrayOutput) {
71 EXPECT_DEATH(FftData().CopyToPackedArray(nullptr), "");
72 }
73
74 // Verifies the check for null output in Spectrum.
TEST(FftDataDeathTest,NonNullSpectrumOutput)75 TEST(FftDataDeathTest, NonNullSpectrumOutput) {
76 EXPECT_DEATH(FftData().Spectrum(Aec3Optimization::kNone, nullptr), "");
77 }
78
79 #endif
80
81 // Verifies that the Assign method properly copies the data from the source and
82 // ensures that the imaginary components for the DC and Nyquist bins are 0.
TEST(FftData,Assign)83 TEST(FftData, Assign) {
84 FftData x;
85 FftData y;
86
87 x.re.fill(1.f);
88 x.im.fill(2.f);
89 y.Assign(x);
90 EXPECT_EQ(x.re, y.re);
91 EXPECT_EQ(0.f, y.im[0]);
92 EXPECT_EQ(0.f, y.im[x.im.size() - 1]);
93 for (size_t k = 1; k < x.im.size() - 1; ++k) {
94 EXPECT_EQ(x.im[k], y.im[k]);
95 }
96 }
97
98 // Verifies that the Clear method properly clears all the data.
TEST(FftData,Clear)99 TEST(FftData, Clear) {
100 FftData x_ref;
101 FftData x;
102
103 x_ref.re.fill(0.f);
104 x_ref.im.fill(0.f);
105
106 x.re.fill(1.f);
107 x.im.fill(2.f);
108 x.Clear();
109
110 EXPECT_EQ(x_ref.re, x.re);
111 EXPECT_EQ(x_ref.im, x.im);
112 }
113
114 // Verifies that the spectrum is correctly computed.
TEST(FftData,Spectrum)115 TEST(FftData, Spectrum) {
116 FftData x;
117
118 for (size_t k = 0; k < x.re.size(); ++k) {
119 x.re[k] = k + 1;
120 }
121
122 x.im[0] = x.im[x.im.size() - 1] = 0.f;
123 for (size_t k = 1; k < x.im.size() - 1; ++k) {
124 x.im[k] = 2.f * (k + 1);
125 }
126
127 std::array<float, kFftLengthBy2Plus1> spectrum;
128 x.Spectrum(Aec3Optimization::kNone, spectrum);
129
130 EXPECT_EQ(x.re[0] * x.re[0], spectrum[0]);
131 EXPECT_EQ(x.re[spectrum.size() - 1] * x.re[spectrum.size() - 1],
132 spectrum[spectrum.size() - 1]);
133 for (size_t k = 1; k < spectrum.size() - 1; ++k) {
134 EXPECT_EQ(x.re[k] * x.re[k] + x.im[k] * x.im[k], spectrum[k]);
135 }
136 }
137
138 // Verifies that the functionality in CopyToPackedArray works as intended.
TEST(FftData,CopyToPackedArray)139 TEST(FftData, CopyToPackedArray) {
140 FftData x;
141 std::array<float, kFftLength> x_packed;
142
143 for (size_t k = 0; k < x.re.size(); ++k) {
144 x.re[k] = k + 1;
145 }
146
147 x.im[0] = x.im[x.im.size() - 1] = 0.f;
148 for (size_t k = 1; k < x.im.size() - 1; ++k) {
149 x.im[k] = 2.f * (k + 1);
150 }
151
152 x.CopyToPackedArray(&x_packed);
153
154 EXPECT_EQ(x.re[0], x_packed[0]);
155 EXPECT_EQ(x.re[x.re.size() - 1], x_packed[1]);
156 for (size_t k = 1; k < x_packed.size() / 2; ++k) {
157 EXPECT_EQ(x.re[k], x_packed[2 * k]);
158 EXPECT_EQ(x.im[k], x_packed[2 * k + 1]);
159 }
160 }
161
162 // Verifies that the functionality in CopyFromPackedArray works as intended
163 // (relies on that the functionality in CopyToPackedArray has been verified in
164 // the test above).
TEST(FftData,CopyFromPackedArray)165 TEST(FftData, CopyFromPackedArray) {
166 FftData x_ref;
167 FftData x;
168 std::array<float, kFftLength> x_packed;
169
170 for (size_t k = 0; k < x_ref.re.size(); ++k) {
171 x_ref.re[k] = k + 1;
172 }
173
174 x_ref.im[0] = x_ref.im[x_ref.im.size() - 1] = 0.f;
175 for (size_t k = 1; k < x_ref.im.size() - 1; ++k) {
176 x_ref.im[k] = 2.f * (k + 1);
177 }
178
179 x_ref.CopyToPackedArray(&x_packed);
180 x.CopyFromPackedArray(x_packed);
181
182 EXPECT_EQ(x_ref.re, x.re);
183 EXPECT_EQ(x_ref.im, x.im);
184 }
185
186 } // namespace webrtc
187