[UE] オーディオインターフェースからの入力と可視化



UE4では、マイク入力やオーディオインターフェースの入力をリアルタイムに取り込んで、音の解析結果をビジュアライズすることができるということが以下の動画からわかります。

https://youtu.be/wux2TZHwmck?t=6112

しかし、実際に音をデバイスからリアルタイムに取り込む方法や、Blueprint/Niagaraでそれぞれどのようなことが実現できるかといった情報が断片的であったりします。なのでこのあたりを個人的なメモとしてまとめます。本記事では、

* オーディオインターフェースなどのデバイスから音をリアルタイムに取得する方法
* 既存のBlueprintノードでできる解析（可視化）
* 既存のNiagaraノードでできる解析（可視化）

を扱います。間違いなどあればご指摘ください。

執筆時のバージョン: `4.26.2` -> `5.2.1` でも確認

以下は、BlurprintやNiagaraでオーディオを用いたエフェクトの例です。

https://twitter.com/ayumu_naga/status/1389322530918260736

# 0. オーディオミキサーの注意点

UE4のオーディオシステムは強力で、様々なDSP処理をゲームプレイにおける負荷を感じさせずに実現できます。空間に応じたリバーブや減衰などの動的な処理はその端的な例です。ミキシングにおいても [**Sound Class**](https://docs.unrealengine.com/ja/WorkingWithMedia/Audio/SoundClasses/index.html)  と [**Submix**](https://docs.unrealengine.com/ja/WorkingWithMedia/Audio/Submixes/index.html) というエンティティを用いて細かく調整できます。`Sound Class` は音源をグループ化してボリュームなどのパラメータを一括で乗算をするのに対して、`Submix` がオーディオシグナルのミキシングをつかさどる単位で**ミキサーのチャンネルに近い**エンティティとなります。`Submix` にエフェクトをアサインできたり、解析をしたりすることができます。様々な音源再生は全て `Submix` にアサインされてミックスされます。

全ての音源や `Submix` はフラットな状態で **`Master Submix`にデフォルトでアウトされます**。`Master Submix` は `Project Settings` > `Engine` > `Audio` > `Master Submix` で指定します。`Submix` 自体の説明は、[公式ドキュメント](https://docs.unrealengine.com/ja/WorkingWithMedia/Audio/Submixes/index.html)や[Historia様の記事](https://historia.co.jp/archives/7421/)を読むと理解がはかどります。

![prjsettings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/78d7f683-fde3-63e7-5dcf-02a6fa986912.png)

デフォルトで設定されている `MasterSubmixDefault` は `Engine Content` 配下にある `Submix`です。Masterも上げ下げしたかったりする場合は `Engine Content` のものよりも `Content` 配下に自前でつくってしまったほうが良いでしょう。

理解するのに時間がかかったのは、 全ての音源の **Master Submixへのアウトは暗黙的である** ということです。音源がわたる `Submix` 指定を `None` にしても音が聞こえる、つまり内部で暗黙的に `Master Submix` にアウトしているということです。この特性は `Submix`それ自体にもあてはまるので、 `Master Submix` に結線されていなくても暗黙的に拾われてしまいますし、そのままだとPlay中に音が聞こえてしまいます。

具体的に説明するために、新規の `Submix` として `RealTimeAudioSubmix` と `MasterSubmix` をそれぞれ作成し、 `MasterSubmix` をプロジェクトのマスターに設定してる状態で2つを結線します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/70b26517-71fe-159f-6b71-21696e1ffa31.png)

この場合の `RealTimeAudioSubmix` は当然 `MasterSubmix` にアウトされるのは理解できるのですが、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/e718b34c-c0fa-be49-6ef2-75f617d53b1e.png)

線を切ってしまっても、 `MasterSubmix` から `RealTimeAudioSubmix` の音が聞こえるのです。`Submix` をユースケースとして意識しない場合は暗黙的に出力されるほうが楽ですが、`Submix` をミキサーとして使っていきたい場合はその点が少し困ったりもします。


# 1. デバイスから音を取り込む

ここでは、オーディオインターフェースや[VoiceMeeter](https://vb-audio.com/Voicemeeter/)のようなバーチャルデバイスの入力を想定します。

## 1.1. デバイス選択

デバイス入力の取得は `Media Player`経由で行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/f3f9ad46-57b0-257b-f311-6e510cc2502f.png)

`Media Player`作成時、ビデオを出力する `Media Texture` を作成するか選べますが、今回はオーディオデバイスなのでチェックをはずします。

![mediadevice.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/4e2593ad-181d-cc15-4c32-d54e7a09bed7.png)

`Media Player`を作成して開くと、左上のフォルダアイコンから入力デバイスを手動で選ぶことができます。とりあえず確認だけしたい場合は、ここから選んで出力を確認することができます。しかし `PIE` での動作やビルドしたときの実行ファイルで音をひろいたい場合は、 `Blueprint` などで明示的に選択する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/b270f805-b55f-280c-9c4a-2fa811060c79.png)

グローバル関数の `Enumerate Audio Capture Devices` で `Media Capture Device` 構造体の配列を取得でき、 `Display Name` をキーに該当のデバイスを探します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/eb7c1917-64e1-e8c7-80c8-b3d91d7f0d7b.png)

探したら構造体の `Url` メンバーを使って `Media Player` の `Open Url` 関数を使ってオーディオデバイスを開きます。


## 1.2. `MediaSound` コンポーネント

`Media Player` でURLを開いただけでは、ゲーム内で音は聞こえません。`MediaSound` コンポーネントを持ったアクターをレベル内に配置します。コンポーネントの設定項目に、 `Media Player` があるので、ここにデバイスを開く用途の `Media Player` を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/fa89c5f4-37b6-dc17-e381-9c6a45d44ba6.png)

`Base Submix` という設定項目には、新規に作成した `Submix` を指定します。この `Submix`　に明示的に出力することで、 `Media Player` で得られた音が `Submix` にルーティングされ、エフェクトをかけたり解析をおこなったりすることができます。なお、ゲーム内で解析のみ行い音を出力させたくない場合は、この `Submix` ではなく（ここで指定すると解析もおこなえないため）、ひとつ下流の `Submix` や `Master Submix` の `Output Volume` を0にしてやればOKです。

![out.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/05ff946c-d7b0-36a3-1415-f8efd604bd10.png)

# 2. 既存のノードでできる解析

ここではオーディオリアクティブを実現することを念頭に、既存のノードでできうる可視化について簡単に説明します。現状は、`Submix` を起点に解析を行うようなデザインになっているように見受けられます。`Submix`は、ローパス、ハイパス、バンドパスのフィルターやイコライジングもできるために、たとえば、一つの音源からバスドラを強調した`Submix`とメロディーを強調した`Submix`を別々に取得して別々に描画する、といったことができます。


## 2.1. Blueprintノード

### 周波数成分の取得: `Add Spectral Analysis Delegate`

`Submix`の関数で、音の波形を特定のアルゴリズムを用いて周波数成分に分解できます。非同期で実行し、コールバックから、成分の値を配列で取得できます。どの周波数帯域をどのような間隔で欲しいかを引数で指定します。コールバックを受け取るには、事前に `Submix` の `Start Spectral Analysis` 関数を呼ぶ必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/ff2d26b3-e2fd-86b8-1011-26a6e8c9b1f4.png)


### エンヴェロープの取得: `Add Envelope Follower Delegate`

エンヴェロープは音量の変化曲線を指します。`Submix`の関数で、非同期で実行し、チャンネル毎の音量を取得できます。コールバックを受け取るには、事前に `Submix` の `Start Envelope Following` 関数を呼ぶ必要があります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/195c344f-7023-6e7d-13aa-a94957a17202.png)

ただどうやら、オーディオをそのままサンプリングした波形データを取得するような関数は `Submix` には無いようでした。

## 2.2. Niagaraノード

### 周波数成分の取得: `Audio Spectrum`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/922c9850-4b1b-54dc-e224-674336017d0b.png)

### 波形の取得: `Sample Audio Buffer`



2つとも、`Submix` を指定して、波形サンプルや解析結果を受け取り、浮動小数の配列から正規化座標（0-1の値）で指定してサンプル値を取得します。エンヴェロープの値の読み出しは無いので、必要であればBlueprintなどからパラメータとして渡して上げる必要があります。 `Submix` を指定しない場合は、デフォルトのMaster Submixが指定されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/2ce33f16-08ed-aef2-0a98-80a8ad0c9d47.png)


注意としては、Niagaraの場合、Submixの中の設定項目である `Auto Deactivate` のチェックを外さないと値の読み出しが動きません。

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76966/e8a9ca2b-84d7-92dd-6b86-2a7bac6516db.png)




# 参考

## 公式ドキュメント

https://docs.unrealengine.com/ja/WorkingWithMedia/Audio/AudioMixer/index.html

https://docs.unrealengine.com/ja/WorkingWithMedia/Audio/Submixes/index.html

## ヒストリア様のSubmixに関する記事

https://historia.co.jp/archives/11784/

https://historia.co.jp/archives/7421/