LMMS
Loading...
Searching...
No Matches
juce_FFT.cpp
Go to the documentation of this file.
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
27{
28namespace dsp
29{
30
32{
33 virtual ~Instance() = default;
34 virtual void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept = 0;
35 virtual void performRealOnlyForwardTransform (float*, bool) const noexcept = 0;
36 virtual void performRealOnlyInverseTransform (float*) const noexcept = 0;
37};
38
40{
41 Engine (int priorityToUse) : enginePriority (priorityToUse)
42 {
43 auto& list = getEngines();
44 list.add (this);
45 std::sort (list.begin(), list.end(), [] (Engine* a, Engine* b) { return b->enginePriority < a->enginePriority; });
46 }
47
48 virtual ~Engine() = default;
49
50 virtual FFT::Instance* create (int order) const = 0;
51
52 //==============================================================================
54 {
55 for (auto* engine : getEngines())
56 if (auto* instance = engine->create (order))
57 return instance;
58
59 jassertfalse; // This should never happen as the fallback engine should always work!
60 return nullptr;
61 }
62
63private:
65 {
66 static Array<Engine*> engines;
67 return engines;
68 }
69
70 int enginePriority; // used so that faster engines have priority over slower ones
71};
72
73template <typename InstanceToUse>
75{
76 EngineImpl() : FFT::Engine (InstanceToUse::priority) {}
77 FFT::Instance* create (int order) const override { return InstanceToUse::create (order); }
78};
79
80//==============================================================================
81//==============================================================================
83{
84 // this should have the least priority of all engines
85 static constexpr int priority = -1;
86
87 static FFTFallback* create (int order)
88 {
89 return new FFTFallback (order);
90 }
91
92 FFTFallback (int order)
93 {
94 configForward.reset (new FFTConfig (1 << order, false));
95 configInverse.reset (new FFTConfig (1 << order, true));
96
97 size = 1 << order;
98 }
99
100 void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
101 {
102 if (size == 1)
103 {
104 *output = *input;
105 return;
106 }
107
109
110 jassert (configForward != nullptr);
111
112 if (inverse)
113 {
114 configInverse->perform (input, output);
115
116 const float scaleFactor = 1.0f / (float) size;
117
118 for (int i = 0; i < size; ++i)
119 output[i] *= scaleFactor;
120 }
121 else
122 {
123 configForward->perform (input, output);
124 }
125 }
126
127 const size_t maxFFTScratchSpaceToAlloca = 256 * 1024;
128
129 void performRealOnlyForwardTransform (float* d, bool) const noexcept override
130 {
131 if (size == 1)
132 return;
133
134 const size_t scratchSize = 16 + (size_t) size * sizeof (Complex<float>);
135
136 if (scratchSize < maxFFTScratchSpaceToAlloca)
137 {
139 performRealOnlyForwardTransform (static_cast<Complex<float>*> (alloca (scratchSize)), d);
141 }
142 else
143 {
144 HeapBlock<char> heapSpace (scratchSize);
146 }
147 }
148
149 void performRealOnlyInverseTransform (float* d) const noexcept override
150 {
151 if (size == 1)
152 return;
153
154 const size_t scratchSize = 16 + (size_t) size * sizeof (Complex<float>);
155
156 if (scratchSize < maxFFTScratchSpaceToAlloca)
157 {
159 performRealOnlyInverseTransform (static_cast<Complex<float>*> (alloca (scratchSize)), d);
161 }
162 else
163 {
164 HeapBlock<char> heapSpace (scratchSize);
166 }
167 }
168
169 void performRealOnlyForwardTransform (Complex<float>* scratch, float* d) const noexcept
170 {
171 for (int i = 0; i < size; ++i)
172 scratch[i] = { d[i], 0 };
173
174 perform (scratch, reinterpret_cast<Complex<float>*> (d), false);
175 }
176
177 void performRealOnlyInverseTransform (Complex<float>* scratch, float* d) const noexcept
178 {
179 auto* input = reinterpret_cast<Complex<float>*> (d);
180
181 for (int i = size >> 1; i < size; ++i)
182 input[i] = std::conj (input[size - i]);
183
184 perform (input, scratch, true);
185
186 for (int i = 0; i < size; ++i)
187 {
188 d[i] = scratch[i].real();
189 d[i + size] = scratch[i].imag();
190 }
191 }
192
193 //==============================================================================
195 {
196 FFTConfig (int sizeOfFFT, bool isInverse)
197 : fftSize (sizeOfFFT), inverse (isInverse), twiddleTable ((size_t) sizeOfFFT)
198 {
199 auto inverseFactor = (inverse ? 2.0 : -2.0) * MathConstants<double>::pi / (double) fftSize;
200
201 if (fftSize <= 4)
202 {
203 for (int i = 0; i < fftSize; ++i)
204 {
205 auto phase = i * inverseFactor;
206
207 twiddleTable[i] = { (float) std::cos (phase),
208 (float) std::sin (phase) };
209 }
210 }
211 else
212 {
213 for (int i = 0; i < fftSize / 4; ++i)
214 {
215 auto phase = i * inverseFactor;
216
217 twiddleTable[i] = { (float) std::cos (phase),
218 (float) std::sin (phase) };
219 }
220
221 for (int i = fftSize / 4; i < fftSize / 2; ++i)
222 {
223 auto other = twiddleTable[i - fftSize / 4];
224
225 twiddleTable[i] = { inverse ? -other.imag() : other.imag(),
226 inverse ? other.real() : -other.real() };
227 }
228
229 twiddleTable[fftSize / 2].real (-1.0f);
230 twiddleTable[fftSize / 2].imag (0.0f);
231
232 for (int i = fftSize / 2; i < fftSize; ++i)
233 {
234 auto index = fftSize / 2 - (i - fftSize / 2);
235 twiddleTable[i] = conj(twiddleTable[index]);
236 }
237 }
238
239 auto root = (int) std::sqrt ((double) fftSize);
240 int divisor = 4, n = fftSize;
241
242 for (int i = 0; i < numElementsInArray (factors); ++i)
243 {
244 while ((n % divisor) != 0)
245 {
246 if (divisor == 2) divisor = 3;
247 else if (divisor == 4) divisor = 2;
248 else divisor += 2;
249
250 if (divisor > root)
251 divisor = n;
252 }
253
254 n /= divisor;
255
256 jassert (divisor == 1 || divisor == 2 || divisor == 4);
257 factors[i].radix = divisor;
258 factors[i].length = n;
259 }
260 }
261
262 void perform (const Complex<float>* input, Complex<float>* output) const noexcept
263 {
264 perform (input, output, 1, 1, factors);
265 }
266
267 const int fftSize;
268 const bool inverse;
269
270 struct Factor { int radix, length; };
273
274 void perform (const Complex<float>* input, Complex<float>* output, int stride, int strideIn, const Factor* facs) const noexcept
275 {
276 auto factor = *facs++;
277 auto* originalOutput = output;
278 auto* outputEnd = output + factor.radix * factor.length;
279
280 if (stride == 1 && factor.radix <= 5)
281 {
282 for (int i = 0; i < factor.radix; ++i)
283 perform (input + stride * strideIn * i, output + i * factor.length, stride * factor.radix, strideIn, facs);
284
285 butterfly (factor, output, stride);
286 return;
287 }
288
289 if (factor.length == 1)
290 {
291 do
292 {
293 *output++ = *input;
294 input += stride * strideIn;
295 }
296 while (output < outputEnd);
297 }
298 else
299 {
300 do
301 {
302 perform (input, output, stride * factor.radix, strideIn, facs);
303 input += stride * strideIn;
304 output += factor.length;
305 }
306 while (output < outputEnd);
307 }
308
309 butterfly (factor, originalOutput, stride);
310 }
311
312 void butterfly (const Factor factor, Complex<float>* data, int stride) const noexcept
313 {
314 switch (factor.radix)
315 {
316 case 1: break;
317 case 2: butterfly2 (data, stride, factor.length); return;
318 case 4: butterfly4 (data, stride, factor.length); return;
319 default: jassertfalse; break;
320 }
321
323 auto* scratch = static_cast<Complex<float>*> (alloca ((size_t) factor.radix * sizeof (Complex<float>)));
325
326 for (int i = 0; i < factor.length; ++i)
327 {
328 for (int k = i, q1 = 0; q1 < factor.radix; ++q1)
329 {
331 scratch[q1] = data[k];
333 k += factor.length;
334 }
335
336 for (int k = i, q1 = 0; q1 < factor.radix; ++q1)
337 {
338 int twiddleIndex = 0;
339 data[k] = scratch[0];
340
341 for (int q = 1; q < factor.radix; ++q)
342 {
343 twiddleIndex += stride * k;
344
345 if (twiddleIndex >= fftSize)
346 twiddleIndex -= fftSize;
347
349 data[k] += scratch[q] * twiddleTable[twiddleIndex];
351 }
352
353 k += factor.length;
354 }
355 }
356 }
357
358 void butterfly2 (Complex<float>* data, const int stride, const int length) const noexcept
359 {
360 auto* dataEnd = data + length;
361 auto* tw = twiddleTable.getData();
362
363 for (int i = length; --i >= 0;)
364 {
365 auto s = *dataEnd;
366 s *= (*tw);
367 tw += stride;
368 *dataEnd++ = *data - s;
369 *data++ += s;
370 }
371 }
372
373 void butterfly4 (Complex<float>* data, const int stride, const int length) const noexcept
374 {
375 auto lengthX2 = length * 2;
376 auto lengthX3 = length * 3;
377
378 auto strideX2 = stride * 2;
379 auto strideX3 = stride * 3;
380
381 auto* twiddle1 = twiddleTable.getData();
382 auto* twiddle2 = twiddle1;
383 auto* twiddle3 = twiddle1;
384
385 for (int i = length; --i >= 0;)
386 {
387 auto s0 = data[length] * *twiddle1;
388 auto s1 = data[lengthX2] * *twiddle2;
389 auto s2 = data[lengthX3] * *twiddle3;
390 auto s3 = s0; s3 += s2;
391 auto s4 = s0; s4 -= s2;
392 auto s5 = *data; s5 -= s1;
393
394 *data += s1;
395 data[lengthX2] = *data;
396 data[lengthX2] -= s3;
397 twiddle1 += stride;
398 twiddle2 += strideX2;
399 twiddle3 += strideX3;
400 *data += s3;
401
402 if (inverse)
403 {
404 data[length] = { s5.real() - s4.imag(),
405 s5.imag() + s4.real() };
406
407 data[lengthX3] = { s5.real() + s4.imag(),
408 s5.imag() - s4.real() };
409 }
410 else
411 {
412 data[length] = { s5.real() + s4.imag(),
413 s5.imag() - s4.real() };
414
415 data[lengthX3] = { s5.real() - s4.imag(),
416 s5.imag() + s4.real() };
417 }
418
419 ++data;
420 }
421 }
422
424 };
425
426 //==============================================================================
428 std::unique_ptr<FFTConfig> configForward, configInverse;
429 int size;
430};
431
433
434//==============================================================================
435//==============================================================================
436#if (JUCE_MAC || JUCE_IOS) && JUCE_USE_VDSP_FRAMEWORK
437struct AppleFFT : public FFT::Instance
438{
439 static constexpr int priority = 5;
440
441 static AppleFFT* create (int order)
442 {
443 return new AppleFFT (order);
444 }
445
446 AppleFFT (int orderToUse)
447 : order (static_cast<vDSP_Length> (orderToUse)),
448 fftSetup (vDSP_create_fftsetup (order, 2)),
449 forwardNormalisation (0.5f),
450 inverseNormalisation (1.0f / static_cast<float> (1 << order))
451 {}
452
453 ~AppleFFT() override
454 {
455 if (fftSetup != nullptr)
456 {
457 vDSP_destroy_fftsetup (fftSetup);
458 fftSetup = nullptr;
459 }
460 }
461
462 void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
463 {
464 auto size = (1 << order);
465
466 DSPSplitComplex splitInput (toSplitComplex (const_cast<Complex<float>*> (input)));
467 DSPSplitComplex splitOutput (toSplitComplex (output));
468
469 vDSP_fft_zop (fftSetup, &splitInput, 2, &splitOutput, 2,
470 order, inverse ? kFFTDirection_Inverse : kFFTDirection_Forward);
471
472 float factor = (inverse ? inverseNormalisation : forwardNormalisation * 2.0f);
473 vDSP_vsmul ((float*) output, 1, &factor, (float*) output, 1, static_cast<size_t> (size << 1));
474 }
475
476 void performRealOnlyForwardTransform (float* inoutData, bool ignoreNegativeFreqs) const noexcept override
477 {
478 auto size = (1 << order);
479 auto* inout = reinterpret_cast<Complex<float>*> (inoutData);
480 auto splitInOut (toSplitComplex (inout));
481
482 inoutData[size] = 0.0f;
483 vDSP_fft_zrip (fftSetup, &splitInOut, 2, order, kFFTDirection_Forward);
484 vDSP_vsmul (inoutData, 1, &forwardNormalisation, inoutData, 1, static_cast<size_t> (size << 1));
485
486 mirrorResult (inout, ignoreNegativeFreqs);
487 }
488
489 void performRealOnlyInverseTransform (float* inoutData) const noexcept override
490 {
491 auto* inout = reinterpret_cast<Complex<float>*> (inoutData);
492 auto size = (1 << order);
493 auto splitInOut (toSplitComplex (inout));
494
495 // Imaginary part of nyquist and DC frequencies are always zero
496 // so Apple uses the imaginary part of the DC frequency to store
497 // the real part of the nyquist frequency
498 if (size != 1)
499 inout[0] = Complex<float> (inout[0].real(), inout[size >> 1].real());
500
501 vDSP_fft_zrip (fftSetup, &splitInOut, 2, order, kFFTDirection_Inverse);
502 vDSP_vsmul (inoutData, 1, &inverseNormalisation, inoutData, 1, static_cast<size_t> (size << 1));
503 vDSP_vclr (inoutData + size, 1, static_cast<size_t> (size));
504 }
505
506private:
507 //==============================================================================
508 void mirrorResult (Complex<float>* out, bool ignoreNegativeFreqs) const noexcept
509 {
510 auto size = (1 << order);
511 auto i = size >> 1;
512
513 // Imaginary part of nyquist and DC frequencies are always zero
514 // so Apple uses the imaginary part of the DC frequency to store
515 // the real part of the nyquist frequency
516 out[i++] = { out[0].imag(), 0.0 };
517 out[0] = { out[0].real(), 0.0 };
518
519 if (! ignoreNegativeFreqs)
520 for (; i < size; ++i)
521 out[i] = std::conj (out[size - i]);
522 }
523
524 static DSPSplitComplex toSplitComplex (Complex<float>* data) noexcept
525 {
526 // this assumes that Complex interleaves real and imaginary parts
527 // and is tightly packed.
528 return { reinterpret_cast<float*> (data),
529 reinterpret_cast<float*> (data) + 1};
530 }
531
532 //==============================================================================
533 vDSP_Length order;
534 FFTSetup fftSetup;
535 float forwardNormalisation, inverseNormalisation;
536};
537
538FFT::EngineImpl<AppleFFT> appleFFT;
539#endif
540
541//==============================================================================
542//==============================================================================
543#if JUCE_DSP_USE_SHARED_FFTW || JUCE_DSP_USE_STATIC_FFTW
544
545#if JUCE_DSP_USE_STATIC_FFTW
546extern "C"
547{
548 void* fftwf_plan_dft_1d (int, void*, void*, int, int);
549 void* fftwf_plan_dft_r2c_1d (int, void*, void*, int);
550 void* fftwf_plan_dft_c2r_1d (int, void*, void*, int);
551 void fftwf_destroy_plan (void*);
552 void fftwf_execute_dft (void*, void*, void*);
553 void fftwf_execute_dft_r2c (void*, void*, void*);
554 void fftwf_execute_dft_c2r (void*, void*, void*);
555}
556#endif
557
558struct FFTWImpl : public FFT::Instance
559{
560 #if JUCE_DSP_USE_STATIC_FFTW
561 // if the JUCE developer has gone through the hassle of statically
562 // linking in fftw, they probably want to use it
563 static constexpr int priority = 10;
564 #else
565 static constexpr int priority = 3;
566 #endif
567
568 struct FFTWPlan;
569 using FFTWPlanRef = FFTWPlan*;
570
571 enum
572 {
573 measure = 0,
574 unaligned = (1 << 1),
575 estimate = (1 << 6)
576 };
577
578 struct Symbols
579 {
580 FFTWPlanRef (*plan_dft_fftw) (unsigned, Complex<float>*, Complex<float>*, int, unsigned);
581 FFTWPlanRef (*plan_r2c_fftw) (unsigned, float*, Complex<float>*, unsigned);
582 FFTWPlanRef (*plan_c2r_fftw) (unsigned, Complex<float>*, float*, unsigned);
583 void (*destroy_fftw) (FFTWPlanRef);
584
585 void (*execute_dft_fftw) (FFTWPlanRef, const Complex<float>*, Complex<float>*);
586 void (*execute_r2c_fftw) (FFTWPlanRef, float*, Complex<float>*);
587 void (*execute_c2r_fftw) (FFTWPlanRef, Complex<float>*, float*);
588
589 #if JUCE_DSP_USE_STATIC_FFTW
590 template <typename FuncPtr, typename ActualSymbolType>
591 static bool symbol (FuncPtr& dst, ActualSymbolType sym)
592 {
593 dst = reinterpret_cast<FuncPtr> (sym);
594 return true;
595 }
596 #else
597 template <typename FuncPtr>
598 static bool symbol (DynamicLibrary& lib, FuncPtr& dst, const char* name)
599 {
600 dst = reinterpret_cast<FuncPtr> (lib.getFunction (name));
601 return (dst != nullptr);
602 }
603 #endif
604 };
605
606 static FFTWImpl* create (int order)
607 {
608 DynamicLibrary lib;
609
610 #if ! JUCE_DSP_USE_STATIC_FFTW
611 #if JUCE_MAC
612 auto libName = "libfftw3f.dylib";
613 #elif JUCE_WINDOWS
614 auto libName = "libfftw3f.dll";
615 #else
616 auto libName = "libfftw3f.so";
617 #endif
618
619 if (lib.open (libName))
620 #endif
621 {
622 Symbols symbols;
623
624 #if JUCE_DSP_USE_STATIC_FFTW
625 if (! Symbols::symbol (symbols.plan_dft_fftw, fftwf_plan_dft_1d)) return nullptr;
626 if (! Symbols::symbol (symbols.plan_r2c_fftw, fftwf_plan_dft_r2c_1d)) return nullptr;
627 if (! Symbols::symbol (symbols.plan_c2r_fftw, fftwf_plan_dft_c2r_1d)) return nullptr;
628 if (! Symbols::symbol (symbols.destroy_fftw, fftwf_destroy_plan)) return nullptr;
629
630 if (! Symbols::symbol (symbols.execute_dft_fftw, fftwf_execute_dft)) return nullptr;
631 if (! Symbols::symbol (symbols.execute_r2c_fftw, fftwf_execute_dft_r2c)) return nullptr;
632 if (! Symbols::symbol (symbols.execute_c2r_fftw, fftwf_execute_dft_c2r)) return nullptr;
633 #else
634 if (! Symbols::symbol (lib, symbols.plan_dft_fftw, "fftwf_plan_dft_1d")) return nullptr;
635 if (! Symbols::symbol (lib, symbols.plan_r2c_fftw, "fftwf_plan_dft_r2c_1d")) return nullptr;
636 if (! Symbols::symbol (lib, symbols.plan_c2r_fftw, "fftwf_plan_dft_c2r_1d")) return nullptr;
637 if (! Symbols::symbol (lib, symbols.destroy_fftw, "fftwf_destroy_plan")) return nullptr;
638
639 if (! Symbols::symbol (lib, symbols.execute_dft_fftw, "fftwf_execute_dft")) return nullptr;
640 if (! Symbols::symbol (lib, symbols.execute_r2c_fftw, "fftwf_execute_dft_r2c")) return nullptr;
641 if (! Symbols::symbol (lib, symbols.execute_c2r_fftw, "fftwf_execute_dft_c2r")) return nullptr;
642 #endif
643
644 return new FFTWImpl (static_cast<size_t> (order), std::move (lib), symbols);
645 }
646
647 return nullptr;
648 }
649
650 FFTWImpl (size_t orderToUse, DynamicLibrary&& libraryToUse, const Symbols& symbols)
651 : fftwLibrary (std::move (libraryToUse)), fftw (symbols), order (static_cast<size_t> (orderToUse))
652 {
653 ScopedLock lock (getFFTWPlanLock());
654
655 auto n = (1u << order);
656 HeapBlock<Complex<float>> in (n), out (n);
657
658 c2cForward = fftw.plan_dft_fftw (n, in.getData(), out.getData(), -1, unaligned | estimate);
659 c2cInverse = fftw.plan_dft_fftw (n, in.getData(), out.getData(), +1, unaligned | estimate);
660
661 r2c = fftw.plan_r2c_fftw (n, (float*) in.getData(), in.getData(), unaligned | estimate);
662 c2r = fftw.plan_c2r_fftw (n, in.getData(), (float*) in.getData(), unaligned | estimate);
663 }
664
665 ~FFTWImpl() override
666 {
667 ScopedLock lock (getFFTWPlanLock());
668
669 fftw.destroy_fftw (c2cForward);
670 fftw.destroy_fftw (c2cInverse);
671 fftw.destroy_fftw (r2c);
672 fftw.destroy_fftw (c2r);
673 }
674
675 void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
676 {
677 if (inverse)
678 {
679 auto n = (1u << order);
680 fftw.execute_dft_fftw (c2cInverse, input, output);
681 FloatVectorOperations::multiply ((float*) output, 1.0f / static_cast<float> (n), (int) n << 1);
682 }
683 else
684 {
685 fftw.execute_dft_fftw (c2cForward, input, output);
686 }
687 }
688
689 void performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept override
690 {
691 if (order == 0)
692 return;
693
694 auto* out = reinterpret_cast<Complex<float>*> (inputOutputData);
695
696 fftw.execute_r2c_fftw (r2c, inputOutputData, out);
697
698 auto size = (1 << order);
699
700 if (! ignoreNegativeFreqs)
701 for (int i = size >> 1; i < size; ++i)
702 out[i] = std::conj (out[size - i]);
703 }
704
705 void performRealOnlyInverseTransform (float* inputOutputData) const noexcept override
706 {
707 auto n = (1u << order);
708
709 fftw.execute_c2r_fftw (c2r, (Complex<float>*) inputOutputData, inputOutputData);
710 FloatVectorOperations::multiply ((float*) inputOutputData, 1.0f / static_cast<float> (n), (int) n);
711 }
712
713 //==============================================================================
714 // fftw's plan_* and destroy_* methods are NOT thread safe. So we need to share
715 // a lock between all instances of FFTWImpl
716 static CriticalSection& getFFTWPlanLock() noexcept
717 {
718 static CriticalSection cs;
719 return cs;
720 }
721
722 //==============================================================================
723 DynamicLibrary fftwLibrary;
724 Symbols fftw;
725 size_t order;
726
727 FFTWPlanRef c2cForward, c2cInverse, r2c, c2r;
728};
729
730FFT::EngineImpl<FFTWImpl> fftwEngine;
731#endif
732
733//==============================================================================
734//==============================================================================
735#if JUCE_DSP_USE_INTEL_MKL
736struct IntelFFT : public FFT::Instance
737{
738 static constexpr int priority = 8;
739
740 static bool succeeded (MKL_LONG status) noexcept { return status == 0; }
741
742 static IntelFFT* create (int orderToUse)
743 {
744 DFTI_DESCRIPTOR_HANDLE mklc2c, mklc2r;
745
746 if (DftiCreateDescriptor (&mklc2c, DFTI_SINGLE, DFTI_COMPLEX, 1, 1 << orderToUse) == 0)
747 {
748 if (succeeded (DftiSetValue (mklc2c, DFTI_PLACEMENT, DFTI_NOT_INPLACE))
749 && succeeded (DftiSetValue (mklc2c, DFTI_BACKWARD_SCALE, 1.0f / static_cast<float> (1 << orderToUse)))
750 && succeeded (DftiCommitDescriptor (mklc2c)))
751 {
752 if (succeeded (DftiCreateDescriptor (&mklc2r, DFTI_SINGLE, DFTI_REAL, 1, 1 << orderToUse)))
753 {
754 if (succeeded (DftiSetValue (mklc2r, DFTI_PLACEMENT, DFTI_INPLACE))
755 && succeeded (DftiSetValue (mklc2r, DFTI_BACKWARD_SCALE, 1.0f / static_cast<float> (1 << orderToUse)))
756 && succeeded (DftiCommitDescriptor (mklc2r)))
757 {
758 return new IntelFFT (static_cast<size_t> (orderToUse), mklc2c, mklc2r);
759 }
760
761 DftiFreeDescriptor (&mklc2r);
762 }
763 }
764
765 DftiFreeDescriptor (&mklc2c);
766 }
767
768 return {};
769 }
770
771 IntelFFT (size_t orderToUse, DFTI_DESCRIPTOR_HANDLE c2cToUse, DFTI_DESCRIPTOR_HANDLE cr2ToUse)
772 : order (orderToUse), c2c (c2cToUse), c2r (cr2ToUse)
773 {}
774
775 ~IntelFFT() override
776 {
777 DftiFreeDescriptor (&c2c);
778 DftiFreeDescriptor (&c2r);
779 }
780
781 void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
782 {
783 if (inverse)
784 DftiComputeBackward (c2c, (void*) input, output);
785 else
786 DftiComputeForward (c2c, (void*) input, output);
787 }
788
789 void performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept override
790 {
791 if (order == 0)
792 return;
793
794 DftiComputeForward (c2r, inputOutputData);
795
796 auto* out = reinterpret_cast<Complex<float>*> (inputOutputData);
797 auto size = (1 << order);
798
799 if (! ignoreNegativeFreqs)
800 for (int i = size >> 1; i < size; ++i)
801 out[i] = std::conj (out[size - i]);
802 }
803
804 void performRealOnlyInverseTransform (float* inputOutputData) const noexcept override
805 {
806 DftiComputeBackward (c2r, inputOutputData);
807 }
808
809 size_t order;
810 DFTI_DESCRIPTOR_HANDLE c2c, c2r;
811};
812
813FFT::EngineImpl<IntelFFT> fftwEngine;
814#endif
815
816//==============================================================================
817//==============================================================================
818// Visual Studio should define no more than one of these, depending on the
819// setting at 'Project' > 'Properties' > 'Configuration Properties' > 'Intel
820// Performance Libraries' > 'Use Intel(R) IPP'
821#if _IPP_SEQUENTIAL_STATIC || _IPP_SEQUENTIAL_DYNAMIC || _IPP_PARALLEL_STATIC || _IPP_PARALLEL_DYNAMIC
822class IntelPerformancePrimitivesFFT : public FFT::Instance
823{
824public:
825 static constexpr auto priority = 9;
826
827 static IntelPerformancePrimitivesFFT* create (const int order)
828 {
829 auto complexContext = Context<ComplexTraits>::create (order);
830 auto realContext = Context<RealTraits> ::create (order);
831
832 if (complexContext.isValid() && realContext.isValid())
833 return new IntelPerformancePrimitivesFFT (std::move (complexContext), std::move (realContext), order);
834
835 return {};
836 }
837
838 void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
839 {
840 if (inverse)
841 {
842 ippsFFTInv_CToC_32fc (reinterpret_cast<const Ipp32fc*> (input),
843 reinterpret_cast<Ipp32fc*> (output),
844 cplx.specPtr,
845 cplx.workBuf.get());
846 }
847 else
848 {
849 ippsFFTFwd_CToC_32fc (reinterpret_cast<const Ipp32fc*> (input),
850 reinterpret_cast<Ipp32fc*> (output),
851 cplx.specPtr,
852 cplx.workBuf.get());
853 }
854 }
855
856 void performRealOnlyForwardTransform (float* inoutData, bool ignoreNegativeFreqs) const noexcept override
857 {
858 ippsFFTFwd_RToCCS_32f_I (inoutData, real.specPtr, real.workBuf.get());
859
860 if (order == 0)
861 return;
862
863 auto* out = reinterpret_cast<Complex<float>*> (inoutData);
864 const auto size = (1 << order);
865
866 if (! ignoreNegativeFreqs)
867 for (auto i = size >> 1; i < size; ++i)
868 out[i] = std::conj (out[size - i]);
869 }
870
871 void performRealOnlyInverseTransform (float* inoutData) const noexcept override
872 {
873 ippsFFTInv_CCSToR_32f_I (inoutData, real.specPtr, real.workBuf.get());
874 }
875
876private:
877 static constexpr auto flag = IPP_FFT_DIV_INV_BY_N;
878 static constexpr auto hint = ippAlgHintFast;
879
880 struct IppFree
881 {
882 template <typename Ptr>
883 void operator() (Ptr* ptr) const noexcept { ippsFree (ptr); }
884 };
885
886 using IppPtr = std::unique_ptr<Ipp8u[], IppFree>;
887
888 template <typename Traits>
889 struct Context
890 {
891 using SpecPtr = typename Traits::Spec*;
892
893 static Context create (const int order)
894 {
895 int specSize = 0, initSize = 0, workSize = 0;
896
897 if (Traits::getSize (order, flag, hint, &specSize, &initSize, &workSize) != ippStsNoErr)
898 return {};
899
900 const auto initBuf = IppPtr (ippsMalloc_8u (initSize));
901 auto specBuf = IppPtr (ippsMalloc_8u (specSize));
902 SpecPtr specPtr = nullptr;
903
904 if (Traits::init (&specPtr, order, flag, hint, specBuf.get(), initBuf.get()) != ippStsNoErr)
905 return {};
906
907 return { std::move (specBuf), IppPtr (ippsMalloc_8u (workSize)), specPtr };
908 }
909
910 Context() noexcept = default;
911
912 Context (IppPtr&& spec, IppPtr&& work, typename Traits::Spec* ptr) noexcept
913 : specBuf (std::move (spec)), workBuf (std::move (work)), specPtr (ptr)
914 {}
915
916 bool isValid() const noexcept { return specPtr != nullptr; }
917
918 IppPtr specBuf, workBuf;
919 SpecPtr specPtr = nullptr;
920 };
921
922 struct ComplexTraits
923 {
924 static constexpr auto getSize = ippsFFTGetSize_C_32fc;
925 static constexpr auto init = ippsFFTInit_C_32fc;
926 using Spec = IppsFFTSpec_C_32fc;
927 };
928
929 struct RealTraits
930 {
931 static constexpr auto getSize = ippsFFTGetSize_R_32f;
932 static constexpr auto init = ippsFFTInit_R_32f;
933 using Spec = IppsFFTSpec_R_32f;
934 };
935
936 IntelPerformancePrimitivesFFT (Context<ComplexTraits>&& complexToUse,
937 Context<RealTraits>&& realToUse,
938 const int orderToUse)
939 : cplx (std::move (complexToUse)),
940 real (std::move (realToUse)),
941 order (orderToUse)
942 {}
943
944 Context<ComplexTraits> cplx;
945 Context<RealTraits> real;
946 int order = 0;
947};
948
949FFT::EngineImpl<IntelPerformancePrimitivesFFT> intelPerformancePrimitivesFFT;
950#endif
951
952//==============================================================================
953//==============================================================================
954FFT::FFT (int order)
955 : engine (FFT::Engine::createBestEngineForPlatform (order)),
956 size (1 << order)
957{
958}
959
960FFT::FFT (FFT&&) noexcept = default;
961
962FFT& FFT::operator= (FFT&&) noexcept = default;
963
964FFT::~FFT() = default;
965
966void FFT::perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept
967{
968 if (engine != nullptr)
969 engine->perform (input, output, inverse);
970}
971
972void FFT::performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept
973{
974 if (engine != nullptr)
975 engine->performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs);
976}
977
978void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcept
979{
980 if (engine != nullptr)
981 engine->performRealOnlyInverseTransform (inputOutputData);
982}
983
984void FFT::performFrequencyOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept
985{
986 if (size == 1)
987 return;
988
989 performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs);
990 auto* out = reinterpret_cast<Complex<float>*> (inputOutputData);
991
992 const auto limit = ignoreNegativeFreqs ? (size / 2) + 1 : size;
993
994 for (int i = 0; i < limit; ++i)
995 inputOutputData[i] = std::abs (out[i]);
996
997 zeromem (inputOutputData + limit, static_cast<size_t> (size * 2 - limit) * sizeof (float));
998}
999
1000} // namespace dsp
1001} // namespace juce
#define noexcept
Definition DistrhoDefines.h:72
uint8_t a
Definition Spc_Cpu.h:141
T limit(T val, T min, T max)
Definition Util.h:78
Definition juce_Array.h:56
Definition juce_HeapBlock.h:87
ElementType * getData() const noexcept
Definition juce_HeapBlock.h:194
Definition juce_SpinLock.h:42
GenericScopedLock< SpinLock > ScopedLockType
Definition juce_SpinLock.h:73
Definition juce_FFT.h:45
int size
Definition juce_FFT.h:125
void performFrequencyOnlyForwardTransform(float *inputOutputData, bool onlyCalculateNonNegativeFrequencies=false) const noexcept
Definition juce_FFT.cpp:984
void performRealOnlyInverseTransform(float *inputOutputData) const noexcept
Definition juce_FFT.cpp:978
std::unique_ptr< Instance > engine
Definition juce_FFT.h:124
FFT(int order)
Definition juce_FFT.cpp:954
void performRealOnlyForwardTransform(float *inputOutputData, bool onlyCalculateNonNegativeFrequencies=false) const noexcept
Definition juce_FFT.cpp:972
void perform(const Complex< float > *input, Complex< float > *output, bool inverse) const noexcept
Definition juce_FFT.cpp:966
register unsigned k
Definition inflate.c:946
unsigned d
Definition inflate.c:940
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
static PuglViewHint hint
Definition pugl.h:1707
static const char * name
Definition pugl.h:1582
JSAMPIMAGE data
Definition jpeglib.h:945
#define JUCE_BEGIN_IGNORE_WARNINGS_MSVC(warnings)
Definition juce_CompilerWarnings.h:198
#define JUCE_END_IGNORE_WARNINGS_MSVC
Definition juce_CompilerWarnings.h:199
#define jassert(expression)
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
#define jassertfalse
static const LV2_Lib_Descriptor lib
Definition lib_descriptor.c:100
float in
Definition lilv_test.c:1460
float out
Definition lilv_test.c:1461
void move(void *from, void *to)
Definition juce_FixedSizeFunction.h:53
Definition juce_AudioBlock.h:29
FFT::EngineImpl< FFTFallback > fftFallback
Definition juce_FFT.cpp:432
std::complex< Type > Complex
Definition juce_dsp.h:194
Definition carla_juce.cpp:31
CriticalSection::ScopedLockType ScopedLock
Definition juce_CriticalSection.h:186
Type unalignedPointerCast(void *ptr) noexcept
Definition juce_Memory.h:88
@ list
Definition juce_AccessibilityRole.h:56
constexpr int numElementsInArray(Type(&)[N]) noexcept
Definition juce_MathsFunctions.h:344
void zeromem(void *memory, size_t numBytes) noexcept
Definition juce_Memory.h:28
png_uint_32 length
Definition png.c:2247
static constexpr FloatType pi
Definition juce_MathsFunctions.h:382
Definition juce_FFT.cpp:40
static FFT::Instance * createBestEngineForPlatform(int order)
Definition juce_FFT.cpp:53
virtual ~Engine()=default
int enginePriority
Definition juce_FFT.cpp:70
static Array< Engine * > & getEngines()
Definition juce_FFT.cpp:64
Engine(int priorityToUse)
Definition juce_FFT.cpp:41
virtual FFT::Instance * create(int order) const =0
Definition juce_FFT.cpp:75
FFT::Instance * create(int order) const override
Definition juce_FFT.cpp:77
EngineImpl()
Definition juce_FFT.cpp:76
Definition juce_FFT.cpp:32
virtual ~Instance()=default
virtual void performRealOnlyForwardTransform(float *, bool) const noexcept=0
virtual void perform(const Complex< float > *input, Complex< float > *output, bool inverse) const noexcept=0
virtual void performRealOnlyInverseTransform(float *) const noexcept=0
int radix
Definition juce_FFT.cpp:270
int length
Definition juce_FFT.cpp:270
Definition juce_FFT.cpp:195
void perform(const Complex< float > *input, Complex< float > *output) const noexcept
Definition juce_FFT.cpp:262
void butterfly(const Factor factor, Complex< float > *data, int stride) const noexcept
Definition juce_FFT.cpp:312
void butterfly2(Complex< float > *data, const int stride, const int length) const noexcept
Definition juce_FFT.cpp:358
void butterfly4(Complex< float > *data, const int stride, const int length) const noexcept
Definition juce_FFT.cpp:373
const int fftSize
Definition juce_FFT.cpp:267
FFTConfig(int sizeOfFFT, bool isInverse)
Definition juce_FFT.cpp:196
const bool inverse
Definition juce_FFT.cpp:268
HeapBlock< Complex< float > > twiddleTable
Definition juce_FFT.cpp:272
Factor factors[32]
Definition juce_FFT.cpp:271
void perform(const Complex< float > *input, Complex< float > *output, int stride, int strideIn, const Factor *facs) const noexcept
Definition juce_FFT.cpp:274
void performRealOnlyForwardTransform(Complex< float > *scratch, float *d) const noexcept
Definition juce_FFT.cpp:169
static FFTFallback * create(int order)
Definition juce_FFT.cpp:87
std::unique_ptr< FFTConfig > configInverse
Definition juce_FFT.cpp:428
void perform(const Complex< float > *input, Complex< float > *output, bool inverse) const noexcept override
Definition juce_FFT.cpp:100
void performRealOnlyInverseTransform(Complex< float > *scratch, float *d) const noexcept
Definition juce_FFT.cpp:177
std::unique_ptr< FFTConfig > configForward
Definition juce_FFT.cpp:428
void performRealOnlyForwardTransform(float *d, bool) const noexcept override
Definition juce_FFT.cpp:129
const size_t maxFFTScratchSpaceToAlloca
Definition juce_FFT.cpp:127
static constexpr int priority
Definition juce_FFT.cpp:85
SpinLock processLock
Definition juce_FFT.cpp:427
FFTFallback(int order)
Definition juce_FFT.cpp:92
int size
Definition juce_FFT.cpp:429
void performRealOnlyInverseTransform(float *d) const noexcept override
Definition juce_FFT.cpp:149
int n
Definition crypt.c:458
b
Definition crypt.c:628
ZCONST uch * init
Definition extract.c:2392
ulg size
Definition extract.c:2350
register uch * q
Definition fileio.c:817
int flag
Definition unix.c:754
typedef int(UZ_EXP MsgFn)()
#define void
Definition unzip.h:396
#define const
Definition zconf.h:137