2013-02-04 46 views
1

我試圖找到帶有加速框架的倒譜分析峯值。我總是在幀的末尾或幀的開始處得到峯值。我正在分析它從麥克風實時獲取音頻。我的代碼有什麼問題?我的代碼如下:加速框架倒譜峯發現

OSStatus microphoneInputCallback (void       *inRefCon, 
           AudioUnitRenderActionFlags *ioActionFlags, 
           const AudioTimeStamp   *inTimeStamp, 
           UInt32      inBusNumber, 
           UInt32      inNumberFrames, 
           AudioBufferList    *ioData){ 

// get reference of test app we need for test app attributes 
TestApp *this = (TestApp *)inRefCon; 
COMPLEX_SPLIT complexArray = this->fftA; 
void *dataBuffer = this->dataBuffer; 
float *outputBuffer = this->outputBuffer; 
FFTSetup fftSetup = this->fftSetup; 

uint32_t log2n = this->fftLog2n; 
uint32_t n = this->fftN; // 4096 
uint32_t nOver2 = this->fftNOver2; 
uint32_t stride = 1; 
int bufferCapacity = this->fftBufferCapacity; // 4096 
SInt16 index = this->fftIndex; 

OSStatus renderErr; 

// observation objects 
float *observerBufferRef = this->observerBuffer; 
int observationCountRef = this->observationCount; 

renderErr = AudioUnitRender(rioUnit, ioActionFlags, 
          inTimeStamp, bus1, inNumberFrames, this->bufferList); 
if (renderErr < 0) { 
    return renderErr; 
} 

// Fill the buffer with our sampled data. If we fill our buffer, run the 
// fft. 
int read = bufferCapacity - index; 
if (read > inNumberFrames) { 
    memcpy((SInt16 *)dataBuffer + index, this->bufferList->mBuffers[0].mData, inNumberFrames*sizeof(SInt16)); 
    this->fftIndex += inNumberFrames; 

} else { 


    // If we enter this conditional, our buffer will be filled and we should PERFORM FFT. 
    memcpy((SInt16 *)dataBuffer + index, this->bufferList->mBuffers[0].mData, read*sizeof(SInt16)); 

    // Reset the index. 
    this->fftIndex = 0; 

    /*************** FFT ***************/ 

    //multiply by window 
    vDSP_vmul((SInt16 *)dataBuffer, 1, this->window, 1, this->outputBuffer, 1, n); 

    // We want to deal with only floating point values here. 
    vDSP_vflt16((SInt16 *) dataBuffer, stride, (float *) outputBuffer, stride, bufferCapacity); 

    /** 
    Look at the real signal as an interleaved complex vector by casting it. 
    Then call the transformation function vDSP_ctoz to get a split complex 
    vector, which for a real signal, divides into an even-odd configuration. 
    */ 
    vDSP_ctoz((COMPLEX*)outputBuffer, 2, &complexArray, 1, nOver2); 

    // Carry out a Forward FFT transform. 
    vDSP_fft_zrip(fftSetup, &complexArray, stride, log2n, FFT_FORWARD); 

    vDSP_ztoc(&complexArray, 1, (COMPLEX *)outputBuffer, 2, nOver2); 


    complexArray.imagp[0] = 0.0f; 
    vDSP_zvmags(&complexArray, 1, complexArray.realp, 1, nOver2); 
    bzero(complexArray.imagp, (nOver2) * sizeof(float)); 

    // scale 
    float scale = 1.0f/(2.0f*(float)n); 
    vDSP_vsmul(complexArray.realp, 1, &scale, complexArray.realp, 1, nOver2); 

    // step 2 get log for cepstrum 
    float *logmag = malloc(sizeof(float)*nOver2); 
    for (int i=0; i < nOver2; i++) 
     logmag[i] = logf(sqrtf(complexArray.realp[i])); 


    // configure float array into acceptable input array format (interleaved) 
    vDSP_ctoz((COMPLEX*)logmag, 2, &complexArray, 1, nOver2); 

    // create cepstrum 
    vDSP_fft_zrip(fftSetup, &complexArray, stride, log2n-1, FFT_INVERSE); 




    //convert interleaved to real 
    float *displayData = malloc(sizeof(float)*n); 
    vDSP_ztoc(&complexArray, 1, (COMPLEX*)displayData, 2, nOver2); 



    float dominantFrequency = 0; 
    int currentBin = 0; 
    float dominantFrequencyAmp = 0; 

    // find peak of cepstrum 
    for (int i=0; i < nOver2; i++){ 
     //get current frequency magnitude 

     if (displayData[i] > dominantFrequencyAmp) { 
      // DLog("Bufferer filled %f", displayData[i]); 
      dominantFrequencyAmp = displayData[i]; 
      currentBin = i; 
     } 
    } 

    DLog("currentBin : %i amplitude: %f", currentBin, dominantFrequencyAmp); 

} 
return noErr; 

}

+0

當你說在開始或結束「幀,」你是什麼意思?你的意思是窗戶嗎?每個窗口只會有一個幅度測量... – iluvcapra

+0

是的,我的意思是窗口,當緩衝區達到fftsize,代碼開始fft和頻譜分析 – ryback3

+0

當你說「在最後或開始」我不明白,因爲每個窗口每個bin只能有一個float值... – iluvcapra

回答

0

我還沒有與加速框架的工作,但似乎採取適當的步驟來計算倒頻譜代碼。

真實聲信號的倒頻譜往往有一個非常大的直流分量,在零頻附近有一個很大的峯值[原文如此]。只需忽略倒頻譜的近DC部分,並尋找高於20 Hz頻率的峯值(超過Cepstrum_Width/20Hz的奇偶性)。

如果輸入信號包含一系列非常緊密間隔的泛音,則倒譜峯在高頻聚焦結束時也將具有較大峯值。

例如,下圖顯示了N = 128和寬度= 4096的Dirichlet核的倒譜,其譜是一系列非常緊密間隔的泛音。

Dirichlet_Kernel_N128_Width4096

您可能需要使用一個靜態的合成信號來測試和調試代碼。測試信號的一個好選擇是具有基本F和幾個泛音的精確整數倍的正弦曲線。

您的Cepstra應該看起來像下面的例子。

首先是合成信號。

下圖顯示了一個合成的穩態E2音符的倒頻譜,它使用一個典型的近似直流分量,一個82.4Hz的基波和8個整數倍的82.4Hz的諧波合成。合成正弦曲線被編程爲產生4096個樣本。

在12.36處觀察到顯着的非直流峯值。倒譜寬度爲1024(第二個FFT的輸出),因此峯值對應於1024/12.36 = 82.8 Hz,非常接近真實基頻82.4 Hz。

Cepstrum of synthetic E2 note

現在真正的聲音信號。

下圖顯示了一個真正的木吉他的E2音符的倒譜。信號在第一次FFT之前未被窗口化。觀察542.9處顯着的非直流峯值。倒譜寬度爲32768(第二個FFT的輸出),因此峯值對應於32768/542.9 = 60.4 Hz,與真實基頻的82.4 Hz相差很遠。

Cepstrum of acoustic guitar E2 note, not windowed

下圖顯示了同一個真實的原聲吉他的E2音符的倒譜,但在此之前的第一FFT此時的信號是漢寧窗。觀察突出的非直流峯值268.46。倒譜寬度爲32768(第二個FFT的輸出),因此峯值對應於32768/268.46 = 122.1 Hz,甚至遠離真實基頻82.4 Hz。

Cepstrum of acoustic guitar E2 note, Hann windowed

木吉他的用於該分析E2注,44.1 kHz的工作室條件下以高品質麥克風進行取樣,它實質上包含零的背景噪音,沒有其他的樂器演奏,也沒有後期處理。

參考文獻:

真實音頻信號數據,合成信號生成,情節,FFT,並倒譜分析在這裏完成:Musical instrument cepstrum

+0

巴布森感謝您的非常詳細的答案,它幫助了我很多。在fir st plot中,您在bin 1024處有一個峯值。此時的相應值是多少?例如,您的採樣率爲44100.每個容器需要1/44100。那麼1024 *(1/44100)給出倒譜bin的時間值?是真的嗎? – ryback3

+0

信號事件發生的時間無法從Spectrum或Cepstrum數據中確定。如果需要解決與頻率有關的信號事件的時間,則必須計算信號的頻譜圖,並且必須爲用於計算頻譜圖的短時FFT選擇合適的窗口大小。一個精心構造和適當調諧的頻譜圖將允許您解決您感興趣的時間事件,因爲它們與頻率有關。 – Babson