如何使用NAudio实时计算FFT(ASIO输出) [英] How to calculate FFT using NAudio in realtime (ASIO out)

查看:492
本文介绍了如何使用NAudio实时计算FFT(ASIO输出)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将吉他(小提琴)Hero的克隆编程为本学年的最终项目.

I am programming clone of guitar (violin) Hero as a final project for this school year.

这个想法是从我的电子小提琴中获取输入,通过FFT进行分析,进行一些逻辑和绘图,然后通过扬声器输出.也许是并行线程中的一些步骤.

The idea is to take input from my electric violin, analyse it via FFT, do some logic and drawing and output it through speakers. Perhaps some steps in parallel threads.

我已经实现了Asio低延迟输入输出,但是实现实时FFT时遇到了很大的问题.

I already have Asio low latency input-output implemented but I am having a great problem implementing realtime FFT.

这是一个与sampleAggregator一起设置asioOut的代码.样本聚合器应存储每次调用AudioAvailable()时添加的样本,并在样本数量超过fftLength时触发FFT计算.

This is a code that sets up asioOut along with sampleAggregator. Sample aggregator should store samples that are added each time AudioAvailable() is called and trigger FFT calculation when the number of samples exceeds fftLength.

private static int fftLength = 8192;
private SampleAggregator sampleAggregator = new SampleAggregator(fftLength);

void asioStartPlaying(object sender, EventArgs e)
{
    sampleAggregator.PerformFFT = true;
    sampleAggregator.FftCalculated += new EventHandler<FftEventArgs>(FftCalculated);
    var asioOut = new AsioOut();
    BufferedWaveProvider wavprov = new BufferedWaveProvider(new WaveFormat(48000, 1));
    asioOut.AudioAvailable += new EventHandler<AsioAudioAvailableEventArgs> (asio_DataAvailable);
    asioOut.InitRecordAndPlayback(wavprov, 1, 25);
    asioOut.Play();
}

void asio_DataAvailable(object sender, AsioAudioAvailableEventArgs e)
{
    byte[] buf = new byte[e.SamplesPerBuffer*4];

    for (int i = 0; i < e.InputBuffers.Length; i++)
    {
        Marshal.Copy(e.InputBuffers[i], buf, 0, e.SamplesPerBuffer*4);
        Marshal.Copy(buf, 0, e.OutputBuffers[i], e.SamplesPerBuffer*4);
    }

    for (int i = 0; i < buf.Length; i=i+4)
    {
        float sample32 = BitConverter.ToSingle(buf, i);
        sampleAggregator.Add(sample32);
    }

    e.WrittenToOutputBuffers = true;
}

SampleAggregator是取自 NAudio fft结果的类,它给出了所有频率C#上的强度.

SampleAggregator is class taken from NAudio fft result gives intensity on all frequencies C#.

Asio以Int32LSB样本类型输出数据.在buf中,值介于0到255之间.

Asio outputs data in Int32LSB sample type. In buf there are values from 0 to 255.

这是在计算fft时应调用的函数(从SampleAggregator类触发).

This is function that should be called when fft is calculated (triggered from SampleAggregator class).

void FftCalculated(object sender, FftEventArgs e)
{
    for (var i = 0; i < e.Result.Length; i++)
    {
        Debug.WriteLine("FFT output.");
        Debug.WriteLine(e.Result[i].X);
        Debug.WriteLine(e.Result[i].Y);
    }
}

但是FFT始终会输出NaN作为结果.

But the FFT always outputs NaN as a result.

我认为转换为float有问题.

I think there is a problem with the conversion to float.

有人能指出我正确的方向吗?

Could someone point me in the right direction?

EDIT_1::我将DataAvailable()中的循环更改为

EDIT_1: I changed the loop in DataAvailable() to

for (int i = 0; i < e.SamplesPerBuffer * 4; i++)
{
    float sample32 = Convert.ToSingle(buf[i]);
    sampleAggregator.Add(sample32);
}

并且FFT现在输出数据.但是我认为它们是不正确的. 错误一定是在asio样本和浮点值之间的转换.但是我对字节操作不太满意.

And FFT now outputs data. But I think they are not correct. The mistake must be in the conversion between asio samples and float values. But I am not much comfortable around byte operations.

e.GetAsInterleavedSamples可以以某种方式提供帮助吗?

Could e.GetAsInterleavedSamples somehow help?

来自FFT的原始数据样本: X:-5,304741 Y:-0,7160959 X:6,270798 Y:-0,4169312 X:-8,851931 Y:-0,4485725

Sample of raw data from FFT: X: -5,304741 Y: -0,7160959 X: 6,270798 Y: -0,4169312 X: -8,851931 Y: -0,4485725

我注意到,来自FFT的原始数据中的前几个值和最后几个值在某种程度上要比其他数据大.使幅度计算变得棘手.

I noticed, that first few and last few values in raw data from FFT are somehow bigger then other data. Making calculation of magnitude tricky.

推荐答案

问题出在我想到的有关Asio样本数据(buf数组中连续4个字节)的数据转换为fft的问题中. BitConvertor应该可以解决问题,但在我的情况下,它会以某种方式使fft输出NaN.所以我尝试了这种转换.

The problem was as I thought in conversion between data about samples from Asio (4 bytes in a row in buf array) to float for fft. BitConvertor should do the trick but it somehow makes fft output NaN in my case. So I tried this conversion instead.

for (int i = 0; i < e.SamplesPerBuffer * 4; i=i+4)
{
    float sample = Convert.ToSingle(buf[i] + buf[i+1] + buf[i+2] + buf[i+3]);
    sampleAggregator.Add(sample);
}

而且效果很好.即使采样率为192 000.

And it works very well. Even with 192 000 sample rate.

这篇关于如何使用NAudio实时计算FFT(ASIO输出)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆