Quartz は、ブループリントによって公開されるスケジュール システムであり、ゲーム、オーディオ ロジック、オーディオ レンダリング スレッドの間のタイミングの問題を解決し、サンプル アキュレートなオーディオの再生を実現します。
Quartz は、多数のアプリケーションを備えています。たとえば、Quartz を以下のことに利用できます。
- ダイナミックな音楽システムを作成する。
- 自動的な武器の発砲など、タイミングに依存するサウンド エフェクトの再生をコントロールする。
レイテンシー:Quartz によって解決される問題
Unreal Audio Engine は、オーディオ サンプルをバッファでサンプリングします。これは、デジタル/アナログ コンバータ (DAC) と呼ばれる出力ハードウェアに個別に送信されます。これらのバッファには一般に数百から数千ものサンプル データが一度に含まれます。
オーディオ レンダリング コマンド (サウンドを再生したりサウンドのパラメータを変更したりする) は、通常、オーディオ バッファ レンダーの最初に処理されます。そのため、レンダリングされたバッファのサイズが、新しいコマンドが処理される速度をコントロールし、任意の発行済みのコマンドで認識可能なレイテンシーを引き起こします。
たとえば、爆発のビジュアル エフェクトと爆発のサウンド エフェクトを同一のゲーム スレッド ティックでトリガーする場合、爆発のビジュアルとサウンドが見えて音が聞こえるまでの間のレイテンシーは、このバッファ サイズで決まります。そのバッファに 48K サンプル/秒 (kHz) でレンダリングされる 2048 サンプルが含まれる場合、聞こえるレイテンシーは最大 43 ミリ秒 (ms) になります。
バッファでレンダリングが開始された後に、再生コマンドが発行される場合 (1)、コマンドは、再生されずに時間が経過し (2)、次のバッファの先頭 (3) で実行されます。
さらに、ゲーム スレッドから発行されたコマンドは、オーディオ エンジンに到達するまで時間がかかります。前述の例で、スレッド化が 13 ミリ秒の場合にコマンドがバッファ レンダリングの最初を行えなかったとすると、最悪の場合、レイテンシーは 56 ms になります。
問題をさらに複雑化させる点として、ゲーム スレッドのティックはきわめて変化しやすく、オーディオ スレッドのタイミングとは切り離され、ガベージ コレクション中やアセットのロード中などはヒッチの影響を受けやすくなります。
こうしたレイテンシーの問題は、一部のオーディオ アプリケーションでは深刻ではありません。CPU のロードやプラットフォームの制限によっては、バッファのサイズや数を微調整し、レイテンシーを認識できないものにすることができます。
Quartz の仕組み
オーディオ バッファの先頭でレンダリングするのではなく、Quartz は、バッファ サイズ、ゲーム スレッドのタイミング、またはその他の変動するレイテンシーの影響を受けないように、時間の値 (秒) または音楽理論の値 (小節や拍) に基づいてレンダリングをスケジュールします。
事前にスケジュールすることで、Quartz はレイテンシーを考慮するため、サウンドでは遅延のないサンプルレベルの正確さでレンダリングができます。
Quartz はサンプルの正確さを提供します。コマンドは、バッファの途中に設定することができ、次のバッファの先頭にオーディオ レンダリングを遅延させることはありません。
スレッド間の通信フロー
上図において、A はゲーム フレーム ティックを区切ってゲーム スレッドを表したものであり、B は、バッファを区切ってオーディオ レンダリング スレッドを表したものです。
スレッド間の通信フローは、次のように進みます。
- ゲーム スレッドが、指定した量子化境界でサウンドを再生するよう Quartz にリクエストします。
- Quartz がリクエストを発行し、その将来のレンダリングをキューに入れます。
- 計算された時間の間、リクエストは保留されます。
- このリクエストの保留は、バッファの先頭を超えて行われる場合もあります。
- 続いて、指定された量子化境界でこのリクエストがレンダリングされます。
Quartz の重要な概念
Quartz Clock (オブジェクト)
Quartz Clock は、オーディオ レンダリング スレッドでのイベントのスケジュールおよびトリガーを行います。Quartz Clock は、Quartz Subsystem を使用して作成し、Quartz Clock Handle を使用して変更します。各 Quartz Clock には Quartz Metronome があります。
Quartz Metronome (オブジェクト)
Quartz Metronome は、オーディオ レンダリング スレッド上のオブジェクトであり、拍子記号や Beats Per Minute (BPM) などの設定に基づいて経過時間をトラッキングし、将来のコマンドをスケジュールします。
Quartz Clock Handle (オブジェクト)
Quartz Clock Handle は、ゲーム スレッド上のプロキシであり、オーディオ レンダラで実行される Quartz Clock をコントロールするために使用されます。Quartz Clock Handle には、Quartz Subsystem からアクセスできます。
Quartz Subsystem (オブジェクト)
Quartz Subsystem は、クロックの作成、クロックの存在の検証、レイテンシー情報のクエリなどの特定のクロックに関連しない汎用システム機能へのアクセスを提供します。
Play Quantized (関数)
Play Quantized は、Audio Component 入力を受け入れ、指定されたタイミングの特定のクロックに基づいてサウンドを再生します。
Play Quantized の呼び出し時には、入力のデリゲートを設定し、量子化されたオーディオと同期できます。
Subscribe to Quantization Event (関数)
Subscribe to Quantization Event は、Quartz Clock Handle を受け入れ、すべての拍など、指定された量子化イベントに基づいて特定の入力のデリゲートを通知します。
Subscribe to All Quantization Events バリアントは、すべての量子化イベントに基づいてトリガーを行います。このバリアントの使用時には、Quantization Type で Switch ノードを使用し、複数のタイミングに基づくロジックを作成できます。