5

私は今学期の最終プロジェクトとして、ギター (バイオリン) ヒーローのクローンをプログラミングしています。

アイデアは、エレクトリック バイオリンから入力を取得し、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 からの生データの最初の数個と最後の数個の値が、他のデータよりも大きいことに気付きました。マグニチュードの計算をトリッキーにする。

4

2 に答える 2

4

問題は、Asio からサンプルに関するデータ (buf 配列で 4 バイト連続) を fft の float に変換する際に考えたとおりでした。BitConvertor はトリックを行う必要がありますが、私の場合、何とか fft 出力を NaN にします。そこで、代わりにこの変換を試みました。

for (int i = 0; i < e.SamplesPerBuffer * 4; i += 4)
{
    float sample = Convert.ToSingle(buf[i] + buf[i + 1] + buf[i + 2] + buf[i + 3]);
    sampleAggregator.Add(sample);
}

そして、それは非常にうまく機能します。192,000 サンプル レートでも。

于 2014-06-04T15:34:19.243 に答える