私は今学期の最終プロジェクトとして、ギター (バイオリン) ヒーローのクローンをプログラミングしています。
アイデアは、エレクトリック バイオリンから入力を取得し、FFT を介して分析し、いくつかのロジックと描画を実行して、スピーカーから出力することです。おそらく、並列スレッドのいくつかのステップ。
既に Asio の低遅延入出力を実装していますが、リアルタイム FFT の実装に大きな問題があります。
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 は、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 を出力します。
float への変換に問題があると思います。
誰かが私を正しい方向に向けることができますか?
EDIT_1: DataAvailable() のループを次のように変更しました
for (int i = 0; i < e.SamplesPerBuffer * 4; i++)
{
float sample32 = Convert.ToSingle(buf[i]);
sampleAggregator.Add(sample32);
}
FFT がデータを出力するようになりました。しかし、それらは正しくないと思います。間違いは、asio サンプルと float 値の間の変換にあるに違いありません。しかし、私はバイト操作にあまり慣れていません。
e.GetAsInterleavedSamples が何らかの形で役立つでしょうか?
FFT からの生データのサンプル: X: -5,304741 Y: -0,7160959 X: 6,270798 Y: -0,4169312 X: -8,851931 Y: -0,4485725
FFT からの生データの最初の数個と最後の数個の値が、他のデータよりも大きいことに気付きました。マグニチュードの計算をトリッキーにする。