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.

188 lines
5.3KB

  1. /* Copyright 2013-2019 Matt Tytel
  2. *
  3. * vital is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * vital is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with vital. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #pragma once
  17. #include "JuceHeader.h"
  18. namespace vital {
  19. #if INTEL_IPP
  20. #include "ipps.h"
  21. class FourierTransform {
  22. public:
  23. FourierTransform(int bits) : size_(1 << bits) {
  24. int spec_size = 0;
  25. int spec_buffer_size = 0;
  26. int buffer_size = 0;
  27. ippsFFTGetSize_R_32f(bits, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, &spec_size, &spec_buffer_size, &buffer_size);
  28. spec_ = std::make_unique<Ipp8u[]>(spec_size);
  29. spec_buffer_ = std::make_unique<Ipp8u[]>(spec_buffer_size);
  30. buffer_ = std::make_unique<Ipp8u[]>(buffer_size);
  31. ippsFFTInit_R_32f(&ipp_specs_, bits, IPP_FFT_DIV_INV_BY_N, ippAlgHintNone, spec_.get(), spec_buffer_.get());
  32. }
  33. void transformRealForward(float* data) {
  34. data[size_] = 0.0f;
  35. ippsFFTFwd_RToPerm_32f_I((Ipp32f*)data, ipp_specs_, buffer_.get());
  36. data[size_] = data[1];
  37. data[size_ + 1] = 0.0f;
  38. data[1] = 0.0f;
  39. }
  40. void transformRealInverse(float* data) {
  41. data[1] = data[size_];
  42. ippsFFTInv_PermToR_32f_I((Ipp32f*)data, ipp_specs_, buffer_.get());
  43. memset(data + size_, 0, size_ * sizeof(float));
  44. }
  45. private:
  46. int size_;
  47. IppsFFTSpec_R_32f *ipp_specs_;
  48. std::unique_ptr<Ipp8u[]> spec_;
  49. std::unique_ptr<Ipp8u[]> spec_buffer_;
  50. std::unique_ptr<Ipp8u[]> buffer_;
  51. JUCE_LEAK_DETECTOR(FourierTransform)
  52. };
  53. #elif JUCE_MODULE_AVAILABLE_juce_dsp
  54. class FourierTransform {
  55. public:
  56. FourierTransform(int bits) : fft_(bits) { }
  57. void transformRealForward(float* data) { fft_.performRealOnlyForwardTransform(data, true); }
  58. void transformRealInverse(float* data) { fft_.performRealOnlyInverseTransform(data); }
  59. private:
  60. dsp::FFT fft_;
  61. JUCE_LEAK_DETECTOR(FourierTransform)
  62. };
  63. #elif __APPLE__
  64. #define VIMAGE_H
  65. #include <Accelerate/Accelerate.h>
  66. class FourierTransform {
  67. public:
  68. FourierTransform(vDSP_Length bits) : setup_(vDSP_create_fftsetup(bits, 2)), bits_(bits), size_(1 << bits) { }
  69. ~FourierTransform() {
  70. vDSP_destroy_fftsetup(setup_);
  71. }
  72. void transformRealForward(float* data) {
  73. static const float kMult = 0.5f;
  74. data[size_] = 0.0f;
  75. DSPSplitComplex split = { data, data + 1 };
  76. vDSP_fft_zrip(setup_, &split, 2, bits_, kFFTDirection_Forward);
  77. vDSP_vsmul(data, 1, &kMult, data, 1, size_);
  78. data[size_] = data[1];
  79. data[size_ + 1] = 0.0f;
  80. data[1] = 0.0f;
  81. }
  82. void transformRealInverse(float* data) {
  83. float multiplier = 1.0f / size_;
  84. DSPSplitComplex split = { data, data + 1 };
  85. data[1] = data[size_];
  86. vDSP_fft_zrip(setup_, &split, 2, bits_, kFFTDirection_Inverse);
  87. vDSP_vsmul(data, 1, &multiplier, data, 1, size_ * 2);
  88. memset(data + size_, 0, size_ * sizeof(float));
  89. }
  90. private:
  91. FFTSetup setup_;
  92. vDSP_Length bits_;
  93. vDSP_Length size_;
  94. JUCE_LEAK_DETECTOR(FourierTransform)
  95. };
  96. #else
  97. #include "kissfft/kissfft.h"
  98. class FourierTransform {
  99. public:
  100. FourierTransform(size_t bits) : bits_(bits), size_(1 << bits), forward_(size_, false), inverse_(size_, true) {
  101. buffer_ = std::make_unique<std::complex<float>[]>(size_);
  102. }
  103. ~FourierTransform() { }
  104. void transformRealForward(float* data) {
  105. for (int i = size_ - 1; i >= 0; --i) {
  106. data[2 * i] = data[i];
  107. data[2 * i + 1] = 0.0f;
  108. }
  109. forward_.transform((std::complex<float>*)data, buffer_.get());
  110. int num_floats = size_ * 2;
  111. memcpy(data, buffer_.get(), num_floats * sizeof(float));
  112. data[size_] = data[1];
  113. data[size_ + 1] = 0.0f;
  114. data[1] = 0.0f;
  115. }
  116. void transformRealInverse(float* data) {
  117. data[0] *= 0.5f;
  118. data[1] = data[size_];
  119. inverse_.transform((std::complex<float>*)data, buffer_.get());
  120. int num_floats = size_ * 2;
  121. float multiplier = 2.0f / size_;
  122. for (int i = 0; i < size_; ++i)
  123. data[i] = buffer_[i].real() * multiplier;
  124. memset(data + size_, 0, size_ * sizeof(float));
  125. }
  126. private:
  127. size_t bits_;
  128. size_t size_;
  129. std::unique_ptr<std::complex<float>[]> buffer_;
  130. kissfft<float> forward_;
  131. kissfft<float> inverse_;
  132. JUCE_LEAK_DETECTOR(FourierTransform)
  133. };
  134. #endif
  135. template <size_t bits>
  136. class FFT {
  137. public:
  138. static FourierTransform* transform() {
  139. static FFT<bits> instance;
  140. return &instance.fourier_transform_;
  141. }
  142. private:
  143. FFT() : fourier_transform_(bits) { }
  144. FourierTransform fourier_transform_;
  145. };
  146. } // namespace vital