使用wav文件和openal在iPhone上进行节拍检测

时间:2010-06-06 05:16:03

标签: iphone objective-c audio-processing

使用这个网站,我试图制作节拍检测引擎。 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和alDatar是(短*)类型;

myDat是NSdata,用于保存格式化为的wav文件的实际音频数据 22050 khz和16位立体声。

这似乎无法正常工作。如果有人能帮助我,这将是惊人的。我已经坚持了3天。

期望的结果是在处理了10秒的数据之后我应该能够将其乘以6并且每分钟有一个估计的节拍。

我目前的成绩是每10秒389次,2334 BPM,我知道的歌曲大约是120 BPM。

1 个答案:

答案 0 :(得分:7)

这个代码真的被丑陋的棍子打乱了。如果您要让其他人为您找到您的错误,那么首先让事物成为现实是个好主意。奇怪的是,这通常会帮助你自己找到它们。

所以,在我指出一些更基本的错误之前,我必须提出一些学术建议:

  1. 请勿使用magic numbers撒上代码。键入const ALuint SAMPLE_RATE = 22050之类的几行真的很难吗?相信我,它使生活更容易

  2. 使用您不会轻易混淆的变量名称。您的一个错误是将alDatal替换为alDatar。如果他们被称为leftright,那可能不会发生。同样地,如果你只是将它与无意义但又或多或少相同的energy一起使用,那么拥有一个有意义的变量名称如aEnergy的重点是什么?为什么不像average那样提供信息?

  3. 声明变量靠近您要使用它们的位置并在适当的范围内。另一个缺点是,当您移动平均窗口时,您不会重置计算的能量总和,因此能量只会累加起来。但是你不需要那个循环之外的能量,如果你在里面声明它就不会发生问题。

  4. 我个人觉得还有其他一些令人讨厌的东西,比如随机支撑和缩进,C和C ++分配的混合,以及匈牙利语前缀的奇怪不一致的碎片,但至少其中一些可能更像是一个问题味道所以我不会继续。

    无论如何,以下是您的代码不起作用的一些原因:

    首先,看看这一行的右侧:

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

    你想要每个频道值的平方,所以它应该说:

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

    发现差异?这些名字不容易,是吗?

    其次,您应该计算每个样本窗口的总能量,但是您只在外部循环外设置energy = 0。因此总和累积,因此当前窗口能量总是是您遇到过的最大值。

    第三,你的方差计算是错误的。你有:

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

    但它应该是与平均值的差异的正方形的总和:

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

    也可能存在其他错误。例如,如果数据缓冲区不是NULL,则不分配数据缓冲区,但假设它们是正确的长度 - 您只是刚刚计算过的。你可以在整个代码中坚持使用一些一致的用法来证明这一点,但从我们在这里看到的看来,它看起来是一个非常糟糕的主意。