Audio plugin host https://kx.studio/carla
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.

1002 lines
34KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  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 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. namespace dsp
  21. {
  22. struct FFT::Instance
  23. {
  24. virtual ~Instance() = default;
  25. virtual void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept = 0;
  26. virtual void performRealOnlyForwardTransform (float*, bool) const noexcept = 0;
  27. virtual void performRealOnlyInverseTransform (float*) const noexcept = 0;
  28. };
  29. struct FFT::Engine
  30. {
  31. Engine (int priorityToUse) : enginePriority (priorityToUse)
  32. {
  33. auto& list = getEngines();
  34. list.add (this);
  35. std::sort (list.begin(), list.end(), [] (Engine* a, Engine* b) { return b->enginePriority < a->enginePriority; });
  36. }
  37. virtual ~Engine() = default;
  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. static Array<Engine*>& getEngines()
  50. {
  51. static Array<Engine*> engines;
  52. return engines;
  53. }
  54. int enginePriority; // used so that faster engines have priority over slower ones
  55. };
  56. template <typename InstanceToUse>
  57. struct FFT::EngineImpl : public FFT::Engine
  58. {
  59. EngineImpl() : FFT::Engine (InstanceToUse::priority) {}
  60. FFT::Instance* create (int order) const override { return InstanceToUse::create (order); }
  61. };
  62. //==============================================================================
  63. //==============================================================================
  64. struct FFTFallback : public FFT::Instance
  65. {
  66. // this should have the least priority of all engines
  67. static constexpr int priority = -1;
  68. static FFTFallback* create (int order)
  69. {
  70. return new FFTFallback (order);
  71. }
  72. FFTFallback (int order)
  73. {
  74. configForward.reset (new FFTConfig (1 << order, false));
  75. configInverse.reset (new FFTConfig (1 << order, true));
  76. size = 1 << order;
  77. }
  78. void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
  79. {
  80. if (size == 1)
  81. {
  82. *output = *input;
  83. return;
  84. }
  85. const SpinLock::ScopedLockType sl(processLock);
  86. jassert (configForward != nullptr);
  87. if (inverse)
  88. {
  89. configInverse->perform (input, output);
  90. const float scaleFactor = 1.0f / (float) size;
  91. for (int i = 0; i < size; ++i)
  92. output[i] *= scaleFactor;
  93. }
  94. else
  95. {
  96. configForward->perform (input, output);
  97. }
  98. }
  99. const size_t maxFFTScratchSpaceToAlloca = 256 * 1024;
  100. void performRealOnlyForwardTransform (float* d, bool) const noexcept override
  101. {
  102. if (size == 1)
  103. return;
  104. const size_t scratchSize = 16 + (size_t) size * sizeof (Complex<float>);
  105. if (scratchSize < maxFFTScratchSpaceToAlloca)
  106. {
  107. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6255)
  108. performRealOnlyForwardTransform (static_cast<Complex<float>*> (alloca (scratchSize)), d);
  109. JUCE_END_IGNORE_WARNINGS_MSVC
  110. }
  111. else
  112. {
  113. HeapBlock<char> heapSpace (scratchSize);
  114. performRealOnlyForwardTransform (unalignedPointerCast<Complex<float>*> (heapSpace.getData()), d);
  115. }
  116. }
  117. void performRealOnlyInverseTransform (float* d) const noexcept override
  118. {
  119. if (size == 1)
  120. return;
  121. const size_t scratchSize = 16 + (size_t) size * sizeof (Complex<float>);
  122. if (scratchSize < maxFFTScratchSpaceToAlloca)
  123. {
  124. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6255)
  125. performRealOnlyInverseTransform (static_cast<Complex<float>*> (alloca (scratchSize)), d);
  126. JUCE_END_IGNORE_WARNINGS_MSVC
  127. }
  128. else
  129. {
  130. HeapBlock<char> heapSpace (scratchSize);
  131. performRealOnlyInverseTransform (unalignedPointerCast<Complex<float>*> (heapSpace.getData()), d);
  132. }
  133. }
  134. void performRealOnlyForwardTransform (Complex<float>* scratch, float* d) const noexcept
  135. {
  136. for (int i = 0; i < size; ++i)
  137. scratch[i] = { d[i], 0 };
  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 (int 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] = { (float) std::cos (phase),
  165. (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] = { (float) std::cos (phase),
  174. (float) std::sin (phase) };
  175. }
  176. for (int i = fftSize / 4; i < fftSize / 2; ++i)
  177. {
  178. auto other = twiddleTable[i - fftSize / 4];
  179. twiddleTable[i] = { inverse ? -other.imag() : other.imag(),
  180. inverse ? other.real() : -other.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. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6255)
  260. auto* scratch = static_cast<Complex<float>*> (alloca ((size_t) factor.radix * sizeof (Complex<float>)));
  261. JUCE_END_IGNORE_WARNINGS_MSVC
  262. for (int i = 0; i < factor.length; ++i)
  263. {
  264. for (int k = i, q1 = 0; q1 < factor.radix; ++q1)
  265. {
  266. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6386)
  267. scratch[q1] = data[k];
  268. JUCE_END_IGNORE_WARNINGS_MSVC
  269. k += factor.length;
  270. }
  271. for (int k = i, q1 = 0; q1 < factor.radix; ++q1)
  272. {
  273. int twiddleIndex = 0;
  274. data[k] = scratch[0];
  275. for (int q = 1; q < factor.radix; ++q)
  276. {
  277. twiddleIndex += stride * k;
  278. if (twiddleIndex >= fftSize)
  279. twiddleIndex -= fftSize;
  280. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6385)
  281. data[k] += scratch[q] * twiddleTable[twiddleIndex];
  282. JUCE_END_IGNORE_WARNINGS_MSVC
  283. }
  284. k += factor.length;
  285. }
  286. }
  287. }
  288. void butterfly2 (Complex<float>* data, const int stride, const int length) const noexcept
  289. {
  290. auto* dataEnd = data + length;
  291. auto* tw = twiddleTable.getData();
  292. for (int i = length; --i >= 0;)
  293. {
  294. auto s = *dataEnd;
  295. s *= (*tw);
  296. tw += stride;
  297. *dataEnd++ = *data - s;
  298. *data++ += s;
  299. }
  300. }
  301. void butterfly4 (Complex<float>* data, const int stride, const int length) const noexcept
  302. {
  303. auto lengthX2 = length * 2;
  304. auto lengthX3 = length * 3;
  305. auto strideX2 = stride * 2;
  306. auto strideX3 = stride * 3;
  307. auto* twiddle1 = twiddleTable.getData();
  308. auto* twiddle2 = twiddle1;
  309. auto* twiddle3 = twiddle1;
  310. for (int i = length; --i >= 0;)
  311. {
  312. auto s0 = data[length] * *twiddle1;
  313. auto s1 = data[lengthX2] * *twiddle2;
  314. auto s2 = data[lengthX3] * *twiddle3;
  315. auto s3 = s0; s3 += s2;
  316. auto s4 = s0; s4 -= s2;
  317. auto s5 = *data; s5 -= s1;
  318. *data += s1;
  319. data[lengthX2] = *data;
  320. data[lengthX2] -= s3;
  321. twiddle1 += stride;
  322. twiddle2 += strideX2;
  323. twiddle3 += strideX3;
  324. *data += s3;
  325. if (inverse)
  326. {
  327. data[length] = { s5.real() - s4.imag(),
  328. s5.imag() + s4.real() };
  329. data[lengthX3] = { s5.real() + s4.imag(),
  330. s5.imag() - s4.real() };
  331. }
  332. else
  333. {
  334. data[length] = { s5.real() + s4.imag(),
  335. s5.imag() - s4.real() };
  336. data[lengthX3] = { s5.real() - s4.imag(),
  337. s5.imag() + s4.real() };
  338. }
  339. ++data;
  340. }
  341. }
  342. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFTConfig)
  343. };
  344. //==============================================================================
  345. SpinLock processLock;
  346. std::unique_ptr<FFTConfig> configForward, configInverse;
  347. int size;
  348. };
  349. FFT::EngineImpl<FFTFallback> fftFallback;
  350. //==============================================================================
  351. //==============================================================================
  352. #if (JUCE_MAC || JUCE_IOS) && JUCE_USE_VDSP_FRAMEWORK
  353. struct AppleFFT : public FFT::Instance
  354. {
  355. static constexpr int priority = 5;
  356. static AppleFFT* create (int order)
  357. {
  358. return new AppleFFT (order);
  359. }
  360. AppleFFT (int orderToUse)
  361. : order (static_cast<vDSP_Length> (orderToUse)),
  362. fftSetup (vDSP_create_fftsetup (order, 2)),
  363. forwardNormalisation (0.5f),
  364. inverseNormalisation (1.0f / static_cast<float> (1 << order))
  365. {}
  366. ~AppleFFT() override
  367. {
  368. if (fftSetup != nullptr)
  369. {
  370. vDSP_destroy_fftsetup (fftSetup);
  371. fftSetup = nullptr;
  372. }
  373. }
  374. void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
  375. {
  376. auto size = (1 << order);
  377. DSPSplitComplex splitInput (toSplitComplex (const_cast<Complex<float>*> (input)));
  378. DSPSplitComplex splitOutput (toSplitComplex (output));
  379. vDSP_fft_zop (fftSetup, &splitInput, 2, &splitOutput, 2,
  380. order, inverse ? kFFTDirection_Inverse : kFFTDirection_Forward);
  381. float factor = (inverse ? inverseNormalisation : forwardNormalisation * 2.0f);
  382. vDSP_vsmul ((float*) output, 1, &factor, (float*) output, 1, static_cast<size_t> (size << 1));
  383. }
  384. void performRealOnlyForwardTransform (float* inoutData, bool ignoreNegativeFreqs) const noexcept override
  385. {
  386. auto size = (1 << order);
  387. auto* inout = reinterpret_cast<Complex<float>*> (inoutData);
  388. auto splitInOut (toSplitComplex (inout));
  389. inoutData[size] = 0.0f;
  390. vDSP_fft_zrip (fftSetup, &splitInOut, 2, order, kFFTDirection_Forward);
  391. vDSP_vsmul (inoutData, 1, &forwardNormalisation, inoutData, 1, static_cast<size_t> (size << 1));
  392. mirrorResult (inout, ignoreNegativeFreqs);
  393. }
  394. void performRealOnlyInverseTransform (float* inoutData) const noexcept override
  395. {
  396. auto* inout = reinterpret_cast<Complex<float>*> (inoutData);
  397. auto size = (1 << order);
  398. auto splitInOut (toSplitComplex (inout));
  399. // Imaginary part of nyquist and DC frequencies are always zero
  400. // so Apple uses the imaginary part of the DC frequency to store
  401. // the real part of the nyquist frequency
  402. if (size != 1)
  403. inout[0] = Complex<float> (inout[0].real(), inout[size >> 1].real());
  404. vDSP_fft_zrip (fftSetup, &splitInOut, 2, order, kFFTDirection_Inverse);
  405. vDSP_vsmul (inoutData, 1, &inverseNormalisation, inoutData, 1, static_cast<size_t> (size << 1));
  406. vDSP_vclr (inoutData + size, 1, static_cast<size_t> (size));
  407. }
  408. private:
  409. //==============================================================================
  410. void mirrorResult (Complex<float>* out, bool ignoreNegativeFreqs) const noexcept
  411. {
  412. auto size = (1 << order);
  413. auto i = size >> 1;
  414. // Imaginary part of nyquist and DC frequencies are always zero
  415. // so Apple uses the imaginary part of the DC frequency to store
  416. // the real part of the nyquist frequency
  417. out[i++] = { out[0].imag(), 0.0 };
  418. out[0] = { out[0].real(), 0.0 };
  419. if (! ignoreNegativeFreqs)
  420. for (; i < size; ++i)
  421. out[i] = std::conj (out[size - i]);
  422. }
  423. static DSPSplitComplex toSplitComplex (Complex<float>* data) noexcept
  424. {
  425. // this assumes that Complex interleaves real and imaginary parts
  426. // and is tightly packed.
  427. return { reinterpret_cast<float*> (data),
  428. reinterpret_cast<float*> (data) + 1};
  429. }
  430. //==============================================================================
  431. vDSP_Length order;
  432. FFTSetup fftSetup;
  433. float forwardNormalisation, inverseNormalisation;
  434. };
  435. FFT::EngineImpl<AppleFFT> appleFFT;
  436. #endif
  437. //==============================================================================
  438. //==============================================================================
  439. #if JUCE_DSP_USE_SHARED_FFTW || JUCE_DSP_USE_STATIC_FFTW
  440. #if JUCE_DSP_USE_STATIC_FFTW
  441. extern "C"
  442. {
  443. void* fftwf_plan_dft_1d (int, void*, void*, int, int);
  444. void* fftwf_plan_dft_r2c_1d (int, void*, void*, int);
  445. void* fftwf_plan_dft_c2r_1d (int, void*, void*, int);
  446. void fftwf_destroy_plan (void*);
  447. void fftwf_execute_dft (void*, void*, void*);
  448. void fftwf_execute_dft_r2c (void*, void*, void*);
  449. void fftwf_execute_dft_c2r (void*, void*, void*);
  450. }
  451. #endif
  452. struct FFTWImpl : public FFT::Instance
  453. {
  454. #if JUCE_DSP_USE_STATIC_FFTW
  455. // if the JUCE developer has gone through the hassle of statically
  456. // linking in fftw, they probably want to use it
  457. static constexpr int priority = 10;
  458. #else
  459. static constexpr int priority = 3;
  460. #endif
  461. struct FFTWPlan;
  462. using FFTWPlanRef = FFTWPlan*;
  463. enum
  464. {
  465. measure = 0,
  466. unaligned = (1 << 1),
  467. estimate = (1 << 6)
  468. };
  469. struct Symbols
  470. {
  471. FFTWPlanRef (*plan_dft_fftw) (unsigned, Complex<float>*, Complex<float>*, int, unsigned);
  472. FFTWPlanRef (*plan_r2c_fftw) (unsigned, float*, Complex<float>*, unsigned);
  473. FFTWPlanRef (*plan_c2r_fftw) (unsigned, Complex<float>*, float*, unsigned);
  474. void (*destroy_fftw) (FFTWPlanRef);
  475. void (*execute_dft_fftw) (FFTWPlanRef, const Complex<float>*, Complex<float>*);
  476. void (*execute_r2c_fftw) (FFTWPlanRef, float*, Complex<float>*);
  477. void (*execute_c2r_fftw) (FFTWPlanRef, Complex<float>*, float*);
  478. #if JUCE_DSP_USE_STATIC_FFTW
  479. template <typename FuncPtr, typename ActualSymbolType>
  480. static bool symbol (FuncPtr& dst, ActualSymbolType sym)
  481. {
  482. dst = reinterpret_cast<FuncPtr> (sym);
  483. return true;
  484. }
  485. #else
  486. template <typename FuncPtr>
  487. static bool symbol (DynamicLibrary& lib, FuncPtr& dst, const char* name)
  488. {
  489. dst = reinterpret_cast<FuncPtr> (lib.getFunction (name));
  490. return (dst != nullptr);
  491. }
  492. #endif
  493. };
  494. static FFTWImpl* create (int order)
  495. {
  496. DynamicLibrary lib;
  497. #if ! JUCE_DSP_USE_STATIC_FFTW
  498. #if JUCE_MAC
  499. auto libName = "libfftw3f.dylib";
  500. #elif JUCE_WINDOWS
  501. auto libName = "libfftw3f.dll";
  502. #else
  503. auto libName = "libfftw3f.so";
  504. #endif
  505. if (lib.open (libName))
  506. #endif
  507. {
  508. Symbols symbols;
  509. #if JUCE_DSP_USE_STATIC_FFTW
  510. if (! Symbols::symbol (symbols.plan_dft_fftw, fftwf_plan_dft_1d)) return nullptr;
  511. if (! Symbols::symbol (symbols.plan_r2c_fftw, fftwf_plan_dft_r2c_1d)) return nullptr;
  512. if (! Symbols::symbol (symbols.plan_c2r_fftw, fftwf_plan_dft_c2r_1d)) return nullptr;
  513. if (! Symbols::symbol (symbols.destroy_fftw, fftwf_destroy_plan)) return nullptr;
  514. if (! Symbols::symbol (symbols.execute_dft_fftw, fftwf_execute_dft)) return nullptr;
  515. if (! Symbols::symbol (symbols.execute_r2c_fftw, fftwf_execute_dft_r2c)) return nullptr;
  516. if (! Symbols::symbol (symbols.execute_c2r_fftw, fftwf_execute_dft_c2r)) return nullptr;
  517. #else
  518. if (! Symbols::symbol (lib, symbols.plan_dft_fftw, "fftwf_plan_dft_1d")) return nullptr;
  519. if (! Symbols::symbol (lib, symbols.plan_r2c_fftw, "fftwf_plan_dft_r2c_1d")) return nullptr;
  520. if (! Symbols::symbol (lib, symbols.plan_c2r_fftw, "fftwf_plan_dft_c2r_1d")) return nullptr;
  521. if (! Symbols::symbol (lib, symbols.destroy_fftw, "fftwf_destroy_plan")) return nullptr;
  522. if (! Symbols::symbol (lib, symbols.execute_dft_fftw, "fftwf_execute_dft")) return nullptr;
  523. if (! Symbols::symbol (lib, symbols.execute_r2c_fftw, "fftwf_execute_dft_r2c")) return nullptr;
  524. if (! Symbols::symbol (lib, symbols.execute_c2r_fftw, "fftwf_execute_dft_c2r")) return nullptr;
  525. #endif
  526. return new FFTWImpl (static_cast<size_t> (order), std::move (lib), symbols);
  527. }
  528. return nullptr;
  529. }
  530. FFTWImpl (size_t orderToUse, DynamicLibrary&& libraryToUse, const Symbols& symbols)
  531. : fftwLibrary (std::move (libraryToUse)), fftw (symbols), order (static_cast<size_t> (orderToUse))
  532. {
  533. ScopedLock lock (getFFTWPlanLock());
  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. ScopedLock lock (getFFTWPlanLock());
  544. fftw.destroy_fftw (c2cForward);
  545. fftw.destroy_fftw (c2cInverse);
  546. fftw.destroy_fftw (r2c);
  547. fftw.destroy_fftw (c2r);
  548. }
  549. void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
  550. {
  551. if (inverse)
  552. {
  553. auto n = (1u << order);
  554. fftw.execute_dft_fftw (c2cInverse, input, output);
  555. FloatVectorOperations::multiply ((float*) output, 1.0f / static_cast<float> (n), (int) n << 1);
  556. }
  557. else
  558. {
  559. fftw.execute_dft_fftw (c2cForward, input, output);
  560. }
  561. }
  562. void performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept override
  563. {
  564. if (order == 0)
  565. return;
  566. auto* out = reinterpret_cast<Complex<float>*> (inputOutputData);
  567. fftw.execute_r2c_fftw (r2c, inputOutputData, out);
  568. auto size = (1 << order);
  569. if (! ignoreNegativeFreqs)
  570. for (int i = size >> 1; i < size; ++i)
  571. out[i] = std::conj (out[size - i]);
  572. }
  573. void performRealOnlyInverseTransform (float* inputOutputData) const noexcept override
  574. {
  575. auto n = (1u << order);
  576. fftw.execute_c2r_fftw (c2r, (Complex<float>*) inputOutputData, inputOutputData);
  577. FloatVectorOperations::multiply ((float*) inputOutputData, 1.0f / static_cast<float> (n), (int) n);
  578. }
  579. //==============================================================================
  580. // fftw's plan_* and destroy_* methods are NOT thread safe. So we need to share
  581. // a lock between all instances of FFTWImpl
  582. static CriticalSection& getFFTWPlanLock() noexcept
  583. {
  584. static CriticalSection cs;
  585. return cs;
  586. }
  587. //==============================================================================
  588. DynamicLibrary fftwLibrary;
  589. Symbols fftw;
  590. size_t order;
  591. FFTWPlanRef c2cForward, c2cInverse, r2c, c2r;
  592. };
  593. FFT::EngineImpl<FFTWImpl> fftwEngine;
  594. #endif
  595. //==============================================================================
  596. //==============================================================================
  597. #if JUCE_DSP_USE_INTEL_MKL
  598. struct IntelFFT : public FFT::Instance
  599. {
  600. static constexpr int priority = 8;
  601. static bool succeeded (MKL_LONG status) noexcept { return status == 0; }
  602. static IntelFFT* create (int orderToUse)
  603. {
  604. DFTI_DESCRIPTOR_HANDLE mklc2c, mklc2r;
  605. if (DftiCreateDescriptor (&mklc2c, DFTI_SINGLE, DFTI_COMPLEX, 1, 1 << orderToUse) == 0)
  606. {
  607. if (succeeded (DftiSetValue (mklc2c, DFTI_PLACEMENT, DFTI_NOT_INPLACE))
  608. && succeeded (DftiSetValue (mklc2c, DFTI_BACKWARD_SCALE, 1.0f / static_cast<float> (1 << orderToUse)))
  609. && succeeded (DftiCommitDescriptor (mklc2c)))
  610. {
  611. if (succeeded (DftiCreateDescriptor (&mklc2r, DFTI_SINGLE, DFTI_REAL, 1, 1 << orderToUse)))
  612. {
  613. if (succeeded (DftiSetValue (mklc2r, DFTI_PLACEMENT, DFTI_INPLACE))
  614. && succeeded (DftiSetValue (mklc2r, DFTI_BACKWARD_SCALE, 1.0f / static_cast<float> (1 << orderToUse)))
  615. && succeeded (DftiCommitDescriptor (mklc2r)))
  616. {
  617. return new IntelFFT (static_cast<size_t> (orderToUse), mklc2c, mklc2r);
  618. }
  619. DftiFreeDescriptor (&mklc2r);
  620. }
  621. }
  622. DftiFreeDescriptor (&mklc2c);
  623. }
  624. return {};
  625. }
  626. IntelFFT (size_t orderToUse, DFTI_DESCRIPTOR_HANDLE c2cToUse, DFTI_DESCRIPTOR_HANDLE cr2ToUse)
  627. : order (orderToUse), c2c (c2cToUse), c2r (cr2ToUse)
  628. {}
  629. ~IntelFFT() override
  630. {
  631. DftiFreeDescriptor (&c2c);
  632. DftiFreeDescriptor (&c2r);
  633. }
  634. void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
  635. {
  636. if (inverse)
  637. DftiComputeBackward (c2c, (void*) input, output);
  638. else
  639. DftiComputeForward (c2c, (void*) input, output);
  640. }
  641. void performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept override
  642. {
  643. if (order == 0)
  644. return;
  645. DftiComputeForward (c2r, inputOutputData);
  646. auto* out = reinterpret_cast<Complex<float>*> (inputOutputData);
  647. auto size = (1 << order);
  648. if (! ignoreNegativeFreqs)
  649. for (int i = size >> 1; i < size; ++i)
  650. out[i] = std::conj (out[size - i]);
  651. }
  652. void performRealOnlyInverseTransform (float* inputOutputData) const noexcept override
  653. {
  654. DftiComputeBackward (c2r, inputOutputData);
  655. }
  656. size_t order;
  657. DFTI_DESCRIPTOR_HANDLE c2c, c2r;
  658. };
  659. FFT::EngineImpl<IntelFFT> fftwEngine;
  660. #endif
  661. //==============================================================================
  662. //==============================================================================
  663. // Visual Studio should define no more than one of these, depending on the
  664. // setting at 'Project' > 'Properties' > 'Configuration Properties' > 'Intel
  665. // Performance Libraries' > 'Use Intel(R) IPP'
  666. #if _IPP_SEQUENTIAL_STATIC || _IPP_SEQUENTIAL_DYNAMIC || _IPP_PARALLEL_STATIC || _IPP_PARALLEL_DYNAMIC
  667. class IntelPerformancePrimitivesFFT : public FFT::Instance
  668. {
  669. public:
  670. static constexpr auto priority = 9;
  671. static IntelPerformancePrimitivesFFT* create (const int order)
  672. {
  673. auto complexContext = Context<ComplexTraits>::create (order);
  674. auto realContext = Context<RealTraits> ::create (order);
  675. if (complexContext.isValid() && realContext.isValid())
  676. return new IntelPerformancePrimitivesFFT (std::move (complexContext), std::move (realContext), order);
  677. return {};
  678. }
  679. void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept override
  680. {
  681. if (inverse)
  682. {
  683. ippsFFTInv_CToC_32fc (reinterpret_cast<const Ipp32fc*> (input),
  684. reinterpret_cast<Ipp32fc*> (output),
  685. cplx.specPtr,
  686. cplx.workBuf.get());
  687. }
  688. else
  689. {
  690. ippsFFTFwd_CToC_32fc (reinterpret_cast<const Ipp32fc*> (input),
  691. reinterpret_cast<Ipp32fc*> (output),
  692. cplx.specPtr,
  693. cplx.workBuf.get());
  694. }
  695. }
  696. void performRealOnlyForwardTransform (float* inoutData, bool ignoreNegativeFreqs) const noexcept override
  697. {
  698. ippsFFTFwd_RToCCS_32f_I (inoutData, real.specPtr, real.workBuf.get());
  699. if (order == 0)
  700. return;
  701. auto* out = reinterpret_cast<Complex<float>*> (inoutData);
  702. const auto size = (1 << order);
  703. if (! ignoreNegativeFreqs)
  704. for (auto i = size >> 1; i < size; ++i)
  705. out[i] = std::conj (out[size - i]);
  706. }
  707. void performRealOnlyInverseTransform (float* inoutData) const noexcept override
  708. {
  709. ippsFFTInv_CCSToR_32f_I (inoutData, real.specPtr, real.workBuf.get());
  710. }
  711. private:
  712. static constexpr auto flag = IPP_FFT_DIV_INV_BY_N;
  713. static constexpr auto hint = ippAlgHintFast;
  714. struct IppFree
  715. {
  716. template <typename Ptr>
  717. void operator() (Ptr* ptr) const noexcept { ippsFree (ptr); }
  718. };
  719. using IppPtr = std::unique_ptr<Ipp8u[], IppFree>;
  720. template <typename Traits>
  721. struct Context
  722. {
  723. using SpecPtr = typename Traits::Spec*;
  724. static Context create (const int order)
  725. {
  726. int specSize = 0, initSize = 0, workSize = 0;
  727. if (Traits::getSize (order, flag, hint, &specSize, &initSize, &workSize) != ippStsNoErr)
  728. return {};
  729. const auto initBuf = IppPtr (ippsMalloc_8u (initSize));
  730. auto specBuf = IppPtr (ippsMalloc_8u (specSize));
  731. SpecPtr specPtr = nullptr;
  732. if (Traits::init (&specPtr, order, flag, hint, specBuf.get(), initBuf.get()) != ippStsNoErr)
  733. return {};
  734. return { std::move (specBuf), IppPtr (ippsMalloc_8u (workSize)), specPtr };
  735. }
  736. Context() noexcept = default;
  737. Context (IppPtr&& spec, IppPtr&& work, typename Traits::Spec* ptr) noexcept
  738. : specBuf (std::move (spec)), workBuf (std::move (work)), specPtr (ptr)
  739. {}
  740. bool isValid() const noexcept { return specPtr != nullptr; }
  741. IppPtr specBuf, workBuf;
  742. SpecPtr specPtr = nullptr;
  743. };
  744. struct ComplexTraits
  745. {
  746. static constexpr auto getSize = ippsFFTGetSize_C_32fc;
  747. static constexpr auto init = ippsFFTInit_C_32fc;
  748. using Spec = IppsFFTSpec_C_32fc;
  749. };
  750. struct RealTraits
  751. {
  752. static constexpr auto getSize = ippsFFTGetSize_R_32f;
  753. static constexpr auto init = ippsFFTInit_R_32f;
  754. using Spec = IppsFFTSpec_R_32f;
  755. };
  756. IntelPerformancePrimitivesFFT (Context<ComplexTraits>&& complexToUse,
  757. Context<RealTraits>&& realToUse,
  758. const int orderToUse)
  759. : cplx (std::move (complexToUse)),
  760. real (std::move (realToUse)),
  761. order (orderToUse)
  762. {}
  763. Context<ComplexTraits> cplx;
  764. Context<RealTraits> real;
  765. int order = 0;
  766. };
  767. FFT::EngineImpl<IntelPerformancePrimitivesFFT> intelPerformancePrimitivesFFT;
  768. #endif
  769. //==============================================================================
  770. //==============================================================================
  771. FFT::FFT (int order)
  772. : engine (FFT::Engine::createBestEngineForPlatform (order)),
  773. size (1 << order)
  774. {
  775. }
  776. FFT::FFT (FFT&&) noexcept = default;
  777. FFT& FFT::operator= (FFT&&) noexcept = default;
  778. FFT::~FFT() = default;
  779. void FFT::perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept
  780. {
  781. if (engine != nullptr)
  782. engine->perform (input, output, inverse);
  783. }
  784. void FFT::performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept
  785. {
  786. if (engine != nullptr)
  787. engine->performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs);
  788. }
  789. void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcept
  790. {
  791. if (engine != nullptr)
  792. engine->performRealOnlyInverseTransform (inputOutputData);
  793. }
  794. void FFT::performFrequencyOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept
  795. {
  796. if (size == 1)
  797. return;
  798. performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs);
  799. auto* out = reinterpret_cast<Complex<float>*> (inputOutputData);
  800. const auto limit = ignoreNegativeFreqs ? (size / 2) + 1 : size;
  801. for (int i = 0; i < limit; ++i)
  802. inputOutputData[i] = std::abs (out[i]);
  803. zeromem (inputOutputData + limit, static_cast<size_t> (size * 2 - limit) * sizeof (float));
  804. }
  805. } // namespace dsp
  806. } // namespace juce