summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/audio_processing/utility/pffft_wrapper_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/libwebrtc/modules/audio_processing/utility/pffft_wrapper_unittest.cc182
1 files changed, 182 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/audio_processing/utility/pffft_wrapper_unittest.cc b/third_party/libwebrtc/modules/audio_processing/utility/pffft_wrapper_unittest.cc
new file mode 100644
index 0000000000..2ad6849cd4
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/utility/pffft_wrapper_unittest.cc
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/utility/pffft_wrapper.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <memory>
+
+#include "test/gtest.h"
+#include "third_party/pffft/src/pffft.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+
+constexpr size_t kMaxValidSizeCheck = 1024;
+
+static constexpr int kFftSizes[] = {
+ 16, 32, 64, 96, 128, 160, 192, 256, 288, 384, 5 * 96, 512,
+ 576, 5 * 128, 800, 864, 1024, 2048, 2592, 4000, 4096, 12000, 36864};
+
+void CreatePffftWrapper(size_t fft_size, Pffft::FftType fft_type) {
+ Pffft pffft_wrapper(fft_size, fft_type);
+}
+
+float* AllocateScratchBuffer(size_t fft_size, bool complex_fft) {
+ return static_cast<float*>(
+ pffft_aligned_malloc(fft_size * (complex_fft ? 2 : 1) * sizeof(float)));
+}
+
+double frand() {
+ return std::rand() / static_cast<double>(RAND_MAX);
+}
+
+void ExpectArrayViewsEquality(rtc::ArrayView<const float> a,
+ rtc::ArrayView<const float> b) {
+ ASSERT_EQ(a.size(), b.size());
+ for (size_t i = 0; i < a.size(); ++i) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(a[i], b[i]);
+ }
+}
+
+// Compares the output of the PFFFT C++ wrapper to that of the C PFFFT.
+// Bit-exactness is expected.
+void PffftValidateWrapper(size_t fft_size, bool complex_fft) {
+ // Always use the same seed to avoid flakiness.
+ std::srand(0);
+
+ // Init PFFFT.
+ PFFFT_Setup* pffft_status =
+ pffft_new_setup(fft_size, complex_fft ? PFFFT_COMPLEX : PFFFT_REAL);
+ ASSERT_TRUE(pffft_status) << "FFT size (" << fft_size << ") not supported.";
+ size_t num_floats = fft_size * (complex_fft ? 2 : 1);
+ int num_bytes = static_cast<int>(num_floats) * sizeof(float);
+ float* in = static_cast<float*>(pffft_aligned_malloc(num_bytes));
+ float* out = static_cast<float*>(pffft_aligned_malloc(num_bytes));
+ float* scratch = AllocateScratchBuffer(fft_size, complex_fft);
+
+ // Init PFFFT C++ wrapper.
+ Pffft::FftType fft_type =
+ complex_fft ? Pffft::FftType::kComplex : Pffft::FftType::kReal;
+ ASSERT_TRUE(Pffft::IsValidFftSize(fft_size, fft_type));
+ Pffft pffft_wrapper(fft_size, fft_type);
+ auto in_wrapper = pffft_wrapper.CreateBuffer();
+ auto out_wrapper = pffft_wrapper.CreateBuffer();
+
+ // Input and output buffers views.
+ rtc::ArrayView<float> in_view(in, num_floats);
+ rtc::ArrayView<float> out_view(out, num_floats);
+ auto in_wrapper_view = in_wrapper->GetView();
+ EXPECT_EQ(in_wrapper_view.size(), num_floats);
+ auto out_wrapper_view = out_wrapper->GetConstView();
+ EXPECT_EQ(out_wrapper_view.size(), num_floats);
+
+ // Random input data.
+ for (size_t i = 0; i < num_floats; ++i) {
+ in_wrapper_view[i] = in[i] = static_cast<float>(frand() * 2.0 - 1.0);
+ }
+
+ // Forward transform.
+ pffft_transform(pffft_status, in, out, scratch, PFFFT_FORWARD);
+ pffft_wrapper.ForwardTransform(*in_wrapper, out_wrapper.get(),
+ /*ordered=*/false);
+ ExpectArrayViewsEquality(out_view, out_wrapper_view);
+
+ // Copy the FFT results into the input buffers to compute the backward FFT.
+ std::copy(out_view.begin(), out_view.end(), in_view.begin());
+ std::copy(out_wrapper_view.begin(), out_wrapper_view.end(),
+ in_wrapper_view.begin());
+
+ // Backward transform.
+ pffft_transform(pffft_status, in, out, scratch, PFFFT_BACKWARD);
+ pffft_wrapper.BackwardTransform(*in_wrapper, out_wrapper.get(),
+ /*ordered=*/false);
+ ExpectArrayViewsEquality(out_view, out_wrapper_view);
+
+ pffft_destroy_setup(pffft_status);
+ pffft_aligned_free(in);
+ pffft_aligned_free(out);
+ pffft_aligned_free(scratch);
+}
+
+} // namespace
+
+TEST(PffftTest, CreateWrapperWithValidSize) {
+ for (size_t fft_size = 0; fft_size < kMaxValidSizeCheck; ++fft_size) {
+ SCOPED_TRACE(fft_size);
+ if (Pffft::IsValidFftSize(fft_size, Pffft::FftType::kReal)) {
+ CreatePffftWrapper(fft_size, Pffft::FftType::kReal);
+ }
+ if (Pffft::IsValidFftSize(fft_size, Pffft::FftType::kComplex)) {
+ CreatePffftWrapper(fft_size, Pffft::FftType::kComplex);
+ }
+ }
+}
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+class PffftInvalidSizeDeathTest : public ::testing::Test,
+ public ::testing::WithParamInterface<size_t> {
+};
+
+TEST_P(PffftInvalidSizeDeathTest, DoNotCreateRealWrapper) {
+ size_t fft_size = GetParam();
+ ASSERT_FALSE(Pffft::IsValidFftSize(fft_size, Pffft::FftType::kReal));
+ EXPECT_DEATH(CreatePffftWrapper(fft_size, Pffft::FftType::kReal), "");
+}
+
+TEST_P(PffftInvalidSizeDeathTest, DoNotCreateComplexWrapper) {
+ size_t fft_size = GetParam();
+ ASSERT_FALSE(Pffft::IsValidFftSize(fft_size, Pffft::FftType::kComplex));
+ EXPECT_DEATH(CreatePffftWrapper(fft_size, Pffft::FftType::kComplex), "");
+}
+
+INSTANTIATE_TEST_SUITE_P(PffftTest,
+ PffftInvalidSizeDeathTest,
+ ::testing::Values(17,
+ 33,
+ 65,
+ 97,
+ 129,
+ 161,
+ 193,
+ 257,
+ 289,
+ 385,
+ 481,
+ 513,
+ 577,
+ 641,
+ 801,
+ 865,
+ 1025));
+
+#endif
+
+// TODO(https://crbug.com/webrtc/9577): Enable once SIMD is always enabled.
+TEST(PffftTest, DISABLED_CheckSimd) {
+ EXPECT_TRUE(Pffft::IsSimdEnabled());
+}
+
+TEST(PffftTest, FftBitExactness) {
+ for (int fft_size : kFftSizes) {
+ SCOPED_TRACE(fft_size);
+ if (fft_size != 16) {
+ PffftValidateWrapper(fft_size, /*complex_fft=*/false);
+ }
+ PffftValidateWrapper(fft_size, /*complex_fft=*/true);
+ }
+}
+
+} // namespace test
+} // namespace webrtc