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

Dma*_*pro 2 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++;
    }

}

}
Run Code Online (Sandbox Code Playgroud)

alDatal和alDatar是(短*)类型;

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

这似乎不正常.如果有人能帮助我,这将是惊人的.我被困在这3天了.

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

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

wal*_*lky 7

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

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

  1. 不要用魔术数字洒你的代码.键入几行是不是很难const ALuint SAMPLE_RATE = 22050?相信我,它使生活了很多容易.

  2. 使用您不会轻易混淆的变量名称.你的一个错误是一个替代alDatalalDatar.如果他们被召唤left,那可能不会发生right.同样,有一个有意义的变量名称的意义是什么,energy如果你只是将它与无意义的一起但又或多或少相同aEnergy?为什么不提供信息丰富的内容average

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

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

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

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

energy+= ((alDatal[i]*alDatal[i]) + (alDatal[i]*alDatar[i]));
Run Code Online (Sandbox Code Playgroud)

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

energy+= ((alDatal[i]*alDatal[i]) + (alDatar[i]*alDatar[i]));
Run Code Online (Sandbox Code Playgroud)

指出不同?这些名字不容易,是吗?

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

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

V += (Ei[i]-aEnergy);
Run Code Online (Sandbox Code Playgroud)

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

V += (Ei[i] - aEnergy) * (Ei[i] - aEnergy);
Run Code Online (Sandbox Code Playgroud)

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