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.

138 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 `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. /** Complex-valued FFT context.
  71. `length` must be a multiple of 16.
  72. */
  73. struct ComplexFFT {
  74. PFFFT_Setup *setup;
  75. int length;
  76. ComplexFFT(size_t length) {
  77. this->length = length;
  78. setup = pffft_new_setup(length, PFFFT_COMPLEX);
  79. }
  80. ~ComplexFFT() {
  81. pffft_destroy_setup(setup);
  82. }
  83. /** Performs the complex FFT.
  84. Input and output must be aligned using the above align*() functions.
  85. Input is `2*length` elements. Output is `2*length` elements.
  86. */
  87. void fftUnordered(const float *input, float *output) {
  88. pffft_transform(setup, input, output, NULL, PFFFT_FORWARD);
  89. }
  90. /** Performs the inverse complex FFT.
  91. Input is `2*length` elements. Output is `2*length` elements.
  92. Scaling is such that FFT(IFFT(x)) = N*x.
  93. */
  94. void ifftUnordered(const float *input, float *output) {
  95. pffft_transform(setup, input, output, NULL, PFFFT_BACKWARD);
  96. }
  97. void fft(const float *input, float *output) {
  98. pffft_transform_ordered(setup, input, output, NULL, PFFFT_FORWARD);
  99. }
  100. void ifft(const float *input, float *output) {
  101. pffft_transform_ordered(setup, input, output, NULL, PFFFT_BACKWARD);
  102. }
  103. void scale(float *x) {
  104. float a = 1.f / length;
  105. for (int i = 0; i < length; i++) {
  106. x[2*i+0] *= a;
  107. x[2*i+1] *= a;
  108. }
  109. }
  110. };
  111. } // namespace dsp
  112. } // namespace rack