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.

142 lines
3.5KB

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