我一直在试验FFT算法。我使用NAudio和来自互联网的FFT算法的工作代码。根据我对表演的观察,所得到的音高是不准确的。C#的FFT不准确性
发生什么是我有一个MIDI(从GuitarPro生成)转换为WAV文件(44.1khz,16位,单声道),包含从E2(最低吉他音符)开始到约E6的音高级数。低音(E2-B3附近)的结果通常非常错误。但是到达C4它有点正确,因为你已经可以看到正确的进程(下一个音符是C#4,然后是D4等)。然而,问题在于检测到的音高比实际音高低一半例如C4应该是注释,但显示D#4)。
您认为什么可能是错误的?如有必要,我可以发布代码。非常感谢!我仍然开始掌握DSP的领域。
编辑:这是一个什么Im做
byte[] buffer = new byte[8192];
int bytesRead;
do
{
bytesRead = stream16.Read(buffer, 0, buffer.Length);
} while (bytesRead != 0);
然后粗糙从头开始:(waveBuffer是一个简单的类,它是有转换的字节[]为浮动[],因为函数只接受浮动[])
public int Read(byte[] buffer, int offset, int bytesRead)
{
int frames = bytesRead/sizeof(float);
float pitch = DetectPitch(waveBuffer.FloatBuffer, frames);
}
最后一点:(Smbpitchfft是具有FFT算法中的类......我相信那里有什么不妥的地方所以我不会在这里张贴)
private float DetectPitch(float[] buffer, int inFrames)
{
Func<int, int, float> window = HammingWindow;
if (prevBuffer == null)
{
prevBuffer = new float[inFrames]; //only contains zeroes
}
// double frames since we are combining present and previous buffers
int frames = inFrames * 2;
if (fftBuffer == null)
{
fftBuffer = new float[frames * 2]; // times 2 because it is complex input
}
for (int n = 0; n < frames; n++)
{
if (n < inFrames)
{
fftBuffer[n * 2] = prevBuffer[n] * window(n, frames);
fftBuffer[n * 2 + 1] = 0; // need to clear out as fft modifies buffer
}
else
{
fftBuffer[n * 2] = buffer[n - inFrames] * window(n, frames);
fftBuffer[n * 2 + 1] = 0; // need to clear out as fft modifies buffer
}
}
SmbPitchShift.smbFft(fftBuffer, frames, -1);
}
并解释结果:
float binSize = sampleRate/frames;
int minBin = (int)(82.407/binSize); //lowest E string on the guitar
int maxBin = (int)(1244.508/binSize); //highest E string on the guitar
float maxIntensity = 0f;
int maxBinIndex = 0;
for (int bin = minBin; bin <= maxBin; bin++)
{
float real = fftBuffer[bin * 2];
float imaginary = fftBuffer[bin * 2 + 1];
float intensity = real * real + imaginary * imaginary;
if (intensity > maxIntensity)
{
maxIntensity = intensity;
maxBinIndex = bin;
}
}
return binSize * maxBinIndex;
UPDATE(如果有人仍有意):
所以,下面陈述的答案之一是从FFT频率峰值并不总是等同于间距。我明白那个。但是我想为自己尝试一些事情(假设有时候频率峰值是最终的音调)。所以基本上,我得到了2个软件(DewResearch的SpectraPLUS和FFTProperties;对他们的评分),能够显示音频信号的频域。
因此,这里有在时域频率峰值的结果:
这是使用测试注意做到:
SpectraPLUS
和FFT属性A2(大约110Hz)。在查看这些图像时,他们的频谱峰值在SpectraPLUS 102-112 Hz范围内,FFT Properties 108 Hz范围内。在我的代码中,我得到了104Hz(我使用8192块,采样率为44.1khz ... 8192然后加倍使其成为复杂的输入,所以最终我得到了5Hz左右的binins,与SpectraPLUS的10Hz binsize相比)。
所以现在我有点困惑,因为在软件上他们似乎返回正确的结果,但在我的代码,我总是得到104Hz(注意,我已经比较了我使用的FFT函数,如Math.Net这似乎是正确的)。
您是否认为这个问题可能与我对数据的解释有关?或者在显示频谱之前软件是否做了其他的事情?谢谢!
嗨!我为maxBinIndex得到的值是在bin 20(大约100-104 Hz),这导致在G#周围,这是从假设的A开始的一半的音符。这与其他.wav文件一致,有时是整个步骤下。 – user488792 2011-02-23 03:54:50
@eryksun谢谢!你最后的观点很有趣。我会试着去研究它。 – user488792 2011-02-23 07:14:47
@eryksun嗨!非常感谢你!这似乎是问题所在。我的代码现在可以工作并返回正确的频率。似乎我错过了Paul R答案的解决方案,因为那时我还没有做过很多有关FFT的内容。但是,我已经学到了很多,谢谢你的帮助。再次感谢! – user488792 2011-02-23 12:30:52