[英]C# Application: Sample Audio from Audio Output -> FFT Algorithm -> Visualize
I am a novice audio programmer and I use FFT for the first time. 我是音频新手,并且第一次使用FFT。 I want to sample audio from my audio output. 我想从音频输出中采样音频。 After that I want to compute this data with a FFT algorithm. 之后,我想使用FFT算法计算此数据。 I am using Naudio.dll
. 我正在使用Naudio.dll
。
Requirements for sampling: 采样要求:
How can I solve this problem? 我怎么解决这个问题? Which dll to use? 使用哪个dll?
I tried to use NAudio's sample aggregator. 我尝试使用NAudio的示例聚合器。 But I don't know how. 但是我不知道如何。
Thanks in advance 提前致谢
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; }
}
The NAudio github repository contains the NAudioWpfDemo
project which also includes an implementation of a spectrum analyzer. NAudio github存储库包含NAudioWpfDemo
项目,该项目还包括频谱分析仪的实现。 I try to explain the most important parts below. 我尝试在下面解释最重要的部分。 I paste the relevant code in this answer but you need to take a look at the original source code to understand it completely. 我在此答案中粘贴了相关代码,但是您需要看一下原始源代码才能完全理解它。
The demo project uses the WPF Polyline
element (see SpectrumAnalyser.xaml ) to visualize the FFT data. 该演示项目使用WPF Polyline
元素(请参见SpectrumAnalyser.xaml )来可视化FFT数据。
<UserControl x:Class="NAudioWpfDemo.SpectrumAnalyser">
<Canvas Background="Black">
<Polyline x:Name="polyline1" Stroke="Yellow" StrokeThickness="1"/>
</Canvas>
</UserControl>
In SpectrumAnalyser.xaml.cs you find the code which updates the Polyline
element. 在SpectrumAnalyser.xaml.cs中,您可以找到更新Polyline
元素的代码。 The method Update(Complex[] fftResults)
receives the FFT data and then loops over all the data points in the FFT data ( fftResults
array) ... 方法Update(Complex[] fftResults)
接收FFT数据,然后循环遍历FFT数据( fftResults
数组)中的所有数据点。
for (int n = 0; n < fftResults.Length / 2; n+= binsPerPoint)
{
// averaging out bins
double yPos = 0;
for (int b = 0; b < binsPerPoint; b++)
{
yPos += GetYPosLog(fftResults[n+b]);
}
AddResult(n / binsPerPoint, yPos / binsPerPoint);
}
... to call GetYPosLog(Complex c)
to calculate the dB value of each FFT data point ... ...调用GetYPosLog(Complex c)
以计算每个FFT数据点的dB值...
double intensityDB = 10 * Math.Log10(Math.Sqrt(c.X * c.X + c.Y * c.Y));
... and to add the converted data point to the polyline1
element in the method AddResult(int index, double power)
...并将转换后的数据点添加到方法AddResult(int index, double power)
的polyline1
元素中
Point p = new Point(CalculateXPos(index), power);
polyline1.Points.Add(p);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.