UE4+ADXで、ゲームの実行中の音声を録音・再生する

# はじめに
アンリアルエンジン4とサウンドミドルウェア「ADX for UE4」を使った際、ゲームの実行中に再生された音声を記録し録音することができます。
一定時間内のキャラクターのボイスなどを記録しプレイバックしたり、擬似的な反響や、やまびこのような表現にも使えるかもしれません。インスタントなゲームプレイのリプレイ機能の一要素としても役立ちそうです。

**録音した音声はランタイム中のみ保持されます。**

当記事ではUE4.26.1を使用します。基本的にブループリントのみでの実装を想定しています。
ADXはインディー向けの「LE版」であれば、無料で使用できます。
https://game.criware.jp/products/adx-le/

なお、最近ADX2からADXへ名称が変更になりましたが、ツール構成は変更ありません（2がないから古いほう、というわけではありません）。

記事執筆時点のADX for UE4のSDKバージョンはv1_29です。

# 前提
ADX2 for UE4の導入や基本的な使い方は以下の記事にあります。必要に応じて参照してください。
ADX2 for UE4の導入で、一歩上のサウンド表現を（導入編）
https://qiita.com/SigRem/items/4250925f6d66a4fd287a
ADX2 for UE4の導入で、一歩上のサウンド表現を（実践編）
https://qiita.com/SigRem/items/c089b71c42e898980a46


# 実装

## 任意のキー入力で音声を再生させる
テスト用に、キー入力に反応してキューを再生するだけの簡単な機能を作ります。
もし既にADX for UE4によって音声を再生する機能を実装済みの場合、この工程は飛ばしてしまってかまいません。
本当に簡易なものなので、今回はレベルブループリントへの記述で済ませてしまいましょう。

レベル上に任意のAtomキューを、コンテンツブラウザからドラッグ・アンド・ドロップして配置します。
![B01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/9fc7b903-bba0-4845-f63c-177c6f8785dc.png)

レベルブループリントを開きます。
![B02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/873cb528-e898-6c3c-64e7-f75798088c74.png)
イベントグラフの空欄を右クリックし、Atomキューのリファレンスノードを作成します。
![B03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/14f2c5ed-c2bc-6776-64e3-5f1bd4f61e8f.png)
ピンから線を伸ばし、**Play(AtomComponent)**を選択して再生用ノードを配置します。
![B04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/902d051c-727d-3423-a4b5-a6ccea77285f.png)
**Input Key R**ノードにより、Rキーを押したら音声が再生されます。
![B05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/441a0fb9-e450-9bae-d809-76499a695ed2.png)
ここまでで、一度音声が鳴るかテストしてみましょう。


## 録音用アクターを作成する

音声の録音を担当するアクターを専用に作成します。
コンテンツブラウザの任意の場所で、右クリックして「Blueprint Class」を作ります。
![B06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/0b6aa0aa-9646-e2d0-dd38-05aa6be230d8.png)
親クラスは「Actor」とします。
![B07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/42fb285b-e4a1-cbfa-1b9a-e7a8e8ca2943.png)
任意の名前をつけ、ダブルクリックして開きます。
![B08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6257d39c-ac5e-8517-a299-cfcbd898cf62.png)

まずは録音をするために必要な「Atom Bus Sampler」を作成します。
**Event Begin Play**から処理を書いていきます。
新しくオブジェクトを作成する**Construct Object from Class**ノードを配置します。
![B09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/8066ff19-a9e6-e43f-4b10-1e523792c9fa.png)
「Class」には「Atom Bus Sampler」を指定します。
![B10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/1c433cb8-75de-d570-4a6c-a199ac99cc67.png)
「Outer」ピンにはオブジェクトの所持者を指定します。本当は何でもいいんですが、**録音中にDestroyされる可能性のないもの**が望ましいです。
シンプルに**Get Self**をつなげ、このアクター自身を所持者とします。
![B11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/829c9ee7-8cc0-16e6-962c-5e4a242fe9d7.png)
青いアウトプットピンからは作成したオブジェクトが返されます。
青いピンを右クリックし、「Promote to Variable」で変数化します。変数の型も自動的に「Atom Bus Sampler」型となっています。
![B12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5c6b816e-20cf-6d02-cbbc-29c70129c0af.png)
変数に名前をつけ、デバッグ用に**Print String**で分かりやすい文字列を表示します。
![B13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/df4fdbf7-08b1-76a9-ebda-b812036ff747.png)


## アクターにキー入力を検知させる

このアクターがキー入力を受け取れるよう設定を変更します。
Componentsパネルでアクターを選択し……
![B14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/70ffe78c-1ecf-7b0e-2646-751ddc26674c.png)
Detailsパネルの検索欄に「input」と入力し、「Auto Receive Input」に「Player 0」を指定します。
![B15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/db480209-4582-c727-00b1-78c76ce169b5.png)
これでアクターがプレイヤーのキー入力を検知できるようになります。


## キー入力によって録音を開始・終了する

任意のキーによって録音を開始・終了する処理を書いていきます。

「Tキー」が入力されたら起動するイベント**Input Key T**と、**Get MyAtomBusSampler**ノードを配置します。
![B16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/23651627-3171-4edc-8e29-3c39bfb14d87.png)
**Get MyAtomBusSampler**から線を伸ばし、**Start Recording**ノードを置きます。
このノードひとつで録音が開始されます。
![B17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5e4a1fd7-84cd-3e48-124b-c33e88529ce8.png)
「In Expected Duration」が録音予定時間（秒）になります。初期値の3秒では少し短いので、10秒にしてみます。
また、録音開始を示すデバッグメッセージも表示しておきます。
![B18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/ae2b4981-ac35-70bb-bb02-bea39f6acd44.png)

録音終了処理もシンプルです。
「Y」キーを押したら録音を終了させる処理です。
録音開始とまったく同じ書き方で、**Finish Recording**で録音を終了できます。
![B19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/db6633ee-db69-edde-d1e6-28ab34e7d7e7.png)


## 録音した音声を再生する

録音した音声の再生には**Play Recorded Sound**、再生の停止には**Stop Recorded Sound**ノードを使用します。
グラフに置いてみるととてもシンプルですね。
![B20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/109b3df1-8e5d-e6ff-1312-d6a49833e9c5.png)
ログを追加し、録音～録音停止、録音再生といった一連の流れをテストしてみましょう。
![B21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/0a59e6e2-905f-9a46-77d4-12f00e48ae94.png)
画面左上に表示されるログを見ながらだと動作が分かりやすいと思います。
![B22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d616efb2-7d60-12a8-c2e7-bad5fd05710c.png)



## 補足

### 録音開始・終了通知を行う

「AtomBusSampler」から、録音を開始または終了したタイミングでイベントを発火することができます。

**Assign On Recording Started**で新しくイベントを作成できます。
![B23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/67dd2e22-9bde-8c7e-71fe-e088f3b0a5b5.png)
**Event Begin Play**からつながる処理の最後にイベントを追加しておくといいでしょう。
![B24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/0305d8c9-f550-f8b1-18c8-caf7eda1896b.png)
イベント時に赤い文字でデバッグメッセージを出すようにしてみました。
実行すると、録音開始・終了時に同時にイベントが実行されていることが分かります。
![B25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/fe4d624c-5ac5-9a26-1ed2-23505bee9f3a.png)


### 録音を一時停止する

録音を一時的に停止し、再開することも可能です。

**Pause Recorded Sound**ノードで、チェックが入っている場合は一時停止、外せば録音を再開します。
グラフの例です。「O」キーを押すと交互に録音を一時停止・再開します。
![B26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/47e63077-cc19-ad2b-1b49-ad24d533626a.png)