2013-03-22 2 views
11

Я прочитал эти вопросы:IOS FFT Розыгрыш спектр

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

Все они описывают, как настроить FFT с рамками ускорения. С их помощью я смог настроить fft и получить базовый анализатор спектра. Прямо сейчас, я показываю все значения, которые я получил от fft. Тем не менее, я хочу показать только 10-15 или переменное число баров, пересчитывающих определенные частоты. Точно так же как измеритель уровня iTunes или WinAmp. 1. Нужно ли мне усреднять значения амплитуд из диапазона частот? Или они просто показывают вам величину для конкретной полосы частот? 2. Кроме того, мне нужно преобразовать значения величин в db? 3. Как сопоставить мои данные с определенным диапазоном. Я сопоставляю с диапазоном max db для своих битов бит? Получение максимального значения для бина приведет к максимальному отображению значений перехода.

Мой 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); 
} 

Играя музыку, я получаю значения от -96db до 0дБ. Plotting точку на:

CGPointMake(i, kMaxSpectrumHeight * (1 - frequencyArray[i]/-96.)); 

дает свой довольно округлый кривую:

plot1

Если я не конвертировать в БД можно построить путем умножения моего значения массива на 10000 и получить хорошие пики.

plot2

я делаю что-то совершенно неправильно? И как я могу показать переменное количество баров?

+0

Просто интересно: но у вас есть окончательный код, который отображает бары? У меня возникают трудности с пониманием, куда идти от ответа ниже. – kezi

ответ

8
  1. мне нужно средних значений величины из диапазона частот ли? Или они просто показывают вам величину для конкретной полосы частот?

Да, вам определенно нужно усреднять значения по диапазонам, которые вы определили. Показывать только один бит FFT - безумие.

  1. Кроме того, мне нужно преобразовать значения величин в db?

Да: дБ - шкала журнала. Не случайно человеческий слух также работает (грубо) в масштабе журнала. Поэтому значения будут выглядеть более естественными для людей, если вы берете log2() значений перед их графикой.

  1. Как сопоставить мои данные с определенным диапазоном. Я сопоставляю с диапазоном max db для своих битов бит? Получение максимального значения для бункера приведет к , что приведет к максимальному отображению значений перехода.

Я считаю, проще всего сделать (по крайней мере, концептуально), чтобы конвертировать ваши значения из любого формата в 0..1, то есть «нормализованного и масштабируется» значения с плавающей точкой. Затем оттуда вы можете конвертировать, если необходимо, что-то, что вам нужно для заговора. Например

SInt16 rawValue = fft[0]; // let's say this comes back as 12990 

float scaledValue = rawValue/32767.; // This is MAX_INT for 16-bit; 
     // dividing we get .396435438 which is much easier for most people 
     // to see conceptually as 39% of our max possible value 

float displayValue = log2(scaledValue); 

my_fft[0] = displayValue; 
Смежные вопросы