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.

139 lines
3.3KB

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