views:

253

answers:

1

Using this website i have tried to make a beat detection engine. http://www.gamedev.net/reference/articles/article1952.asp

{


ALfloat energy = 0;
ALfloat aEnergy = 0;
ALint beats = 0;
bool init = false;
ALfloat Ei[42];
ALfloat V = 0;
ALfloat C = 0;


ALshort *hold;
hold = new ALshort[[myDat length]/2];

[myDat getBytes:hold length:[myDat length]];

ALuint uiNumSamples;
uiNumSamples = [myDat length]/4;

if(alDatal == NULL)
    alDatal = (ALshort *) malloc(uiNumSamples*2);
if(alDatar == NULL)
    alDatar = (ALshort *) malloc(uiNumSamples*2);
for (int i = 0; i < uiNumSamples; i++)
{
    alDatal[i] = hold[i*2];
    alDatar[i] = hold[i*2+1];
}
energy = 0;
for(int start = 0; start<(22050*10); start+=512){
for(int i = start; i<(start+512); i++){
    energy+= ((alDatal[i]*alDatal[i]) + (alDatal[i]*alDatar[i]));

}
    aEnergy = 0;
for(int i = 41; i>=0; i--){

    if(i ==0){
        Ei[0] = energy;
    }
    else {
    Ei[i] = Ei[i-1];
    }
    if(start >= 21504){
    aEnergy+=Ei[i];
    }
}
    aEnergy = aEnergy/43.f;
    if (start >= 21504) {
        for(int i = 0; i<42; i++){
            V += (Ei[i]-aEnergy);
        }
        V = V/43.f;
        C = (-0.0025714*V)+1.5142857;
        init = true;
        if(energy >(C*aEnergy)) beats++;
    }

}

}

alDatal and alDatar are (short*) type;

myDat is NSdata that holds the actual audio data of a wav file formatted to 22050 khz and 16 bit stereo.

This doesn't seem to work correctly. If anyone could help me out that would be amazing. I've been stuck on this for 3 days.

The desired result is after the 10 seconds worth of data has been processed i should be able to multiply that by 6 and have an estimated beats per minute.

My current results are 389 beats every 10 seconds, 2334 BPM the song i know is right around 120 BPM.

+1  A: 

That code really has been smacked about with the ugly stick. If you're going to ask other people to find your bugs for you, it's a good idea to make things presentable first. Strangely enough, this will often help you to find them for yourself too.

So, before I point out some of the more fundamental errors, I have to make a few schoolmarmly suggestions:

  1. Don't sprinkle your code with magic numbers. Is it really that hard to type a few lines like const ALuint SAMPLE_RATE = 22050? Trust me, it makes life a lot easier.

  2. Use variable names that you aren't going to mix up easily. One of your bugs is a substitution of alDatal for alDatar. That probably wouldn't have happened if they were called left and right. Similarly, what is the point of having a meaningful variable name like energy if you're just going to stick it alongside the meaningless but more or less identical aEnergy? Why not something informative like average?

  3. Declare variables close to where you're going to use them and in the appropriate scope. Another of your bugs is that you don't reset your calculated energy sum when you move your averaging window, so the energy will just add up and up. But you don't need the energy outside that loop, and if you declared it inside the problem couldn't happen.

There are some other things I personally find a little irksome, like the random bracing and indentation, and mixing of C and C++ allocations, and odd inconsistent scraps of Hungarian prefixing, but at least some of those may be more a matter of taste so I won't go on.

Anyway, here are some reasons why your code doesn't work:

First up, look at the right hand side of this line:

energy+= ((alDatal[i]*alDatal[i]) + (alDatal[i]*alDatar[i]));

You want the square of each channel value, so it should really say:

energy+= ((alDatal[i]*alDatal[i]) + (alDatar[i]*alDatar[i]));

Spot the difference? Not easy with those names, is it?

Second, you should be computing the total energy over each window of samples, but you're only setting energy = 0 outside the outer loop. So the sum accumulates, and consequently the current window energy will always be the biggest you've ever encountered.

Third, your variance calculation is wrong. You have:

V += (Ei[i]-aEnergy);

But it should be the sum of the squares of the differences from the mean:

V += (Ei[i] - aEnergy) * (Ei[i] - aEnergy);

There may well be other errors as well. For instance, you don't allocate the data buffers if they're not NULL, but assume that they're the right length -- which you've only just calculated. You may justify that in terms of some consistent usage you've stuck to throughout your code, but from the perspective of what we can see here it looks like a pretty bad idea.

walkytalky