31 virtual ~Instance() =
default;
32 virtual void perform (
const Complex<float>* input, Complex<float>* output,
bool inverse)
const noexcept = 0;
33 virtual void performRealOnlyForwardTransform (
float*,
bool)
const noexcept = 0;
34 virtual void performRealOnlyInverseTransform (
float*)
const noexcept = 0;
39 Engine (
int priorityToUse) : enginePriority (priorityToUse)
41 auto& list = getEngines();
43 std::sort (list.begin(), list.end(), [] (Engine* a, Engine* b) { return b->enginePriority < a->enginePriority; });
46 virtual ~Engine() =
default;
48 virtual FFT::Instance* create (
int order)
const = 0;
51 static FFT::Instance* createBestEngineForPlatform (
int order)
53 for (
auto* engine : getEngines())
54 if (auto* instance = engine->create (order))
62 static Array<Engine*>& getEngines()
64 static Array<Engine*> engines;
71template <
typename InstanceToUse>
72struct FFT::EngineImpl :
public FFT::Engine
74 EngineImpl() :
FFT::Engine (InstanceToUse::priority) {}
75 FFT::Instance* create (
int order)
const override {
return InstanceToUse::create (order); }
80struct FFTFallback final :
public FFT::Instance
83 static constexpr int priority = -1;
85 static FFTFallback* create (
int order)
87 return new FFTFallback (order);
90 FFTFallback (
int order)
92 configForward.reset (
new FFTConfig (1 << order,
false));
93 configInverse.reset (
new FFTConfig (1 << order,
true));
98 void perform (
const Complex<float>* input, Complex<float>* output,
bool inverse)
const noexcept override
108 jassert (configForward !=
nullptr);
112 configInverse->perform (input, output);
114 const float scaleFactor = 1.0f / (float) size;
116 for (
int i = 0; i < size; ++i)
117 output[i] *= scaleFactor;
121 configForward->perform (input, output);
125 const size_t maxFFTScratchSpaceToAlloca = 256 * 1024;
127 void performRealOnlyForwardTransform (
float* d,
bool)
const noexcept override
132 const size_t scratchSize = 16 + (size_t) size *
sizeof (Complex<float>);
134 if (scratchSize < maxFFTScratchSpaceToAlloca)
136 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6255)
137 performRealOnlyForwardTransform (static_cast<Complex<
float>*> (alloca (scratchSize)), d);
138 JUCE_END_IGNORE_WARNINGS_MSVC
142 HeapBlock<char> heapSpace (scratchSize);
143 performRealOnlyForwardTransform (unalignedPointerCast<Complex<float>*> (heapSpace.getData()), d);
147 void performRealOnlyInverseTransform (
float* d)
const noexcept override
152 const size_t scratchSize = 16 + (size_t) size *
sizeof (Complex<float>);
154 if (scratchSize < maxFFTScratchSpaceToAlloca)
156 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6255)
157 performRealOnlyInverseTransform (static_cast<Complex<
float>*> (alloca (scratchSize)), d);
158 JUCE_END_IGNORE_WARNINGS_MSVC
162 HeapBlock<char> heapSpace (scratchSize);
163 performRealOnlyInverseTransform (unalignedPointerCast<Complex<float>*> (heapSpace.getData()), d);
167 void performRealOnlyForwardTransform (Complex<float>* scratch,
float* d)
const noexcept
169 for (
int i = 0; i < size; ++i)
170 scratch[i] = { d[i], 0 };
172 perform (scratch,
reinterpret_cast<Complex<float>*
> (d),
false);
175 void performRealOnlyInverseTransform (Complex<float>* scratch,
float* d)
const noexcept
177 auto* input =
reinterpret_cast<Complex<float>*
> (d);
179 for (
int i = size >> 1; i < size; ++i)
180 input[i] = std::conj (input[size - i]);
182 perform (input, scratch,
true);
184 for (
int i = 0; i < size; ++i)
186 d[i] = scratch[i].real();
187 d[i + size] = scratch[i].imag();
194 FFTConfig (
int sizeOfFFT,
bool isInverse)
195 : fftSize (sizeOfFFT), inverse (isInverse), twiddleTable ((size_t) sizeOfFFT)
201 for (
int i = 0; i < fftSize; ++i)
203 auto phase = i * inverseFactor;
205 twiddleTable[i] = { (float) std::cos (phase),
206 (float) std::sin (phase) };
211 for (
int i = 0; i < fftSize / 4; ++i)
213 auto phase = i * inverseFactor;
215 twiddleTable[i] = { (float) std::cos (phase),
216 (float) std::sin (phase) };
219 for (
int i = fftSize / 4; i < fftSize / 2; ++i)
221 auto other = twiddleTable[i - fftSize / 4];
223 twiddleTable[i] = { inverse ? -other.imag() : other.imag(),
224 inverse ? other.real() : -other.real() };
227 twiddleTable[fftSize / 2].real (-1.0f);
228 twiddleTable[fftSize / 2].imag (0.0f);
230 for (
int i = fftSize / 2; i < fftSize; ++i)
232 auto index = fftSize / 2 - (i - fftSize / 2);
233 twiddleTable[i] = conj (twiddleTable[index]);
237 auto root = (int) std::sqrt ((
double) fftSize);
238 int divisor = 4, n = fftSize;
240 for (
int i = 0; i < numElementsInArray (factors); ++i)
242 while ((n % divisor) != 0)
244 if (divisor == 2) divisor = 3;
245 else if (divisor == 4) divisor = 2;
254 jassert (divisor == 1 || divisor == 2 || divisor == 4);
255 factors[i].radix = divisor;
256 factors[i].length = n;
260 void perform (
const Complex<float>* input, Complex<float>* output)
const noexcept
262 perform (input, output, 1, 1, factors);
268 struct Factor {
int radix, length; };
270 HeapBlock<Complex<float>> twiddleTable;
272 void perform (
const Complex<float>* input, Complex<float>* output,
int stride,
int strideIn,
const Factor* facs)
const noexcept
274 auto factor = *facs++;
275 auto* originalOutput = output;
276 auto* outputEnd = output + factor.radix * factor.length;
278 if (stride == 1 && factor.radix <= 5)
280 for (
int i = 0; i < factor.radix; ++i)
281 perform (input + stride * strideIn * i, output + i * factor.length, stride * factor.radix, strideIn, facs);
283 butterfly (factor, output, stride);
287 if (factor.length == 1)
292 input += stride * strideIn;
294 while (output < outputEnd);
300 perform (input, output, stride * factor.radix, strideIn, facs);
301 input += stride * strideIn;
302 output += factor.length;
304 while (output < outputEnd);
307 butterfly (factor, originalOutput, stride);
310 void butterfly (
const Factor factor, Complex<float>* data,
int stride)
const noexcept
312 switch (factor.radix)
315 case 2: butterfly2 (data, stride, factor.length);
return;
316 case 4: butterfly4 (data, stride, factor.length);
return;
317 default: jassertfalse;
break;
320 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6255)
321 auto* scratch = static_cast<Complex<
float>*> (alloca ((
size_t) factor.radix * sizeof (Complex<
float>)));
322 JUCE_END_IGNORE_WARNINGS_MSVC
324 for (
int i = 0; i < factor.length; ++i)
326 for (
int k = i, q1 = 0; q1 < factor.radix; ++q1)
328 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6386)
329 scratch[q1] = data[k];
330 JUCE_END_IGNORE_WARNINGS_MSVC
334 for (
int k = i, q1 = 0; q1 < factor.radix; ++q1)
336 int twiddleIndex = 0;
337 data[k] = scratch[0];
339 for (
int q = 1; q < factor.radix; ++q)
341 twiddleIndex += stride * k;
343 if (twiddleIndex >= fftSize)
344 twiddleIndex -= fftSize;
346 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6385)
347 data[k] += scratch[q] * twiddleTable[twiddleIndex];
348 JUCE_END_IGNORE_WARNINGS_MSVC
356 void butterfly2 (Complex<
float>* data, const
int stride, const
int length) const noexcept
358 auto* dataEnd = data + length;
359 auto* tw = twiddleTable.getData();
361 for (
int i = length; --i >= 0;)
366 *dataEnd++ = *data - s;
371 void butterfly4 (Complex<float>* data,
const int stride,
const int length)
const noexcept
373 auto lengthX2 = length * 2;
374 auto lengthX3 = length * 3;
376 auto strideX2 = stride * 2;
377 auto strideX3 = stride * 3;
379 auto* twiddle1 = twiddleTable.getData();
380 auto* twiddle2 = twiddle1;
381 auto* twiddle3 = twiddle1;
383 for (
int i = length; --i >= 0;)
385 auto s0 = data[length] * *twiddle1;
386 auto s1 = data[lengthX2] * *twiddle2;
387 auto s2 = data[lengthX3] * *twiddle3;
388 auto s3 = s0; s3 += s2;
389 auto s4 = s0; s4 -= s2;
390 auto s5 = *data; s5 -= s1;
393 data[lengthX2] = *data;
394 data[lengthX2] -= s3;
396 twiddle2 += strideX2;
397 twiddle3 += strideX3;
402 data[length] = { s5.real() - s4.imag(),
403 s5.imag() + s4.real() };
405 data[lengthX3] = { s5.real() + s4.imag(),
406 s5.imag() - s4.real() };
410 data[length] = { s5.real() + s4.imag(),
411 s5.imag() - s4.real() };
413 data[lengthX3] = { s5.real() - s4.imag(),
414 s5.imag() + s4.real() };
421 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFTConfig)
425 SpinLock processLock;
426 std::unique_ptr<FFTConfig> configForward, configInverse;
430FFT::EngineImpl<FFTFallback> fftFallback;
434#if (JUCE_MAC || JUCE_IOS) && JUCE_USE_VDSP_FRAMEWORK
435struct AppleFFT final :
public FFT::Instance
437 static constexpr int priority = 5;
439 static AppleFFT* create (
int order)
441 return new AppleFFT (order);
444 AppleFFT (
int orderToUse)
445 : order (static_cast<vDSP_Length> (orderToUse)),
446 fftSetup (vDSP_create_fftsetup (order, 2)),
447 forwardNormalisation (0.5f),
448 inverseNormalisation (1.0f / static_cast<float> (1 << order))
453 if (fftSetup !=
nullptr)
455 vDSP_destroy_fftsetup (fftSetup);
460 void perform (
const Complex<float>* input, Complex<float>* output,
bool inverse)
const noexcept override
462 auto size = (1 << order);
464 DSPSplitComplex splitInput (toSplitComplex (
const_cast<Complex<float>*
> (input)));
465 DSPSplitComplex splitOutput (toSplitComplex (output));
467 vDSP_fft_zop (fftSetup, &splitInput, 2, &splitOutput, 2,
468 order, inverse ? kFFTDirection_Inverse : kFFTDirection_Forward);
470 float factor = (inverse ? inverseNormalisation : forwardNormalisation * 2.0f);
471 vDSP_vsmul ((
float*) output, 1, &factor, (
float*) output, 1,
static_cast<size_t> (size << 1));
474 void performRealOnlyForwardTransform (
float* inoutData,
bool ignoreNegativeFreqs)
const noexcept override
476 auto size = (1 << order);
477 auto* inout =
reinterpret_cast<Complex<float>*
> (inoutData);
478 auto splitInOut (toSplitComplex (inout));
480 inoutData[size] = 0.0f;
481 vDSP_fft_zrip (fftSetup, &splitInOut, 2, order, kFFTDirection_Forward);
482 vDSP_vsmul (inoutData, 1, &forwardNormalisation, inoutData, 1,
static_cast<size_t> (size << 1));
484 mirrorResult (inout, ignoreNegativeFreqs);
487 void performRealOnlyInverseTransform (
float* inoutData)
const noexcept override
489 auto* inout =
reinterpret_cast<Complex<float>*
> (inoutData);
490 auto size = (1 << order);
491 auto splitInOut (toSplitComplex (inout));
497 inout[0] = Complex<float> (inout[0].real(), inout[size >> 1].real());
499 vDSP_fft_zrip (fftSetup, &splitInOut, 2, order, kFFTDirection_Inverse);
500 vDSP_vsmul (inoutData, 1, &inverseNormalisation, inoutData, 1,
static_cast<size_t> (size << 1));
501 vDSP_vclr (inoutData + size, 1,
static_cast<size_t> (size));
506 void mirrorResult (Complex<float>* out,
bool ignoreNegativeFreqs)
const noexcept
508 auto size = (1 << order);
514 out[i++] = { out[0].imag(), 0.0 };
515 out[0] = { out[0].real(), 0.0 };
517 if (! ignoreNegativeFreqs)
518 for (; i < size; ++i)
519 out[i] = std::conj (out[size - i]);
522 static DSPSplitComplex toSplitComplex (Complex<float>* data)
noexcept
526 return {
reinterpret_cast<float*
> (data),
527 reinterpret_cast<float*
> (data) + 1};
533 float forwardNormalisation, inverseNormalisation;
536FFT::EngineImpl<AppleFFT> appleFFT;
541#if JUCE_DSP_USE_SHARED_FFTW || JUCE_DSP_USE_STATIC_FFTW
543#if JUCE_DSP_USE_STATIC_FFTW
546 void* fftwf_plan_dft_1d (
int,
void*,
void*,
int,
int);
547 void* fftwf_plan_dft_r2c_1d (
int,
void*,
void*,
int);
548 void* fftwf_plan_dft_c2r_1d (
int,
void*,
void*,
int);
549 void fftwf_destroy_plan (
void*);
550 void fftwf_execute_dft (
void*,
void*,
void*);
551 void fftwf_execute_dft_r2c (
void*,
void*,
void*);
552 void fftwf_execute_dft_c2r (
void*,
void*,
void*);
556struct FFTWImpl :
public FFT::Instance
558 #if JUCE_DSP_USE_STATIC_FFTW
561 static constexpr int priority = 10;
563 static constexpr int priority = 3;
567 using FFTWPlanRef = FFTWPlan*;
572 unaligned = (1 << 1),
578 FFTWPlanRef (*plan_dft_fftw) (unsigned, Complex<float>*, Complex<float>*, int, unsigned);
579 FFTWPlanRef (*plan_r2c_fftw) (unsigned,
float*, Complex<float>*, unsigned);
580 FFTWPlanRef (*plan_c2r_fftw) (unsigned, Complex<float>*,
float*, unsigned);
581 void (*destroy_fftw) (FFTWPlanRef);
583 void (*execute_dft_fftw) (FFTWPlanRef,
const Complex<float>*, Complex<float>*);
584 void (*execute_r2c_fftw) (FFTWPlanRef,
float*, Complex<float>*);
585 void (*execute_c2r_fftw) (FFTWPlanRef, Complex<float>*,
float*);
587 #if JUCE_DSP_USE_STATIC_FFTW
588 template <
typename FuncPtr,
typename ActualSymbolType>
589 static bool symbol (FuncPtr& dst, ActualSymbolType sym)
591 dst =
reinterpret_cast<FuncPtr
> (sym);
595 template <
typename FuncPtr>
596 static bool symbol (DynamicLibrary& lib, FuncPtr& dst,
const char* name)
598 dst =
reinterpret_cast<FuncPtr
> (lib.getFunction (name));
599 return (dst !=
nullptr);
604 static FFTWImpl* create (
int order)
608 #if ! JUCE_DSP_USE_STATIC_FFTW
610 auto libName =
"libfftw3f.dylib";
612 auto libName =
"libfftw3f.dll";
614 auto libName =
"libfftw3f.so";
617 if (lib.open (libName))
622 #if JUCE_DSP_USE_STATIC_FFTW
623 if (! Symbols::symbol (symbols.plan_dft_fftw, fftwf_plan_dft_1d))
return nullptr;
624 if (! Symbols::symbol (symbols.plan_r2c_fftw, fftwf_plan_dft_r2c_1d))
return nullptr;
625 if (! Symbols::symbol (symbols.plan_c2r_fftw, fftwf_plan_dft_c2r_1d))
return nullptr;
626 if (! Symbols::symbol (symbols.destroy_fftw, fftwf_destroy_plan))
return nullptr;
628 if (! Symbols::symbol (symbols.execute_dft_fftw, fftwf_execute_dft))
return nullptr;
629 if (! Symbols::symbol (symbols.execute_r2c_fftw, fftwf_execute_dft_r2c))
return nullptr;
630 if (! Symbols::symbol (symbols.execute_c2r_fftw, fftwf_execute_dft_c2r))
return nullptr;
632 if (! Symbols::symbol (lib, symbols.plan_dft_fftw,
"fftwf_plan_dft_1d"))
return nullptr;
633 if (! Symbols::symbol (lib, symbols.plan_r2c_fftw,
"fftwf_plan_dft_r2c_1d"))
return nullptr;
634 if (! Symbols::symbol (lib, symbols.plan_c2r_fftw,
"fftwf_plan_dft_c2r_1d"))
return nullptr;
635 if (! Symbols::symbol (lib, symbols.destroy_fftw,
"fftwf_destroy_plan"))
return nullptr;
637 if (! Symbols::symbol (lib, symbols.execute_dft_fftw,
"fftwf_execute_dft"))
return nullptr;
638 if (! Symbols::symbol (lib, symbols.execute_r2c_fftw,
"fftwf_execute_dft_r2c"))
return nullptr;
639 if (! Symbols::symbol (lib, symbols.execute_c2r_fftw,
"fftwf_execute_dft_c2r"))
return nullptr;
642 return new FFTWImpl (
static_cast<size_t> (order), std::move (lib), symbols);
648 FFTWImpl (
size_t orderToUse, DynamicLibrary&& libraryToUse,
const Symbols& symbols)
649 : fftwLibrary (std::move (libraryToUse)), fftw (symbols), order (static_cast<size_t> (orderToUse))
651 ScopedLock lock (getFFTWPlanLock());
653 auto n = (1u << order);
654 HeapBlock<Complex<float>> in (n), out (n);
656 c2cForward = fftw.plan_dft_fftw (n, in.getData(), out.getData(), -1, unaligned | estimate);
657 c2cInverse = fftw.plan_dft_fftw (n, in.getData(), out.getData(), +1, unaligned | estimate);
659 r2c = fftw.plan_r2c_fftw (n, (
float*) in.getData(), in.getData(), unaligned | estimate);
660 c2r = fftw.plan_c2r_fftw (n, in.getData(), (
float*) in.getData(), unaligned | estimate);
665 ScopedLock lock (getFFTWPlanLock());
667 fftw.destroy_fftw (c2cForward);
668 fftw.destroy_fftw (c2cInverse);
669 fftw.destroy_fftw (r2c);
670 fftw.destroy_fftw (c2r);
673 void perform (
const Complex<float>* input, Complex<float>* output,
bool inverse)
const noexcept override
677 auto n = (1u << order);
678 fftw.execute_dft_fftw (c2cInverse, input, output);
679 FloatVectorOperations::multiply ((
float*) output, 1.0f /
static_cast<float> (n), (
int) n << 1);
683 fftw.execute_dft_fftw (c2cForward, input, output);
687 void performRealOnlyForwardTransform (
float* inputOutputData,
bool ignoreNegativeFreqs)
const noexcept override
692 auto* out =
reinterpret_cast<Complex<float>*
> (inputOutputData);
694 fftw.execute_r2c_fftw (r2c, inputOutputData, out);
696 auto size = (1 << order);
698 if (! ignoreNegativeFreqs)
699 for (
int i = size >> 1; i < size; ++i)
700 out[i] = std::conj (out[size - i]);
703 void performRealOnlyInverseTransform (
float* inputOutputData)
const noexcept override
705 auto n = (1u << order);
707 fftw.execute_c2r_fftw (c2r, (Complex<float>*) inputOutputData, inputOutputData);
708 FloatVectorOperations::multiply ((
float*) inputOutputData, 1.0f /
static_cast<float> (n), (
int) n);
714 static CriticalSection& getFFTWPlanLock() noexcept
716 static CriticalSection cs;
721 DynamicLibrary fftwLibrary;
725 FFTWPlanRef c2cForward, c2cInverse, r2c, c2r;
728FFT::EngineImpl<FFTWImpl> fftwEngine;
733#if JUCE_DSP_USE_INTEL_MKL
734struct IntelFFT final :
public FFT::Instance
736 static constexpr int priority = 8;
738 static bool succeeded (MKL_LONG status)
noexcept {
return status == 0; }
740 static IntelFFT* create (
int orderToUse)
742 DFTI_DESCRIPTOR_HANDLE mklc2c, mklc2r;
744 if (DftiCreateDescriptor (&mklc2c, DFTI_SINGLE, DFTI_COMPLEX, 1, 1 << orderToUse) == 0)
746 if (succeeded (DftiSetValue (mklc2c, DFTI_PLACEMENT, DFTI_NOT_INPLACE))
747 && succeeded (DftiSetValue (mklc2c, DFTI_BACKWARD_SCALE, 1.0f /
static_cast<float> (1 << orderToUse)))
748 && succeeded (DftiCommitDescriptor (mklc2c)))
750 if (succeeded (DftiCreateDescriptor (&mklc2r, DFTI_SINGLE, DFTI_REAL, 1, 1 << orderToUse)))
752 if (succeeded (DftiSetValue (mklc2r, DFTI_PLACEMENT, DFTI_INPLACE))
753 && succeeded (DftiSetValue (mklc2r, DFTI_BACKWARD_SCALE, 1.0f /
static_cast<float> (1 << orderToUse)))
754 && succeeded (DftiCommitDescriptor (mklc2r)))
756 return new IntelFFT (
static_cast<size_t> (orderToUse), mklc2c, mklc2r);
759 DftiFreeDescriptor (&mklc2r);
763 DftiFreeDescriptor (&mklc2c);
769 IntelFFT (
size_t orderToUse, DFTI_DESCRIPTOR_HANDLE c2cToUse, DFTI_DESCRIPTOR_HANDLE cr2ToUse)
770 : order (orderToUse), c2c (c2cToUse), c2r (cr2ToUse)
775 DftiFreeDescriptor (&c2c);
776 DftiFreeDescriptor (&c2r);
779 void perform (
const Complex<float>* input, Complex<float>* output,
bool inverse)
const noexcept override
782 DftiComputeBackward (c2c, (
void*) input, output);
784 DftiComputeForward (c2c, (
void*) input, output);
787 void performRealOnlyForwardTransform (
float* inputOutputData,
bool ignoreNegativeFreqs)
const noexcept override
792 DftiComputeForward (c2r, inputOutputData);
794 auto* out =
reinterpret_cast<Complex<float>*
> (inputOutputData);
795 auto size = (1 << order);
797 if (! ignoreNegativeFreqs)
798 for (
int i = size >> 1; i < size; ++i)
799 out[i] = std::conj (out[size - i]);
802 void performRealOnlyInverseTransform (
float* inputOutputData)
const noexcept override
804 DftiComputeBackward (c2r, inputOutputData);
808 DFTI_DESCRIPTOR_HANDLE c2c, c2r;
811FFT::EngineImpl<IntelFFT> fftwEngine;
819#if _IPP_SEQUENTIAL_STATIC || _IPP_SEQUENTIAL_DYNAMIC || _IPP_PARALLEL_STATIC || _IPP_PARALLEL_DYNAMIC
820class IntelPerformancePrimitivesFFT final :
public FFT::Instance
823 static constexpr auto priority = 9;
825 static IntelPerformancePrimitivesFFT* create (
const int order)
827 auto complexContext = Context<ComplexTraits>::create (order);
828 auto realContext = Context<RealTraits> ::create (order);
830 if (complexContext.isValid() && realContext.isValid())
831 return new IntelPerformancePrimitivesFFT (std::move (complexContext), std::move (realContext), order);
836 void perform (
const Complex<float>* input, Complex<float>* output,
bool inverse)
const noexcept override
840 ippsFFTInv_CToC_32fc (
reinterpret_cast<const Ipp32fc*
> (input),
841 reinterpret_cast<Ipp32fc*
> (output),
847 ippsFFTFwd_CToC_32fc (
reinterpret_cast<const Ipp32fc*
> (input),
848 reinterpret_cast<Ipp32fc*
> (output),
854 void performRealOnlyForwardTransform (
float* inoutData,
bool ignoreNegativeFreqs)
const noexcept override
856 ippsFFTFwd_RToCCS_32f_I (inoutData, real.specPtr, real.workBuf.get());
861 auto* out =
reinterpret_cast<Complex<float>*
> (inoutData);
862 const auto size = (1 << order);
864 if (! ignoreNegativeFreqs)
865 for (
auto i = size >> 1; i < size; ++i)
866 out[i] = std::conj (out[size - i]);
869 void performRealOnlyInverseTransform (
float* inoutData)
const noexcept override
871 ippsFFTInv_CCSToR_32f_I (inoutData, real.specPtr, real.workBuf.get());
875 static constexpr auto flag = IPP_FFT_DIV_INV_BY_N;
876 static constexpr auto hint = ippAlgHintFast;
880 template <
typename Ptr>
881 void operator() (Ptr* ptr)
const noexcept { ippsFree (ptr); }
884 using IppPtr = std::unique_ptr<Ipp8u[], IppFree>;
886 template <
typename Traits>
889 using SpecPtr =
typename Traits::Spec*;
891 static Context create (
const int order)
893 int specSize = 0, initSize = 0, workSize = 0;
895 if (Traits::getSize (order, flag, hint, &specSize, &initSize, &workSize) != ippStsNoErr)
898 const auto initBuf = IppPtr (ippsMalloc_8u (initSize));
899 auto specBuf = IppPtr (ippsMalloc_8u (specSize));
900 SpecPtr specPtr =
nullptr;
902 if (Traits::init (&specPtr, order, flag, hint, specBuf.get(), initBuf.get()) != ippStsNoErr)
905 return { std::move (specBuf), IppPtr (ippsMalloc_8u (workSize)), specPtr };
908 Context() noexcept = default;
910 Context (IppPtr&& spec, IppPtr&& work, typename Traits::Spec* ptr) noexcept
911 : specBuf (std::move (spec)), workBuf (std::move (work)), specPtr (ptr)
914 bool isValid() const noexcept {
return specPtr !=
nullptr; }
916 IppPtr specBuf, workBuf;
917 SpecPtr specPtr =
nullptr;
922 static constexpr auto getSize = ippsFFTGetSize_C_32fc;
923 static constexpr auto init = ippsFFTInit_C_32fc;
924 using Spec = IppsFFTSpec_C_32fc;
929 static constexpr auto getSize = ippsFFTGetSize_R_32f;
930 static constexpr auto init = ippsFFTInit_R_32f;
931 using Spec = IppsFFTSpec_R_32f;
934 IntelPerformancePrimitivesFFT (Context<ComplexTraits>&& complexToUse,
935 Context<RealTraits>&& realToUse,
936 const int orderToUse)
937 : cplx (std::move (complexToUse)),
938 real (std::move (realToUse)),
942 Context<ComplexTraits> cplx;
943 Context<RealTraits> real;
947FFT::EngineImpl<IntelPerformancePrimitivesFFT> intelPerformancePrimitivesFFT;
953 : engine (
FFT::Engine::createBestEngineForPlatform (order)),
966 if (engine !=
nullptr)
967 engine->perform (input, output, inverse);
972 if (engine !=
nullptr)
978 if (engine !=
nullptr)
992 for (
int i = 0; i <
limit; ++i)
GenericScopedLock< SpinLock > ScopedLockType
void performFrequencyOnlyForwardTransform(float *inputOutputData, bool onlyCalculateNonNegativeFrequencies=false) const noexcept
void performRealOnlyInverseTransform(float *inputOutputData) const noexcept
void performRealOnlyForwardTransform(float *inputOutputData, bool onlyCalculateNonNegativeFrequencies=false) const noexcept
static constexpr FloatType pi