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.

83 lines
3.4KB

  1. #include "FFTProvider.hpp"
  2. FFTProvider::FFTProvider() : _inputBuffer(new float[FFT_SIZE]),
  3. _fftBuffer(new float[FFT_SIZE]),
  4. _outputs(new float[NUM_OUTPUTS]),
  5. _fft(FFT_ORDER),
  6. _isStereo(false),
  7. _binWidth(0) {
  8. juce::FloatVectorOperations::fill(_inputBuffer, 0, FFT_SIZE);
  9. juce::FloatVectorOperations::fill(_fftBuffer, 0, FFT_SIZE);
  10. juce::FloatVectorOperations::fill(_outputs, 0, NUM_OUTPUTS);
  11. for (auto& env : _envs) {
  12. env.setAttackTimeMs(0.1);
  13. env.setReleaseTimeMs(0.5);
  14. env.setFilterEnabled(false);
  15. }
  16. }
  17. FFTProvider::~FFTProvider() {
  18. WECore::AudioSpinLock lock(_fftMutex);
  19. delete[] _inputBuffer;
  20. delete[] _fftBuffer;
  21. delete[] _outputs;
  22. }
  23. void FFTProvider::setSampleRate(double sampleRate) {
  24. _binWidth = (sampleRate / 2) / NUM_OUTPUTS;
  25. for (auto& env : _envs) {
  26. env.setSampleRate(sampleRate);
  27. }
  28. }
  29. void FFTProvider::reset() {
  30. for (auto& env : _envs) {
  31. env.reset();
  32. }
  33. }
  34. void FFTProvider::processBlock(juce::AudioBuffer<float>& buffer) {
  35. WECore::AudioSpinTryLock lock(_fftMutex);
  36. if (lock.isLocked()) {
  37. const size_t numBuffersRequired {static_cast<size_t>(
  38. std::ceil(static_cast<double>(buffer.getNumSamples()) / FFT_SIZE)
  39. )};
  40. for (size_t bufferNumber {0}; bufferNumber < numBuffersRequired; bufferNumber++) {
  41. // Calculate how many samples need to be processed in this chunk
  42. const size_t numSamplesRemaining {buffer.getNumSamples() - (bufferNumber * FFT_SIZE)};
  43. const size_t numSamplesToCopy {
  44. std::min(numSamplesRemaining, static_cast<size_t>(FFT_SIZE))
  45. };
  46. // The input buffer size might be smaller than the FFT buffer size, so then we need to
  47. // append the the existing FFT buffer by shifting it back and adding the new samples to
  48. // the end
  49. juce::FloatVectorOperations::copy(_inputBuffer, _inputBuffer + numSamplesToCopy, FFT_SIZE - numSamplesToCopy);
  50. float* const fillStart {_inputBuffer + FFT_SIZE - numSamplesToCopy};
  51. if (_isStereo) {
  52. // Add the left and right buffers
  53. const float* const leftBufferInputStart {buffer.getReadPointer(0) + bufferNumber * FFT_SIZE};
  54. const float* const rightBufferInputStart {buffer.getReadPointer(1) + bufferNumber * FFT_SIZE};
  55. juce::FloatVectorOperations::add(fillStart, leftBufferInputStart, rightBufferInputStart, numSamplesToCopy);
  56. juce::FloatVectorOperations::multiply(fillStart, 0.5, numSamplesToCopy);
  57. } else {
  58. const float* const bufferInputStart {buffer.getReadPointer(0) + bufferNumber * FFT_SIZE};
  59. juce::FloatVectorOperations::copy(fillStart, bufferInputStart, numSamplesToCopy);
  60. }
  61. // Perform the FFT
  62. juce::FloatVectorOperations::copy(_fftBuffer, _inputBuffer, FFT_SIZE);
  63. _fft.performFrequencyOnlyForwardTransform(_fftBuffer);
  64. // Run each FFT output bin through an envelope follower so that it is smoothed when
  65. // displayed on the UI
  66. for (int index {0}; index < NUM_OUTPUTS; index++) {
  67. _outputs[index] = _envs[index].getNextOutput(_fftBuffer[index]);
  68. }
  69. }
  70. }
  71. }