我正在编程吉他(小提琴)英雄的克隆作为本学年的最后一个项目。
这个想法是从我的电小提琴中获取输入,通过 FFT 对其进行分析,进行一些逻辑和绘图并通过扬声器输出。也许并行线程中的一些步骤。
我已经实现了 Asio 低延迟输入输出,但我在实现实时 FFT 时遇到了很大的问题。
这是一个设置 asioOut 和 sampleAggregator 的代码。样本聚合器应存储每次调用 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 是取自NAudio fft 结果的类,给出了所有频率 C# 的强度。
Asio 以 Int32LSB 样本类型输出数据。在 buf 中有从 0 到 255 的值。
这是计算 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);
}
}
但是 FFT 总是输出 NaN 作为结果。
我认为转换为浮动存在问题。
有人能指出我正确的方向吗?
EDIT_1:我将 DataAvailable() 中的循环更改为
for (int i = 0; i < e.SamplesPerBuffer * 4; i++)
{
float sample32 = Convert.ToSingle(buf[i]);
sampleAggregator.Add(sample32);
}
FFT 现在输出数据。但我认为它们是不正确的。错误一定是在asio 样本和浮点值之间的转换。但是我对字节操作不太满意。
e.GetAsInterleavedSamples 能以某种方式提供帮助吗?
FFT 的原始数据样本:X:-5,304741 Y:-0,7160959 X:6,270798 Y:-0,4169312 X:-8,851931 Y:-0,4485725
我注意到,来自 FFT 的原始数据中的前几个和最后几个值在某种程度上比其他数据大。计算量级很棘手。