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.

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