7

私は現在、個人的なプロジェクトに取り組んでいます。Flash でリアルタイム オーディオ合成用のライブラリを作成しています。簡単に言うと、ウェーブジェネレーター、フィルター、ミキサーなどを相互に接続し、サウンドカードに生の (リアルタイムの) データを供給するツールです。max/msp や Reaktor のようなもの。

私はすでにいくつかの機能を持っていますが、私が書いた基本的なセットアップが正しいかどうか疑問に思っています。後でアプリのコアを変更せざるを得ないような問題に遭遇したくありません (常に発生する可能性はありますが)。

基本的に、私が今やっていることは、チェーンの最後、(生の) サウンドデータが (サウンドカードに) 「出力」される場所から開始することです。そのためには、バイトのチャンク (ByteArrays) をオブジェクトに書き込む必要があり、そのチャンクを取得するには、「Sound Out」モジュールに接続されているモジュールにチャンクを提供するように依頼します。そのモジュールは、彼の入力に接続されているモジュールに同じ要求を行い、それはチェーンの開始に達するまで発生し続けます。

これは正しいアプローチですか?フィードバックループがある場合、または出力のない別のモジュールがある場合に問題が発生することを想像できます。スペクトルアナライザーをどこかに接続すると、チェーンの行き止まりになります (出力のないモジュール、入力のみ)。私の現在のセットアップでは、サウンド出力モジュールから計算を開始するだけなので、そのようなモジュールは機能しません。

このようなプログラミングの経験がある人はいますか?正しいアプローチについての考えに非常に興味があります。(明確にするために: 特定の Flash 実装を探しているわけではないため、この質問を flash または actionscript の下にタグ付けしませんでした)

4

2 に答える 2

1

私はしばらく前に同様のことを行いました.私はあなたと同じアプローチを使用しました-仮想ラインアウトから始めて、信号を上にトレースします. ただし、バッファごとではなく、サンプルごとにこれを行いました。私が今日同じアプリケーションを書くとしたら、代わりにバッファーごとを選択するかもしれません。

分光計は挿入モジュールとして設計されました。つまり、入力と出力の両方が接続されている場合にのみ機能し、入力を変更せずに出力に渡します。

フィードバックを処理するために、1 サンプルの遅延を導入し、サイクルごとに 1 回だけ入力をフェッチする特別なヘルパー モジュールを用意しました。

また、浮動小数点数を使用してすべての内部処理を実行し、したがって浮動小数点数の配列をバッファーとして実行することは、バイト配列よりもはるかに簡単であり、整数と浮動小数点数を常に変換する余分な労力を節約できると思います。

于 2010-11-30T18:29:44.003 に答える
0

それ以降のバージョンでは、ネットワークのさまざまな部分で異なるパケット レートになる可能性があります。

1 つの例は、ディスクとの間でデータを転送するように拡張する場合です。もう 1 つの例は、エコー遅延を制御するものなどの低データ レート制御変数が、後でネットワークの一部になる可能性があることです。おそらく、オーディオ パケットを処理するのと同じ頻度で制御変数を処理したくないでしょうが、それらは依然として「リアルタイム」であり、機能ネットワークの一部です。たとえば、突然の遷移を避けるためにスムージングが必要になる場合があります。

すべての関数を同じ速度で呼び出しており、すべての関数が本質的に一定の時間を取っている限り、データを引き出すアプローチはうまく機能します。データのプルとプッシュのどちらを選択するかはほとんどありません。オーディオの再生ではプルの方がやや自然であり、録音ではプッシュの方がやや自然ですが、どちらも機能し、基になるオーディオ処理関数に対して同じ呼び出しを行うことになります。

  • 分光計の場合、データの複数のシンクの問題がありますが、それは問題ではありません。実際のシンクからダミー リンクを導入します。ダミー リンクは、受け入れられないデータの要求を引き起こす可能性があります。ダミー リンクがダミーであることを認識し、データの不足を気にしない限り、すべて問題ありません。これは、複数のシンクまたはソースを 1 つに減らすための標準的な手法です。

  • この種のネットワークでは、1 回の完全な更新で同じ計算を 2 回行うことは望ましくありません。たとえば、信号のハイパス バージョンとローパス バージョンを混合する場合、元の信号を 2 回評価することは望ましくありません。各バッファーでタイマーのティック値を記録し、現在のティック値が既に存在することがわかったらプルの伝播を停止するなどの操作を行う必要があります。これと同じメカニズムにより、評価中のフィードバック ループからも保護されます。

したがって、これら 2 つの懸念事項は、現在のフレームワーク内で簡単に対処できます。

ネットワークのさまざまな部分でさまざまなパケット レートが存在するレート マッチングは、現在のアプローチの問題が始まるところです。オーディオをディスクに書き込んでいる場合、効率を高めるために、大きなチャンクを頻繁には書きません。これらの書き込み中に、より頻繁に発生する小さなオーディオ入力および出力処理パケットのサービスをブロックしたくありません。シングルレートのプルまたはプッシュ戦略だけでは十分ではありません。

ある時点で、シングル レート ネットワークよりも洗練された更新方法が必要になる可能性があることを受け入れてください。その場合、実行中のさまざまな速度のスレッドが必要になるか、速度を一致させるために、評価頻度の低い関数を n 回呼び出すだけの簡単な独自の単純なスケジューラを作成します。これについて事前に計画する必要はありません。ほとんどの場合、オーディオ関数は、入力バッファーの準備が整っていることを確認する責任を既に委任しており、オーディオ関数自体ではなく、他の関数のみを変更する必要があります。

この段階で私がアドバイスしたいことの 1 つは、オーディオ バッファーの割り当てを一元化するように注意することです。バッファーは柵の支柱のようなものであることに注意してください。それらはオーディオ機能に属しておらず、オーディオ機能の間にあります。バッファの割り当てを集中化すると、ネットワークのさまざまな部分でさまざまなレートの更新戦略をさかのぼって簡単に変更できます。

于 2010-11-30T22:15:06.417 に答える