The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
6.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. struct FFTUnitTest : public UnitTest
  20. {
  21. FFTUnitTest() : UnitTest("FFT") {}
  22. static void fillRandom (Random& random, Complex<float>* buffer, size_t n)
  23. {
  24. for (size_t i = 0; i < n; ++i)
  25. buffer[i] = Complex<float> ((2.0f * random.nextFloat()) - 1.0f,
  26. (2.0f * random.nextFloat()) - 1.0f);
  27. }
  28. static void fillRandom (Random& random, float* buffer, size_t n)
  29. {
  30. for (size_t i = 0; i < n; ++i)
  31. buffer[i] = (2.0f * random.nextFloat()) - 1.0f;
  32. }
  33. static Complex<float> freqConvolution (const Complex<float>* in, float freq, size_t n)
  34. {
  35. Complex<float> sum (0.0, 0.0);
  36. for (size_t i = 0; i < n; ++i)
  37. sum += in[i] * exp (Complex<float> (0, static_cast<float> (i) * freq));
  38. return sum;
  39. }
  40. static void performReferenceFourier (const Complex<float>* in, Complex<float>* out,
  41. size_t n, bool reverve)
  42. {
  43. float base_freq = static_cast<float>(((reverve ? 1.0 : -1.0) * 2.0 * double_Pi)
  44. / static_cast<float> (n));
  45. for (size_t i = 0; i < n; ++i)
  46. out[i] = freqConvolution (in, static_cast<float>(i) * base_freq, n);
  47. }
  48. static void performReferenceFourier (const float* in, Complex<float>* out,
  49. size_t n, bool reverve)
  50. {
  51. HeapBlock<Complex<float>> buffer (n);
  52. for (size_t i = 0; i < n; ++i)
  53. buffer.getData()[i] = Complex<float> (in[i], 0.0f);
  54. float base_freq = static_cast<float>(((reverve ? 1.0 : -1.0) * 2.0 * double_Pi)
  55. / static_cast<float> (n));
  56. for (size_t i = 0; i < n; ++i)
  57. out[i] = freqConvolution (buffer.getData(), static_cast<float>(i) * base_freq, n);
  58. }
  59. //==============================================================================
  60. template <typename Type>
  61. static bool checkArrayIsSimilar (Type* a, Type* b, size_t n) noexcept
  62. {
  63. for (size_t i = 0; i < n; ++i)
  64. if (std::abs (a[i] - b[i]) > 1e-3f)
  65. return false;
  66. return true;
  67. }
  68. struct RealTest
  69. {
  70. static void run (FFTUnitTest& u)
  71. {
  72. Random random (378272);
  73. for (size_t order = 0; order <= 8; ++order)
  74. {
  75. auto n = (1u << order);
  76. FFT fft ((int) order);
  77. HeapBlock<float> input (n);
  78. HeapBlock<Complex<float>> reference (n), output (n);
  79. fillRandom (random, input.getData(), n);
  80. performReferenceFourier (input.getData(), reference.getData(), n, false);
  81. // fill only first half with real numbers
  82. zeromem (output.getData(), n * sizeof (Complex<float>));
  83. memcpy (reinterpret_cast<float*> (output.getData()), input.getData(), n * sizeof (float));
  84. fft.performRealOnlyForwardTransform ((float*) output.getData());
  85. u.expect (checkArrayIsSimilar (reference.getData(), output.getData(), n));
  86. memcpy (output.getData(), reference.getData(), n * sizeof (Complex<float>));
  87. fft.performRealOnlyInverseTransform ((float*) output.getData());
  88. u.expect (checkArrayIsSimilar ((float*) output.getData(), input.getData(), n));
  89. }
  90. }
  91. };
  92. struct FrequencyOnlyTest
  93. {
  94. static void run(FFTUnitTest& u)
  95. {
  96. Random random (378272);
  97. for (size_t order = 0; order <= 8; ++order)
  98. {
  99. auto n = (1u << order);
  100. FFT fft ((int) order);
  101. HeapBlock<float> inout (n << 1), reference (n << 1);
  102. HeapBlock<Complex<float> > frequency (n);
  103. fillRandom (random, inout.getData(), n);
  104. zeromem (reference.getData(), sizeof (float) * (n << 1));
  105. performReferenceFourier (inout.getData(), frequency.getData(), n, false);
  106. for (size_t i = 0; i < n; ++i)
  107. reference.getData()[i] = std::abs (frequency.getData()[i]);
  108. fft.performFrequencyOnlyForwardTransform (inout.getData());
  109. u.expect (checkArrayIsSimilar (inout.getData(), reference.getData(), n));
  110. }
  111. }
  112. };
  113. struct ComplexTest
  114. {
  115. static void run(FFTUnitTest& u)
  116. {
  117. Random random (378272);
  118. for (size_t order = 0; order <= 7; ++order)
  119. {
  120. auto n = (1u << order);
  121. FFT fft ((int) order);
  122. HeapBlock<Complex<float> > input (n), buffer (n), output (n), reference (n);
  123. fillRandom (random, input.getData(), n);
  124. performReferenceFourier (input.getData(), reference.getData(), n, false);
  125. memcpy (buffer.getData(), input.getData(), sizeof (Complex<float>) * n);
  126. fft.perform (buffer.getData(), output.getData(), false);
  127. u.expect (checkArrayIsSimilar (output.getData(), reference.getData(), n));
  128. memcpy (buffer.getData(), reference.getData(), sizeof (Complex<float>) * n);
  129. fft.perform (buffer.getData(), output.getData(), true);
  130. u.expect (checkArrayIsSimilar (output.getData(), input.getData(), n));
  131. }
  132. }
  133. };
  134. template <class TheTest>
  135. void runTestForAllTypes (const char* unitTestName)
  136. {
  137. beginTest (unitTestName);
  138. TheTest::run (*this);
  139. }
  140. void runTest() override
  141. {
  142. runTestForAllTypes<RealTest> ("Real input numbers Test");
  143. runTestForAllTypes<FrequencyOnlyTest> ("Frequency only Test");
  144. runTestForAllTypes<ComplexTest> ("Complex input numbers Test");
  145. }
  146. };
  147. static FFTUnitTest fftUnitTest;