Неточность БПФ для C #

Я экспериментировал с алгоритмом БПФ. Я использую NAudio вместе с рабочим кодом алгоритма БПФ из Интернета. Основываясь на моих наблюдениях за исполнением, итоговая высота звука неточна.

Что происходит, так это то, что у меня есть 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 - это класс, который имеет алгоритм БПФ ... я считаю, что есть в этом нет ничего плохого, поэтому я не публикую его здесь)

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; им спасибо), которые могут отображать частотную область для аудиосигналов. enter image description here

Это было сделано с использованием тестовой ноты A2 (около 110 Гц). Глядя на изображения, можно увидеть пики частот в диапазоне 102–112 Гц для SpectraPLUS и 108 Гц для свойств БПФ. В моем коде я получаю 104 Гц (я использую 8192 блока и частоту дискретизации 44,1 кГц ... 8192 затем удваиваются, чтобы сделать его сложным вводом, поэтому в итоге я получаю около 5 Гц для размера бункера по сравнению с размером бункера 10 Гц SpectraPLUS. ).

Теперь я немного запутался, так как в программном обеспечении они, кажется, возвращают правильный результат, но в моем коде я всегда получаю 104 Гц (обратите внимание, что я сравнивал функцию БПФ, которую я использовал, с другими, такими как Math.Net и кажется правильным).

Как вы думаете, проблема может быть в моей интерпретации данных? Или программное обеспечение делает что-то другое перед отображением частотного спектра? Спасибо!

10
задан Ilmari Karonen 26 October 2013 в 17:57
поделиться