Getting the pitch/frequency of microphone audio in C#

Viewed 30

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!

1 Answers

I implemented your procedure but I get some weird values like 218525442.36 in the freqN variable after the second block of calculations in the GetFrequency procedure. It is from the variables dL and dr that values of the type 1 560 501 425 are returned to me and I don't understand why You have suggestions Thank you Mimmo

Related