diff --git a/modules/juce_dsp/frequency/juce_FFT.cpp b/modules/juce_dsp/frequency/juce_FFT.cpp index c6dd10d657..862cfcd05c 100644 --- a/modules/juce_dsp/frequency/juce_FFT.cpp +++ b/modules/juce_dsp/frequency/juce_FFT.cpp @@ -969,10 +969,10 @@ void FFT::perform (const Complex* input, Complex* output, bool inv engine->perform (input, output, inverse); } -void FFT::performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNeagtiveFreqs) const noexcept +void FFT::performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept { if (engine != nullptr) - engine->performRealOnlyForwardTransform (inputOutputData, ignoreNeagtiveFreqs); + engine->performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs); } void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcept @@ -981,18 +981,20 @@ void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcep engine->performRealOnlyInverseTransform (inputOutputData); } -void FFT::performFrequencyOnlyForwardTransform (float* inputOutputData) const noexcept +void FFT::performFrequencyOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept { if (size == 1) return; - performRealOnlyForwardTransform (inputOutputData); + performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs); auto* out = reinterpret_cast*> (inputOutputData); - for (int i = 0; i < size; ++i) + const auto limit = ignoreNegativeFreqs ? (size / 2) + 1 : size; + + for (int i = 0; i < limit; ++i) inputOutputData[i] = std::abs (out[i]); - zeromem (&inputOutputData[size], static_cast (size) * sizeof (float)); + zeromem (inputOutputData + limit, static_cast (size * 2 - limit) * sizeof (float)); } } // namespace dsp diff --git a/modules/juce_dsp/frequency/juce_FFT.h b/modules/juce_dsp/frequency/juce_FFT.h index f746e6fb1e..5943252254 100644 --- a/modules/juce_dsp/frequency/juce_FFT.h +++ b/modules/juce_dsp/frequency/juce_FFT.h @@ -70,22 +70,22 @@ public: As the coefficients of the negative frequencies (frequencies higher than N/2 or pi) are the complex conjugate of their positive counterparts, it may not be necessary to calculate them for your particular application. - You can use dontCalculateNegativeFrequencies to let the FFT + You can use onlyCalculateNonNegativeFrequencies to let the FFT engine know that you do not plan on using them. Note that this is only a hint: some FFT engines (currently only the Fallback engine), will still - calculate the negative frequencies even if dontCalculateNegativeFrequencies + calculate the negative frequencies even if onlyCalculateNonNegativeFrequencies is true. The size of the array passed in must be 2 * getSize(), and the first half should contain your raw input sample data. On return, if - dontCalculateNegativeFrequencies is false, the array will contain size + onlyCalculateNonNegativeFrequencies is false, the array will contain size complex real + imaginary parts data interleaved. If - dontCalculateNegativeFrequencies is true, the array will contain at least + onlyCalculateNonNegativeFrequencies is true, the array will contain at least (size / 2) + 1 complex numbers. Both outputs can be passed to performRealOnlyInverseTransform() in order to convert it back to reals. */ void performRealOnlyForwardTransform (float* inputOutputData, - bool dontCalculateNegativeFrequencies = false) const noexcept; + bool onlyCalculateNonNegativeFrequencies = false) const noexcept; /** Performs a reverse operation to data created in performRealOnlyForwardTransform(). @@ -99,8 +99,13 @@ public: /** Takes an array and simply transforms it to the magnitude frequency response spectrum. This may be handy for things like frequency displays or analysis. The size of the array passed in must be 2 * getSize(). + + On return, if onlyCalculateNonNegativeFrequencies is false, the array will contain size + magnitude values. If onlyCalculateNonNegativeFrequencies is true, the array will contain + at least size / 2 + 1 magnitude values. */ - void performFrequencyOnlyForwardTransform (float* inputOutputData) const noexcept; + void performFrequencyOnlyForwardTransform (float* inputOutputData, + bool onlyCalculateNonNegativeFrequencies = false) const noexcept; /** Returns the number of data points that this FFT was created to work with. */ int getSize() const noexcept { return size; } diff --git a/modules/juce_dsp/frequency/juce_FFT_test.cpp b/modules/juce_dsp/frequency/juce_FFT_test.cpp index 1abf309d06..7242e078c1 100644 --- a/modules/juce_dsp/frequency/juce_FFT_test.cpp +++ b/modules/juce_dsp/frequency/juce_FFT_test.cpp @@ -135,7 +135,7 @@ struct FFTUnitTest : public UnitTest struct FrequencyOnlyTest { - static void run(FFTUnitTest& u) + static void run (FFTUnitTest& u) { Random random (378272); for (size_t order = 0; order <= 8; ++order) @@ -144,19 +144,23 @@ struct FFTUnitTest : public UnitTest FFT fft ((int) order); - HeapBlock inout (n << 1), reference (n << 1); - HeapBlock> frequency (n); + std::vector inout ((size_t) n << 1), reference ((size_t) n << 1); + std::vector> frequency (n); - fillRandom (random, inout.getData(), n); - zeromem (reference.getData(), sizeof (float) * ((size_t) n << 1)); - performReferenceFourier (inout.getData(), frequency.getData(), n, false); + fillRandom (random, inout.data(), n); + zeromem (reference.data(), sizeof (float) * ((size_t) n << 1)); + performReferenceFourier (inout.data(), frequency.data(), n, false); for (size_t i = 0; i < n; ++i) - reference.getData()[i] = std::abs (frequency.getData()[i]); - - fft.performFrequencyOnlyForwardTransform (inout.getData()); - - u.expect (checkArrayIsSimilar (inout.getData(), reference.getData(), n)); + reference[i] = std::abs (frequency[i]); + + for (auto ignoreNegative : { false, true }) + { + auto inoutCopy = inout; + fft.performFrequencyOnlyForwardTransform (inoutCopy.data(), ignoreNegative); + auto numMatching = ignoreNegative ? (n / 2) + 1 : n; + u.expect (checkArrayIsSimilar (inoutCopy.data(), reference.data(), numMatching)); + } } } };