次の方法で共有


イベントのタイムスタンプ

シンセサイザーのタイミングの全体像は、再生する必要があるときにノートを正確に送信するのではなく、各ノートにタイムスタンプが付けられ、バッファに配置されるということです。 このバッファは、タイムスタンプで指定された時間から 2 ミリ秒以内に処理され、再生されます。 (タイミングの分解能は数百ナノ秒ですが、ここでは議論に便利な時間単位であるミリ秒で説明します。)

レイテンシはレイテンシ クロックを通じてシステムに認識されるため、タイムスタンプ付きのイベントは、単にイベントをキューにドロップしてレイテンシが低いことを期待するのではなく、適切な時間に再生されるようバッファ内で待機することができます。

マスター クロックは、COM IReferenceClock インターフェイスを実装します (Microsoft Windows SDK ドキュメントで説明されています)。 システム上のすべてのデバイスがこの基準時間を使用します。

Microsoft のウェーブ シンク実装は、20 ミリ秒ごとに起動するスレッドを構築します。 スレッドの仕事は、別のバッファを作成して DirectSound に渡すことです。 そのバッファを作成するには、シンセサイザを呼び出し、指定された量の音楽データをレンダリングするように要求します。 要求される量は、スレッドが起動する実際の時間によって決まりますが、正確に 20 ミリ秒になることはほとんどありません。

実際にシンセサイザーに渡されるのは、PCM バッファーへのデータの書き込みを開始するメモリー内の位置へのポインターと、書き込むデータ量を指定する長さパラメーターだけです。 その後、シンセは PCM データをこのバッファに書き込み、指定された量まで埋めることができます。 つまり、開始アドレスから指定された長さに達するまでレンダリングされます。 このメモリ ブロックは DirectSoundBuffer (デフォルトの場合) である可能性がありますが、DirectShow グラフまたはウェーブ シンクによって定義された他のターゲットである可能性もあります。

PCM バッファーは概念的には循環的です (つまり、常にループしています)。 シンセサイザーは、サウンドを表す 16 ビットの数値をバッファーの連続したスライスにレンダリングします。 シンクは正確に 20 ミリ秒ごとに起動できないため、スライス サイズはスレッドが起動するたびにわずかに異なります。 したがって、スレッドがウェイクアップするたびに、キャッチアップを実行して、スリープに戻る前にバッファ内でどこまで進むべきかを決定します。

アプリケーションの観点から見ると、シンセ ポート ドライバー自体には、波シンクからクロックを取得する IDirectMusicSynth::GetLatencyClock 関数があります。 したがって、時計は 2 つあります:

  • 波シンクも含めて誰もが聞くマスタークロック。

  • 波シンクによって実装されるレイテンシ クロック。アプリケーションでは、レイテンシ クロックを提供する DirectMusic ポートとして認識されます。

言い換えれば、アプリケーションはレイテンシ クロックを要求しますが、そのクロックは Wave シンクからではなく DirectMusic ポート抽象化から来ているものと見なされます。

このレイテンシ クロックによって返される時刻は、バッファをレンダリングできる最も早い時刻です。これは、シンセサイザーがバッファ内のその時点までにすでにレンダリングを行っているためです。 シンセサイザーが最後の書き込み時にレンダリングするバッファーが小さければ、レイテンシーも小さくなります。

したがって、ウェーブ シンクはシンセサイザーで IDirectMusicSynth::Render を呼び出し、バッファーを提示し、レンダリングされたデータでバッファーを埋めるように要求します。 次の図に示すように、シンセサイザーは、IDirectMusicSynth::PlayBuffer 関数呼び出しの結果として受信されるタイムスタンプ付きイベントをすべて受け取ります。

Diagram illustrating the queuing process of time-stamped messages in a synthesizer.

各入力バッファにはタイムスタンプ付きのメッセージが含まれています。 これらの各メッセージはキューに入れられ、タイムスタンプで指定された時刻にバッファーにレンダリングされます。

このモデルの重要な点の 1 つは、タイムスタンプ以外に特別な順序がないことです。 これらのイベントはストリーミングされるため、レンダリング前でいつでもキューに追加できます。 時間に関してはすべてがイベントベースです。 たとえば、基準時刻が現在 400 時間単位である場合、時刻 400 に発生するようにタイムスタンプが設定されているすべてのことが現在発生しています。 今から 10 単位後に発生するようにタイムスタンプが設定されたイベントは、時刻 410 に発生します。