Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用NAudio实时计算FFT(ASIO输出)_C#_Fft_Naudio_Asio - Fatal编程技术网

C# 如何使用NAudio实时计算FFT(ASIO输出)

C# 如何使用NAudio实时计算FFT(ASIO输出),c#,fft,naudio,asio,C#,Fft,Naudio,Asio,我正在为《吉他(小提琴)英雄的克隆》编程,作为本学年的最后一个项目 这个想法是从我的电子小提琴上获取输入,通过FFT进行分析,做一些逻辑和绘图,然后通过扬声器输出。可能是并行线程中的一些步骤 我已经实现了Asio低延迟输入输出,但是我在实现实时FFT时遇到了一个很大的问题 这是一段与sampleAggregator一起设置输出的代码。样本聚合器应存储每次调用AudioAvailable()时添加的样本,并在样本数超过FFT长度时触发FFT计算 private static int fftLeng

我正在为《吉他(小提琴)英雄的克隆》编程,作为本学年的最后一个项目

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

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

这是一段与sampleAggregator一起设置输出的代码。样本聚合器应存储每次调用AudioAvailable()时添加的样本,并在样本数超过FFT长度时触发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;
}
private static int fftLength=8192;
私有SampleAggregator SampleAggregator=新的SampleAggregator(fftLength);
void asiostarplaying(对象发送方,事件参数e)
{
sampleAggregator.PerformFFT=true;
sampleAggregator.FftCalculated+=新事件处理程序(FftCalculated);
var asioOut=新的asioOut();
BufferedWaveProvider wavprov=新的BufferedWaveProvider(新的波形格式(48000,1));
asioOut.AudioAvailable+=新的事件处理程序

Asio以Int32LSB样本类型输出数据。在buf中有0到255的值

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

void FftCalculated(对象发送方,FftEventArgs e)
{
对于(var i=0;i
但是FFT总是输出NaN作为结果

我认为转换为浮动有问题

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

编辑\u 1:我将DataAvailable()中的循环更改为

for(int i=0;i
FFT现在输出数据。但我认为它们是不正确的。错误一定是在asio采样和浮点值之间的转换中。但我对字节操作不太熟悉

e.GetaInterleavedSamples有什么帮助吗

来自FFT的原始数据样本: X:-5304741 Y:-07160959 X:6270798 Y:-04169312 X:-8851931 Y:-04485725


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

我没有使用NAudio,但我们在DirectSound中实现了非常类似的功能。LightningChart Ultimate SDK中有用于此功能的工具。AudioInput组件从so中捕获波形数据und设备,数据同时被转发到FFT计算(SpectrumCalculator组件)和波形监视器。然后,FFT数据被可视化为二维或三维频谱图。AudioOutput将数据写入声音设备,以便通过扬声器听到

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

我们的库是商业性的,但我认为,即使您没有寻找任何其他组件,也不妨看看我们的音频示例,源代码在演示应用程序Visual Studio项目中可见。您可能会有新的想法,至少:-)我相信,您可以为NAudio应用一些方法

从下载LightningChart演示,运行它不需要任何费用


[我是LightningChart组件的首席技术官]

问题在于,我在将Asio(buf数组中一行4个字节)中的样本数据转换为用于fft的浮点数据时想到了这一点。位转换器应该可以做到这一点,但在我的情况下,它会以某种方式使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);
}
for(int i=0;i

它工作得非常好。即使有192000个采样率。

我不知道NAudio,但是为什么要将
sampleAggregator.PerformFFT
设置为
false
?我猜计算每个窗口的FFT必须是真的。这是一个很好的观点。我在进行实验时,忘记在stackoverflow的示例中设置它。ThaNKS。考虑使用RX来获得更好的程序流。你确定你的ASIO驱动程序提供浮点样本吗?更常见的是得到16或24位整数样本。我不确定。我已经从ASOIODIOVAudiabeEngEARG中发现我的AsioSampleType是Int32 LSB。在BUF中有从0到255(字节?)的值。.我只是尝试了一个在“编辑1”中更详细描述的更改。但我认为这不是一个正确的方法。谢谢你的链接。你的视觉效果确实不错。但我认为我的问题更具体。
for (int i = 0; i < e.SamplesPerBuffer * 4; i++)
{
    float sample32 = Convert.ToSingle(buf[i]);
    sampleAggregator.Add(sample32);
}
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);
}