ADX2 for Unityを他のアセットと一緒に使う(DOTween, UniTask, DoozyUI)

# よく利用されるUnityアセットとADX2の連携

ゲーム向け統合サウンドミドルウェア「ADX2」をプロジェクト内で使う際、ほかのUnityアセット（ライブラリ）との連携をしたい場合があります。

[MusicEngine](https://github.com/geekdrums/MusicEngine)や[宴](https://madnesslabo.net/utage/?page_id=7519)など、ライブラリ自体がADX2との連携機能を提供しているパターンもありますが、サウンド機能に直接のかかわりがないアセット類は特に連携機能が用意されていません。

そこで、Unityでよく使われるアセットをピックアップし、連携拡張クラスの作り方を考えてみます。今回は「DOTween」「UniTask」「Doozy UI」の連携について紹介します。

## DOTweenでADX2のAISAC値を滑らかに変化させる

DOTweenはUnity向けのTweenライブラリです。Unity Asset Storeで販売されています。

![DOTween.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/e1194137-29c9-f02b-93dd-9bc0f466bb23.png)

https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676?locale=ja-JP

DOTweenを使えば、さまざまな値の設定メソッドをTween化できます。ADX2と一緒に使うとしたときに一番恩恵があるのが、「SetAisac」メソッドのTween対応です。

ADXはサウンドデータの中に様々な制御情報を埋め込むことができます。AISAC(アイザック)は、0から1までのパラメータ範囲の中で音の変化を設定できる機能です。
たとえば、「スポーツスタジアムの歓声」というループ効果音が強中弱の３種類あったとき、３つを同時に流しつつそれぞれのボリュームを調整して、普通の盛り上がり～逆転ゴールの超盛り上がり、のような変化を作る処理を考えます。ADX2のAISAC機能を使って、状況に応じてボリュームなどの各パラメーターがどのように変化するか、グラフで設計できます。

![Aisacの例.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/d93f8ab2-3f82-cd53-dda5-1ff23a17b2ef.png)

上の図はADX2に同梱のツールAtom CraftのAISAC設定画面です。黄色い線がボリュームの変化を表しています。Unityからは「0から1まで」の１つのパラメータを渡してあげるだけで、３つのループ音声それぞれのボリュームを同時に変更できます。

便利なAISAC機能ですが、ADX2側にはAISACの値をTweenで変化させる機能がありません。キューの再生中にAISAC値を変更する場合は、Tween処理を入れてなだらかに数値を動かすほうがよいです。これは、DOTweenの導入と、次の拡張メソッドを使うことで実現できます。

```CriAtomDotweenExtension.cs
    public static class CriAtomDotweenExtension
    {
        public static TweenerCore<float, float, FloatOptions>  DOSetAisacControl(this CriAtomSource target, CriAtomExPlayback playback, string aisacName, float startValue,float endValue, float duration)
        {
            return DOSetAisacControl(target.player, playback, aisacName, startValue, endValue, duration);
        }

        public static TweenerCore<float, float, FloatOptions>  DOSetAisacControl(this CriAtomExPlayer target, CriAtomExPlayback playback, string aisacName, float startValue,float endValue, float duration)
        {
            TweenerCore<float, float, FloatOptions> t = DOTween.To(()=> startValue, x=>
            {
                target.SetAisacControl(aisacName, x);
                target.Update(playback);
            }, endValue, duration);
            t.SetTarget(target);
            
            return t;
        }
   }

```
このスクリプトは、CriAtomSourceクラスとCriAtomExPlayerクラスに拡張メソッド「DOSetAisacControl」を追加しています。
内部ではDOTween.Toを使い、AISACの値を更新するSetAisacControlメソッドと、その更新を反映するUpdateを呼んでいます。

呼び出し側は次の通りです。


```呼び出し側.cs

    public CriAtomSource loopSeAtomSource;

    private void Start()
    {
        var atomPlayback = loopSeAtomSource.Play();
        loopSeAtomSource.DOSetAisacControl(atomPlayback ,"YellHeatUp",0f, 0.5f, 2f);
    }

```
この例ではAisac名「YellHeatUp」のパラメータを、0から0.5まで2秒かけて変化させています。
急に音の聞こえ方が変わってしまうと気になります。ADX2とDOTweenを併用することで、滑らかに変化せることができます。
ソースコード全体はgistにアップロードしています。

#### DOTweenでADX2の制御をするための拡張
https://gist.github.com/TakaakiIchijo/ae8ed1f778cf4e3f7eeff5c396fcb0f8

### DOTweenを使ったADX2サウンド再生のフェードイン・アウト

DOTweenはUnity標準サウンドのAudioSourceに「DoFade」というフェードイン・アウトのメソッドを追加します。上記ソースコードではCriAtomSourceメソッドにもDOFaderを用意してあります。同様に、ピッチもDOTween経由で使えるようにしてあります。

ADX2は元からフェードの機構(AttachFader)を持っているほか、データ側にフェードイン・アウトの設定ができるので基本そちらの機能を使います。

ADX2でフェードインフェードアウト
https://w.atwiki.jp/soundtasukeai/pages/37.html

ただFaderの利用ができない場面がまれにあるため(ADX2側の特殊機能を使っている場合など）や、スクリプト側からシンプルに操作したい場合はDOFadeも使えます。

## UniTaskでキューシートの読み込みを非同期待ちする

UniTaskは、C# 5.0から導入された「async/await」をUnityで使いやすくするライブラリです。Unityオブジェクトとの連携や、Unityが提供する処理の多くを非同期待ちできるようになります。

Cysharp/UniTask
https://github.com/Cysharp/UniTask

これをADX2でも使ってみることを考えます。ADX2の利用において非同期で待ちたい処理といったらば、「キューシートのロード」です。StreamingAssetsディレクトリ（または端末内の任意のディレクトリ）からADX2の圧縮ファイルであるACBファイルの読み込みを非同期待ちしたいと思います。

CriAtomCueSheetクラスにGetAwaiterを追加することでawait可能にします。

```ADX2Extensions.cs

using UniRx.Async;

public static UniTask<CriAtomCueSheet>.Awaiter GetAwaiter(this CriAtomCueSheet cueSheet)
{
	UniTask<CriAtomCueSheet> task = new UniTask<CriAtomCueSheet>(async ()=> 
	{		
		await UniTask.WaitWhile(() => cueSheet.IsLoading);
		return cueSheet;
	});
	
	return new UniTask<CriAtomCueSheet>.Awaiter(task);
}

```

上記のスクリプトをどこかにおいておけば、CriAtom.AddCueSheetAsyncメソッドがそのままawaitできるようになります。しかも戻り値CriCueSheetなので、すぐCriAtomExPlayerに渡して再生できます。便利。

```呼び出し側.cs

CriAtomCueSheet cueSheet = await CriAtom.AddCueSheetAsync("cueSheetName","cuesheet.acb","cuesheet.awb");

criAtomExPlayer.SetCue(cueSheet.acb, cueName);
criAtomExPlayer.Start();

```

## Doozy UI のノードエディターからADX2のデータを鳴らす

Doozy UIは、UI開発の統合ライブラリです。UI遷移をノードベースで設計できるほか、豊富なUIアニメーションやプレイヤーカスタマイズ機能などを持ちます。

![doozyuistore.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/074c9a18-2614-99f5-d325-81d64efe4268.png)

https://assetstore.unity.com/packages/tools/gui/doozyui-complete-ui-management-system-138361?locale=ja-JP

Doozy UIはUIの遷移を専用のノードエディタNodyで組んでいきます。サウンド再生にはSoundyというこのアセットにビルドインされた管理の仕組みがあるのですが、ADX2のデータを鳴らすためには機能の拡張が必要です。
こちらはサンプルソースだけでは収まらなかったので、githubにパッケージを用意しました。

#### ADX2forDoozyUI
https://github.com/TakaakiIchijo/ADX2forDoozyUI

この.unitypackageを Doozy UIとADX2が導入されているプロジェクトにインポートすると、連携機能が利用できます。
ちなみにDoozy UIの動作には前述のDOTweenが必須です（無料版で動きます）。こちらのパッケージでは、さきほどCriAtomDotweenExtension.csも一緒に導入されます。

### Doozy Nodeとの統合

Doozy UIが元から用意しているノードと同じようなADX2のノードを用意しました。
キューシートの読み込みとその待ち処理、キューの再生・停止ができます。

![ADX2Nodes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/f5b96af4-a62e-3a69-fbac-0b288d484c84.png)

Nody上の右クリックメニューから「ADX2」を選べばノードが生成できます。Actionを「Load Cue Sheet」に変更して、キューシート名、acbファイルのパス（ストリーミング再生の場合はawbのパスも）を指定します。

![LoadCueSheetAction.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/bc68de14-6c35-ddff-0f09-57bea3732641.png)

キューシートのロードはCRIAtomのインスタンスで起動時にロードしてもかまいませんが、キュー再生のノードを処理する前に読んでおく必要があります。
キュー再生ノードにはキューシート名とキュー名を設定します。

![PlayAction.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/52f65aa1-3d57-913a-18a1-ce1435d97149.png)

これで、Nodyの中で任意のタイミングでADX2のキューを再生できます。

処理の実態としては、シーン内に「DoozyAtomSourceManager」というCriAtomSourceのマネージャークラスを生成して再生を実行しています。


### Doozy UI のボタン入力からADX2のデータを鳴らす

Doozy UIに同梱のサウンド管理ライブラリSoundyは、AudioSouceをベースに作られています。UIの遷移やアニメーションをトリガーとしてサウンドを再生できます。
ADX2を使って音を鳴らしたい場合は、Doozy UIのUI Viewクラスに定義されているUnity Eventのトリガーをフックして音を再生します。

```DoozyActionAtomPlayer.cs
using Doozy.Engine.UI;
using UnityEngine;

namespace Doozy.Engine.ADX2
{
    [RequireComponent(typeof(UIView))]
    public class DoozyActionAtomPlayer : MonoBehaviour
    {
        public string cueSheetName;

        public void PlayCue(string cueName)
        {
            DoozyAtomSourceManager.Instance.Play(cueSheetName, cueName);
        }
    }
}

```

OnClickイベントにキューの再生を紐づける設定は次の画像の通りです。

![DoozyActionAtomPlayer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/146a17e1-5cd1-f3d8-d83d-41add6543dff.png)

このスクリプトを使うためには、前述のDoozyAtomSourceManager.csのインスタンスがシーン内に存在している必要があります。

## ADX2と他Unityアセットの連携
今回「DOTween」「UniTask」「Doozy UI」を選んだのは、私が開発中のゲームで導入しているためです。（プロジェクトからADX2との連携部分のみを取り出しました）
他にもUIやアニメーションに関するたくさんのアセットがUnityにはありますが、それらに関してADX2を連携させたい場合は、ここで紹介する実装が参考になると思います。