【问题标题】:Beat Detection on iPhone with wav files and openal使用 wav 文件和 openal 在 iPhone 上进行节拍检测
【发布时间】:2011-02-28 07:38:02
【问题描述】:

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

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

这似乎无法正常工作。如果有人能帮助我,那就太棒了。我已经坚持了 3 天了。

所需的结果是在处理完 10 秒的数据后,我应该能够将其乘以 6 并估算出每分钟的节拍数。

我目前的结果是每 10 秒 389 拍,2334 BPM 我知道的歌曲大约是 120 BPM。

【问题讨论】:

  • [A code sn-p] + ["这似乎无法正常工作。"] = [您没有尽职尽责地描述您的预期结果以及三天的结果如何工作偏离了预期。]
  • 对不起。我更新了我原来的问题。

标签: iphone objective-c audio-processing


【解决方案1】:

那段代码真的被丑陋的棍子砸了。如果您要让其他人为您找到错误,最好先让事情看起来像样。奇怪的是,这通常也会帮助您自己找到它们。

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

  1. 不要在你的代码中添加magic numbers。像const ALuint SAMPLE_RATE = 22050这样打几行真的有那么难吗?相信我,它让生活轻松了很多

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

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

还有一些我个人觉得有点讨厌的东西,比如随机的支撑和缩进,以及 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,则不要分配它们,而是假设它们的长度是正确的——您只是刚刚计算出的。您可能会证明您在整个代码中坚持的一些一致用法是合理的,但从我们在这里看到的角度来看,这似乎是一个非常糟糕的主意。

【讨论】:

    猜你喜欢
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 2015-07-18
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多