ADX2 for UE4でつくるクォンタイズ（テクニック補完編）

# はじめに
アンリアルエンジン4とサウンドミドルウェア「ADX2 for UE4」を連携させ、インタラクティブミュージックの要素である「クォンタイズ」に様々な機能を追加し、より細かい演出や利便性を加えてみます。

クォンタイズの基本的な実装についての記事はこちら
**ADX2 for UE4で作る、インタラクティブミュージック中のクォンタイズ機能**
https://qiita.com/SigRem/private/17d5f52b1b1b2e7a1dc1

https://twitter.com/sleepyslowsheep/status/1448548617694838791?s=20

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

記事執筆時点のADX2 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


# 実装

## コンボシーケンシャルによる演出

ADX2の機能「コンボシーケンシャル」を使い、一定時間内の発音回数によってサウンドを変化させていく手法です。
演出にメリハリがつくだけでなく、評価の高いゲームプレイをした際の明確さやハイスコアを取る気持ちよさを増幅させる効果がありそうです。

コンボシーケンシャル機能を使うには、AtomCraftで対応するキューを作成する必要があります。
ワークユニットツリーの任意のキューシートを右クリックし、「新規オブジェクト」→「キュー『コンボシーケンシャル』の作成」を選択してキューを作成します。
![A01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/9b1fa7be-14d4-6ceb-7f98-522c537df2a0.png)
キューのタイムラインにて、連続して再生するためのサウンド（マテリアル）を1トラックずつ配置していきます。
![A02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c2d87932-55ce-fbe3-2d19-bf6f35744e3e.png)
ワークユニットツリーにてキューを選択するか、タイムラインの一番上のキュー本体をクリックして選択します。
![A03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a2463297-7367-c3c6-a3aa-9be151f1100c.png)
インスペクターを下にスクロールしていくと「特殊再生」の項目があります。
「コンボ間隔」を入力すると、その時間が経過するまでに再度キューが再生されることでコンボが成立します。
単位はミリ秒なので、「2000」と入力すると2秒以内の再生でコンボが成立し、2トラック目以降が再生されることになります。
![A04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d2cba5a8-3b04-de3e-854b-83bbe8257f19.png)
「コンボ戻り」はコンボが最後まで再生された後、さらにキューが呼び出された場合に再生されるトラックです。
「0」とするとまた0トラック目からコンボがループしていき、最後のトラック番号を指定するとコンボが続く限り最後のトラックが再生され続けます。
![A05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c99e290d-6c6f-22b4-d07a-9ec334c9da8f.png)
また、コンボ確率によりコンボが再生されるかどうかのブレを作ることができます。
スコアやプレイのうまさによるコンボシーケンシャルを呼び出す場合は、プレイングを正当に評価してあげるため確率は100%のままがいいでしょう。
![A06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c481f14f-248c-400b-e8b0-476943ec821e.png)



## より長いループに対応する

基本実装では4ビート単位でカウントしていましたが、カウント数を増やすことでより長いループや演奏に対応します。

対象のキューを選択し、タイムライン上部にある「BeatSync」マーカーをクリックして選択します。
![B01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/1b6d7694-aa98-4bda-45a1-7a25ed0d0fa5.png)
インスペクターにて、「ビート同期」項目にある「分子」を「4」から「8」に変更します。
これでビートのカウントが1小節でなく2小節でリセットされることになります。
![B02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/ace793f2-6c4c-433d-7f93-a82f29aa0995.png)
もしさらに細かく刻みたい場合は「16」に変更してみるのもいいでしょう。この場合は4小節ぶんカウントが持続します。
![B03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/e74e15a3-da6f-8f29-8b2e-9935894d4c4e.png)
UE4にキューシートをインポートし、ブループリントにて「Beat Sync Info」の「Beat Cnt」を文字として出力してみます。
![B04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/9001ca53-f5a3-9683-8da3-846d236caea7.png)
設定したビート数までリセットされずにカウントされています。
![B05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/987296aa-fa82-2657-3d46-71d5c05a18bd.png)
これを利用して、「2小節毎にしか鳴らないサウンド」や「ループの始めにクラッシュを鳴らし、以後4小節は再生しない」などの演出を実装することが可能になります。



## より細かいビートを検知する

基本的な実装では1小節に4ビートをカウントしていましたが、8カウントにしてより細かいビートを刻めるようにします。

AtomCraftで対象のキューを選択します。
力技ではありますが、ビート同期情報に倍のBPMを入力し、ビートのカウント数を2倍にすることで、ビートを刻む数を2倍にしています。
この際、1小節あたりのビート数も2倍に増えることを考慮して「分子」のパラメータも2倍にするといいでしょう。
![C01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/67cfe25c-9082-33a7-86f8-b476d7c73122.png)
UE4に持っていくと、基本実装の2倍の速度でビートが刻まれるようになります。


## 入力とビートによる再生のずれを軽減する

ビートがカウントされた直後にキーを入力すると、次のビートまでに待ちが発生するため音の再生が遅れた印象になってしまいます。キューの再生タイミングを緩和することで、入力と再生のずれの印象を軽減してみます。

まずは基本実装で処理を書いたレベルブループリントを開きます。
![D00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/03cd963a-1666-7d4b-d4cc-ae6547735507.png)
新規に変数を追加します。型はfloatで、適当に名前をつけておきましょう。
![D01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/0e554683-1260-da72-4d39-e1a5e4686660.png)
**Event Tick**で「Count」に「Delta Seconds」を加えます。これはゲーム中の経過時間をカウントする処理です。
また、ビートを検知したタイミングで変数「Count」を「0」にリセットします。
![D02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c253c030-b4d5-8bc1-acf6-4c6d6e937c20.png)
これにより、変数「Count」は**前回のビートからの経過時間**を記録するものになります。

あとはキー入力時に経過時間を参照し、一定値以下であればそのまま再生する処理を加えます。
いつでもサウンドの再生処理を呼び出したいので、カスタムイベントを追加し再生処理につなげておきます。
![D03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/395a17b4-d90f-2cf1-97ec-d218e1776ff2.png)
キー入力時に**Branch**で「Count」が一定値以下であることを確認し、Trueであればカスタムイベントを呼び出します。
![D04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/4da660d5-510f-3088-73c3-73877f9b4052.png)
また、キー入力時に変数「Count」の値を画面に出力するとしきい値が設定しやすいかと思います。
![D05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d0fcfc2a-3dfe-ceb2-0c80-b430e840802f.png)
テスト再生してみましょう。
キーを入力すると前回のビートからの経過時間が出力され、またその値が「0.2」以下であれば次のビートを待たずにサウンドが再生されるはずです。
![D06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/b67f2574-8859-dbf3-9db6-dbd5bc6d60d7.png)
入力を試してしきい値のベストタイミングを見つけ、プレイヤーの入力とビートのタイミングのちょうどいい距離感を見つけてみましょう。