3
$\begingroup$

I need some help clarifying FFTs and what they represent. I have a buffer containing compressed audio. Due to limitations, I can't handle the full uncompressed audio but can decompress small segments at a time.

Lets say I take 10 seconds of uncompressed samples, I would need to store this in PCMaudiobuffer of size 10 * 44100 * sizeof(float) and I'd have 441000 samples. I then loop through these 441000 samples with a length of 1024 (with a 512 overlap).

for(int i =0; i < 441000; i += 512)
{
   //code to copy (i + 1024) from PCMaudiobuffer to tempbuffer. (not shown)

   //perform FFT
   InPlaceFFT(tempbuffer);

   //copy the first 512 values of the tempbuffer across to 
   //a new buffer so tempbuffer can be reused in the loop
   CopyArray(512, finalbuffer);
}

Assuming all of this is correct, this is where I'm confused. Am I right in copying only the first 512 values (N/2) to the finalbuffer? (I'm using the Accelerate framework's FFT method). Is this an efficient/correct way of performing FFTs offline? Lastly, I want to be able to create a frequency spectrum from finalbuffer. To do this do I simply loop through every 44100 (1 second) and calculate the magnitude, or is 1 second generally too inaccurate for a frequency spectrum?

I may be misunderstanding all of this, so feel free to tell me to throw all this out the window :) Thanks for any help, this is quite confusing!

Edit The Apple docs on this aren't easy to follow, but I'm using the method outlined here in vDSP_fft_zrip. (The formatting of the Apple site sometimes messes up the anchor position, so you may have to scroll down slightly). I found this post to be a helpful guide on how to use it. Thanks.

$\endgroup$
2
  • $\begingroup$ Could you add some context of exactly what signal processing steps you're trying to implement? It's hard for anyone to say how you should move data in and out of your FFTs without an indication of what the overall desired effect is. With regard to your question about calculating a frequency spectrum, the FFT can be used to do that; some more specification of what you're looking for is useful. Do you want a time-frequency representation of the signal, do you want a high-resolution spectrum of the whole signal, etc. $\endgroup$
    – Jason R
    Sep 26, 2011 at 15:19
  • $\begingroup$ Hey Jason. I'd like to be able to perform onset detection offline. The detection starts off relatively simple - just check if certain frequencies are above a threshold but may get a bit more complex by using spectral flux. So, the user would provide an mp3 and, as fast as possible, my system would be able to give all the timings of when an onset occurs. Whilst I don't need to render the time-frequency representation, I think the data would need to be in that format anyway for me to be able to get the seconds at which there's an onset. $\endgroup$
    – XSL
    Sep 26, 2011 at 16:33

1 Answer 1

2
$\begingroup$

You are missing one important piece of information in your question and that is the prototype definition for the InPlaceFFT() function. The most important thing to be aware of is that the FFT returns complex valued numbers. It can be that the function expects the data to be formatted such that real and imaginary values are interleaved or it could be that the function expects the real parts to be placed first in the buffer and the imaginary part to be placed in the end of the buffer. It could also be that the function returns data bit reversed (see section "Data reordering, bit reversal, and in-place algorithms" here http://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm).

Another potential issue is the length of the buffer you pass as argument, your temp buffer. You might have to pass a buffer with a length that is at least 1024*sizeof(float) or 2048*sizeof(float), if you are sure that the InPlaceFFT() function expects a float* as input. If the InPlaceFFT() function is constrained to work on real input, a buffer size of 1024 might be sufficient. But you should take a better look at the documentation for how the InPlaceFFT() works in order to find out how large the size of you temp buffer should be and how the output is laid out in the temp buffer after it returns. Another thing that looks strange is that you don't need to pass the FFT size to InPlaceFFT().

If you are sure that the sample rate is always 44.1kHz it is fine to hardcode 44.1kHz into the code, otherwise you might want to make your code more flexible by loading the sample rate into a variable and use that in your code.

A 1024 point FFT returns 1024 values (complex). You only need the first 513 output values (these values are typically called bins), the rest are in principle redundant (although the can be handy to have). If you then want to compute the magnitude spectrum you need to compute the absolute value of the complex numbers (so your abs() function should work on complex numbers) and you are in principle done. The only thing left to do is to correct the values from index 1 to index 511 by multiplying them with 2. The values at index 0 and index 512 are real and need no correction. If you are going to plot the magnitude spectrum in a GUI you probably want to plot the magnitudes in dB. So you need to compute the log (base 10) of the magnitude values and multiply by 20.

It would be useful if you could update your post with the documentation for InPlaceFFT().

$\endgroup$
1
  • $\begingroup$ Thank you for the explanation. I guess I need the first 513 and not 512 because '0' would be the DC output. I've updated my question with details of the FFT method I'm using. $\endgroup$
    – XSL
    Sep 26, 2011 at 13:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.