diff --git a/modules/juce_dsp/frequency/juce_FFT.cpp b/modules/juce_dsp/frequency/juce_FFT.cpp index 481b905373..e142badc72 100644 --- a/modules/juce_dsp/frequency/juce_FFT.cpp +++ b/modules/juce_dsp/frequency/juce_FFT.cpp @@ -30,7 +30,7 @@ struct FFT::Instance { virtual ~Instance() = default; virtual void perform (const Complex* input, Complex* output, bool inverse) const noexcept = 0; - virtual void performRealOnlyForwardTransform (float*, bool) const noexcept = 0; + virtual void performRealOnlyForwardTransform (float*) const noexcept = 0; virtual void performRealOnlyInverseTransform (float*) const noexcept = 0; }; @@ -124,7 +124,7 @@ struct FFTFallback final : public FFT::Instance const size_t maxFFTScratchSpaceToAlloca = 256 * 1024; - void performRealOnlyForwardTransform (float* d, bool) const noexcept override + void performRealOnlyForwardTransform (float* d) const noexcept override { if (size == 1) return; @@ -471,7 +471,7 @@ struct AppleFFT final : public FFT::Instance vDSP_vsmul ((float*) output, 1, &factor, (float*) output, 1, static_cast (size << 1)); } - void performRealOnlyForwardTransform (float* inoutData, bool ignoreNegativeFreqs) const noexcept override + void performRealOnlyForwardTransform (float* inoutData) const noexcept override { auto size = (1 << order); auto* inout = reinterpret_cast*> (inoutData); @@ -481,7 +481,12 @@ struct AppleFFT final : public FFT::Instance vDSP_fft_zrip (fftSetup, &splitInOut, 2, order, kFFTDirection_Forward); vDSP_vsmul (inoutData, 1, &forwardNormalisation, inoutData, 1, static_cast (size << 1)); - mirrorResult (inout, ignoreNegativeFreqs); + // Imaginary part of nyquist and DC frequencies are always zero + // so Apple uses the imaginary part of the DC frequency to store + // the real part of the nyquist frequency + auto* out = reinterpret_cast*> (inoutData); + out[size >> 1] = { out[0].imag(), 0.0 }; + out[0] = { out[0].real(), 0.0 }; } void performRealOnlyInverseTransform (float* inoutData) const noexcept override @@ -503,22 +508,6 @@ struct AppleFFT final : public FFT::Instance private: //============================================================================== - void mirrorResult (Complex* out, bool ignoreNegativeFreqs) const noexcept - { - auto size = (1 << order); - auto i = size >> 1; - - // Imaginary part of nyquist and DC frequencies are always zero - // so Apple uses the imaginary part of the DC frequency to store - // the real part of the nyquist frequency - out[i++] = { out[0].imag(), 0.0 }; - out[0] = { out[0].real(), 0.0 }; - - if (! ignoreNegativeFreqs) - for (; i < size; ++i) - out[i] = std::conj (out[size - i]); - } - static DSPSplitComplex toSplitComplex (Complex* data) noexcept { // this assumes that Complex interleaves real and imaginary parts @@ -684,7 +673,7 @@ struct FFTWImpl : public FFT::Instance } } - void performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept override + void performRealOnlyForwardTransform (float* inputOutputData) const noexcept override { if (order == 0) return; @@ -692,12 +681,6 @@ struct FFTWImpl : public FFT::Instance auto* out = reinterpret_cast*> (inputOutputData); fftw.execute_r2c_fftw (r2c, inputOutputData, out); - - auto size = (1 << order); - - if (! ignoreNegativeFreqs) - for (int i = size >> 1; i < size; ++i) - out[i] = std::conj (out[size - i]); } void performRealOnlyInverseTransform (float* inputOutputData) const noexcept override @@ -784,19 +767,12 @@ struct IntelFFT final : public FFT::Instance DftiComputeForward (c2c, (void*) input, output); } - void performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept override + void performRealOnlyForwardTransform (float* inputOutputData) const noexcept override { if (order == 0) return; DftiComputeForward (c2r, inputOutputData); - - auto* out = reinterpret_cast*> (inputOutputData); - auto size = (1 << order); - - if (! ignoreNegativeFreqs) - for (int i = size >> 1; i < size; ++i) - out[i] = std::conj (out[size - i]); } void performRealOnlyInverseTransform (float* inputOutputData) const noexcept override @@ -851,19 +827,9 @@ public: } } - void performRealOnlyForwardTransform (float* inoutData, bool ignoreNegativeFreqs) const noexcept override + void performRealOnlyForwardTransform (float* inoutData) const noexcept override { ippsFFTFwd_RToCCS_32f_I (inoutData, real.specPtr, real.workBuf.get()); - - if (order == 0) - return; - - auto* out = reinterpret_cast*> (inoutData); - const auto size = (1 << order); - - if (! ignoreNegativeFreqs) - for (auto i = size >> 1; i < size; ++i) - out[i] = std::conj (out[size - i]); } void performRealOnlyInverseTransform (float* inoutData) const noexcept override @@ -970,7 +936,19 @@ void FFT::perform (const Complex* input, Complex* output, bool inv void FFT::performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept { if (engine != nullptr) - engine->performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs); + engine->performRealOnlyForwardTransform (inputOutputData); + + if (! ignoreNegativeFreqs && size != 1) + { + // Preserve compatibility with legacy implementation + // where the redundant negative frequencies were also generated. + + auto* out = reinterpret_cast*> (inputOutputData); + + if (! ignoreNegativeFreqs) + for (auto i = size >> 1; i < size; ++i) + out[i] = std::conj (out[size - i]); + } } void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcept