2

加速フレームワークでケプストラム分析のピーク値を見つけようとしています。フレームの最後または最初に常にピーク値を取得します。マイクから音声をリアルタイムで取得して分析しています。この私のコードの何が問題になっていますか? 私のコードは以下です:

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;

}

4

1 に答える 1

0

Accelerate Framework を使用したことはありませんが、コードはケプストラムを計算するための適切な手順を実行しているようです。

実際の音響信号のケプストラムは、非常に大きな DC 成分を持つ傾向があり、ケフレンシーが 0 付近で大きなピークを持ちます [原文のまま]。Cepstrum の DC に近い部分を無視して、周波数が 20 Hz を超えるピーク (Cepstrum_Width/20Hz のケフレンシーを超える) を探します。

入力信号に一連の非常に狭い間隔の倍音が含まれている場合、ケプストラムもケフレンシーの高い端に大きなピークがあります。

たとえば、以下のプロットは、N=128 および幅=4096 のディリクレ カーネルのケプストラムを示しています。そのスペクトルは、一連の非常に狭い間隔の倍音です。

Dirichlet_Kernel_N128_Width4096

コードをテストおよびデバッグするために、静的合成シグナルを使用することができます。テスト信号として適切な選択は、基本 F と、F の正確な整数倍の複数の倍音を持つ任意の正弦波です。

Cepstra は次の例のようになります。

まず合成信号。

以下のプロットは、典型的な近 DC コンポーネント、82.4 Hz の基本波、および 82.4 Hz の整数倍の 8 つの高調波を使用して合成された合成定常状態 E2 ノートのケプストラムを示しています。合成正弦波は、4096 サンプルを生成するようにプログラムされました。

12.36 で顕著な非 DC ピークを観察します。ケプストラム幅は 1024 (2 番目の FFT の出力) であるため、ピークは 1024/12.36 = 82.8 Hz に対応し、これは真の基本周波数である 82.4 Hz に非常に近い値です。

合成 E2 ノートのケプストラム

これで、実際の音響信号が得られました。

以下のプロットは、実際のアコースティック ギターの E2 ノートのケプストラムを示しています。信号は、最初の FFT の前にウィンドウ処理されませんでした。542.9 で顕著な非 DC ピークを観察します。ケプストラム幅は 32768 (2 番目の FFT の出力) であるため、ピークは 32768/542.9 = 60.4 Hz に対応し、これは真の基本周波数である 82.4 Hz からかなり離れています。

アコースティック ギターの E2 ノートのケプストラム、窓なし

以下のプロットは、同じ本物のアコースティック ギターの E2 ノートのケプストラムを示していますが、今回の信号は最初の FFT の前にハン ウィンドウ処理されています。268.46 で顕著な非 DC ピークを観察します。ケプストラム幅は 32768 (2 番目の FFT の出力) であるため、ピークは 32768/268.46 = 122.1 Hz に対応し、これは真の基本周波数である 82.4 Hz からさらに離れています。

アコースティック ギター E2 ノートのケプストラム、ハン ウィンドウ

この分析に使用されたアコースティック ギターの E2 ノートは、スタジオ条件下で高品質のマイクを使用して 44.1 KHz でサンプリングされました。バックグラウンド ノイズは基本的にゼロで、他の楽器や声は含まれておらず、後処理もありません。

参考文献:

実際のオーディオ信号データ、合成信号生成、プロット、FFT、およびケプストラム分析は、ここで行われました:楽器のケプストラム

于 2013-02-15T08:33:51.930 に答える