1
0

TinyFFT.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * TinyFFT.cpp
  3. * -----------
  4. * Purpose: A simple FFT implementation for power-of-two FFTs
  5. * Notes : This is a C++ adaption of Ryuhei Mori's BSD 2-clause licensed TinyFFT
  6. * available from https://github.com/ryuhei-mori/tinyfft
  7. * Authors: Ryuhei Mori
  8. * OpenMPT Devs
  9. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  10. */
  11. #include "stdafx.h"
  12. #include "TinyFFT.h"
  13. OPENMPT_NAMESPACE_BEGIN
  14. void TinyFFT::GenerateTwiddleFactors(uint32 i, uint32 b, std::complex<double> z)
  15. {
  16. if(b == 0)
  17. w[i] = z;
  18. else
  19. {
  20. GenerateTwiddleFactors(i, b >> 1, z);
  21. GenerateTwiddleFactors(i | b, b >> 1, z * w[b]);
  22. }
  23. }
  24. TinyFFT::TinyFFT(const uint32 fftSize)
  25. : w(std::size_t(1) << (fftSize - 1))
  26. , k(fftSize)
  27. {
  28. const uint32 m = 1 << k;
  29. constexpr double PI2_ = 6.28318530717958647692;
  30. const double arg = -PI2_ / m;
  31. for(uint32 i = 1, j = m / 4; j; i <<= 1, j >>= 1)
  32. {
  33. w[i] = std::exp(I * (arg * j));
  34. }
  35. GenerateTwiddleFactors(0, m / 4, 1);
  36. }
  37. uint32 TinyFFT::Size() const noexcept
  38. {
  39. return 1 << k;
  40. }
  41. // Computes in-place FFT of size 2^k of A, result is in bit-reversed order.
  42. void TinyFFT::FFT(std::vector<std::complex<double>> &A) const
  43. {
  44. MPT_ASSERT(A.size() == (std::size_t(1) << k));
  45. const uint32 m = 1 << k;
  46. uint32 u = 1;
  47. uint32 v = m / 4;
  48. if(k & 1)
  49. {
  50. for(uint32 j = 0; j < m / 2; j++)
  51. {
  52. auto Ajv = A[j + (m / 2)];
  53. A[j + (m / 2)] = A[j] - Ajv;
  54. A[j] += Ajv;
  55. }
  56. u <<= 1;
  57. v >>= 1;
  58. }
  59. for(uint32 i = k & ~1; i > 0; i -= 2)
  60. {
  61. for(uint32 jh = 0; jh < u; jh++)
  62. {
  63. auto wj = w[jh << 1];
  64. auto wj2 = w[jh];
  65. auto wj3 = wj2 * wj;
  66. for(uint32 j = jh << i, je = j + v; j < je; j++)
  67. {
  68. auto tmp0 = A[j];
  69. auto tmp1 = wj * A[j + v];
  70. auto tmp2 = wj2 * A[j + 2 * v];
  71. auto tmp3 = wj3 * A[j + 3 * v];
  72. auto ttmp0 = tmp0 + tmp2;
  73. auto ttmp2 = tmp0 - tmp2;
  74. auto ttmp1 = tmp1 + tmp3;
  75. auto ttmp3 = -I * (tmp1 - tmp3);
  76. A[j] = ttmp0 + ttmp1;
  77. A[j + v] = ttmp0 - ttmp1;
  78. A[j + 2 * v] = ttmp2 + ttmp3;
  79. A[j + 3 * v] = ttmp2 - ttmp3;
  80. }
  81. }
  82. u <<= 2;
  83. v >>= 2;
  84. }
  85. }
  86. // Computes in-place IFFT of size 2^k of A, input is expected to be in bit-reversed order.
  87. void TinyFFT::IFFT(std::vector<std::complex<double>> &A) const
  88. {
  89. MPT_ASSERT(A.size() == (std::size_t(1) << k));
  90. const uint32 m = 1 << k;
  91. uint32 u = m / 4;
  92. uint32 v = 1;
  93. for(uint32 i = 2; i <= k; i += 2)
  94. {
  95. for(uint32 jh = 0; jh < u; jh++)
  96. {
  97. auto wj = std::conj(w[jh << 1]);
  98. auto wj2 = std::conj(w[jh]);
  99. auto wj3 = wj2 * wj;
  100. for(uint32 j = jh << i, je = j + v; j < je; j++)
  101. {
  102. auto tmp0 = A[j];
  103. auto tmp1 = A[j + v];
  104. auto tmp2 = A[j + 2 * v];
  105. auto tmp3 = A[j + 3 * v];
  106. auto ttmp0 = tmp0 + tmp1;
  107. auto ttmp1 = tmp0 - tmp1;
  108. auto ttmp2 = tmp2 + tmp3;
  109. auto ttmp3 = I * (tmp2 - tmp3);
  110. A[j] = ttmp0 + ttmp2;
  111. A[j + v] = wj * (ttmp1 + ttmp3);
  112. A[j + 2 * v] = wj2 * (ttmp0 - ttmp2);
  113. A[j + 3 * v] = wj3 * (ttmp1 - ttmp3);
  114. }
  115. }
  116. u >>= 2;
  117. v <<= 2;
  118. }
  119. if(k & 1)
  120. {
  121. for(uint32 j = 0; j < m / 2; j++)
  122. {
  123. auto Ajv = A[j + (m / 2)];
  124. A[j + (m / 2)] = A[j] - Ajv;
  125. A[j] += Ajv;
  126. }
  127. }
  128. }
  129. void TinyFFT::Normalize(std::vector<std::complex<double>> &data)
  130. {
  131. const double s = static_cast<double>(data.size());
  132. for(auto &v : data)
  133. v /= s;
  134. }
  135. OPENMPT_NAMESPACE_END