🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
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.

166 lines
4.7 KiB

  1. #include "config.h"
  2. #include "alcomplex.h"
  3. #include <algorithm>
  4. #include <cassert>
  5. #include <cmath>
  6. #include <cstddef>
  7. #include <utility>
  8. #include "albit.h"
  9. #include "alnumbers.h"
  10. #include "alnumeric.h"
  11. #include "opthelpers.h"
  12. namespace {
  13. using ushort = unsigned short;
  14. using ushort2 = std::pair<ushort,ushort>;
  15. /* Because std::array doesn't have constexpr non-const accessors in C++14. */
  16. template<typename T, size_t N>
  17. struct our_array {
  18. T mData[N];
  19. };
  20. constexpr size_t BitReverseCounter(size_t log2_size) noexcept
  21. {
  22. /* Some magic math that calculates the number of swaps needed for a
  23. * sequence of bit-reversed indices when index < reversed_index.
  24. */
  25. return (1u<<(log2_size-1)) - (1u<<((log2_size-1u)/2u));
  26. }
  27. template<size_t N>
  28. constexpr auto GetBitReverser() noexcept
  29. {
  30. static_assert(N <= sizeof(ushort)*8, "Too many bits for the bit-reversal table.");
  31. our_array<ushort2, BitReverseCounter(N)> ret{};
  32. const size_t fftsize{1u << N};
  33. size_t ret_i{0};
  34. /* Bit-reversal permutation applied to a sequence of fftsize items. */
  35. for(size_t idx{1u};idx < fftsize-1;++idx)
  36. {
  37. size_t revidx{0u}, imask{idx};
  38. for(size_t i{0};i < N;++i)
  39. {
  40. revidx = (revidx<<1) | (imask&1);
  41. imask >>= 1;
  42. }
  43. if(idx < revidx)
  44. {
  45. ret.mData[ret_i].first = static_cast<ushort>(idx);
  46. ret.mData[ret_i].second = static_cast<ushort>(revidx);
  47. ++ret_i;
  48. }
  49. }
  50. assert(ret_i == al::size(ret.mData));
  51. return ret;
  52. }
  53. /* These bit-reversal swap tables support up to 10-bit indices (1024 elements),
  54. * which is the largest used by OpenAL Soft's filters and effects. Larger FFT
  55. * requests, used by some utilities where performance is less important, will
  56. * use a slower table-less path.
  57. */
  58. constexpr auto BitReverser2 = GetBitReverser<2>();
  59. constexpr auto BitReverser3 = GetBitReverser<3>();
  60. constexpr auto BitReverser4 = GetBitReverser<4>();
  61. constexpr auto BitReverser5 = GetBitReverser<5>();
  62. constexpr auto BitReverser6 = GetBitReverser<6>();
  63. constexpr auto BitReverser7 = GetBitReverser<7>();
  64. constexpr auto BitReverser8 = GetBitReverser<8>();
  65. constexpr auto BitReverser9 = GetBitReverser<9>();
  66. constexpr auto BitReverser10 = GetBitReverser<10>();
  67. constexpr al::span<const ushort2> gBitReverses[11]{
  68. {}, {},
  69. BitReverser2.mData,
  70. BitReverser3.mData,
  71. BitReverser4.mData,
  72. BitReverser5.mData,
  73. BitReverser6.mData,
  74. BitReverser7.mData,
  75. BitReverser8.mData,
  76. BitReverser9.mData,
  77. BitReverser10.mData
  78. };
  79. } // namespace
  80. void complex_fft(const al::span<std::complex<double>> buffer, const double sign)
  81. {
  82. const size_t fftsize{buffer.size()};
  83. /* Get the number of bits used for indexing. Simplifies bit-reversal and
  84. * the main loop count.
  85. */
  86. const size_t log2_size{static_cast<size_t>(al::countr_zero(fftsize))};
  87. if(unlikely(log2_size >= al::size(gBitReverses)))
  88. {
  89. for(size_t idx{1u};idx < fftsize-1;++idx)
  90. {
  91. size_t revidx{0u}, imask{idx};
  92. for(size_t i{0};i < log2_size;++i)
  93. {
  94. revidx = (revidx<<1) | (imask&1);
  95. imask >>= 1;
  96. }
  97. if(idx < revidx)
  98. std::swap(buffer[idx], buffer[revidx]);
  99. }
  100. }
  101. else for(auto &rev : gBitReverses[log2_size])
  102. std::swap(buffer[rev.first], buffer[rev.second]);
  103. /* Iterative form of Danielson-Lanczos lemma */
  104. const double pi{al::numbers::pi * sign};
  105. size_t step2{1u};
  106. for(size_t i{0};i < log2_size;++i)
  107. {
  108. const double arg{pi / static_cast<double>(step2)};
  109. /* TODO: Would std::polar(1.0, arg) be any better? */
  110. const std::complex<double> w{std::cos(arg), std::sin(arg)};
  111. std::complex<double> u{1.0, 0.0};
  112. const size_t step{step2 << 1};
  113. for(size_t j{0};j < step2;j++)
  114. {
  115. for(size_t k{j};k < fftsize;k+=step)
  116. {
  117. std::complex<double> temp{buffer[k+step2] * u};
  118. buffer[k+step2] = buffer[k] - temp;
  119. buffer[k] += temp;
  120. }
  121. u *= w;
  122. }
  123. step2 <<= 1;
  124. }
  125. }
  126. void complex_hilbert(const al::span<std::complex<double>> buffer)
  127. {
  128. inverse_fft(buffer);
  129. const double inverse_size = 1.0/static_cast<double>(buffer.size());
  130. auto bufiter = buffer.begin();
  131. const auto halfiter = bufiter + (buffer.size()>>1);
  132. *bufiter *= inverse_size; ++bufiter;
  133. bufiter = std::transform(bufiter, halfiter, bufiter,
  134. [inverse_size](const std::complex<double> &c) -> std::complex<double>
  135. { return c * (2.0*inverse_size); });
  136. *bufiter *= inverse_size; ++bufiter;
  137. std::fill(bufiter, buffer.end(), std::complex<double>{});
  138. forward_fft(buffer);
  139. }