帮助实现这个节拍检测算法吗?
我最近尝试实现在这里找到的节拍检测代码,即推导和梳状滤波器算法#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 部分,因为我正在为此使用一个库。
非常感谢!
I recently tried to implement a beat detection code found here, namely the Derivation and Combfilter algorithm #1:: http://archive.gamedev.net/reference/programming/features/beatdetection/page2.asp
Im not too sure if I implemented it successfully as I am not getting good results. I was wondering if anyone have implemented this successfully or just towards the good people who want to help in general. Here is my implementation:
//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;
}
}
The results that I am getting are always very high, usually around 190 and 200BPM, which should NOT be the case, as my .wav files have tempos only between 60-120BPM.
Note that I am using a .WAV file (44.1Khz, 16-bit, Mono), so that some of the formulas are a bit modified (i.e. calculating the energy) to work with only one channel. I would like to confirm if there have been any discrepancies in my implementation? I am not worrying about the FFT part because I am using a library for that.
Thank you very much!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
绘制能量与频率的关系图。
我认为您会发现谐波具有与基本信号几乎相同的能量,并且如果实际频率落在频率箱之间的中间,则对二次谐波的峰值进行采样,并轻松地将两个样本击败到真实频率的任一侧。
您需要稍微惩罚更高的频率来克服这种影响。
请注意,虽然 C# 对于实时实现此类算法或批量处理来说并不是一个不合理的选择,但它对于算法开发和调整来说是可怕的。我建议使用 MatLab(或免费克隆 Octave)来获得正确的算法,并且只有在它处理某些测试用例时,才将代码转换为 C#(或 C++)。
Make a plot of energy vs frequency.
I think you'll find that the harmonics have nearly identical energy to the base signal, and if the actual frequency falls halfway between frequency bins, then the second harmonic's peak is sampled and easily beats the two samples to either side of the true frequency.
You'll need to penalize higher frequencies a little bit to overcome this effect.
Please note, while C# is not an unreasonable choice for implementation of such an algorithm in real time or for bulk batch processing, it's horrible for algorithm development and tweaking. I'd recommend using MatLab (or the free clone, Octave) to get the algorithm right, and only once it's working on some test cases, convert the code to C# (or C++).
我不太确定这是否是想要的,但在这个块中,注释不适合代码:
根据代码 fftPulseBuffer,因为第一个注释的大小为 512,然后它说 1024。
I'm not quite sure if this is wanted but in this block the comments do not fit the code:
According to code fftPulseBuffer because of first comment has size 512, and then it says 1024.