Я экспериментировал с алгоритмом FFT. Я использую NAudio вместе с рабочим кодом алгоритма FFT из Интернета. Основываясь на моих наблюдениях за производительностью, результирующий шаг является неточным.
Что происходит, так это то, что у меня есть MIDI (сгенерированный GuitarPro), преобразованный в WAV файл (44.1khz, 16-bit, mono), который содержит прогрессию основного тона, начиная с E2 (самая низкая гитарная нота) до приблизительно E6. Каковы результаты для нижних нот (вокруг E2-B3), как правило, это очень неправильно. Но, достигнув C4, он несколько верен в том, что вы уже можете видеть правильную прогрессию (следующая заметка - С# 4, затем D4 и т.д.). Однако проблема заключается в том, что обнаруженный шаг на половину меньше, чем фактический шаг ( например, C4 должна быть заметкой, но отображается D # 4).
Как вы думаете, может быть неправильно? При необходимости я могу отправить код. Огромное спасибо! Я все еще начинаю понимать поле DSP.
Изменить: вот грубая царапина того, что я делаю
byte[] buffer = new byte[8192];
int bytesRead;
do
{
bytesRead = stream16.Read(buffer, 0, buffer.Length);
} while (bytesRead != 0);
И затем: (waveBuffer - это просто класс, который должен преобразовать байт [] в float [], поскольку функция принимает только float [])
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 (если кому-то все еще интересно):
Итак, в одном из приведенных ниже ответов указано, что пик частоты из БПФ не всегда эквивалентен тангажу. Я это понимаю. Но я хотел попробовать что-то для себя, если бы это было так (в предположении, что бывают моменты, когда пик частоты - это результат). Таким образом, в основном, у меня есть 2 программного обеспечения (SpectraPLUS и FFTProperties от DewResearch, кредиты для них), которые могут отображать частотную область для аудиосигналов.
Итак, вот результаты частотных пиков во временной области:
SpectraPLUS
и свойства FFT:
Это было сделано с использованием тестовой ноты A2 (около 110 Гц). При просмотре изображений они имеют частотные пики в диапазоне 102-112 Гц для SpectraPLUS и 108 Гц для свойств FFT. На моем коде я получаю 104 Гц (я использую 8192 блока и выборку 44.1khz... 8192 затем удваивается, чтобы сделать его сложным, поэтому в конце я получаю около 5 Гц для binsize по сравнению с 10 Гц binsize SpectraPLUS).
Итак, теперь я немного смущен, так как на программном обеспечении они, похоже, вернут правильный результат, но в моем коде я всегда получаю 104 Гц (учтите, что я сравнил функцию FFT, которую я использовал с другими, такими как Math.Net и это кажется правильным).
Считаете ли вы, что проблема может быть связана с моей интерпретацией данных? Или же программное обеспечение делает что-то еще перед отображением частотного спектра? Спасибо!