2011-07-03 9 views
5

recientemente he tratado de poner en práctica un código de detección de latidos encontrar aquí, a saber, la derivación y el algoritmo de filtro de peine # 1 :: http://archive.gamedev.net/reference/programming/features/beatdetection/page2.asp¿Ayuda con la implementación de este algoritmo de detección de tiempos?

No estoy muy seguro de si he implementado con éxito, ya que no estoy consiguiendo buenos resultados. Me preguntaba si alguien lo ha implementado con éxito o solo para las buenas personas que quieren ayudar en general. Aquí está mi aplicación:

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

Los resultados que estoy obteniendo son siempre muy alta, por lo general alrededor de 190 a 200bpm, que no debe ser el caso, ya que mis archivos .wav tienen tempos sólo entre 60-120BPM.

Tenga en cuenta que estoy usando un archivo .WAV (44.1Khz, 16-bit, Mono), por lo que algunas de las fórmulas están un poco modificadas (es decir, calculando la energía) para trabajar con un solo canal. Me gustaría confirmar si ha habido alguna discrepancia en mi implementación. No me preocupa la parte de FFT porque estoy usando una biblioteca para eso.

Muchas gracias!

Respuesta

3

Haz un gráfico de la energía frente a la frecuencia.

Creo que encontrará que los armónicos tienen energía casi idéntica a la señal base, y si la frecuencia real cae a mitad de camino entre los bucles de frecuencia, se muestrea el pico del segundo armónico y supera fácilmente las dos muestras a cada lado la verdadera frecuencia

Deberá penalizar un poco las frecuencias más altas para superar este efecto.


Tenga en cuenta, mientras que C# no es una opción razonable para la implementación de un algoritmo en tiempo real o para el procesamiento por lotes a granel, es horrible para el desarrollo de algoritmos y ajustes. Recomiendo usar MatLab (o el clon gratuito, Octave) para obtener el algoritmo correcto, y solo una vez que esté funcionando en algunos casos de prueba, conviértalo en C# (o C++).

0

No estoy muy seguro de si esto es deseado, pero en este bloque los comentarios no se ajustan al código:

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

acuerdo con el código fftPulseBuffer debido primer comentario tiene un tamaño de 512, y luego dice 1024

+0

Vaya, sí, lo siento, fue solo un error en el comentario. El tamaño es realmente 512. Pero intentaré experimentar en esa parte. – dspboy

Cuestiones relacionadas