Я экспериментировал с алгоритмом FFT.Я использую NAudio вместе с рабочим кодом алгоритма FFT из Интернета.Исходя из моих наблюдений за производительностью, результирующая высота звука неточна.
В результате получается, что у меня есть MIDI (сгенерированный из GuitarPro), преобразованный в WAV-файл (44,1 кГц, 16-битный, моно), который содержитизменение высоты звука, начиная с E2 (самая низкая гитарная нота) до E6.Какие результаты для нижних нот (около E2-B3), как правило, очень неправильно.Но достижение C4 несколько корректно в том смысле, что вы уже можете видеть правильную прогрессию (следующая нота - C # 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;
ОБНОВЛЕНИЕ (если кому-то все еще интересно):
Итак, в одном из ответов ниже указано, что пик частоты от БПФне всегда эквивалентно высоте тона.Я это понимаю.Но я хотел попробовать что-то для себя, если бы это было так (при условии, что бывают периоды, когда пик частоты равен результирующей высоте).В общем, я получил 2 программного обеспечения (SpectraPLUS и FFTProperties от DewResearch; кредиты для них), которые могут отображать частотную область для аудиосигналов.
Итак, вот результаты частотных пиков во временидомен:
SpectraPLUS
и свойства FFT:
Это было сделано с использованием тестовой ноты A2 (около 110 Гц),Посмотрев на изображения, они имеют частотные пики в диапазоне 102-112 Гц для SpectraPLUS и 108 Гц для свойств FFT.В моем коде я получаю 104 Гц (я использую 8192 блока и частоту дискретизации 44,1 кГц ... 8192 затем удваивается, чтобы сделать его сложным входным сигналом, поэтому в итоге я получаю около 5 Гц для двоичного размера по сравнению с 10 Гц для SpectraPLUS).
Так что теперь я немного сбит с толку, так как в программном обеспечении они, кажется, возвращают правильный результат, но в моем коде я всегда получаю 104 Гц (обратите внимание, что я сравнил функцию FFT, которую я использовал с другими, такими как Math.Net и это кажется правильным).
Как вы думаете, проблема может быть в моей интерпретации данных?Или программное обеспечение делает что-то еще перед отображением частотного спектра?Спасибо!