5

I recently tried to implement a beat detection code found here, namely the Derivation and Combfilter algorithm #1:: http://archive.gamedev.net/reference/programming/features/beatdetection/page2.asp

Im not too sure if I implemented it successfully as I am not getting good results. I was wondering if anyone have implemented this successfully or just towards the good people who want to help in general. Here is my implementation:

//Cycle through Tempo's (60 to 200) incrementing each time by 10
for (int i = (int)mintempo; i <= maxtempo; i += 10)
{
    //Clear variables to be used
    curtempo = i;
    fftPulse.Clear();
    offset = 0;
    energy = 0;
    short[] prevBuffer = null;

    //Calculate ti
    ti = (60 / curtempo) * 44100;
    ti = Math.Round(ti, 0);

    //Generate pulse train
    for (int j = 0; j < pulseTrain.Length; j++)
    {
        if ((j % ti) == 0)
            pulseTrain[j] = short.MaxValue;
        else
            pulseTrain[j] = 0;
    }

    //Compute FFT of the pulseTrain array
    while (offset < pulseTrain.Length)
    {
        //Generate block samples (1024 is my blocksize)
        short[] fftPulseBuffer = new short[po.blocksize / 2];

        //Store samples from pulseTrain in a 1024 block buffer for passing to the FFT algorithm
        index = 0;
        for (int j = offset; j < (offset + (po.blocksize / 2)) && j < pulseTrain.Length; j++)
        {
            fftPulseBuffer[index] = pulseTrain[j];
            index++;
        }

        //Initialize prevBuffer, which contains samples from the previous block, used in conjunction with the current block for the FFT
        if (prevBuffer == null)
            prevBuffer = new short[po.blocksize / 2];

        //Calculate the FFT using the current and previous blocks
        fftPulse.Add(CalculateFFT(fftPulseBuffer,prevBuffer));

        //Set prevBuffer and increment to next block start position
        prevBuffer = fftPulseBuffer;
        offset += (po.blocksize / 2);
    }

//Calculate energy
    for (int j = 0; j < intendomainarr.Count; j++)
    {
        double[] signalarr = intendomainarr[j];
        double[] pulsearr = fftPulse[j];
        for (int x = 0; x < signalarr.Length; x++)
        {
            energy += Math.Abs(signalarr[x] * pulsearr[x]);
        }
    }

    //Get current best tempo match
    if (energy > maxenergy)
    {
        chosentempo = curtempo;
        maxenergy = energy;
    }
}

The results that I am getting are always very high, usually around 190 and 200BPM, which should NOT be the case, as my .wav files have tempos only between 60-120BPM.

Note that I am using a .WAV file (44.1Khz, 16-bit, Mono), so that some of the formulas are a bit modified (i.e. calculating the energy) to work with only one channel. I would like to confirm if there have been any discrepancies in my implementation? I am not worrying about the FFT part because I am using a library for that.

Thank you very much!

4

2 に答える 2

3

エネルギー対周波数のプロットを作成します。

高調波は基本信号とほぼ同じエネルギーを持ち、実際の周波数が周波数ビンの中間にある場合、2 番目の高調波のピークがサンプリングされ、真の周波数の両側に 2 つのサンプルを簡単に打ち負かすことがわかると思います。

この影響を克服するには、より高い周波数に少しペナルティを課す必要があります。


C# は、このようなアルゴリズムをリアルタイムで実装したり、大量のバッチ処理を行ったりするのに不合理な選択ではありませんが、アルゴリズムの開発と微調整には恐ろしい選択であることに注意してください。MatLab (または無料のクローン、Octave) を使用してアルゴリズムを正しくすることをお勧めします。いくつかのテスト ケースで動作するようになったら、コードを C# (または C++) に変換します。

于 2011-07-03T13:53:21.583 に答える
0

これが必要かどうかはよくわかりませんが、このブロックではコメントがコードに適合しません。

    //Generate block samples (1024 is my blocksize)
    short[] fftPulseBuffer = new short[po.blocksize / 2];

    //Store samples from pulseTrain in a 1024 block buffer for passing to the FFT algorithm
    index = 0;
    for (int j = offset; j < (offset + (po.blocksize / 2)) && j < pulseTrain.Length; j++)
    {
        fftPulseBuffer[index] = pulseTrain[j];
        index++;
    }

最初のコメントのサイズが 512 であるため、コード fftPulseBuffer によると、1024 と表示されます。

于 2011-07-03T14:05:07.617 に答える