【问题标题】:Help with implementing this beat-detection algorithm?帮助实现这个节拍检测算法?
【发布时间】:2011-09-27 15:13:16
【问题描述】:

我最近尝试实现在这里找到的节拍检测代码,即 Derivation and Combfilter algorithm #1:: http://archive.gamedev.net/reference/programming/features/beatdetection/page2.asp

我不太确定我是否成功实施它,因为我没有得到好的结果。我想知道是否有人成功地实施了这一点,或者只是针对一般想要提供帮助的好人。这是我的实现:

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

我得到的结果总是很高,通常在 190 和 200BPM 左右,但不应该是这种情况,因为我的 .wav 文件的速度只有 60-120BPM 之间。

请注意,我使用的是 .WAV 文件(44.1Khz,16 位,单声道),因此对某些公式进行了一些修改(即计算能量)以仅用于一个通道。我想确认我的实施是否有任何差异?我不担心 FFT 部分,因为我为此使用了一个库。

非常感谢!

【问题讨论】:

    标签: c# algorithm audio-processing


    【解决方案1】:

    绘制能量与频率的关系图。

    我想你会发现谐波与基本信号的能量几乎相同,如果实际频率落在频率区间的中间,那么二次谐波的峰值会被采样,并且很容易将两个样本击败到真实频率。

    你需要稍微惩罚更高的频率来克服这种影响。


    请注意,虽然 C# 对于实时实现此类算法或批量批处理来说并不是一个不合理的选择,但对于算法开发和调整来说却是可怕的。我建议使用 MatLab(或免费克隆,Octave)来获得正确的算法,并且只有在它处理某些测试用例时,才将代码转换为 C#(或 C++)。

    【讨论】:

      【解决方案2】:

      我不太确定是否需要这样做,但在这个块中,cmets 不适合代码:

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

      根据代码 fftPulseBuffer 因为第一个注释的大小为 512,然后它说 1024。

      【讨论】:

      • 糟糕,抱歉,这只是评论中的错误。尺寸确实是 512。但我会尝试在这部分进行实验。
      猜你喜欢
      • 2011-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-11
      • 1970-01-01
      • 2018-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多