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.

fft.hpp 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #pragma once
  2. #include <pffft.h>
  3. #include <dsp/common.hpp>
  4. namespace rack {
  5. namespace dsp {
  6. /** Real-valued FFT context.
  7. Wrapper for [PFFFT](https://bitbucket.org/jpommier/pffft/)
  8. `length` must be a multiple of 32.
  9. Buffers must be aligned to 16-byte boundaries. new[] and malloc() do this for you.
  10. */
  11. struct RealFFT {
  12. PFFFT_Setup* setup;
  13. int length;
  14. RealFFT(size_t length) {
  15. this->length = length;
  16. setup = pffft_new_setup(length, PFFFT_REAL);
  17. }
  18. ~RealFFT() {
  19. pffft_destroy_setup(setup);
  20. }
  21. /** Performs the real FFT.
  22. Input and output must be aligned using the above align*() functions.
  23. Input and output arrays may overlap.
  24. Input is `length` elements. Output is `2*length` elements.
  25. Output is arbitrarily ordered for performance reasons.
  26. However, this ordering is consistent, so element-wise multiplication with line up with other results, and the inverse FFT will return a correctly ordered result.
  27. */
  28. void rfftUnordered(const float* input, float* output) {
  29. pffft_transform(setup, input, output, NULL, PFFFT_FORWARD);
  30. }
  31. /** Performs the inverse real FFT.
  32. Input is `2*length` elements. Output is `length` elements.
  33. Scaling is such that IRFFT(RFFT(x)) = N*x.
  34. */
  35. void irfftUnordered(const float* input, float* output) {
  36. pffft_transform(setup, input, output, NULL, PFFFT_BACKWARD);
  37. }
  38. /** Slower than the above methods, but returns results in the "canonical" FFT order as follows.
  39. output[0] = F(0)
  40. output[1] = F(n/2)
  41. output[2] = real(F(1))
  42. output[3] = imag(F(1))
  43. output[4] = real(F(2))
  44. output[5] = imag(F(2))
  45. ...
  46. output[length - 2] = real(F(n/2 - 1))
  47. output[length - 1] = imag(F(n/2 - 1))
  48. */
  49. void rfft(const float* input, float* output) {
  50. pffft_transform_ordered(setup, input, output, NULL, PFFFT_FORWARD);
  51. }
  52. void irfft(const float* input, float* output) {
  53. pffft_transform_ordered(setup, input, output, NULL, PFFFT_BACKWARD);
  54. }
  55. /** Scales the RFFT so that `scale(IFFT(FFT(x))) = x`.
  56. */
  57. void scale(float* x) {
  58. float a = 1.f / length;
  59. for (int i = 0; i < length; i++) {
  60. x[i] *= a;
  61. }
  62. }
  63. };
  64. /** Complex-valued FFT context.
  65. `length` must be a multiple of 16.
  66. */
  67. struct ComplexFFT {
  68. PFFFT_Setup* setup;
  69. int length;
  70. ComplexFFT(size_t length) {
  71. this->length = length;
  72. setup = pffft_new_setup(length, PFFFT_COMPLEX);
  73. }
  74. ~ComplexFFT() {
  75. pffft_destroy_setup(setup);
  76. }
  77. /** Performs the complex FFT.
  78. Input and output must be aligned using the above align*() functions.
  79. Input is `2*length` elements. Output is `2*length` elements.
  80. */
  81. void fftUnordered(const float* input, float* output) {
  82. pffft_transform(setup, input, output, NULL, PFFFT_FORWARD);
  83. }
  84. /** Performs the inverse complex FFT.
  85. Input is `2*length` elements. Output is `2*length` elements.
  86. Scaling is such that FFT(IFFT(x)) = N*x.
  87. */
  88. void ifftUnordered(const float* input, float* output) {
  89. pffft_transform(setup, input, output, NULL, PFFFT_BACKWARD);
  90. }
  91. void fft(const float* input, float* output) {
  92. pffft_transform_ordered(setup, input, output, NULL, PFFFT_FORWARD);
  93. }
  94. void ifft(const float* input, float* output) {
  95. pffft_transform_ordered(setup, input, output, NULL, PFFFT_BACKWARD);
  96. }
  97. void scale(float* x) {
  98. float a = 1.f / length;
  99. for (int i = 0; i < length; i++) {
  100. x[2 * i + 0] *= a;
  101. x[2 * i + 1] *= a;
  102. }
  103. }
  104. };
  105. } // namespace dsp
  106. } // namespace rack