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.

846 lines
29KB

  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. namespace juce
  20. {
  21. namespace dsp
  22. {
  23. struct FFT::Instance
  24. {
  25. virtual ~Instance() {}
  26. virtual void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept = 0;
  27. virtual void performRealOnlyForwardTransform (float*, bool) const noexcept = 0;
  28. virtual void performRealOnlyInverseTransform (float*) const noexcept = 0;
  29. };
  30. struct FFT::Engine
  31. {
  32. Engine (int priorityToUse) : enginePriority (priorityToUse)
  33. {
  34. EnginePriorityComparator comparator;
  35. getEngines().addSorted (comparator, this);
  36. }
  37. virtual ~Engine() {}
  38. virtual FFT::Instance* create (int order) const = 0;
  39. //==============================================================================
  40. static FFT::Instance* createBestEngineForPlatform (int order)
  41. {
  42. for (auto* engine : getEngines())
  43. if (auto* instance = engine->create (order))
  44. return instance;
  45. jassertfalse; // This should never happen as the fallback engine should always work!
  46. return nullptr;
  47. }
  48. private:
  49. struct EnginePriorityComparator
  50. {
  51. static int compareElements (Engine* first, Engine* second) noexcept
  52. {
  53. // sort in reverse order
  54. return DefaultElementComparator<int>::compareElements (second->enginePriority, first->enginePriority);
  55. }
  56. };
  57. static Array<Engine*>& getEngines()
  58. {
  59. static Array<Engine*> engines;
  60. return engines;
  61. }
  62. int enginePriority; // used so that faster engines have priority over slower ones
  63. };
  64. template <typename InstanceToUse>
  65. struct FFT::EngineImpl : public FFT::Engine
  66. {
  67. EngineImpl() : FFT::Engine (InstanceToUse::priority) {}
  68. FFT::Instance* create (int order) const override { return InstanceToUse::create (order); }
  69. };
  70. //==============================================================================
  71. //==============================================================================
  72. struct FFTFallback : public FFT::Instance
  73. {
  74. // this should have the least priority of all engines
  75. static constexpr int priority = -1;
  76. static FFTFallback* create (int order)
  77. {
  78. return new FFTFallback (order);
  79. }
  80. FFTFallback (int order)
  81. {
  82. configForward = new FFTConfig (1 << order, false);
  83. configInverse = new FFTConfig (1 << order, true);
  84. size = 1 << order;
  85. }
  86. void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
  87. {
  88. if (size == 1)
  89. {
  90. *output = *input;
  91. return;
  92. }
  93. const SpinLock::ScopedLockType sl(processLock);
  94. jassert (configForward != nullptr);
  95. if (inverse)
  96. {
  97. configInverse->perform (input, output);
  98. const float scaleFactor = 1.0f / size;
  99. for (int i = 0; i < size; ++i)
  100. output[i] *= scaleFactor;
  101. }
  102. else
  103. {
  104. configForward->perform (input, output);
  105. }
  106. }
  107. const size_t maxFFTScratchSpaceToAlloca = 256 * 1024;
  108. void performRealOnlyForwardTransform (float* d, bool) const noexcept override
  109. {
  110. if (size == 1)
  111. return;
  112. const size_t scratchSize = 16 + sizeof (Complex<float>) * (size_t) size;
  113. if (scratchSize < maxFFTScratchSpaceToAlloca)
  114. {
  115. performRealOnlyForwardTransform (static_cast<Complex<float>*> (alloca (scratchSize)), d);
  116. }
  117. else
  118. {
  119. HeapBlock<char> heapSpace (scratchSize);
  120. performRealOnlyForwardTransform (reinterpret_cast<Complex<float>*> (heapSpace.getData()), d);
  121. }
  122. }
  123. void performRealOnlyInverseTransform (float* d) const noexcept override
  124. {
  125. if (size == 1)
  126. return;
  127. const size_t scratchSize = 16 + sizeof (Complex<float>) * (size_t) size;
  128. if (scratchSize < maxFFTScratchSpaceToAlloca)
  129. {
  130. performRealOnlyInverseTransform (static_cast<Complex<float>*> (alloca (scratchSize)), d);
  131. }
  132. else
  133. {
  134. HeapBlock<char> heapSpace (scratchSize);
  135. performRealOnlyInverseTransform (reinterpret_cast<Complex<float>*> (heapSpace.getData()), d);
  136. }
  137. }
  138. void performRealOnlyForwardTransform (Complex<float>* scratch, float* d) const noexcept
  139. {
  140. for (int i = 0; i < size; ++i)
  141. {
  142. scratch[i].real (d[i]);
  143. scratch[i].imag (0);
  144. }
  145. perform (scratch, reinterpret_cast<Complex<float>*> (d), false);
  146. }
  147. void performRealOnlyInverseTransform (Complex<float>* scratch, float* d) const noexcept
  148. {
  149. auto* input = reinterpret_cast<Complex<float>*> (d);
  150. for (auto i = size >> 1; i < size; ++i)
  151. input[i] = std::conj (input[size - i]);
  152. perform (input, scratch, true);
  153. for (int i = 0; i < size; ++i)
  154. {
  155. d[i] = scratch[i].real();
  156. d[i + size] = scratch[i].imag();
  157. }
  158. }
  159. //==============================================================================
  160. struct FFTConfig
  161. {
  162. FFTConfig (int sizeOfFFT, bool isInverse)
  163. : fftSize (sizeOfFFT), inverse (isInverse), twiddleTable ((size_t) sizeOfFFT)
  164. {
  165. const double inverseFactor = (inverse ? 2.0 : -2.0) * double_Pi / (double) fftSize;
  166. if (fftSize <= 4)
  167. {
  168. for (int i = 0; i < fftSize; ++i)
  169. {
  170. const double phase = i * inverseFactor;
  171. twiddleTable[i].real ((float) std::cos (phase));
  172. twiddleTable[i].imag ((float) std::sin (phase));
  173. }
  174. }
  175. else
  176. {
  177. for (int i = 0; i < fftSize / 4; ++i)
  178. {
  179. const double phase = i * inverseFactor;
  180. twiddleTable[i].real ((float) std::cos (phase));
  181. twiddleTable[i].imag ((float) std::sin (phase));
  182. }
  183. for (int i = fftSize / 4; i < fftSize / 2; ++i)
  184. {
  185. const int index = i - fftSize / 4;
  186. twiddleTable[i].real (inverse ? -twiddleTable[index].imag() : twiddleTable[index].imag());
  187. twiddleTable[i].imag (inverse ? twiddleTable[index].real() : -twiddleTable[index].real());
  188. }
  189. twiddleTable[fftSize / 2].real (-1.0f);
  190. twiddleTable[fftSize / 2].imag (0.0f);
  191. for (int i = fftSize / 2; i < fftSize; ++i)
  192. {
  193. const int index = fftSize / 2 - (i - fftSize / 2);
  194. twiddleTable[i] = conj(twiddleTable[index]);
  195. }
  196. }
  197. const int root = (int) std::sqrt ((double) fftSize);
  198. int divisor = 4, n = fftSize;
  199. for (int i = 0; i < numElementsInArray (factors); ++i)
  200. {
  201. while ((n % divisor) != 0)
  202. {
  203. if (divisor == 2) divisor = 3;
  204. else if (divisor == 4) divisor = 2;
  205. else divisor += 2;
  206. if (divisor > root)
  207. divisor = n;
  208. }
  209. n /= divisor;
  210. jassert (divisor == 1 || divisor == 2 || divisor == 4);
  211. factors[i].radix = divisor;
  212. factors[i].length = n;
  213. }
  214. }
  215. void perform (const Complex<float>* input, Complex<float>* output) const noexcept
  216. {
  217. perform (input, output, 1, 1, factors);
  218. }
  219. const int fftSize;
  220. const bool inverse;
  221. struct Factor { int radix, length; };
  222. Factor factors[32];
  223. HeapBlock<Complex<float>> twiddleTable;
  224. void perform (const Complex<float>* input, Complex<float>* output, int stride, int strideIn, const Factor* facs) const noexcept
  225. {
  226. auto factor = *facs++;
  227. auto* originalOutput = output;
  228. auto* outputEnd = output + factor.radix * factor.length;
  229. if (stride == 1 && factor.radix <= 5)
  230. {
  231. for (int i = 0; i < factor.radix; ++i)
  232. perform (input + stride * strideIn * i, output + i * factor.length, stride * factor.radix, strideIn, facs);
  233. butterfly (factor, output, stride);
  234. return;
  235. }
  236. if (factor.length == 1)
  237. {
  238. do
  239. {
  240. *output++ = *input;
  241. input += stride * strideIn;
  242. }
  243. while (output < outputEnd);
  244. }
  245. else
  246. {
  247. do
  248. {
  249. perform (input, output, stride * factor.radix, strideIn, facs);
  250. input += stride * strideIn;
  251. output += factor.length;
  252. }
  253. while (output < outputEnd);
  254. }
  255. butterfly (factor, originalOutput, stride);
  256. }
  257. void butterfly (const Factor factor, Complex<float>* data, int stride) const noexcept
  258. {
  259. switch (factor.radix)
  260. {
  261. case 1: break;
  262. case 2: butterfly2 (data, stride, factor.length); return;
  263. case 4: butterfly4 (data, stride, factor.length); return;
  264. default: jassertfalse; break;
  265. }
  266. auto* scratch = static_cast<Complex<float>*> (alloca (sizeof (Complex<float>) * (size_t) factor.radix));
  267. for (int i = 0; i < factor.length; ++i)
  268. {
  269. for (int k = i, q1 = 0; q1 < factor.radix; ++q1)
  270. {
  271. scratch[q1] = data[k];
  272. k += factor.length;
  273. }
  274. for (int k = i, q1 = 0; q1 < factor.radix; ++q1)
  275. {
  276. int twiddleIndex = 0;
  277. data[k] = scratch[0];
  278. for (int q = 1; q < factor.radix; ++q)
  279. {
  280. twiddleIndex += stride * k;
  281. if (twiddleIndex >= fftSize)
  282. twiddleIndex -= fftSize;
  283. data[k] += scratch[q] * twiddleTable[twiddleIndex];
  284. }
  285. k += factor.length;
  286. }
  287. }
  288. }
  289. void butterfly2 (Complex<float>* data, const int stride, const int length) const noexcept
  290. {
  291. auto* dataEnd = data + length;
  292. auto* tw = twiddleTable.getData();
  293. for (int i = length; --i >= 0;)
  294. {
  295. auto s = *dataEnd;
  296. s *= (*tw);
  297. tw += stride;
  298. *dataEnd++ = *data - s;
  299. *data++ += s;
  300. }
  301. }
  302. void butterfly4 (Complex<float>* data, const int stride, const int length) const noexcept
  303. {
  304. auto lengthX2 = length * 2;
  305. auto lengthX3 = length * 3;
  306. auto strideX2 = stride * 2;
  307. auto strideX3 = stride * 3;
  308. auto* twiddle1 = twiddleTable.getData();
  309. auto* twiddle2 = twiddle1;
  310. auto* twiddle3 = twiddle1;
  311. for (int i = length; --i >= 0;)
  312. {
  313. auto s0 = data[length] * *twiddle1;
  314. auto s1 = data[lengthX2] * *twiddle2;
  315. auto s2 = data[lengthX3] * *twiddle3;
  316. auto s3 = s0; s3 += s2;
  317. auto s4 = s0; s4 -= s2;
  318. auto s5 = *data; s5 -= s1;
  319. *data += s1;
  320. data[lengthX2] = *data;
  321. data[lengthX2] -= s3;
  322. twiddle1 += stride;
  323. twiddle2 += strideX2;
  324. twiddle3 += strideX3;
  325. *data += s3;
  326. if (inverse)
  327. {
  328. data[length].real (s5.real() - s4.imag());
  329. data[length].imag (s5.imag() + s4.real());
  330. data[lengthX3].real (s5.real() + s4.imag());
  331. data[lengthX3].imag (s5.imag() - s4.real());
  332. }
  333. else
  334. {
  335. data[length].real (s5.real() + s4.imag());
  336. data[length].imag (s5.imag() - s4.real());
  337. data[lengthX3].real (s5.real() - s4.imag());
  338. data[lengthX3].imag (s5.imag() + s4.real());
  339. }
  340. ++data;
  341. }
  342. }
  343. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFTConfig)
  344. };
  345. //==============================================================================
  346. SpinLock processLock;
  347. ScopedPointer<FFTConfig> configForward, configInverse;
  348. int size;
  349. };
  350. FFT::EngineImpl<FFTFallback> fftFallback;
  351. //==============================================================================
  352. //==============================================================================
  353. #if (JUCE_MAC || JUCE_IOS) && JUCE_USE_VDSP_FRAMEWORK
  354. struct AppleFFT : public FFT::Instance
  355. {
  356. static constexpr int priority = 5;
  357. static AppleFFT* create (int order)
  358. {
  359. return new AppleFFT (order);
  360. }
  361. AppleFFT (int orderToUse)
  362. : order (static_cast<vDSP_Length> (orderToUse)),
  363. fftSetup (vDSP_create_fftsetup (order, 2)),
  364. forwardNormalisation (.5f),
  365. inverseNormalisation (1.0f / static_cast<float> (1 << order))
  366. {}
  367. ~AppleFFT() override
  368. {
  369. if (fftSetup != nullptr)
  370. {
  371. vDSP_destroy_fftsetup (fftSetup);
  372. fftSetup = nullptr;
  373. }
  374. }
  375. void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
  376. {
  377. auto size = (1 << order);
  378. DSPSplitComplex splitInput (toSplitComplex (const_cast<Complex<float>*> (input)));
  379. DSPSplitComplex splitOutput (toSplitComplex (output));
  380. vDSP_fft_zop (fftSetup, &splitInput, 2, &splitOutput, 2,
  381. order, inverse ? kFFTDirection_Inverse : kFFTDirection_Forward);
  382. float factor = (inverse ? inverseNormalisation : forwardNormalisation * 2.0f);
  383. vDSP_vsmul ((float*) output, 1, &factor, (float*) output, 1, static_cast<size_t> (size << 1));
  384. }
  385. void performRealOnlyForwardTransform (float* inoutData, bool ignoreNegativeFreqs) const noexcept override
  386. {
  387. auto size = (1 << order);
  388. auto* inout = reinterpret_cast<Complex<float>*> (inoutData);
  389. auto splitInOut (toSplitComplex (inout));
  390. inoutData[size] = 0.0f;
  391. vDSP_fft_zrip (fftSetup, &splitInOut, 2, order, kFFTDirection_Forward);
  392. vDSP_vsmul (inoutData, 1, &forwardNormalisation, inoutData, 1, static_cast<size_t> (size << 1));
  393. mirrorResult (inout, ignoreNegativeFreqs);
  394. }
  395. void performRealOnlyInverseTransform (float* inoutData) const noexcept override
  396. {
  397. auto* inout = reinterpret_cast<Complex<float>*> (inoutData);
  398. auto size = (1 << order);
  399. auto splitInOut (toSplitComplex (inout));
  400. // Imaginary part of nyquist and DC frequencies are always zero
  401. // so Apple uses the imaginary part of the DC frequency to store
  402. // the real part of the nyquist frequency
  403. if (size != 1)
  404. inout[0] = Complex<float> (inout[0].real(), inout[size >> 1].real());
  405. vDSP_fft_zrip (fftSetup, &splitInOut, 2, order, kFFTDirection_Inverse);
  406. vDSP_vsmul (inoutData, 1, &inverseNormalisation, inoutData, 1, static_cast<size_t> (size << 1));
  407. vDSP_vclr (inoutData + size, 1, static_cast<size_t> (size));
  408. }
  409. private:
  410. //==============================================================================
  411. void mirrorResult (Complex<float>* out, bool ignoreNegativeFreqs) const noexcept
  412. {
  413. auto size = (1 << order);
  414. auto i = size >> 1;
  415. // Imaginary part of nyquist and DC frequencies are always zero
  416. // so Apple uses the imaginary part of the DC frequency to store
  417. // the real part of the nyquist frequency
  418. out[i++] = { out[0].imag(), 0.0 };
  419. out[0] = { out[0].real(), 0.0 };
  420. if (! ignoreNegativeFreqs)
  421. for (; i < size; ++i)
  422. out[i] = std::conj (out[size - i]);
  423. }
  424. static DSPSplitComplex toSplitComplex (Complex<float>* data) noexcept
  425. {
  426. // this assumes that Complex interleaves real and imaginary parts
  427. // and is tightly packed.
  428. return { reinterpret_cast<float*> (data),
  429. reinterpret_cast<float*> (data) + 1};
  430. }
  431. //==============================================================================
  432. vDSP_Length order;
  433. FFTSetup fftSetup;
  434. float forwardNormalisation, inverseNormalisation;
  435. };
  436. FFT::EngineImpl<AppleFFT> appleFFT;
  437. #endif
  438. //==============================================================================
  439. //==============================================================================
  440. #if JUCE_DSP_USE_SHARED_FFTW || JUCE_DSP_USE_STATIC_FFTW
  441. #if JUCE_DSP_USE_STATIC_FFTW
  442. extern "C"
  443. {
  444. void* fftwf_plan_dft_1d (int, void*, void*, int, int);
  445. void* fftwf_plan_dft_r2c_1d (int, void*, void*, int);
  446. void* fftwf_plan_dft_c2r_1d (int, void*, void*, int);
  447. void fftwf_destroy_plan (void*);
  448. void fftwf_execute_dft (void*, void*, void*);
  449. void fftwf_execute_dft_r2c (void*, void*, void*);
  450. void fftwf_execute_dft_c2r (void*, void*, void*);
  451. }
  452. #endif
  453. struct FFTWImpl : public FFT::Instance
  454. {
  455. #if JUCE_DSP_USE_STATIC_FFTW
  456. // if the JUCE developer has gone through the hassle of statically
  457. // linking in fftw, they probably want to use it
  458. static constexpr int priority = 10;
  459. #else
  460. static constexpr int priority = 3;
  461. #endif
  462. struct FFTWPlan;
  463. using FFTWPlanRef = FFTWPlan*;
  464. enum
  465. {
  466. measure = 0,
  467. unaligned = (1 << 1),
  468. estimate = (1 << 6)
  469. };
  470. struct Symbols
  471. {
  472. FFTWPlanRef (*plan_dft_fftw) (unsigned, Complex<float>*, Complex<float>*, int, unsigned);
  473. FFTWPlanRef (*plan_r2c_fftw) (unsigned, float*, Complex<float>*, unsigned);
  474. FFTWPlanRef (*plan_c2r_fftw) (unsigned, Complex<float>*, float*, unsigned);
  475. void (*destroy_fftw) (FFTWPlanRef);
  476. void (*execute_dft_fftw) (FFTWPlanRef, const Complex<float>*, Complex<float>*);
  477. void (*execute_r2c_fftw) (FFTWPlanRef, float*, Complex<float>*);
  478. void (*execute_c2r_fftw) (FFTWPlanRef, Complex<float>*, float*);
  479. #if JUCE_DSP_USE_STATIC_FFTW
  480. template <typename FuncPtr, typename ActualSymbolType>
  481. static bool symbol (FuncPtr& dst, ActualSymbolType sym)
  482. {
  483. dst = reinterpret_cast<FuncPtr> (sym);
  484. return true;
  485. }
  486. #else
  487. template <typename FuncPtr>
  488. static bool symbol (DynamicLibrary& lib, FuncPtr& dst, const char* name)
  489. {
  490. dst = reinterpret_cast<FuncPtr> (lib.getFunction (name));
  491. return (dst != nullptr);
  492. }
  493. #endif
  494. };
  495. static FFTWImpl* create (int order)
  496. {
  497. DynamicLibrary lib;
  498. #if ! JUCE_DSP_USE_STATIC_FFTW
  499. #if JUCE_MAC
  500. const char* libsuffix = "dylib";
  501. #elif JUCE_WINDOWS
  502. const char* libsuffix = "dll";
  503. #else
  504. const char* libsuffix = "so";
  505. #endif
  506. if (lib.open (String ("libfftw3f.") + libsuffix))
  507. #endif
  508. {
  509. Symbols symbols;
  510. #if JUCE_DSP_USE_STATIC_FFTW
  511. if (! Symbols::symbol (symbols.plan_dft_fftw, fftwf_plan_dft_1d)) return nullptr;
  512. if (! Symbols::symbol (symbols.plan_r2c_fftw, fftwf_plan_dft_r2c_1d)) return nullptr;
  513. if (! Symbols::symbol (symbols.plan_c2r_fftw, fftwf_plan_dft_c2r_1d)) return nullptr;
  514. if (! Symbols::symbol (symbols.destroy_fftw, fftwf_destroy_plan)) return nullptr;
  515. if (! Symbols::symbol (symbols.execute_dft_fftw, fftwf_execute_dft)) return nullptr;
  516. if (! Symbols::symbol (symbols.execute_r2c_fftw, fftwf_execute_dft_r2c)) return nullptr;
  517. if (! Symbols::symbol (symbols.execute_c2r_fftw, fftwf_execute_dft_c2r)) return nullptr;
  518. #else
  519. if (! Symbols::symbol (lib, symbols.plan_dft_fftw, "fftwf_plan_dft_1d")) return nullptr;
  520. if (! Symbols::symbol (lib, symbols.plan_r2c_fftw, "fftwf_plan_dft_r2c_1d")) return nullptr;
  521. if (! Symbols::symbol (lib, symbols.plan_c2r_fftw, "fftwf_plan_dft_c2r_1d")) return nullptr;
  522. if (! Symbols::symbol (lib, symbols.destroy_fftw, "fftwf_destroy_plan")) return nullptr;
  523. if (! Symbols::symbol (lib, symbols.execute_dft_fftw, "fftwf_execute_dft")) return nullptr;
  524. if (! Symbols::symbol (lib, symbols.execute_r2c_fftw, "fftwf_execute_dft_r2c")) return nullptr;
  525. if (! Symbols::symbol (lib, symbols.execute_c2r_fftw, "fftwf_execute_dft_c2r")) return nullptr;
  526. #endif
  527. return new FFTWImpl (static_cast<size_t> (order), static_cast<DynamicLibrary&&> (lib), symbols);
  528. }
  529. return nullptr;
  530. }
  531. FFTWImpl (size_t orderToUse, DynamicLibrary&& libraryToUse, const Symbols& symbols)
  532. : fftwLibrary (std::move (libraryToUse)), fftw (symbols), order (static_cast<size_t> (orderToUse))
  533. {
  534. auto n = (1u << order);
  535. HeapBlock<Complex<float>> in (n), out (n);
  536. c2cForward = fftw.plan_dft_fftw (n, in.getData(), out.getData(), -1, unaligned | estimate);
  537. c2cInverse = fftw.plan_dft_fftw (n, in.getData(), out.getData(), +1, unaligned | estimate);
  538. r2c = fftw.plan_r2c_fftw (n, (float*) in.getData(), in.getData(), unaligned | estimate);
  539. c2r = fftw.plan_c2r_fftw (n, in.getData(), (float*) in.getData(), unaligned | estimate);
  540. }
  541. ~FFTWImpl() override
  542. {
  543. fftw.destroy_fftw (c2cForward);
  544. fftw.destroy_fftw (c2cInverse);
  545. fftw.destroy_fftw (r2c);
  546. fftw.destroy_fftw (c2r);
  547. }
  548. void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
  549. {
  550. if (inverse)
  551. {
  552. auto n = (1u << order);
  553. fftw.execute_dft_fftw (c2cInverse, input, output);
  554. FloatVectorOperations::multiply ((float*) output, 1.0f / static_cast<float> (n), (int) n << 1);
  555. }
  556. else
  557. {
  558. fftw.execute_dft_fftw (c2cForward, input, output);
  559. }
  560. }
  561. void performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept override
  562. {
  563. if (order == 0)
  564. return;
  565. auto* out = reinterpret_cast<Complex<float>*> (inputOutputData);
  566. fftw.execute_r2c_fftw (r2c, inputOutputData, out);
  567. auto size = (1 << order);
  568. if (! ignoreNegativeFreqs)
  569. for (auto i = size >> 1; i < size; ++i)
  570. out[i] = std::conj (out[size - i]);
  571. }
  572. void performRealOnlyInverseTransform (float* inputOutputData) const noexcept override
  573. {
  574. auto n = (1u << order);
  575. fftw.execute_c2r_fftw (c2r, (Complex<float>*) inputOutputData, inputOutputData);
  576. FloatVectorOperations::multiply ((float*) inputOutputData, 1.0f / static_cast<float> (n), (int) n);
  577. }
  578. //==============================================================================
  579. DynamicLibrary fftwLibrary;
  580. Symbols fftw;
  581. size_t order;
  582. FFTWPlanRef c2cForward, c2cInverse, r2c, c2r;
  583. };
  584. FFT::EngineImpl<FFTWImpl> fftwEngine;
  585. #endif
  586. //==============================================================================
  587. //==============================================================================
  588. #if JUCE_DSP_USE_INTEL_MKL
  589. struct IntelFFT : public FFT::Instance
  590. {
  591. static constexpr int priority = 8;
  592. static bool succeeded (MKL_LONG status) noexcept { return status == 0; }
  593. static IntelFFT* create (int orderToUse)
  594. {
  595. DFTI_DESCRIPTOR_HANDLE mklc2c, mklc2r;
  596. if (DftiCreateDescriptor (&mklc2c, DFTI_SINGLE, DFTI_COMPLEX, 1, 1 << orderToUse) == 0)
  597. {
  598. if (succeeded (DftiSetValue (mklc2c, DFTI_PLACEMENT, DFTI_NOT_INPLACE))
  599. && succeeded (DftiSetValue (mklc2c, DFTI_BACKWARD_SCALE, 1.0f / static_cast<float> (1 << orderToUse)))
  600. && succeeded (DftiCommitDescriptor (mklc2c)))
  601. {
  602. if (succeeded (DftiCreateDescriptor (&mklc2r, DFTI_SINGLE, DFTI_REAL, 1, 1 << orderToUse)))
  603. {
  604. if (succeeded (DftiSetValue (mklc2r, DFTI_PLACEMENT, DFTI_INPLACE))
  605. && succeeded (DftiSetValue (mklc2r, DFTI_BACKWARD_SCALE, 1.0f / static_cast<float> (1 << orderToUse)))
  606. && succeeded (DftiCommitDescriptor (mklc2r)))
  607. {
  608. return new IntelFFT (static_cast<size_t> (orderToUse), mklc2c, mklc2r);
  609. }
  610. DftiFreeDescriptor (&mklc2r);
  611. }
  612. }
  613. DftiFreeDescriptor (&mklc2c);
  614. }
  615. return {};
  616. }
  617. IntelFFT (size_t orderToUse, DFTI_DESCRIPTOR_HANDLE c2cToUse, DFTI_DESCRIPTOR_HANDLE cr2ToUse)
  618. : order (orderToUse), c2c (c2cToUse), c2r (cr2ToUse)
  619. {}
  620. ~IntelFFT()
  621. {
  622. DftiFreeDescriptor (&c2c);
  623. DftiFreeDescriptor (&c2r);
  624. }
  625. void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
  626. {
  627. if (inverse)
  628. DftiComputeBackward (c2c, (void*) input, output);
  629. else
  630. DftiComputeForward (c2c, (void*) input, output);
  631. }
  632. void performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept override
  633. {
  634. if (order == 0)
  635. return;
  636. DftiComputeForward (c2r, inputOutputData);
  637. auto* out = reinterpret_cast<Complex<float>*> (inputOutputData);
  638. auto size = (1 << order);
  639. if (! ignoreNegativeFreqs)
  640. for (auto i = size >> 1; i < size; ++i)
  641. out[i] = std::conj (out[size - i]);
  642. }
  643. void performRealOnlyInverseTransform (float* inputOutputData) const noexcept override
  644. {
  645. DftiComputeBackward (c2r, inputOutputData);
  646. }
  647. size_t order;
  648. DFTI_DESCRIPTOR_HANDLE c2c, c2r;
  649. };
  650. FFT::EngineImpl<IntelFFT> fftwEngine;
  651. #endif
  652. //==============================================================================
  653. //==============================================================================
  654. FFT::FFT (int order)
  655. : engine (FFT::Engine::createBestEngineForPlatform (order)),
  656. size (1 << order)
  657. {}
  658. FFT::~FFT() {}
  659. void FFT::perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept
  660. {
  661. if (engine != nullptr)
  662. engine->perform (input, output, inverse);
  663. }
  664. void FFT::performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNeagtiveFreqs) const noexcept
  665. {
  666. if (engine != nullptr)
  667. engine->performRealOnlyForwardTransform (inputOutputData, ignoreNeagtiveFreqs);
  668. }
  669. void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcept
  670. {
  671. if (engine != nullptr)
  672. engine->performRealOnlyInverseTransform (inputOutputData);
  673. }
  674. void FFT::performFrequencyOnlyForwardTransform (float* inputOutputData) const noexcept
  675. {
  676. if (size == 1)
  677. return;
  678. performRealOnlyForwardTransform (inputOutputData);
  679. auto* out = reinterpret_cast<Complex<float>*> (inputOutputData);
  680. for (auto i = 0; i < size; ++i)
  681. inputOutputData[i] = std::abs (out[i]);
  682. zeromem (&inputOutputData[size], sizeof (float) * static_cast<size_t> (size));
  683. }
  684. } // namespace dsp
  685. } // namespace juce