2013-03-22 101 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.如何將我的數據映射到特定範圍。我是否會針對最大分貝範圍映射我的聲音bitdepth?獲取箱的最大值將導致跳躍最大映射值。

我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值到0dB。

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

是給我的一個相當圓潤的曲線: 在繪製一個點

plot1

如果我不轉換爲DB我可以通過我的10000陣列值乘以繪製並獲得好的山峯。

plot2

我做得完全錯誤的?我怎樣才能顯示可變數量的酒吧?

+0

只是想知道:但是你有最終的代碼,呈現酒吧?我很難從下面的答案中知道要去哪裏。 – kezi 2014-08-14 04:30:13

回答

8
  1. 我需要平均幅度值在一定範圍的頻率?或者他們只是告訴你一個特定頻率的大小?

是的,您絕對需要在您定義的樂隊中平均值。只顯示一個FFT箱是瘋狂的。

  1. 此外,我是否需要將我的幅度值轉換爲db?

是:dB是對數刻度。並非巧合的是,人類聽覺也可以(大致)在對數尺度上起作用。因此,如果您在繪製值之前取值log2(),那麼這些值對於人類來說會更自然。

  • 如何將我的數據映射到一定範圍內。我是否會針對最大分貝範圍映射我的聲音bitdepth?獲取bin的最大值將導致跳轉最大映射值 。
  • ,我覺得這樣做(在概念上至少)是你的價值觀從任何格式轉換成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;