我一直在試驗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