2013-03-22 113 views
11

私はこれらの質問を読んだ:彼らはすべてが加速するフレームワークにどのようにセットアップFFTに説明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から得たすべての値を表示しています。しかし、私は、特定の周波数をrespresetingバーの10-15、または可変数を表示したいだけです。ちょうどiTunesまたはWinAmpレベルメーターのように。 1.ある範囲の周波数から平均値を求める必要がありますか?または、特定の周波数バーの大きさを表示するだけですか? 2.マグニチュード値をdbに変換する必要がありますか? 3.データを特定の範囲にマップするにはどうすればよいですか。私は私の音のビット深度の最大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からの値が0dBのことを得ます。 でポイントをプロット:私は10000で、私の配列値を乗じてプロットし、取得することができ、DBに変換されない場合は

plot1

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

は私ではなく丸みを帯びた曲線を与えています素晴らしいピーク。

plot2

私は完全に間違って何かをやっていますか?そして、どのように変化する数のバーを表示するのですか?

+0

ちょうど不思議ですが、バーをレンダリングする最終コードはありますか?私は以下の答えからどこに行くのかを知るのが難しいです。 – kezi

答えて

8
  1. 周波数の範囲から平均値を求める必要がありますか?または、特定の周波数バーの大きさを表示するだけですか?

はい、定義したバンド間で値を平均する必要があります。 1つのFFTビンだけを表示することは狂気です。

  1. また、振幅値をdbに変換する必要がありますか?

はい:dBはログスケールです。偶然にも、人間の聴覚は大まかに対数スケールで機能します。したがって、プロットする前に値のlog2()を取ると、値は人間にとってより自然に見えます。

  1. データを特定の範囲にマップするにはどうすればよいですか。私は私の音のビット深度の最大db範囲に対してマップしますか?ビンの最大値を取得すると、 は最大のマッピング値をジャンプします。

は、私は(概念的には、少なくとも)0..1、すなわち「正規化とスケール」float値にどのような形式から自分の価値観を転換することである最も簡単な方法を見つけます。そこから必要に応じてプロットする必要があるものに変換することができます。たとえば、

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;