簡體   English   中英

從iPhone上的音頻流中獲取Hz頻率

[英]Get Hz frequency from audio stream on iPhone

在iOS上從音頻流(音樂)獲取Hz頻率值的最佳方法是什么? Apple提供了哪些最好,最簡單的框架。 提前致謝。

以下是我使用Accelerate Framework在iOS中執行FFT的一些代碼,這使得它非常快。

//keep all internal stuff inside this struct
    typedef struct FFTHelperRef {
        FFTSetup fftSetup; // Accelerate opaque type that contains setup information for a given FFT transform.
        COMPLEX_SPLIT complexA; // Accelerate type for complex number
        Float32 *outFFTData; // Your fft output data
        Float32 *invertedCheckData; // This thing is to verify correctness of output. Compare it with input.
    } FFTHelperRef;

//首先 - 使用此函數初始化您的FFTHelperRef。

FFTHelperRef * FFTHelperCreate(long numberOfSamples) {

    FFTHelperRef *helperRef = (FFTHelperRef*) malloc(sizeof(FFTHelperRef));
    vDSP_Length log2n = log2f(numberOfSamples);    
    helperRef->fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2);
    int nOver2 = numberOfSamples/2;
    helperRef->complexA.realp = (Float32*) malloc(nOver2*sizeof(Float32) );
    helperRef->complexA.imagp = (Float32*) malloc(nOver2*sizeof(Float32) );

    helperRef->outFFTData = (Float32 *) malloc(nOver2*sizeof(Float32) );
    memset(helperRef->outFFTData, 0, nOver2*sizeof(Float32) );

    helperRef->invertedCheckData = (Float32*) malloc(numberOfSamples*sizeof(Float32) );

    return  helperRef;
}

//在這里傳遞初始化的FFTHelperRef,數據和數據大小。 返回numSamples / 2大小的FFT數據。

Float32 * computeFFT(FFTHelperRef *fftHelperRef, Float32 *timeDomainData, long numSamples) {
    vDSP_Length log2n = log2f(numSamples);
    Float32 mFFTNormFactor = 1.0/(2*numSamples);

    //Convert float array of reals samples to COMPLEX_SPLIT array A
    vDSP_ctoz((COMPLEX*)timeDomainData, 2, &(fftHelperRef->complexA), 1, numSamples/2);

    //Perform FFT using fftSetup and A
    //Results are returned in A
    vDSP_fft_zrip(fftHelperRef->fftSetup, &(fftHelperRef->complexA), 1, log2n, FFT_FORWARD);

    //scale fft 
    vDSP_vsmul(fftHelperRef->complexA.realp, 1, &mFFTNormFactor, fftHelperRef->complexA.realp, 1, numSamples/2);
    vDSP_vsmul(fftHelperRef->complexA.imagp, 1, &mFFTNormFactor, fftHelperRef->complexA.imagp, 1, numSamples/2);

    vDSP_zvmags(&(fftHelperRef->complexA), 1, fftHelperRef->outFFTData, 1, numSamples/2);

    //to check everything =============================
    vDSP_fft_zrip(fftHelperRef->fftSetup, &(fftHelperRef->complexA), 1, log2n, FFT_INVERSE);
    vDSP_ztoc( &(fftHelperRef->complexA), 1, (COMPLEX *) fftHelperRef->invertedCheckData , 2, numSamples/2);
    //=================================================    

    return fftHelperRef->outFFTData;
}

像這樣使用它:

  1. 初始化它: FFTHelperCreate(TimeDomainDataLenght);

  2. 傳遞Float32時域數據,返回時得到頻域數據: Float32 * fftData = computeFFT(fftHelper,buffer,frameSize);

現在你有一個數組,其中索引=頻率,值=幅度(平方幅度?)。 根據奈奎斯特定理 ,該陣列中的最大可能頻率是采樣率的一半。 也就是說,如果您的采樣率= 44100,您可以編碼的最大頻率為22050 Hz。

因此,請找出您的采樣率的奈奎斯特最大頻率: const Float32 NyquistMaxFreq = SAMPLE_RATE / 2.0;

查找Hz很簡單: Float32 hz =((Float32)someIndex /(Float32)fftDataSize)* NyquistMaxFreq; (fftDataSize = frameSize / 2.0)

這適合我。 如果我在Audacity中生成特定頻率並播放它 - 此代碼檢測到正確的頻率(最強的一個,您還需要在fftData中找到max來執行此操作)。

(在1-2%左右仍然存在一些不匹配。不知道為什么會發生這種情況。如果有人能解釋我為什么 - 那將非常感激。)

編輯:

這種不匹配的發生是因為我用於FFT的碎片太小了。 使用更大的時域數據塊(16384幀)解決了這個問題。 這個問題解釋了: 無法在iPhone上獲得正確的頻率值

編輯:這是示例項目: https//github.com/krafter/DetectingAudioFrequency

這樣的問題在這里有很多問題。 (我在這里回答了類似的問題 )所以我寫了一個代碼的小教程,即使在商業和閉源應用程序中也可以使用。 這不一定是最好的方式,但它是許多人理解的方式。 您必須根據“每個短音樂片段的Hz平均值”的含義對其進行修改。 你的意思是基本音高或頻率質心。

您可能希望在另一個答案建議的加速框架中使用Apple的FFT。

希望能幫助到你。

http://blog.bjornroche.com/2012/07/frequency-detection-using-fft-aka-pitch.html

Apple沒有提供頻率或音高估算的框架。 但是,iOS Accelerate框架確實包含用於FFT和自相關的例程,這些例程可用作更復雜的頻率和音調識別或估計算法的組件。

除了可能在幾乎零噪聲中的單個長連續恆定頻率純正弦音調之外,沒有辦法既簡單又好,其中長窗口FFT的內插幅度峰值可能是合適的。 對於語音和音樂,這種簡單的方法通常根本不起作用。 但是搜索音高檢測或估算方法將會出現大量關於更合適的算法的研究論文。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM