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