EZAudio icon indicating copy to clipboard operation
EZAudio copied to clipboard

More precise frequency from FFT with EZAudio?

Open audiokit16 opened this issue 7 years ago • 2 comments

I've generated a few pure sine tones with Audacity at different frequencies to test with. The issue I'm seeing is that the code is returning the same frequency for two different sine tones that are relatively close in value.

For example: A sine tone generated at 19255Hz will show up from FFT as 19293.750000Hz. So will a sine tone generated at 19330Hz. Something must be off in the calculations.

Any assistance in how I can modify the above code to get a more precise FFT frequency reading for pure sine tones is greatly appreciated. Thank you!

// // Initialize FFT // float maximumBufferSizeBytes = self.maximumBufferSize * sizeof(float); self.info = (EZAudioFFTInfo *)calloc(1, sizeof(EZAudioFFTInfo)); vDSP_Length log2n = log2f(self.maximumBufferSize); self.info->fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2); long nOver2 = maximumBufferSizeBytes / 2; size_t maximumSizePerComponentBytes = nOver2 * sizeof(float); self.info->complexA.realp = (float *)malloc(maximumSizePerComponentBytes); self.info->complexA.imagp = (float *)malloc(maximumSizePerComponentBytes); self.info->outFFTData = (float *)malloc(maximumSizePerComponentBytes); memset(self.info->outFFTData, 0, maximumSizePerComponentBytes); self.info->inversedFFTData = (float *)malloc(maximumSizePerComponentBytes);

// // Calculate real + imaginary components and normalize // vDSP_Length log2n = log2f(bufferSize); long nOver2 = bufferSize / 2; float mFFTNormFactor = 10.0 / (2 * bufferSize); vDSP_ctoz((COMPLEX*)buffer, 2, &(self.info->complexA), 1, nOver2); vDSP_fft_zrip(self.info->fftSetup, &(self.info->complexA), 1, log2n, FFT_FORWARD); vDSP_vsmul(self.info->complexA.realp, 1, &mFFTNormFactor, self.info->complexA.realp, 1, nOver2); vDSP_vsmul(self.info->complexA.imagp, 1, &mFFTNormFactor, self.info->complexA.imagp, 1, nOver2); vDSP_zvmags(&(self.info->complexA), 1, self.info->outFFTData, 1, nOver2); vDSP_fft_zrip(self.info->fftSetup, &(self.info->complexA), 1, log2n, FFT_INVERSE); vDSP_ztoc(&(self.info->complexA), 1, (COMPLEX *) self.info->inversedFFTData , 2, nOver2); self.info->outFFTDataLength = nOver2;

// // Calculate max freq // if (self.sampleRate > 0.0f) { vDSP_maxvi(self.info->outFFTData, 1, &self.info->maxFrequencyMangitude, &self.info->maxFrequencyIndex, nOver2); self.info->maxFrequency = [self frequencyAtIndex:self.info->maxFrequencyIndex];

float nyquistMaxFreq = self.sampleRate / 2.0;
NSLog(@"FREQ: %f", (((float)self.info->maxFrequencyIndex / (float)self.info->outFFTDataLength) * nyquistMaxFreq));

} EZAudio code here: https://github.com/syedhali/EZAudio/blob/master/EZAudio/EZAudioFFT.m

audiokit16 avatar Jan 03 '18 20:01 audiokit16

Any suggestions for this question? I'm interested too on this topic 🤓

heyaibek avatar Jan 21 '20 21:01 heyaibek

I would guess that this issue is a result of the use of FFT. It quantizes the frequencies into bins (log2n is effectively the number of bins in the example). If you need more frequency resolution, you can try weighing the bins around the loudest bin according to their energies or use another algorithm.

JanX2 avatar Jan 27 '20 16:01 JanX2