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