OpenShot Audio Library | OpenShotAudio  0.3.0
juce_FFT_test.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11  Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12  27th April 2017).
13 
14  End User License Agreement: www.juce.com/juce-5-licence
15  Privacy Policy: www.juce.com/juce-5-privacy-policy
16 
17  Or: You may also use this code under the terms of the GPL v3 (see
18  www.gnu.org/licenses).
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 namespace dsp
30 {
31 
32 struct FFTUnitTest : public UnitTest
33 {
34  FFTUnitTest()
35  : UnitTest ("FFT", UnitTestCategories::dsp)
36  {}
37 
38  static void fillRandom (Random& random, Complex<float>* buffer, size_t n)
39  {
40  for (size_t i = 0; i < n; ++i)
41  buffer[i] = Complex<float> ((2.0f * random.nextFloat()) - 1.0f,
42  (2.0f * random.nextFloat()) - 1.0f);
43  }
44 
45  static void fillRandom (Random& random, float* buffer, size_t n)
46  {
47  for (size_t i = 0; i < n; ++i)
48  buffer[i] = (2.0f * random.nextFloat()) - 1.0f;
49  }
50 
51  static Complex<float> freqConvolution (const Complex<float>* in, float freq, size_t n)
52  {
53  Complex<float> sum (0.0, 0.0);
54  for (size_t i = 0; i < n; ++i)
55  sum += in[i] * exp (Complex<float> (0, static_cast<float> (i) * freq));
56 
57  return sum;
58  }
59 
60  static void performReferenceFourier (const Complex<float>* in, Complex<float>* out,
61  size_t n, bool reverse)
62  {
63  auto base_freq = static_cast<float> (((reverse ? 1.0 : -1.0) * MathConstants<double>::twoPi)
64  / static_cast<float> (n));
65 
66  for (size_t i = 0; i < n; ++i)
67  out[i] = freqConvolution (in, static_cast<float>(i) * base_freq, n);
68  }
69 
70  static void performReferenceFourier (const float* in, Complex<float>* out,
71  size_t n, bool reverse)
72  {
73  HeapBlock<Complex<float>> buffer (n);
74 
75  for (size_t i = 0; i < n; ++i)
76  buffer.getData()[i] = Complex<float> (in[i], 0.0f);
77 
78  float base_freq = static_cast<float> (((reverse ? 1.0 : -1.0) * MathConstants<double>::twoPi)
79  / static_cast<float> (n));
80 
81  for (size_t i = 0; i < n; ++i)
82  out[i] = freqConvolution (buffer.getData(), static_cast<float>(i) * base_freq, n);
83  }
84 
85 
86  //==============================================================================
87  template <typename Type>
88  static bool checkArrayIsSimilar (Type* a, Type* b, size_t n) noexcept
89  {
90  for (size_t i = 0; i < n; ++i)
91  if (std::abs (a[i] - b[i]) > 1e-3f)
92  return false;
93 
94  return true;
95  }
96 
97  struct RealTest
98  {
99  static void run (FFTUnitTest& u)
100  {
101  Random random (378272);
102 
103  for (size_t order = 0; order <= 8; ++order)
104  {
105  auto n = (1u << order);
106 
107  FFT fft ((int) order);
108 
109  HeapBlock<float> input (n);
110  HeapBlock<Complex<float>> reference (n), output (n);
111 
112  fillRandom (random, input.getData(), n);
113  performReferenceFourier (input.getData(), reference.getData(), n, false);
114 
115  // fill only first half with real numbers
116  zeromem (output.getData(), n * sizeof (Complex<float>));
117  memcpy (reinterpret_cast<float*> (output.getData()), input.getData(), n * sizeof (float));
118 
119  fft.performRealOnlyForwardTransform ((float*) output.getData());
120  u.expect (checkArrayIsSimilar (reference.getData(), output.getData(), n));
121 
122  // fill only first half with real numbers
123  zeromem (output.getData(), n * sizeof (Complex<float>));
124  memcpy (reinterpret_cast<float*> (output.getData()), input.getData(), n * sizeof (float));
125 
126  fft.performRealOnlyForwardTransform ((float*) output.getData(), true);
127  std::fill (reference.getData() + ((n >> 1) + 1), reference.getData() + n, std::complex<float> (0.0f));
128  u.expect (checkArrayIsSimilar (reference.getData(), output.getData(), (n >> 1) + 1));
129 
130  memcpy (output.getData(), reference.getData(), n * sizeof (Complex<float>));
131  fft.performRealOnlyInverseTransform ((float*) output.getData());
132  u.expect (checkArrayIsSimilar ((float*) output.getData(), input.getData(), n));
133  }
134  }
135  };
136 
137  struct FrequencyOnlyTest
138  {
139  static void run(FFTUnitTest& u)
140  {
141  Random random (378272);
142  for (size_t order = 0; order <= 8; ++order)
143  {
144  auto n = (1u << order);
145 
146  FFT fft ((int) order);
147 
148  HeapBlock<float> inout (n << 1), reference (n << 1);
149  HeapBlock<Complex<float>> frequency (n);
150 
151  fillRandom (random, inout.getData(), n);
152  zeromem (reference.getData(), sizeof (float) * (n << 1));
153  performReferenceFourier (inout.getData(), frequency.getData(), n, false);
154 
155  for (size_t i = 0; i < n; ++i)
156  reference.getData()[i] = std::abs (frequency.getData()[i]);
157 
158  fft.performFrequencyOnlyForwardTransform (inout.getData());
159 
160  u.expect (checkArrayIsSimilar (inout.getData(), reference.getData(), n));
161  }
162  }
163  };
164 
165  struct ComplexTest
166  {
167  static void run(FFTUnitTest& u)
168  {
169  Random random (378272);
170 
171  for (size_t order = 0; order <= 7; ++order)
172  {
173  auto n = (1u << order);
174 
175  FFT fft ((int) order);
176 
177  HeapBlock<Complex<float>> input (n), buffer (n), output (n), reference (n);
178 
179  fillRandom (random, input.getData(), n);
180  performReferenceFourier (input.getData(), reference.getData(), n, false);
181 
182  memcpy (buffer.getData(), input.getData(), sizeof (Complex<float>) * n);
183  fft.perform (buffer.getData(), output.getData(), false);
184 
185  u.expect (checkArrayIsSimilar (output.getData(), reference.getData(), n));
186 
187  memcpy (buffer.getData(), reference.getData(), sizeof (Complex<float>) * n);
188  fft.perform (buffer.getData(), output.getData(), true);
189 
190 
191  u.expect (checkArrayIsSimilar (output.getData(), input.getData(), n));
192  }
193  }
194  };
195 
196  template <class TheTest>
197  void runTestForAllTypes (const char* unitTestName)
198  {
199  beginTest (unitTestName);
200 
201  TheTest::run (*this);
202  }
203 
204  void runTest() override
205  {
206  runTestForAllTypes<RealTest> ("Real input numbers Test");
207  runTestForAllTypes<FrequencyOnlyTest> ("Frequency only Test");
208  runTestForAllTypes<ComplexTest> ("Complex input numbers Test");
209  }
210 };
211 
212 static FFTUnitTest fftUnitTest;
213 
214 } // namespace dsp
215 } // namespace juce
UnitTest(const String &name, const String &category=String())
static const FloatType twoPi