xref: /aosp_15_r20/external/webrtc/modules/audio_processing/aec3/aec3_fft_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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