Помогите с реализацией этого алгоритма обнаружения ударов? - PullRequest
5 голосов
/ 03 июля 2011

Я недавно пытался реализовать найденный здесь код обнаружения ударов, а именно алгоритм Деривации и Combfilter # 1 :: http://archive.gamedev.net/reference/programming/features/beatdetection/page2.asp

Я не слишком уверен, успешно ли я его реализовал, так как не получаю хороших результатов,Мне было интересно, если кто-нибудь реализовал это успешно или просто к хорошим людям, которые хотят помочь в целом.Вот моя реализация:

//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;
    }
}

Результаты, которые я получаю, всегда очень высоки, обычно около 190 и 200 ударов в минуту, что НЕ должно иметь место, поскольку мои файлы .wav имеют темпы только между 60-120 ударов в минуту..

Обратите внимание, что я использую файл .WAV (44,1 кГц, 16-битный, моно), поэтому некоторые формулы немного изменены (т. Е. Вычислены значения энергии) для работы только с одним каналом.Я хотел бы подтвердить, были ли какие-либо расхождения в моей реализации?Я не беспокоюсь о части FFT, потому что я использую библиотеку для этого.

Большое спасибо!

Ответы [ 2 ]

3 голосов
/ 03 июля 2011

Составьте график зависимости энергии от частоты.

Я думаю, вы обнаружите, что гармоники имеют почти идентичную энергию с базовым сигналом, и если фактическая частота падает на полпути между частотными бинами, то пик второй гармоники дискретизируется и легко бьет две выборки по обе стороны истинная частота.

Вам нужно будет немного оштрафовать высокие частоты, чтобы преодолеть этот эффект.


Обратите внимание, что хотя C # не является необоснованным выбором для реализации такого алгоритма в режиме реального времени или для массовой пакетной обработки, он ужасен для разработки и настройки алгоритма. Я бы порекомендовал использовать MatLab (или бесплатный клон, Octave), чтобы получить правильный алгоритм, и только после того, как он заработает на некоторых тестовых примерах, преобразуйте код в C # (или C ++).

0 голосов
/ 03 июля 2011

Я не совсем уверен, требуется ли это, но в этом блоке комментарии не соответствуют коду:

    //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++;
    }

Согласно коду fftPulseBuffer, поскольку первый комментарий имеет размер 512, а затем он говорит1024.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...