NAudio WaspiLoopback Goertzel

Обновление № 2:

Я продолжал возиться с кодом, моя единственная проблема в том, что он определяет частоты, когда звук присутствует через микрофон, но алгоритм не работает вообще. Я прошу его на частоте 500 Гц, и он выдаст уровень мощности даже при отсутствии звука на этой частоте. Код ниже (я видел, что на этот пост не обращали особого внимания, поэтому я постоянно обновляюсь)

    private void button3_Click(object sender, EventArgs e)
    {
        waveIn = new WasapiLoopbackCapture();
        waveIn.DataAvailable += OnDtAvailable;
        waveIn.StartRecording();
    }

    void OnDtAvailable(object sender, WaveInEventArgs e)
    {
        byte[] buffer = e.Buffer;
        int bytesRecorded = e.BytesRecorded;
        int bufferIncrement = waveIn.WaveFormat.BlockAlign;

        for (int index = 0; index < bytesRecorded; index += bufferIncrement)
        {
            float[] samples = new float[buffer.Length];
            Buffer.BlockCopy(buffer, index, samples, 0, bufferIncrement);

            double d1 = CalculateGoertzel(samples, 1336, 44100);
            double c2 = CalculateGoertzel(samples, 770, 48000);
            Console.WriteLine(index + ": Frequency 1336Hz - " + d1 + " Frequency 770Hz - " + c2);
        }
    }

    private static double CalculateGoertzel(float[] samples, double frequency, int sampleRate)
    {
        var normalizedFrequency = Math.Round(frequency * samples.Length / sampleRate);
        var w = (2.0 * Math.PI / samples.Length) * normalizedFrequency;
        var cosine = Math.Cos(w);
        var sine = Math.Sin(w);
        var coeff = 2.0 * cosine;

        var q0 = 0.0;
        var q1 = 0.0;
        var q2 = 0.0;

        foreach (var sample in samples)
        {
            q0 = coeff * q1 - q2 + sample;
            q2 = q1;
            q1 = q0;
        }

        return Math.Sqrt(q1 * q1 + q2 * q2 - q1 * q2 * coeff);
    }

Обновление № 1:

Я возился с кодом и, наконец, сумел получить что-то, что может работать без ошибок, но это ОЧЕНЬ неточно, кто-нибудь может показать мне лучший способ сделать это (код "рабочей" версии приведен ниже)?

    private void button3_Click(object sender, EventArgs e)
    {
        waveIn = new WasapiLoopbackCapture();
        waveIn.DataAvailable += OnDataAvailable;
        waveIn.StartRecording();
    }

    void OnDataAvailable(object sender, WaveInEventArgs e)
    {
        byte[] buffer = e.Buffer;

        if ((CalculateGoertzel(buffer, 1633.0, 48000) > 84) && (CalculateGoertzel(buffer, 697.0, 48000) > 84))
        {
            DateTime dt = DateTime.Now;
            Console.WriteLine(dt.ToString("mm:ss:fff - ") + "a");
        }
    }

   public static double CalculateGoertzel(byte[] sample, double frequency, int samplerate)
    {
        double Skn, Skn1, Skn2;
        Skn = Skn1 = Skn2 = 0;
        for (int i = 0; i < sample.Length; i++)
        {
            Skn2 = Skn1;
            Skn1 = Skn;
            Skn = 2 * Math.Cos(2 * Math.PI * frequency / samplerate) * Skn1 - Skn2 + sample[i];
        }
        double WNk = Math.Exp(-2 * Math.PI * frequency / samplerate);
        return 20 * Math.Log10(Math.Abs((Skn - WNk * Skn1)));
    }

Я пытаюсь создать решение, которое может получать энергию частоты, которая воспроизводится на компьютере через микрофон (это похоже на DTMF, так как мой проект также планирует использовать несколько частот).

Ниже вы найдете код, который я пробую, с помощью которого выдается сообщение об ошибке:

Смещение и длина вышли за пределы массива, или число больше, чем количество элементов от индекса до конца исходной коллекции.

Кажется, я не могу понять, почему он выдает ошибку "вне границ" - возможно, потому, что я очень плохо знаком с DSP и NAudio (я пытался часами - я также пробовал поиск в Google и поиск других сообщений stackru, я Я нашел тот, который немного помог, и вот как я попал туда, где я сейчас нахожусь).

Чтобы загрузить 50-секундный 50-тональный файл 525 Гц, который я воспроизводил, на свой микрофон по умолчанию из опции воспроизведения Audacity WASPI, нажмите здесь.

Любая помощь в получении этого на работу будет принята с благодарностью.

    public static double CalculateGoertzel(short[] sample, double frequency, int samplerate)
    {
        double Skn, Skn1, Skn2;
        Skn = Skn1 = Skn2 = 0;
        for (int i = 0; i < sample.Length; i++)
        {
            Skn2 = Skn1;
            Skn1 = Skn;
            Skn = 2 * Math.Cos(2 * Math.PI * frequency / samplerate) * Skn1 - Skn2 + sample[i];
        }
        double WNk = Math.Exp(-2 * Math.PI * frequency / samplerate);
        return 20 * Math.Log10(Math.Abs((Skn - WNk * Skn1)));
    }

    private void button3_Click(object sender, EventArgs e)
    {
        waveIn = new WasapiLoopbackCapture();
        waveIn.DataAvailable += OnDtAvailable;
        waveIn.StartRecording();
    }
    void OnDtAvailable(object sender, WaveInEventArgs e)
    {
        byte[] buffer = e.Buffer;
        int bytesRecorded = e.BytesRecorded;
        int bufferIncrement = waveIn.WaveFormat.BlockAlign;

        for (int index = 0; index < bytesRecorded; index += bufferIncrement)
        {
            short[] sampleBuffer = new short[buffer.Length];
            Buffer.BlockCopy(buffer, index, sampleBuffer, 0, bytesRecorded);
            Console.WriteLine(CalculateGoertzel(sampleBuffer, 525, 48000));
        }
    }

1 ответ

BlockCopy копирует количество байтов, указанных из источника в dest, причем последним числом является количество копируемых байтов, поэтому вместо этого (я думаю) вместо этого нужно то, что вы хотите

Buffer.BlockCopy(buffer, index, sampleBuffer, 0, bufferIncrement);

то, что вы делаете, это копирование всего исходного массива в место назначения снова и снова. Хотя я не уверен, почему бы вам не захотеть сделать всю копию сразу (что и сделал ваш первый метод без цикла)?

Другие вопросы по тегам