オーディオ ストリーム キャッシング は、オーディオをメモリにロードしたり解放したりする方法を大幅に変更します。
この機能をクック時に有効化すると、ほとんどすべての圧縮されたオーディオ データを USoundWave アセットから分離して、「.pak」ファイルの末尾に配置します。これによりオーディオを任意の時点でメモリにロードして、しばらく使用しない場合は再びリリースできます。
このメモリ管理方法は、特定のユースケースで実際に必要なオーディオを事前に決定することが難しいオープン ワールド ゲームでよく利用されます。この方法の主な欠点は、USoundWave がロードされているからといって、オーディオがすぐに再生できるように保証しないことです。一方でこのメリットは、デザイナーがメモリの境界を超えずにオーディオ アセットを必要な数だけ参照できるシステムです。さらにこのシステムは、オーディオ エンジンが管理する状態に依存せずに、エンジニアが圧縮されたオーディオのチャンクをロードして参照する方法も提供します。また、ストリーム キャッシュでオーディオ再生時のレイテンシーを軽減する方が、ストリーム キャッシュを使用しないでメモリの問題を軽減するよりも簡単です。
Windows に対してオーディオ ストリーム キャッシングを有効化する
現在、デスクトップ プラットフォームでオーディオ ストリーム キャッシングをサポートするのは Windows のみです。他、Android、iOS、Xbox One、PS4、Switch などのプラットフォームもサポートされています。
-
プロジェクトを開いている状態で、メイン メニューから [Edit (編集)] > [Project Settings (プロジェクト設定)] を選択します。
-
[Project (プロジェクト)] メニューで [Platforms (プラットフォーム)]> [Windows] > [Audio] に移動します。
-
[Use Stream Caching (Experimental) (ストリーム キャッシングを使用 (実験的機能))] を有効化します。
エディタを再起動せずにエディタでストリームキャッシングを Windows に対して有効化できますが、現在再生中のサウンドがすべて停止します。
適切なキャッシュ サイズを決定する
Max Cache Size (最大キャッシュ サイズ) は、圧縮されたオーディオ データが使用するメモリの厳しい制限で、ヘッダーとサウンドを除いてメモリ内に保持するよう明示的にマークします。キャッシュが小さすぎるとサウンドのアンロードが速すぎて、サウンドのロード時にレイテンシーが発生します。
極端な例
キャッシュの制限を 8 MB に設定した場合、それぞれのチャンクは最大で 256 KB なので、32 個のチャンクをいつでもキャッシュに保存できます。これはつまり、同時に 32 個のサウンドを再生する場合は、それ以上チャンクをロードできません。
それほど極端ではない例
次にキャッシュの制限を 16 MB に設定したと仮定すると、キャッシュは 256 KB のチャンクを 64 個許容します。つまり同時に 32 のサウンドを再生した場合でも、さらに 32 のサウンドをプライムする余地があります。ただし、再生している 32 のサウンドがすべて複数のチャンクを占めるほど長い場合、シーケンスで次に来るチャンクは自動的にキャッシュにロードされたままになります。つまり、この間にキャッシュにプライムするサウンドは、32 の再生サウンド用に事前にロードしてある 32 のチャンクによって締め出されることを意味します。
通常の例
キャッシュの制限を 32 MB に設定した場合、最大 256 KB の要素を 128 詰めることができます。同時に 32 のサウンドを再生している場合でも、レイテンシーを回避するためにさらに 96 のオーディオ チャンクをキャッシュに保持できます。制限が 48 MB の場合は 192 要素の余裕があるため、同時に 32 のサウンドを再生しても、さらに 160 のチャンクをプライムできます。
キャッシュ サイズを構成する
-
プロジェクトを開いている状態で、メイン メニューから [Edit (編集)] > [Project Settings (プロジェクト設定)] を選択します。
-
[Project (プロジェクト)] メニューから [Platforms (プラットフォーム)] > [Windows] > [Audio] > [Compression Overrides (圧縮オーバーライド)] > [CookOverrides] > [Stream Caching] に移動します。
-
[Max Cache Size (KB) (最大キャッシュ サイズ (KB))] を設定して、キャッシュに必要な要素の数を決定します。
この値を 「0」 に設定した場合は、デフォルトで値が 32 KB になります。キャッシュ サイズの最大値は 2,147,483,647 MB ですが、実行するマシンのメモリが枯渇するほど大きなキャッシュ サイズを使用する場合は注意が必要です。
ストリーム キャッシングを有効化した状態で 最大キャッシュ サイズ を変更した場合は、エディタを再起動してキャッシュ サイズの変更を反映する必要があります。
適時にサウンドをキャッシュしてレイテンシーを回避する
サウンドは再生時点までにメモリに常駐しているのが理想です。これは実現するには次の方法があります。
再生用のサウンドをプライムする準備
もうすぐサウンドを再生する必要があると予想できる場合は、ブループリントで Prime Sound For Playback を呼び出します (もしくは C++ の UAudioMixerBlueprintLibrary::PrimeSoundForPlayback)
たとえばオープン ワールド ゲームで、プレイヤーが車から数フィート以内に近づくと、車両のサウンドとラジオ放送をキャッシュにロードします。プレーヤーが車に乗らない場合、サウンドはやがて解放されるまでキャッシュに残ります。
サウンド キューをプライムすることもできますが、読み込みが完了してもデリゲートが起動しません。(デリゲート は、オブジェクト インスタンスへのポインタまたは参照をラップするクラスです。これはオブジェクト インスタンスで呼び出されるオブジェクトのクラスのメンバー メソッドであり、その呼び出しをトリガーするメソッドを提供します。)
サウンドのデフォルト ロード ビヘイビアを設定する
ロードした直後にサウンドを再生すると予想できる場合は、サウンド ウェーブのロード ビヘイビアを [Prime on Load] に設定します。
または、サウンド ウェーブのサウンド クラスでロード ビヘイビアを [Prime on Load] に設定することもできます。
さらに au.streamcache.DefaultSoundWaveLoadingBehavior を 「2」 に設定することで、サウンド ウェーブをすべて [Prime on Load] に設定できます。
サウンドをメモリ上に残す
サウンドをどんな状況でもレイテンシー無く再生する必要がある場合、USoundWave の存続期間すべてにわたりメモリ上に保持しておくと便利です。
サウンド ウェーブをメモリ上に強制的に常駐させる
サウンド ウェーブのロード ビヘイビアを [Retain on Load] に設定することで、そのサウンドの最初のオーディオ チャンクが永続的にキャッシュされる設定になります。
au.streamcache.DefaultSoundWaveLoadingBehavior を「 2 」に設定すると、デフォルトでサウンド ウェーブすべての最初のチャンクを保持するように設定できます。
特定のしきい値を下回るすべてのサウンド ウェーブを強制的にインライン化する
ストリーム キャッシングを有効にすると [Stream All Soundwaves Longer Than] 設定を使用して特定の値よりも短いサウンド ウェーブを強制的にメモリ上に保持できます。これは UI や銃声などの短いサウンドを、個々のサウンドを確認やテストすることなく、最初の再生でレイテンシー無く確実に再生する必要がある場合に役立ちます。
[Stream All Soundwaves Longer Than] を設定すると、サウンド ウェーブの [Force Streaming] チェックボックスを使用して、この再生時間より短いサウンドをストリーミングに登録できます。
メモリを整理する
アプリケーションが追加のメモリをさらに必要とする場合は、[Trim Audio Cache] 関数 (UAudioMixerBlueprintLibrary::TrimAudioCache) を使用してキャッシュからオーディオの使用していないチャンクを解放できます。
[Trim Audio Cache] 関数はキャッシュを繰り返し処理して、[In Megabytes To Free] 引数で指定された量に達するまで使用していないチャンクを解放します。この関数は正常に解放されたメモリを返し、
C++ から呼び出した場合はスレッド セーフです。ただし、キャッシュをロックするため、潜在的に高コストであることに注意してください。つまり関数の実行中にストリーミング オーディオがアンダーランになる可能性があります。
ストリーム キャッシュを監視する
コンソールに「stat audiostreaming」と入力するとキャッシュ表示を切り替えることができます。
stat audiostreaming コマンドは、現在キャッシュにロードされているオーディオのチャンクを、最も最近使用したものから最も長い間使用されていないものの順に表示します。
ここに表示されたチャンクは色分けされています。
| 色 | 状態 |
|---|---|
| 青灰色 | ロード済みで現在再生していないチャンク。 |
| 緑 | 現在再生中のチャンク。 |
| 赤 | TrimMemory の呼び出しにより削除されたチャンク。 |
それぞれのチャンクは次の情報を持っています。
| 名前 | 説明 |
|---|---|
| Size | メモリ上のチャンクのサイズ (キロバイト単位)。 |
| Chunk | .pak ファイル内のチャンクのインデックス。 |
| Request Count | このチャンクをデコーダが使用した回数またはプライミングから要求された回数。 |
| Number of Decoders Using Chunk | このサウンドを同時に再生するソースの合計数。 |
| Chunk Load Time | このチャンクをディスクからロードするのにかかった時間 (ミリ秒単位)。 |
| 名前 | このチャンクが属するサウンド ウェーブの名前。 |
キャッシュがあふれる
キャッシュの要素をすべて使用している時にオーディオのチャンクをロードや再生しようとすると、(チャンクは再生中か、ディスクからの読み込み中であるため) キャッシュがあふれます。この場合、 AudioStreamingCache.cpp で確実にヒットします。
頻繁にキャッシュがあふれる場合は、次の 5 つのオプションがあります。
キャッシュのサイズを増やす。 保持するサウンド ウェーブの量を減らす。 音声の制限を下げる。 キャッシュがあふれた場合にロードを試みるサウンドの量を減らす。 * 無視してチャンク要求を止める。
最悪の場合にキャッシュの利用率を高める
短いサウンドが多数ある場合、キャッシュが小さなチャンクでいっぱいになり、キャッシュ サイズのうちの一部しか使用できません。
たとえば、キャッシュの長さが 128 チャンクで、チャンクの最大サイズが 256 KB で、64 KB のサウンドを多数ロードする場合、制限が 32 MB のときはキャッシュを 8 MB だけしか使用できません。
これを補うために、チャンクの最大数を MaxCacheSize/MaxChunkSize よりも大きく設定して、現在プールに割り当てられたバイト数の実行中のカウンタを保持し、メモリ カウンタがキャッシュの最大サイズやチャンクの最大数に達したら、最も古いチャンクを削除することができます。Cvar au.streamcaching.MinimumCacheUsage を使用して、チャンクの最大数を決定します。
au.streamcaching.MinimumCacheUsage を設定する
au.streamcaching.MinimumCacheUsage には 0.0–1.00 の値を設定できます。これは IAudioStreamingManager を初期化する前にのみ設定できます。ゲームプレイ中にこれを設定しても、実際には何も影響しません。
この値を増やすと、キャッシュに入れることができるチャンクの最大数が増えます。たとえば、au.streamcaching.MinimumCacheUsage が 0.75 で、キャッシュ サイズが 32 MB の場合、チャンクの最大数は 512 です。64 KB のオーディオ アセットを多数ロードした場合でも、まだ 32 MB を使用できます。すなわち au.streamcaching.MinimumCacheUsage が 1 に近いほど、キャッシュを完全に利用するのに必要なチャンクの平均サイズが小さくなります。
| au.streamcaching.MinimumCacheUsage | キャッシュ サイズ (メガバイト) | チャンクの最大数 | 使用率が 100% の場合のチャンクの最小平均サイズ (KB) |
|---|---|---|---|
| 0.0 | 32 | 128 | 256 |
| 0.0 | 16 | 64 | 256 |
| 0.5 | 32 | 256 | 128 |
| 0.5 | 16 | 128 | 128 |
| 0.75 | 32 | 512 | 64 |
| 0.75 | 16 | 256 | 64 |
| 0.825 | 32 | 1024 | 32 |
| 0.825 | 16 | 512 | 32 |
すべてのオーディオ アセットのサイズに対して 100% のキャッシュ使用率を保証することはできません。これはチャンクの最大数を無限にする必要があるためです。
au.streamcaching.MinimumCacheUsage を増加すると、次のような影響があります。
- 最悪の場合にオーディオをより多くキャッシュしておくため、通常時でもディスク IO の読み取りが減少する。
- 小さいチャンクをより多く処理できるため、通常時でもメモリ使用量が増加する。
- キャッシュ内のチャンクを探すため通常時の CPU コストが増加する。
- チャンクの挿入/削除のコストには影響しない。
au.streamcaching.TrimCacheWhenOverBudget を使用する
au.streamcaching.TrimCacheWhenOverBudget のデフォルト値は 1 です。au.streamcaching.MinimumCacheUsage をゼロより大きい任意の値に設定すると、ストリーミング キャッシュでリークしたメモリの潜在的なベクターを解決します。こうしたリークは、LRU キャッシュ内で大きなアセットのために小さなアセットを削除するときに発生します。これが連続して何度も発生する可能性があるため、ターゲットの最大キャッシュ サイズより結果的にはるかに大きいキャッシュ使用量になります。
au.streamcaching.TrimCacheWhenOverBudget が使用するソリューションは、正常範囲に戻るまで最も長い間使用されていないチャンクを整理するためのものです。これに対するトレードオフは、削除される最近使用していないサウンドで、プライミングやサウンドの再生を呼び出す可能性があることです。
オーディオの読み取りに優先順位を付ける
IAsyncReadRequest のインスタンスを使用してオーディオのチャンクをディスクから読み取ります。これはテクスチャ ストリーミングやジオメトリ ストリーミングのシステムと同様です。そのため、CVar au.streamcaching.ReadRequestPriority を使用して、オーディオ チャンクのロードの優先度をエンジン内の他のストリーミングシステムに対して上げたり下げたりできます。この値には 0 から 4 までを設定することができ、0 が最高の優先度で、4 が最低です。
| au.streamcaching.ReadRequestPriority | AsyncIOPriority | この優先度を使用する他のストリーミング マネージャー |
|---|---|---|
| 0 | AIOP_High | アニメーション、テクスチャ、シェーダーコード |
| 1 | AIOP_Normal | Async pak reads |
| 2 | AIOP_BelowNormal | ジオメトリ ストリーミング |
| 3 | AIOP_Low | |
| 4 | AIOP_MIN |
キャッシュされたオーディオ ストリーミング リクエストのデフォルト値は 2 です。