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.

135 lines
3.2KB

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