帮助实现此节拍检测算法
本文关键字:检测 算法 实现 帮助 | 更新日期: 2023-09-27 18:00:54
我最近尝试实现这里的节拍检测代码,即Derivation和Combfilter算法#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文件的tempo仅在60-120BPM之间。
请注意,我使用的是一个.WAV文件(44.1Khz,16位,Mono(,因此一些公式被稍微修改了一下(即计算能量(,只适用于一个通道。我想确认一下我的执行过程中是否存在任何差异?我并不担心FFT部分,因为我使用的是一个库。
非常感谢!
绘制能量与频率的关系图。
我想你会发现谐波的能量与基本信号几乎相同,如果实际频率落在频率仓之间的一半,那么二次谐波的峰值就会被采样,并且很容易将两个样本拍到真实频率的两侧。
你需要稍微惩罚更高的频率来克服这种影响。
请注意,虽然C#对于实时实现这样的算法或批量处理来说并不是一个不合理的选择,但它对算法开发和调整来说是可怕的。我建议使用MatLab(或免费的克隆Octave(来正确使用算法,并且只有在它对一些测试用例起作用后,才能将代码转换为C#(或C++(。
我不太确定是否需要这样做,但在这个块中,注释不适合代码:
//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。