0

更新#2:

我一直在弄乱代码,我唯一的问题是当声音通过麦克风出现时它正在检测频率,但算法根本不起作用。我要求它为 500Hz,它会输出一个功率电平,即使在那个频率下没有声音下面的代码(我看到这篇文章没有引起太多关注,所以我一直在更新)

    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 很陌生(我已经尝试了几个小时——我也尝试过谷歌搜索和搜索其他 stackoverflow 帖子,我我找到了一个有点帮助的人,这就是我现在所处的位置)。

要从 Audacity 的 WASPI 播放选项下载我正在播放到默认麦克风的 525Hz 50 秒音调文件,请单击此处

任何帮助使其工作的帮助将不胜感激。

    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));
        }
    }
4

1 回答 1

0

BlockCopy将指定的字节数从源复制到目标,最后一个数字是要复制的字节数,所以(我认为)你想要的是

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

您正在做的是将整个源数组一遍又一遍地复制到目标。虽然我不确定你为什么不想一次完成整个副本(这是你的第一个方法在没有循环的情况下所做的)?

于 2015-12-11T03:56:03.723 回答