C#应用:音频输出中的音频样本->;FFT算法->;可视化

C#应用:音频输出中的音频样本->;FFT算法->;可视化,c#,forms,audio,naudio,spectrum,C#,Forms,Audio,Naudio,Spectrum,我是一个新手音频程序员,我第一次使用FFT。我想从音频输出中采样音频。之后,我想用FFT算法计算这些数据。我正在使用Naudio.dll 取样要求: 音频输出采样 必须在GUI上调整采样频率 缓冲区大小必须在GUI上可调 振幅值必须为原始值(无对数滤波器/无sqrt()滤波器…) 我怎样才能解决这个问题?要使用哪个dll 我尝试使用NAudio的样本聚合器。但我不知道怎么做 提前谢谢 public class SampleAggregator : ISampleProvider {

我是一个新手音频程序员,我第一次使用FFT。我想从音频输出中采样音频。之后,我想用FFT算法计算这些数据。我正在使用
Naudio.dll

取样要求:

  • 音频输出采样
  • 必须在GUI上调整采样频率
  • 缓冲区大小必须在GUI上可调
  • 振幅值必须为原始值(无对数滤波器/无sqrt()滤波器…)
我怎样才能解决这个问题?要使用哪个dll

我尝试使用NAudio的样本聚合器。但我不知道怎么做

提前谢谢

public class SampleAggregator : ISampleProvider
{
    public event EventHandler<MaxSampleEventArgs> MaximumCalculated;
    private float maxValue;
    private float minValue;
    public int NotificationCount { get; set; }
    int count;

    public event EventHandler<FftEventArgs> FftCalculated;
    public bool PerformFFT { get; set; }
    private readonly Complex[] fftBuffer;
    private readonly FftEventArgs fftArgs;
    private int fftPos;
    private readonly int fftLength;
    private readonly int m;
    private readonly ISampleProvider source;

    private readonly int channels;

    public SampleAggregator(ISampleProvider source, int fftLength = 1024)
    {
        channels = source.WaveFormat.Channels;
        if (!IsPowerOfTwo(fftLength))
        {
            throw new ArgumentException("FFT Length must be a power of two");
        }
        m = (int)Math.Log(fftLength, 2.0);
        this.fftLength = fftLength;
        fftBuffer = new Complex[fftLength];
        fftArgs = new FftEventArgs(fftBuffer);
        this.source = source;
    }

    static bool IsPowerOfTwo(int x)
    {
        return (x & (x - 1)) == 0;
    }


    public void Reset()
    {
        count = 0;
        maxValue = minValue = 0;
    }

    private void Add(float value)
    {
        if (PerformFFT && FftCalculated != null)
        {
            fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HammingWindow(fftPos, fftLength));
            fftBuffer[fftPos].Y = 0;
            fftPos++;
            if (fftPos >= fftBuffer.Length)
            {
                fftPos = 0;
                // 1024 = 2^10
                FastFourierTransform.FFT(true, m, fftBuffer);
                FftCalculated(this, fftArgs);
            }
        }

        maxValue = Math.Max(maxValue, value);
        minValue = Math.Min(minValue, value);
        count++;
        if (count >= NotificationCount && NotificationCount > 0)
        {
            MaximumCalculated?.Invoke(this, new MaxSampleEventArgs(minValue, maxValue));
            Reset();
        }
    }

    public WaveFormat WaveFormat => source.WaveFormat;

    public int Read(float[] buffer, int offset, int count)
    {
        var samplesRead = source.Read(buffer, offset, count);

        for (int n = 0; n < samplesRead; n+=channels)
        {
            Add(buffer[n+offset]);
        }
        return samplesRead;
    }
}

public class MaxSampleEventArgs : EventArgs
{
    [DebuggerStepThrough]
    public MaxSampleEventArgs(float minValue, float maxValue)
    {
        MaxSample = maxValue;
        MinSample = minValue;
    }
    public float MaxSample { get; private set; }
    public float MinSample { get; private set; }
}

public class FftEventArgs : EventArgs
{
    [DebuggerStepThrough]
    public FftEventArgs(Complex[] result)
    {
        Result = result;
    }
    public Complex[] Result { get; private set; }
}
public类SampleAggregator:ISampleProvider
{
已计算公共事件处理程序最大值;
私有浮动最大值;
私有价值;
公共int通知计数{get;set;}
整数计数;
公共事件事件处理程序FFT计算;
公共bool PerformFFT{get;set;}
私有只读复合体[]fftBuffer;
专用只读FftEventArgs fftArgs;
私人国际保税港区办事处;
私有只读整数长度;
私有只读int m;
私有只读ISampleProvider源;
专用只读int通道;
公共采样聚合器(ISampleProvider源,int-fftLength=1024)
{
通道=震源.WaveFormat.channels;
如果(!IsPowerOfTwo(fft长度))
{
抛出新的ArgumentException(“FFT长度必须是2的幂”);
}
m=(int)Math.Log(fftLength,2.0);
this.fft长度=fft长度;
fftBuffer=新络合物[fftLength];
fftArgs=新的FftEventArgs(fftBuffer);
this.source=源;
}
静态bool IsPowerOfTwo(int x)
{
返回值(x&(x-1))==0;
}
公共无效重置()
{
计数=0;
maxValue=minValue=0;
}
专用无效添加(浮动值)
{
if(PerformFFT&&FftCalculated!=null)
{
fftBuffer[fftPos].X=(float)(值*FastFourierTransform.HammingWindow(fftPos,fftLength));
fftBuffer[fftPos].Y=0;
fftPos++;
如果(fftPos>=fftBuffer.Length)
{
fftPos=0;
// 1024 = 2^10
快速傅立叶变换(真,m,fftBuffer);
FFT计算(即fftArgs);
}
}
maxValue=Math.Max(maxValue,value);
minValue=Math.Min(minValue,value);
计数++;
如果(计数>=NotificationCount&&NotificationCount>0)
{
MaximumComputed?.Invoke(这个,新的MaxSampleEventArgs(minValue,maxValue));
重置();
}
}
公共WaveFormat WaveFormat=>source.WaveFormat;
公共整数读取(浮点[]缓冲区、整数偏移量、整数计数)
{
var samplesRead=source.Read(缓冲区、偏移量、计数);
对于(int n=0;n
包含
NAudioWpfDemo
项目,该项目还包括频谱分析仪的实现。我试着解释下面最重要的部分。我将相关代码粘贴在这个答案中,但您需要查看原始源代码才能完全理解它

演示项目使用WPF
Polyline
元素(请参阅)可视化FFT数据

<UserControl x:Class="NAudioWpfDemo.SpectrumAnalyser">
    <Canvas Background="Black">
        <Polyline x:Name="polyline1" Stroke="Yellow" StrokeThickness="1"/>
    </Canvas>
</UserControl>
。。。调用
GetYPosLog(复数c)
计算每个FFT数据点的dB值

double intensityDB = 10 * Math.Log10(Math.Sqrt(c.X * c.X + c.Y * c.Y));
。。。并将转换后的数据点添加到方法
AddResult(整数索引,双幂)中的
polyline1
元素中


谢谢你的回答。对我来说看起来很有希望,但我也不知道如何使用它-/是的,你也可以用这个。包含频谱分析仪的示例代码。试着让代码运行,然后对其进行更改,使其符合您的需求。如果你被卡住了,用你的具体问题发布一个新问题。
double intensityDB = 10 * Math.Log10(Math.Sqrt(c.X * c.X + c.Y * c.Y));
Point p = new Point(CalculateXPos(index), power);
polyline1.Points.Add(p);