我一直在尝试 FFT 算法。我正在使用 NAudio 以及来自互联网的 FFT 算法的工作代码。根据我对表演的观察,最终的音调是不准确的。
发生的情况是,我将 MIDI(由 GuitarPro 生成)转换为 WAV 文件(44.1khz,16 位,单声道),其中包含从 E2(最低的吉他音符)到大约 E6 的音高级别。低音(E2-B3 附近)的结果通常非常错误。但达到 C4 在某种程度上是正确的,因为您已经可以看到正确的进展(下一个音符是 C#4,然后是 D4,等等)。但是,问题是检测到的音高比实际音高低半音(例如, C4 应该是一个注释,但它写着 D#4)。
您认为可能出了什么问题?如果需要的话我可以发布代码。太感谢了!我还在开始掌握 DSP 领域。
编辑:这是我正在做的事情的一个粗略的草稿
字节[]缓冲区=新字节[8192];
int 字节读取;
做
{
bytesRead = www.sychzs.cn(buffer, 0, buffer.Length);
while (bytesRead != 0);
那么:(waveBuffer只是一个将byte[]转换为float[]的类,因为该函数只接受float[])
public int Read(byte[] buffer, int offset, int bytesRead)
{
int 帧 = bytesRead / sizeof(float);
浮动音高 = DetectPitch(waveBuffer.FloatBuffer, 帧);
}
最后:(smbpitchfft是一个带有FFT算法的类...我相信没有什么问题,所以这里就不贴出来了)
private float DetectPitch(float[] buffer, int inFrames)
{
Func 窗口 = HammingWindow;
if (prevBuffer == null)
{
prevBuffer = new float[inFrames]; //仅包含零
}// 双帧,因为我们正在组合当前和先前的缓冲区
int 帧 = inFrames * 2;
if (fftBuffer == null)
{
fftBuffer = new float[帧数 * 2]; // 乘以2,因为它是复杂的输入
}
for (int n = 0; n < 帧; n++)
{
if (n < 帧内数)
{
fftBuffer[n * 2] = prevBuffer[n] * 窗口(n,帧);
fftBuffer[n * 2 + 1] = 0; // 当fft修改缓冲区时需要清除
}
别的
{
fftBuffer[n * 2] = 缓冲区[n - inFrames] * 窗口(n, 帧);
fftBuffer[n * 2 + 1] = 0; // 当fft修改缓冲区时需要清除
}
}
SmbPitchShift.smbFft(fftBuffer, 帧, -1);
}
并且为了解释结果:
float binSize = 采样率 / 帧数;
int minBin = (int)(82.407 / binSize); //吉他上最低的E弦
int maxBin = (int)(1244.508 / binSize); //吉他上最高的E弦
浮动最大强度 = 0f;
int maxBinIndex = 0;
for (int bin = minBin; bin <= maxBin; bin++)
{浮点实数 = fftBuffer[bin * 2];
浮点虚数 = fftBuffer[bin * 2 + 1];
浮点强度 = 实数 * 实数 + 虚数 * 虚数;
如果(强度 > 最大强度)
{
最大强度=强度;
maxBinIndex = bin;
}
}
返回 binSize * maxBinIndex;
更新(如果有人仍然感兴趣):
因此,下面的答案之一指出 FFT 的频率峰值并不总是等于音调。我明白那个。但是,如果是这种情况,我想自己尝试一些东西(假设有时频率峰值是最终音调)。基本上,我有 2 个软件(DewResearch 的 SpectraPLUS 和 FFTProperties;相信它们)能够显示音频信号的频域。
以下是时域中频率峰值的结果:
光谱PLUS
和 FFT 属性:
这是使用 A2 的测试记录(大约 110Hz)完成的。查看图像时,SpectraPLUS 的频率峰值约为 102-112 Hz,FFT 属性的频率峰值约为 108 Hz。在我的代码中,我得到 104Hz(我使用 8192 个块,采样率为 44.1khz...8192 然后加倍以使其复杂输入,所以最终,我得到大约 5Hz binsize,与 SpectraPLUS 的 10Hz binsize 相比)。
所以现在我有点困惑,因为在软件上它们似乎返回了正确的结果,但在我的代码上我总是得到 104Hz(注意我已经将我使用的 FFT 函数与 www.sychzs.cn 等其他函数进行了比较,似乎是正确的)。
您认为问题可能与我对数据的解释有关吗?或者软件在显示光谱之前是否做了其他事情?谢谢!