22

RSSフィード用のモールス信号を再生するC#プロジェクトがあります。Managed DirectXを使用して記述しましたが、Managed DirectXが古く、廃止されていることがわかりました。私が持っているタスクは、持続時間に関して正確にタイミングが調整された無音期間(コード)が点在する純粋な正弦波バーストを再生することです。純音を何ミリ秒も再生する関数を呼び出してから、Thread.Sleep()を呼び出してから、別の関数を再生する必要があります。最速では、音とスペースを40ミリ秒まで短くすることができます。

これは、ManagedDirectXで非常にうまく機能しています。正確なタイミングのトーンを得るために、私は1秒を作成します。正弦波を2次バッファーに入れてから、特定の持続時間のトーンを再生するために、バッファーの終わりからxミリ秒以内に前方にシークしてから再生します。

System.Media.SoundPlayerを試しました。任意のトーンの長さに対してPlay()、Sleep()、Stop()の順に実行する必要があるため、これは敗者です[編集-以下の私の答えを参照] 。その結果、トーンが長すぎて、CPU負荷によって変化します。実際に音を止めるには不確定な時間がかかります。

次に、NAudio1.3を使用するための長い試みに着手しました。最終的には、メモリ常駐ストリームがトーンデータを提供し、ストリームに必要な長さのトーンを残して前方に移動し、再生することになりました。これはしばらくの間DirectSoundOutクラスで問題なく機能しましたが(以下を参照)、WaveOutクラスは、PlayerStopped = trueにもかかわらず、バッファーがまだキューにあることを示す内部アサートですぐに終了します。トーンの終わりから次のトーンの始まりまで同じ時間待機するので、これは奇妙です。40ミリ秒のトーンの再生を開始してから80ミリ秒後に、キューにバッファがないと思うでしょう。

DirectSoundOutはしばらくの間はうまく機能しますが、問題は、トーンバーストPlay()ごとに個別のスレッドをスピンオフすることです。最終的に(5分程度)動作を停止します。VS2008 IDEでプロジェクトを実行している間、出力ウィンドウでスレッドが終了した後のスレッドを確認できます。再生中に新しいオブジェクトを作成することはありません。トーンストリームをSeek()してから、Play()を何度も呼び出すだけなので、孤立したバッファや、チョークされるまで積み重なるものに問題はないと思います。

私はこれに我慢できていないので、ここの誰かが同様の要件に直面し、可能性のある解決策のある方向に私を導くことができることを願っています。

4

4 に答える 4

8

信じられません...System.Media.SoundPlayerに戻って、やりたいことを実行しました... 95%の未使用のコードや癖が発見されるのを待っている巨大な依存関係ライブラリはありません:-) 。さらに、Mono(2.6)のMacOSXで動作します!!! [間違っています-音が出ません、別の質問をします]

私はMemoryStreamとBinaryWriterを使用して、RIFFヘッダーとチャンクを備えたWAVファイルをベビーベッドに入れました。「ファクト」チャンクは必要ありません。これは44100Hzの16ビットサンプルです。これで、1000msのサンプルを含むMemoryStreamができ、BinaryReaderでラップされました。

RIFFファイルには、2つの4バイト/ 32ビット長があります。ストリームに4バイト入る「全体」の長さ(ASCIIの「RIFF」の直後)と、サンプルデータバイトの直前の「データ」の長さです。 。私の戦略は、ストリームを検索し、BinaryWriterを使用して2つの長さを変更し、SoundPlayerをだまして、オーディオストリームが必要な長さ/長さであると考えさせ、Play()することでした。次回は期間が異なるため、MemoryStreamの長さをもう一度BinaryWriterで上書きし、Flush()して、もう一度Play()を呼び出します。

これを試したところ、Streamプロパティを設定しても、SoundPlayerにストリームへの変更を表示させることができませんでした。私は新しいSoundPlayerを作成することを余儀なくされました...40ミリ秒ごとに??? いいえ。

今日はそのコードに戻り、SoundPlayerのメンバーを調べ始めました。「SoundLocation」を見て読んだ。そこでは、SoundLocationを設定することの副作用は、Streamプロパティを無効にすることであり、Streamの場合はその逆であると述べています。そこで、SOundLocationプロパティを偽の「x」に設定するコード行を追加してから、Streamプロパティを(変更したばかりの)MemoryStreamに設定しました。それがそれを拾わず、私が要求した限り正確にトーンを再生しなかった場合は気にしないでください。その後のデッドタイムやメモリの増加などのクレイジーな副作用はないようです、または??? WAVストリームの微調整を行ってからプレーヤーをロード/起動するのに1〜2ミリ秒かかりますが、それは非常に小さく、価格は適切です。

また、サンプルを再生成し、Seek / BinaryWriterトリックを使用して、RIFF / WAV MemoryStream内の古いデータを同じ数のサンプルで異なる頻度でオーバーレイする、Frequencyプロパティを実装しました。また、同じことを行いました。振幅プロパティ。

このプロジェクトはSourceForgeにありますSPTones.CSのこのハックのC#コードは、SVNブラウザーのこのページから入手できます。私の考えに近い@arkeを含め、これに関する情報を提供してくれたすべての人に感謝します。ありがたいです。

于 2010-04-28T03:46:35.267 に答える
3

正弦波と無音を一緒に生成して、再生するバッファーに入れるのが最善です。つまり、常に何かを再生しますが、次に必要なものはすべてそのバッファーに書き込みます。

あなたはサンプルレートを知っています、そしてサンプルレートを与えられて、あなたはあなたが書く必要があるサンプルの量を計算することができます。

uint numSamples = timeWantedInSeconds * sampleRate;

これは、正弦波または無音のいずれかを生成するために必要なサンプルの量です。次に、必要に応じてバッファを埋めます。そうすれば、可能な限り最も正確なタイミングを得ることができます。

于 2010-04-27T21:44:58.150 に答える
1

XNAを使用してみてください。

ループできるファイルまたは静的トーンへのストリームを提供する必要があります。次に、そのトーンのピッチと音量を変更できます。

XNAはゲーム用に作成されているため、40ミリ秒の遅延でまったく問題はありません。

于 2010-04-27T21:37:16.310 に答える
1

ManagedDX からSlimDXへの変換はかなり簡単なはずです...

編集:正弦波の「n」個のサンプルを事前に生成するだけで、何があなたを止めますか?(n は、必要なミリ秒数に最も近い値です)。データを生成するのにそれほど時間はかかりません。さらに、22Khz バッファがあり、最後の 100 サンプルが必要な場合は、'buffer + 21950' を送信して、バッファ長を 100 サンプルに設定してみませんか?

于 2010-04-27T22:08:43.857 に答える