Получение частоты потокового аудио с микрофона. Naudio

Нужно постоянно получать частоту с микрофона с неким интервалом. Я не понимаю, как брать данные микрофона и обрабатывать их постоянно. Я видел примеры, где берут готовый Wav файл и находят частоту звука этого файла по первым 1024 семплам с помощью Быстрого Преобразования Фурье. Но мне нужно, чтобы данные с микрофона обрабатывались постоянно и частота выводилась в TextBox.

Данные с Wav файла преобразовываются в PCM формат. Насколько я понимаю, в таком формате хранятся и данные с микрофона, которые можно вытащить из e.Buffer в переменную типа Byte[].

Сначала я подумал постоянно перезаписывать Wav файл, примерно каждые 0.1 секунду, потом таким способом находить частоту и выводить на экран. Но я понимаю, что есть более эффективные способ. Помогите, пожалуйста разобраться

Здесь берётся Wav файл, преобразовывается в PCM поток. Дальше в метод PrintFrequency передаётся float[] с количеством ячеек 1024, насколько я понимаю. Так же предаётся prov, который получили из PCM потока с помощью ToSampleProvider. Я хотел сделать то же самое с WaveIn, но не удаётся преобразовать его в SampleProvider.

Я чувствую, что нужно использовать bute[] из е.Buffer, но не понимаю как

WaveStream readerStream = new WaveFileReader("C:\\Users\\alenu\\Downloads\\Sound_21119_Violin_440.000.wav");

WaveStream pcmStream;
WaveStream stream;

//создаем поток в PCM-формате
if (readerStream.WaveFormat.Encoding != WaveFormatEncoding.Pcm)
{
    pcmStream = WaveFormatConversionStream.CreatePcmStream(readerStream);
    stream = new BlockAlignReductionStream(pcmStream);
}
else
{
    pcmStream = readerStream;
    stream = readerStream;
}



float[] samples;
const int N_SAMPLES = 1024; //количество сэмплов для спектрального анализа
ISampleProvider prov;

using (stream)
using (readerStream)
using (pcmStream)
{
    prov = stream.ToSampleProvider();
    samples = new float[N_SAMPLES * prov.WaveFormat.Channels];

    int res = prov.Read(samples, 0, N_SAMPLES * prov.WaveFormat.Channels);
    if (res < N_SAMPLES * prov.WaveFormat.Channels) throw new Exception("Not enough data");

}
MessageBox.Show(Convert.ToString(samples));

PrintFrequency(samples, N_SAMPLES, prov.WaveFormat);

Вот метод PrintFrequency

void PrintFrequency(float[] samples, int n_samples, WaveFormat fmt)
{
    textBox1.Text = "";
    for (int i = 0; i < fmt.Channels; i++)
    {
        SampleAggregator aggregator = new SampleAggregator(n_samples);
        aggregator.PerformFFT = true;

        int j;
        float f;

        //выделяем данные одного канала
        for (j = 0; j < n_samples; j++)
        {
            int index = (j * fmt.Channels) + i;
            f = samples[index];
            aggregator.Add(f);
        }

        float[] fft_x = new float[aggregator.FftBuffer.Length / 2]; //только первая половина БПФ имеет смысл

        for (j = 0; j < fft_x.Length; j++)
        {
            float real = aggregator.FftBuffer[j].X;
            float imag = aggregator.FftBuffer[j].Y;
            fft_x[j] = (float)Math.Sqrt(real * real + imag * imag); //получаем амплитуду  
        }

        fft_x[0] = 0.0f;//избавляемся от постоянной составляющей

        int i_peak = fft_x.ToList().IndexOf(fft_x.Max());

        for (j = 0; j < fft_x.Length; j++)
        {
            fft_x[j] = (float)Math.Log(Math.Abs(aggregator.FftBuffer[j].X));
        }

        var i_interp = parabolic(fft_x, i_peak);

        float freq = fmt.SampleRate * i_interp / (float)n_samples;

        textBox1.Text += ("Channel " + i.ToString() + ": " + freq.ToString() + " Hz" + Environment.NewLine);
    }

Класс SampleAgreggator

public event EventHandler<MaxSampleEventArgs> MaximumCalculated;

    private float maxValue;
    private float minValue;
    public int NotificationCount { get; set; }
    public Complex[] FftBuffer { get { return this.fftBuffer; } }
    int count;

    // FFT
    public event EventHandler<FftEventArgs> FftCalculated;
    public bool PerformFFT { get; set; }
    private Complex[] fftBuffer;
    private FftEventArgs fftArgs;
    private int fftPos;
    private int fftLength;
    private int m;

    public SampleAggregator(int fftLength = 1024)
    {
        if (!IsPowerOfTwo(fftLength))
        {
            throw new ArgumentException("FFT Length must be a power of two");
        }
        this.m = (int)Math.Log(fftLength, 2.0);
        this.fftLength = fftLength;
        this.fftBuffer = new Complex[fftLength];
        this.fftArgs = new FftEventArgs(fftBuffer);
    }

    bool IsPowerOfTwo(int x)
    {
        return (x & (x - 1)) == 0;
    }


    public void Reset()
    {
        count = 0;
        maxValue = minValue = 0;
    }

    public void Add(float value)
    {
        if (PerformFFT)
        {
            fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HammingWindow(fftPos, fftBuffer.Length));
            fftBuffer[fftPos].Y = 0;
            fftPos++;
            if (fftPos >= fftBuffer.Length)
            {
                fftPos = 0;
                // 1024 = 2^10
                FastFourierTransform.FFT(true, m, fftBuffer);

                if (FftCalculated != null) FftCalculated(this, fftArgs);
            }
        }

        maxValue = Math.Max(maxValue, value);
        minValue = Math.Min(minValue, value);
        count++;
        if (count >= NotificationCount && NotificationCount > 0)
        {
            if (MaximumCalculated != null)
            {
                MaximumCalculated(this, new MaxSampleEventArgs(minValue, maxValue));
            }
            Reset();
        }
    }
}

public class MaxSampleEventArgs : EventArgs
{
    [DebuggerStepThrough]
    public MaxSampleEventArgs(float minValue, float maxValue)
    {
        this.MaxSample = maxValue;
        this.MinSample = minValue;
    }
    public float MaxSample { get; private set; }
    public float MinSample { get; private set; }
}

public class FftEventArgs : EventArgs
{
    [DebuggerStepThrough]
    public FftEventArgs(Complex[] result)
    {
        this.Result = result;
    }
    public Complex[] Result { get; private set; }
}

Ответы (0 шт):