Essentially, I'm trying to write a piece of software that can display the pitch of any incoming audio. I have a C# console app, and I'm using NAudio as a way to take in audio. Here's the code I have to do that:
int SampleRate = 44100;
int BufferMS = 1000;
NAudio.Wave.WaveInEvent Wave = new()
{
DeviceNumber = 0,
WaveFormat = new NAudio.Wave.WaveFormat(SampleRate, 1),
BufferMilliseconds = BufferMS
};
Wave.DataAvailable += OnWaveInData;
Wave.StartRecording();
void OnWaveInData(object? sender, NAudio.Wave.WaveInEventArgs e)
{
// get the frequency of the audio
var freq = GetFrequency(e.Buffer, e.BytesRecorded);
// print freq in hz
Console.WriteLine($"\r{freq} Hz");
}
I used GitHub Copilot to help me write this next part, as I know I need to use some math to get a frequency out of this, but it seemed quite advanced.
double GetFrequency(byte[] buffer, int bytesRecorded)
{
double max = 0;
int maxN = 0;
for (int i = 0; i < bytesRecorded / 2; i++)
{
var real = buffer[2 * i];
var imag = buffer[2 * i + 1];
var magnitude = Math.Sqrt(real * real + imag * imag);
if (magnitude > max)
{
max = magnitude;
maxN = i;
}
}
double freqN = maxN;
if (maxN > 0 && maxN < bytesRecorded / 2 - 1)
{
var dL = buffer[2 * (maxN - 1)];
var dR = buffer[2 * (maxN + 1)];
freqN += 0.5 * (dR * dR - dL * dL) / (dR + dL - 2 * buffer[2 * maxN]);
}
return freqN * SampleRate / bytesRecorded;
}
It works somewhat okay, but the issue is the frequency reported can be quite sporadic and jump around which is not desireable. Should I just write a filter function to remove these "outliers", or am I approaching this completely incorrectly?
Thanks for any help!