UE4 サウンドキュー作成例

# 概要
UnrealEngine のサウンドキュー(SoundCue)についてのメモ書きと作成例について記述しています。


## 環境
Windows10
Visual Studio 2017
UnrealEngine 4.22

## 参考
以下を参考にさせて頂きました、ありがとうございます。

[公式 - サウンドキューリファレンス](https://docs.unrealengine.com/ja/Engine/Audio/SoundCues/NodeReference/index.html)
[UE4 Saitama 初心者向けハンズオン #6『サウンド再生』](https://www.slideshare.net/YuukiOgino/ue4-saitama-6)


# サウンドキュー作成例

## SEの順次再生
複数のサウンドウェーブデータを順次再生させる、途中で[Looping]にチェックを入れてしまうとそれ以降が再生されなくなってしまいます。

![SoundCue_Concatenator.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/eda14729-60f5-966e-e757-4475eee0c6c1.png)

1番目と2番目のピンに接続したときの音のみ隙間なく再生されるようです。（3番目以降は継ぎ目に僅かに隙間があるとのことです）


## SEのランダム再生
幾つかのサウンドウェーブデータからランダムで１つ再生させる。

![SoundCue_Random.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/26bea5cf-1267-4c0a-b98a-936b8612eb32.png)

このランダムは FMath のランダムを使用しているため、例えば毎回同じ乱数にするためには FMathの乱数の初期化がいるようです。


## イントロ付きループのBGM（その１）
waveファイルのループタグ情報は無視されるため、イントロ付ループBGMを実現するにはイントロとループのサウンドウェーブデータを自前で繋いであげる必要があります。

1. イントロ、ループに分割したサウンドウェーブデータを用意する。
2. [Concatenator]ノードで繋ぐ。
3. ループデータの方の[WavePlayer]ノードの[Looping]にチェックを入れる。

サウンドキュー例
![IntroLoop_SoundCue2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/61e201d3-5872-d70b-2113-3f23a99715c0.png)

環境にもよるのかもしれませんが、イントロループの繋ぎ目にわずかに隙間があると思います。


## イントロ付きループのBGM（その２）
イントロとループの繋ぎ目を目立たなくするためにやや強引な方法を使ってみます。

1. イントロ、ループに分割したサウンドウェーブデータを用意する。（waveファイルのループタグ情報は無視されます）
1. サウンドノード[Wave Player]を2つ用意し、それぞれイントロとループのサウンドウェーブデータを割り当てます。ループデータのほうには[Looping]にチェックを入れます。
1. [Delay]ノードと[Mixer]ノードを用意し繋いでアウトプットへ。
1. [Delay]ノードにはイントロサウンドの再生時間分のディレイ時間を設定します。

サウンドキュー例
![IntroLoop_SoundCue.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/1347bf53-6f42-302d-86fc-c2a556a01eb4.png)

ディレイ時間はイントロウェーブデータの再生時間ピッタリではなく、わずかに短くするとマシになります。また、DelayMinとDelayMaxは同じ値を入れます。


## 足音
床の種類に対して幾つかランダムで再生するようにすると良いと思われます。

1. 床タイプに基づいて足音種類を用意し、各床タイプでランダムで繋ぐ。
2. 床タイプが入った外部パラメータ(FloorType)にて[Switch]ノードで分岐させる。
3. [Modulator]ノードでピッチの変化を、[Countinuous Modulator]ノードで外部パラメータでボリュームをそれぞれ設定する。
4. 対応するアクターBPなどからパラメータをオーディオコンポーネントに対し更新する。
5. サウンドキューの再生はアニメ―ションシーケンスのAnimNotifySoundなどから行う。

サウンドキュー例
![FootStep.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/5ef27f94-9e69-f9d0-45de-8c66b6cbdf93.png)

ピッチの変化を入れています。
![FootStep_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/984c41f1-b9e8-1bbb-ec73-932f6dea1a66.png)

ボリュームを外部パラメータから更新します。
![FootStep_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/6e17ffaf-0f2b-d33b-91b2-53e18473167b.png)



## エンジン音などのパラメータ変化する音
スピードやエンジンの回転数を表す変数を用意し、その値に伴ってピッチの変化をつけることで表現をしていきます。

1. 低速時エンジン音と高速時エンジン音を用意し、それぞれ[Looping]にチェックを入れ[Continuous Modulator]ノードにつなぎます。
2. [Crossfade by Param]ノードで繋いでアウトプットへ。
3. パラメータ名を決めて、[Continuous Modulator]ノードのピッチに設定します。
4. 以下は[Speed]というパラメータ名で変化するピッチを設定しています。
5. 設定したパラメータに入力するBPを書いてオーディオコンポーネントの[SetFloatParameter]へ設定します。この時[InName]には決めたパラメータ名を入れます。

低速時の設定例、速度パラメータは0～200を想定しています。
![Modulator1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/25092283-96d9-0c2a-be9c-e09198a7935e.png)

高速時の設定例、速度パラメータは20～4000を想定しています。
![Modulator2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/ef14c34b-e700-2f8e-81ce-baf7915b1b15.png)

BP設定例：対象アクターのTick処理などでパラメータを更新します。
![EngineBP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/e45646c2-05b0-e716-8414-21ae8baaf51e.png)

C++コードは以下の様になります。

```cpp:.cpp
// オーディオコンポーネントに浮動小数パラメータを"Speed"という名前で設定する
AudioComponent->SetFloatParameter(FName(TEXT("Speed")), GetSpeed());
```

サウンドキュー例
![SoundCue_Engine.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/4fbff5f4-64a7-53f3-4ed6-166ea24a7687.png)


# その他
## オーディオコンポーネントのサウンドキューへのパラメータ設定
サウンドキューへのパラメータ設定のメソッドは以下の様になります。それぞれBPノードもあります。

```cpp:Components/AudioComponent.h

// サウンドキューへ浮動小数パラメータを設定する
UFUNCTION(BlueprintCallable, Category="Audio|Components|Audio")
void SetFloatParameter(FName InName, float InFloat);

// サウンドキューのWaveParamノードへサウンドウェーブデータをパラメータ設定する
UFUNCTION(BlueprintCallable, Category="Audio|Components|Audio")
void SetWaveParameter(FName InName, class USoundWave* InWave);

// サウンドキューへブール値パラメータを設定する
UFUNCTION(BlueprintCallable, Category="Audio|Components|Audio", meta=(DisplayName="Set Boolean Parameter"))
void SetBoolParameter(FName InName, bool InBool);
	
// サウンドキューへ整数型パラメータを設定する
UFUNCTION(BlueprintCallable, Category="Audio|Components|Audio", meta=(DisplayName="Set Integer Parameter"))
void SetIntParameter(FName InName, int32 InInt);
```



# まとめ
[Branch][Random][Switch]などの本来サウンド再生を呼び出す側でプログラムコードに書いたであろう処理をサウンドキュー内で書くことができるため（変数を渡す必要はありますが）、どのような使い方をするかをサウンドデータ側に書けるのが良い部分かと思います。

記述したサウンドキュー例については、よりよい方法がありましたら教えて頂きたいです。

また、サウンドデータをストリームにするとループなどの繋ぎ部分が上手くつながらず、うまい方法が見当たりません、エンジン側でのサウンド機能修正を期待したいです。:warning: