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.

207 lines
7.4KB

  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. // fill only first half with real numbers
  87. zeromem (output.getData(), n * sizeof (Complex<float>));
  88. memcpy (reinterpret_cast<float*> (output.getData()), input.getData(), n * sizeof (float));
  89. fft.performRealOnlyForwardTransform ((float*) output.getData(), true);
  90. std::fill (reference.getData() + ((n >> 1) + 1), reference.getData() + n, std::complex<float> (0.0f));
  91. u.expect (checkArrayIsSimilar (reference.getData(), output.getData(), (n >> 1) + 1));
  92. memcpy (output.getData(), reference.getData(), n * sizeof (Complex<float>));
  93. fft.performRealOnlyInverseTransform ((float*) output.getData());
  94. u.expect (checkArrayIsSimilar ((float*) output.getData(), input.getData(), n));
  95. }
  96. }
  97. };
  98. struct FrequencyOnlyTest
  99. {
  100. static void run(FFTUnitTest& u)
  101. {
  102. Random random (378272);
  103. for (size_t order = 0; order <= 8; ++order)
  104. {
  105. auto n = (1u << order);
  106. FFT fft ((int) order);
  107. HeapBlock<float> inout (n << 1), reference (n << 1);
  108. HeapBlock<Complex<float> > frequency (n);
  109. fillRandom (random, inout.getData(), n);
  110. zeromem (reference.getData(), sizeof (float) * (n << 1));
  111. performReferenceFourier (inout.getData(), frequency.getData(), n, false);
  112. for (size_t i = 0; i < n; ++i)
  113. reference.getData()[i] = std::abs (frequency.getData()[i]);
  114. fft.performFrequencyOnlyForwardTransform (inout.getData());
  115. u.expect (checkArrayIsSimilar (inout.getData(), reference.getData(), n));
  116. }
  117. }
  118. };
  119. struct ComplexTest
  120. {
  121. static void run(FFTUnitTest& u)
  122. {
  123. Random random (378272);
  124. for (size_t order = 0; order <= 7; ++order)
  125. {
  126. auto n = (1u << order);
  127. FFT fft ((int) order);
  128. HeapBlock<Complex<float> > input (n), buffer (n), output (n), reference (n);
  129. fillRandom (random, input.getData(), n);
  130. performReferenceFourier (input.getData(), reference.getData(), n, false);
  131. memcpy (buffer.getData(), input.getData(), sizeof (Complex<float>) * n);
  132. fft.perform (buffer.getData(), output.getData(), false);
  133. u.expect (checkArrayIsSimilar (output.getData(), reference.getData(), n));
  134. memcpy (buffer.getData(), reference.getData(), sizeof (Complex<float>) * n);
  135. fft.perform (buffer.getData(), output.getData(), true);
  136. u.expect (checkArrayIsSimilar (output.getData(), input.getData(), n));
  137. }
  138. }
  139. };
  140. template <class TheTest>
  141. void runTestForAllTypes (const char* unitTestName)
  142. {
  143. beginTest (unitTestName);
  144. TheTest::run (*this);
  145. }
  146. void runTest() override
  147. {
  148. runTestForAllTypes<RealTest> ("Real input numbers Test");
  149. runTestForAllTypes<FrequencyOnlyTest> ("Frequency only Test");
  150. runTestForAllTypes<ComplexTest> ("Complex input numbers Test");
  151. }
  152. };
  153. static FFTUnitTest fftUnitTest;