I've read these question:
Using the Apple FFT and Accelerate Framework
How do I set up a buffer when doing an FFT using the Accelerate framework?
iOS FFT Accerelate.framework draw spectrum during playback
They all describe how to setup fft with the accelerate framework. With their help I was able to setup fft and get a basic spectrum analyzer. Right now, I'm displaying all values I got from the fft. However, I only want to show 10-15, or a variable number, of bars respreseting certain frequencies. Just like the iTunes or WinAmp Level Meter. 1. Do I need to average magnitude values from a range of frequencies? Or do they just show you a magnitude for the specific frequency bar? 2. Also, do I need to convert my magnitude values to db? 3. How do I map my data to a certain range. Do I map against the max db range for my sounds bitdepth? Getting the max Value for a bin will lead to jumping max mapping values.
My RenderCallback:
static OSStatus PlaybackCallback(void *inRefCon,
                                 AudioUnitRenderActionFlags *ioActionFlags,
                                 const AudioTimeStamp *inTimeStamp,
                                 UInt32 inBusNumber,
                                 UInt32 inNumberFrames,
                                 AudioBufferList *ioData)
{
    UInt32 maxSamples = kAudioBufferNumFrames;
    UInt32 log2n = log2f(maxSamples); //bins
    UInt32 n = 1 << log2n;
    UInt32 stride = 1;
    UInt32 nOver2 = n/2;
    COMPLEX_SPLIT   A;
    float          *originalReal, *obtainedReal, *frequencyArray, *window, *in_real;
    in_real = (float *) malloc(maxSamples * sizeof(float));
    A.realp = (float *) malloc(nOver2 * sizeof(float));
    A.imagp = (float *) malloc(nOver2 * sizeof(float));
    memset(A.imagp, 0, nOver2 * sizeof(float));
    obtainedReal = (float *) malloc(n * sizeof(float));
    originalReal = (float *) malloc(n * sizeof(float));
    frequencyArray = (float *) malloc(n * sizeof(float));
    //-- window
    UInt32 windowSize = maxSamples;
    window = (float *) malloc(windowSize * sizeof(float));
    memset(window, 0, windowSize * sizeof(float));
    //    vDSP_hann_window(window, windowSize, vDSP_HANN_DENORM);
    vDSP_blkman_window(window, windowSize, 0);
    vDSP_vmul(ioBuffer, 1, window, 1, in_real, 1, maxSamples);
    //-- window
    vDSP_ctoz((COMPLEX*)in_real, 2, &A, 1, maxSamples/2);
    vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_FORWARD);
    vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_INVERSE);
    float scale = (float) 1.0 / (2 * n);
    vDSP_vsmul(A.realp, 1, &scale, A.realp, 1, nOver2);
    vDSP_vsmul(A.imagp, 1, &scale, A.imagp, 1, nOver2);
    vDSP_ztoc(&A, 1, (COMPLEX *) obtainedReal, 2, nOver2);
    vDSP_zvmags(&A, 1, obtainedReal, 1, nOver2);
    Float32 one = 1;
    vDSP_vdbcon(obtainedReal, 1, &one, obtainedReal, 1, nOver2, 0);
    for (int i = 0; i < nOver2; i++) {
        frequencyArray[i] = obtainedReal[i];
    }
    // Extract the maximum value
    double fftMax = 0.0;
    vDSP_maxmgvD((double *)obtainedReal, 1, &fftMax, nOver2);
    float max = sqrt(fftMax);
}
Playing some music, I get values from -96db to 0db. Plotting a point at:
CGPointMake(i, kMaxSpectrumHeight * (1 - frequencyArray[i]/-96.));
is giving my a rather rounded curve:
If I don't convert to db I can plot by multiplying my array value by 10000 and get nice peaks.
Am I doing something totally wrong? And how do I get to showing a variable number of bars?
 
     
    