2011-07-03 19 views
5

Niedawno próbował zaimplementować kod wykrywania rytm znaleźć tutaj, a mianowicie Wyprowadzenie i algorytm Filtr grzebieniowy # 1 :: http://archive.gamedev.net/reference/programming/features/beatdetection/page2.aspPomoc przy implementacji tego algorytmu wykrywania rytmu?

Nie jestem zbyt pewien, czy to z powodzeniem wdrożony jak ja nie osiąga dobre wyniki. Zastanawiałem się, czy ktoś wdrożył to z powodzeniem lub tylko w stosunku do dobrych ludzi, którzy chcą pomóc w ogóle. Oto moja realizacja:

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

Wyniki że ja dostaję zawsze są bardzo wysokie, zwykle około 190 i 200BPM, co nie powinno być w przypadku, gdy moje pliki .wav mieć tempa tylko między 60-120BPM.

Zauważ, że używam pliku .WAV (44.1KHz, 16-bit, Mono), więc niektóre formuły są nieco zmodyfikowane (to znaczy obliczenie energii), aby pracować tylko z jednym kanałem. Chciałbym potwierdzić, czy wystąpiły jakieś rozbieżności w mojej implementacji? Nie martwię się o część FFT, ponieważ używam do tego biblioteki.

Dziękuję bardzo!

Odpowiedz

3

Wykonaj wykres energii względem częstotliwości.

Myślę, że okaże się, że harmoniczne mają prawie taką samą energię jak sygnał podstawowy, a jeśli rzeczywista częstotliwość spadnie w połowie między przedziałami częstotliwości, wówczas pik drugiej harmonicznej jest próbkowany i łatwo bije dwie próbki po obu stronach prawdziwa częstotliwość.

Musisz trochę ukarać wyższe częstotliwości, aby pokonać ten efekt.


Uwaga, podczas gdy C# nie jest rozsądnym wyborem dla realizacji takiego algorytmu w czasie rzeczywistym lub do zbiorczego przetwarzania wsadowego, to straszne dla rozwoju algorytmów i szczypanie. Zalecam użycie MatLab (lub darmowego klonu, Octave), aby uzyskać prawidłowy algorytm, i tylko gdy działa on w niektórych przypadkach testowych, przekonwertuj kod na C# (lub C++).

0

Nie jestem pewien, czy to jest potrzebne ale w tym bloku komentarze nie pasuje do kodu:

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

Według kodu fftPulseBuffer powodu pierwszego komentarza ma wielkość 512, a potem mówi: 1024

+0

Ups, tak, przepraszam, że był po prostu błędem w komentarzu. Rozmiar jest naprawdę 512. Ale spróbuję eksperymentować na tej części. – dspboy