如何使用NAudio实时计算FFT (ASIO)

时间:2022-09-08 23:44:35

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

我正在为这个学年的最后一个项目——吉他(小提琴)英雄编程。

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.

我的想法是,从我的电学小提琴中提取输入,通过FFT分析,做一些逻辑和绘图,然后通过扬声器输出。也许在并行线程中有一些步骤。

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

我已经实现了Asio的低延迟输入输出,但是我有一个非常大的问题来实现realtime 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.

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

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 is class taken from NAudio fft result gives intensity on all frequencies C#.

SampleAggregator是来自NAudio fft结果的类,它给出了所有频率c#的强度。

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

Asio在Int32LSB样本类型中输出数据。在buf中,值从0到255。

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

这是计算fft时应该调用的函数(由SampleAggregator类触发)。

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

But the FFT always outputs NaN as a result.

但是FFT总是输出NaN的结果。

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

我认为转换到浮动是有问题的。

Could someone point me in the right direction?

有人能告诉我正确的方向吗?

EDIT_1: I changed the loop in DataAvailable() to

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

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

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.

FFT现在输出数据。但我认为他们是不正确的。错误必须在asio样本和浮点值之间的转换中。但我对字节操作不太满意。

Could e.GetAsInterleavedSamples somehow help?

e。GetAsInterleavedSamples不知怎么帮助?

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的原始数据样本:X: -5,304741 Y: -0,7160959 X: 6,270798 Y: -0,4169312 X: -8,851931, Y: -0,4485725。

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.

我注意到,在FFT的原始数据中,前几个和最后几个值都比其他数据更大。计算数量级的技巧。

2 个解决方案

#1


3  

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.

问题是,我在转换数据的时候,从Asio(4个字节,在buf数组中)的数据转换为fft。BitConvertor应该做这个技巧,但它在我的情况下让fft输出NaN。所以我尝试了这种转换。

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

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

而且效果很好。即使有192 000个采样率。

#2


2  

I haven't used NAudio, but we have implemented pretty much similar thing with DirectSound. There's tools for this in LightningChart Ultimate SDK. AudioInput component captures waveform data from sound device, and the data is forwarded to FFT calculation (SpectrumCalculator component) and waveform monitors at same time. FFT data is then visualized as spectrograms in 2D or 3D. AudioOutput writes the data to sound device to be audible through speakers.

我没有使用过NAudio,但是我们已经实现了与DirectSound类似的功能。在LightningChart终极SDK中有这个工具。AudioInput组件从声音设备捕获波形数据,同时将数据转发到FFT计算(频谱计算器组件)和波形监视器。FFT数据随后被可视化为2D或3D的光谱图。AudioOutput将数据写入声音设备,以便通过扬声器发声。

Overall the audio input/output, FFT calculation and visualization run with very low CPU load.

总体来说,音频输入/输出,FFT计算和可视化运行的CPU负载非常低。

如何使用NAudio实时计算FFT (ASIO)

Our libraries are commercial, but I think even if you were not looking for any additional components, it might be a good idea to take a look at our audio examples, source code is visible in the demo application Visual Studio projects. You may get fresh ideas, at least :-) You can apply some methods for NAudio, I believe.

我们的库是商业的,但我认为,即使您没有寻找任何其他组件,查看我们的音频示例可能是一个好主意,在演示应用程序Visual Studio项目中可以看到源代码。你可能会得到一些新鲜的想法,至少你可以用一些方法来做NAudio,我相信。

Download LightningChart demo from LightningChart web site, running it costs you nothing.

下载LightningChart网站的LightningChart演示,运行它将花费你什么都没有。

[I'm CTO of LightningChart components]

[我是LightningChart组件的CTO]

#1


3  

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.

问题是,我在转换数据的时候,从Asio(4个字节,在buf数组中)的数据转换为fft。BitConvertor应该做这个技巧,但它在我的情况下让fft输出NaN。所以我尝试了这种转换。

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

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

而且效果很好。即使有192 000个采样率。

#2


2  

I haven't used NAudio, but we have implemented pretty much similar thing with DirectSound. There's tools for this in LightningChart Ultimate SDK. AudioInput component captures waveform data from sound device, and the data is forwarded to FFT calculation (SpectrumCalculator component) and waveform monitors at same time. FFT data is then visualized as spectrograms in 2D or 3D. AudioOutput writes the data to sound device to be audible through speakers.

我没有使用过NAudio,但是我们已经实现了与DirectSound类似的功能。在LightningChart终极SDK中有这个工具。AudioInput组件从声音设备捕获波形数据,同时将数据转发到FFT计算(频谱计算器组件)和波形监视器。FFT数据随后被可视化为2D或3D的光谱图。AudioOutput将数据写入声音设备,以便通过扬声器发声。

Overall the audio input/output, FFT calculation and visualization run with very low CPU load.

总体来说,音频输入/输出,FFT计算和可视化运行的CPU负载非常低。

如何使用NAudio实时计算FFT (ASIO)

Our libraries are commercial, but I think even if you were not looking for any additional components, it might be a good idea to take a look at our audio examples, source code is visible in the demo application Visual Studio projects. You may get fresh ideas, at least :-) You can apply some methods for NAudio, I believe.

我们的库是商业的,但我认为,即使您没有寻找任何其他组件,查看我们的音频示例可能是一个好主意,在演示应用程序Visual Studio项目中可以看到源代码。你可能会得到一些新鲜的想法,至少你可以用一些方法来做NAudio,我相信。

Download LightningChart demo from LightningChart web site, running it costs you nothing.

下载LightningChart网站的LightningChart演示,运行它将花费你什么都没有。

[I'm CTO of LightningChart components]

[我是LightningChart组件的CTO]