将音频流转换为频率

6

我已经成功地使用NAudio将音频数据流传输到输出设备(扬声器):

private void OnDataAvailable(object sender, WaveInEventArgs e)
        {
            var buffer = e.Buffer;
            var bytesRecorded = e.BytesRecorded;
            Debug.WriteLine($"Bytes {bytesRecorded}");

并且样例输出为:

Bytes 19200
Bytes 19200
Bytes 19200
Bytes 19200
Bytes 19200
Bytes 19200
Bytes 19200
Bytes 19200
Bytes 19200
Bytes 19200
Bytes 19200
Bytes 23040
Bytes 19200
Bytes 19200
Bytes 19200
Bytes 19200
Bytes 19200

我随后使用https://dev59.com/g3bZa4cB1Zd3GeqPKtzX#20414331将其转换(FFT)为x和y值:

var buffer = e.Buffer;
            var bytesRecorded = e.BytesRecorded;
            //Debug.WriteLine($"Bytes {bytesRecorded}");
            var bufferIncrement = _waveIn.WaveFormat.BlockAlign;

            for (var index = 0; index < bytesRecorded; index += bufferIncrement)
            {
                var sample32 = BitConverter.ToSingle(buffer, index);
                _sampleAggregator.Add(sample32);
            }

使用样例输出:

x: -9.79634E-05, y: -9.212703E-05
x: 6.897306E-05, y: 2.489315E-05
x: 0.0002080683, y: 0.0004317867
x: -0.0001720883, y: -6.681971E-05
x: -0.0001245111, y: 0.0002880402
x: -0.0005751926, y: -0.0002682915
x: -5.280507E-06, y: 7.297558E-05
x: -0.0001143928, y: -0.0001156801
x: 0.0005231025, y: -0.000153206
x: 0.0001011164, y: 7.681748E-05
x: 0.000330695, y: 0.0002293986

不确定这是否可能,或者我是否误解了流返回的内容,但我想获取音频流的频率,以便对飞利浦Hue进行一些操作。上面的x、y值太小,无法在CIE色彩空间中使用。我是做错了什么,还是完全误解了OnDataAvailable缓冲区中的数据?谢谢!编辑:根据评论和Autotune程序的教程,我修改了我的OnDataAvailable代码如下:
private void OnDataAvailable(object sender, WaveInEventArgs e)
        {
            var buffer = e.Buffer;
            float sample32 = 0;

            for (var index = buffer.Length > 1024 ? buffer.Length - 1024 : buffer.Length; index < e.BytesRecorded; index += 2)
            {
                var sample = (short) ((buffer[index + 1] << 8) | buffer[index + 0]);
                sample32 = sample / 32768f;
                Debug.WriteLine(sample32);
                LightsController.SetLights(Convert.ToByte(Math.Abs(sample32) * 255));
                _sampleAggregator.Add(sample32);
            }
            var floats = BytesToFloats(buffer);

            if (sample32 != 0.0f)
            {
                var pitchDetect = new FftPitchDetector(sample32);
                var pitch = pitchDetect.DetectPitch(floats, floats.Length);
                Debug.WriteLine($"Pitch {pitch}");
            }
        }

希望我只使用缓冲区中的最后一组元素,因为它似乎不会自动清除,并且我只对最新可用的数据集感兴趣,以获取当前音频的频率。但是,当调用DetectPitch方法时,有时仍会出现索引异常。我做错了什么?我希望使用频率来更改色调灯泡的颜色和亮度。

1
你看过这篇帖子吗:http://stackoverflow.com/questions/15009084/implementing-fftpitchdetector-in-c-sharp? - David Tansey
@DavidTansey 没有。我会调查一下并回报。 - Adam Short
@DavidTansey 我修改了我的OnDataAvailable代码,以匹配并传递“floats”和“floats.Length”到pitchDetect.DetectPitch,但我在SmbPitchShift.smbFft(fftBuffer,frames,-1);处得到了一个索引超出范围的异常;如果注释掉,会在float real = fftBuffer [bin * 2];处得到相同的异常。有什么想法吗? - Adam Short
修改后,你是指在那篇帖子中OP展示的代码还是Mark Heath在答案中提供的链接中展示的代码?此外,如果您查看Mark答案下面的评论,您会发现有人遇到了“索引超出范围”的问题,而Mark在另一个评论中提供了解决方法。 - David Tansey
@DavidTansey 两者都是相同的代码。从马克的回答中可以看出,SampleAggregator的目的是使事物成为2的幂次方,所以我不需要改变我传递给音高检测器的内容,对吗? - Adam Short
1个回答

1

使用

fPeak = 采样率 * 峰值的频率序号 / FFT长度 ;


“BinNumberOfPeak”是什么?“FFTLength”在哪里?你的回答没有提供足够的细节。我想了解NAudio返回的数据代表什么以及如何从数据中获取频率。 - Adam Short
FFT长度=4096(= N计算点数),Bin编号是FFT数组中的索引0、1、2.. 频率峰值计算基于单边或双边谱,这很棘手。您必须遵循此处的第4点以了解真实的计算。 - SACn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接