我目前正在制作一个程序,分析播放乐器的独奏音乐家的wav文件并检测其中的音符。为此,它执行FFT,然后查看生成的数据。目标是(在某些时候)通过编写midi文件来制作乐谱。
我只是希望得到一些关于它可能有什么困难的意见,无论是之前有人试过,也许是研究一些好事。目前我最大的困难是,并非所有音符都是纯粹的一个频率,我还不能发现和弦;只是单笔记。在我检测到的音符之间也必须有一个暂停,所以我确定一个已经结束而另一个已经开始。对此有任何意见也非常欢迎!
这是我从信号进入新帧时使用的代码。它寻找样本中最主要的频率:
//Get frequency vector for power match
double[] frequencyVectorDoubleArray = Accord.Audio.Tools.GetFrequencyVector(waveSignal.Length, waveSignal.SampleRate);
powerSpectrumDoubleArray[0] = 0; // zero DC
double[,] frequencyPowerDoubleArray = new double[powerSpectrumDoubleArray.Length, 2];
for (int i = 0; i < powerSpectrumDoubleArray.Length; i++)
{
if (frequencyVectorDoubleArray[i] > 15.00)
{
frequencyPowerDoubleArray[i, 0] = frequencyVectorDoubleArray[i];
frequencyPowerDoubleArray[i, 1] = powerSpectrumDoubleArray[i];
}
}
//Method for finding the highest frequency in a sample of frequency domain data
//But I want to filter out stuff
pulsePowerDouble = lowestPowerAcceptedDouble;//0;//lowestPowerAccepted;
int frequencyIndexAtPulseInt = 0;
int oldFrequencyIndexAtPulse = 0;
for (int j = 0; j < frequencyPowerDoubleArray.Length / 2; j++)
{
if (frequencyPowerDoubleArray[j, 1] > pulsePowerDouble)
{
oldPulsePowerDouble = pulsePowerDouble;
pulsePowerDouble = frequencyPowerDoubleArray[j, 1];
oldFrequencyIndexAtPulse = frequencyIndexAtPulseInt;
frequencyIndexAtPulseInt = j;
}
}
foundFreq = frequencyPowerDoubleArray[frequencyIndexAtPulseInt, 0];
答案 0 :(得分:4)
1)关于频率估计和音调估计(两个不同的主题)的研究文献有很多(几十年)。
2)峰值FFT频率与音高不同。一些独奏乐器可以产生十几个频率峰值,只有一个音符,更不用说和弦了,并且音乐音高附近没有任何最大的峰值。对于一些常见的仪器,峰值甚至可能不是数学上精确的谐波。
3)使用短的非窗口FFT的峰值区间不是一个很好的频率估计器。
4)注意起始检测可能需要一些复杂的模式匹配,具体取决于仪器。
答案 1 :(得分:1)
您不希望专注于最高频率,而是最低频率。来自任何乐器的每个音符都充满了谐波。期待听到它的基本和每个八度音阶。加上所有二次和三次谐波。
谐音是使小号音响与长号不同的原因,当它们都演奏相同音符时。
答案 2 :(得分:1)
不幸的是,这是一个非常难的问题,已经给出了一些原因。我将从文献检索(例如Google学术搜索)开始,进行“音符识别”。
如果这不是一个业余时间项目,请注意 - 我在这个特殊的浅滩上看到了这些创始人,而没有得到任何有用的结果。