AppleFFT::performRealOnlyForwardTransform() nonsensical

Tried the juce supplied FFT, and the result is not what I was expecting.
Looking at AppleFFT::performRealOnlyForwardTransform() there a multiple issues:

void performRealOnlyForwardTransform (float* inoutData, bool ignoreNegativeFreqs) const noexcept override
{
	auto size = (1 << order);
	auto* inout = reinterpret_cast<Complex<float>*> (inoutData);
	auto splitInOut (toSplitComplex (inout));

	//writes behind buffer. Also unclear what this is supposed to do.
	inoutData[size] = 0.0f;	
	
	//good
	vDSP_fft_zrip (fftSetup, &splitInOut, 2, order, kFFTDirection_Forward);
	
	//with (size << 1), this scales twice as many elements as allowed
	vDSP_vsmul (inoutData, 1, &forwardNormalisation, inoutData, 1, static_cast<size_t> (size << 1)); 
	
	//this is just nonsense.
	mirrorResult (inout, ignoreNegativeFreqs);
}

Other functions of AppleFFT have similar issues.

inoutData[size] = 0.0f;

I would guess it is to make sure vDSP_vsmul always work on proper data (inoutData[size] might initialized)?

vDSP_vsmul (inoutData, 1, &forwardNormalisation, inoutData, 1, static_cast<size_t> (size << 1));

To me, multiplying size number of points would be enough.

mirrorResult (inout, ignoreNegativeFreqs);

It matches the API docs, right? And it unpacks Perm format to CCS format.

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.

Although, I have never found the conjugate part useful :slight_smile: Therefore I always passed the flag as true (when I used juce::dsp::FFTbefore).

Keep in mind that the input buffer is supposed to have length size * 2 so it doesn’t write behind the buffer.

1 Like