CRI ADX2で「アクション」ベースの実装を行う

#まえがき
本投稿は、ゲーム開発者向けサウンドミドルウェア「ADX2」をある程度使ったことがことがある人向けの機能ガイドラインです。

全く触ったことが無い、という場合は、まずは下記の記事にてどう使うのか、どんなことができるのかを見てもらえばと思います。

Unity向け：Unityのサウンド機能をADX2で強化する
https://qiita.com/Takaaki_Ichijo/items/16e6501fc07f5b3b3377

Unreal Engine 4向け：ADX2 for UE4の導入で、一歩上のサウンド表現を（導入編）
https://qiita.com/SigRem/items/4250925f6d66a4fd287a

#アクション機能とは
ADX2は、ゲームの音を「キュー」という単位で扱います。
「キュー」は再生する音声データそのものと、ボリューム・ピッチ・再生優先度・カテゴリ分けタグ情報など、ゲーム用の多数の制御パラメータを含んでいます。

キューは独立したツールAtomCraftで設定を行い、ゲーム側のスクリプトでキューを指定・再生します。再生は、「プレイヤー」と呼ばれるクラス単位で行われます（Unityの場合はAtomSource、UE4の場合はAtom Component）。
つまり、キューとは「何らかの音の再生」であり、パラメータを変更したり、再生を停止したい場合はプレイヤーに対してスクリプトで操作を行います。

代わって「アクション機能」は、このキューの立ち位置を大きく変化させるものです。

キューに「アクション機能」を設定することで、音を再生すること以外の処理についても「キュー」をトリガに処理を実行します。音の停止やパラメータの変更など、これまでスクリプト側で呼んでいた設定をキュー内部に埋め込んでしまい、なんでもかんでも「キューの再生」で実行できるようにします。

ざっくりいうとこう変わります。

■通常
・音を鳴らす：キューを再生
・音を止める：再生中のプレイヤーを停止
・パラメータを変える：再生中のプレイヤーに対してスクリプトで呼ぶ
・フィルタを加える：ADX2ランタイムに対してスクリプトで呼ぶ

■アクション機能を経由
・音を鳴らす：キューを再生
・音を止める：キューを再生
・パラメータを変える：キューを再生
・フィルタを加える：キューを再生

※コピペミスではないです

キューを「音が鳴るための単位」として扱っていた考え方を変え、ゲーム内で発生する音に関わる何らかの「アクション」である、と考えます。
音に関するアクションが発生するタイミングにキューを呼ぶ、その先のデータ内で再生なのか、停止なのか、パラメータの変更なのかを管理します。

音を鳴らすのも止めるのも、パラメータを変えるのもすべて「音に関するアクションだ」として、どのような処理を行うかをすべてAtom Craft側で設定し、スクリプトからはアクション（キュー）を再生するだけ、というワークフローになります。

これまでは「〇〇の音を鳴らす！」という処理単位で設計していたものを、「〇〇という音に関するアクションが発生する！」という、一歩抽象化する設計でゲームの音を作っていくことになります。

## アクションで操作できるもの
アクションで操作できるものは、キューの「再生・停止・ポーズ・再開」、「セレクタラベルの変更」「キューパラメータの変更」です。

キューパラメータの変更は「再生パラメータアクション」という名前で呼ばれており、数値を滑らかに変化できることが特徴です。ボリュームを滑らかに変えてフェードアウトを実現したり、DSPバスのセンド量を切り替えてフィルタの強弱を変更できます。
また、AISACの切り替えも再生パラメータアクションで実装できます。

## アクションの活用方法
アクション機能が嬉しい点としては、実装者が「今どのプレイヤーで何が鳴っているか」を気にせず再生停止を呼べること、とりあえずキューをアクション発生地点で読んでおけば、中身のアクションはツール側で自由に変更できる点が魅力的です。

プログラマーとサウンドデザイナーが分かれている場合は特に効力が大きいです。
アクションキューの再生さえ呼ばれていれば、そのアクションの時点でどんな音が鳴るか、あるいはどんな音が停止されるか、フィルタがどうなるかをサウンドデザイナーが自在に決めることができます。

たとえばプレイヤーの剣を構える、振る、止める、剣をしまうのアニメーションの開始と停止時点にとりあえずぜんぶアクションキューを呼ぶようにしておきます。

呼ばれたキューの名前で武器名を判定してセレクタラベルで音を切り替え、剣を振った時に風切り音を再生開始して、振りが止まった時に再生を停止する、といった音付けが、プログラム側の改修をせずに設定できます。

実装例としては、ポーズ中に音を変化させる演出に利用する方法を公式マニュアルが紹介しています。

https://game.criware.jp/manual/adx2_tool/latest/craftv2_tips_performance_pause.html

# アクション機能を使ってみる
実際にAtom Craftでアクション機能を設定してみます。

たとえば、「ゲームキャラクターのセリフ音声を流す」処理と、「キャラクターが途中で歩き出したらセリフ音声が中断される」処理を考えてみましょう。

通常は、「キャラのセリフ」「足音」を用意して、セリフを再生後、足音を再生時にキャラのセリフがまだ再生中だったら停止する、というスクリプトを組む形になります。

アクション機能を使って「セリフの停止」というキューを作成・呼び出すことで、スクリプト側での再生判定と停止処理を不要になります。

まずは、シンプルな波形を１つ含んだキューを用意します。

![CRI Atom Craft  LE Ver.3.40.17 (built on Jun 10 20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/1194d803-9b82-0dfb-fd78-9daaa676ab3e.png)

キュー名はBoyStartTalkにしています。これは「キャラが何かしゃべりだす」というアクションである、という雰囲気です。

では、次のBoyStartMoveですが、これは「キャラが歩き出した」というアクションになります。
このキューには別途作った足音を自動繰り返し再生する設定になっていますが、同時にアクションを定義した「アクショントラック」でBoyStartTalkの停止を実行しています。

![actiontrack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19010/fbe6d97f-df37-f0dc-c669-7af8a72290be.png)

これにより、スクリプト側でキャラが話すときにBoyStartTalkキューを再生、歩くときにBoyStartWalkキューを再生と指定しておくだけで、「音の停止」も含めた演出がAtom Craftで指定可能になります。

## アクション機能のデメリット
以上が簡単なアクション機能の説明になります。アクションは色々な処理がキューの再生だけで済むので魅力的に見えますが、一方でデメリットもあります。それは「サウンドデザイナーの手間が増える」ということです。

### キューの総量が増え、データ作成の手間が増える
「音を作る」前に「音を鳴らす/止めるアクションを定義する」という手間が挟まるため、ツール上での操作が煩雑になります。

また、ゲーム中のアクションそれぞれをユニークなキューとして設定する必要があるので、キューの数も増え、ゲーム全体で管理する名前が多くなります。

### 分業スタイルの場合、プログラマーが想定していない処理負荷が発生する可能性がある
多数のスタッフで開発している場合は、キューをあらかじめたくさんのタイミングに埋め込んで置き、サウンドデザイナー側にどんな風に音が鳴る・止まるかを一任できます。これにより、サウンドデザイナーの自由度が上がります。
しかしながら、キューの中でフィルタなど様々な処理を呼べるので、意図せず重い処理が重なってしまう可能性があります。

これはどちらかというとコミュニケーションの問題で、プログラマー側が負荷の指標を設計してサウンドデザイナーへあらかじめ開示し、それによってサウンドデザイナーが負荷を意識した設計ができるのであれば問題はありません。

サウンドデザイナー側がAtom Craftのプロファイラーやセッション機能を駆使して、処理負荷が増大しないかチェックしながら組んで行けば大丈夫です。

### サウンドデザイナーの責務が重くなる
やれることが増える≒やらなくてはならないことが増える、ということです。前述した負荷計測も（もちろんこれまでもサウンドデザイナーがチェックできることが望ましかったですが）、アクション機能ベースのワークフローではその重要性が高まります。
逆に言えばその分プログラマーを介さずに作り込みが可能になり、やりがいがあるとも言えます。

#まとめ
アクション機能はAtom Craft側でできることが増えるため、ワークフローによっては恩恵が大きいです。特に、責務がはっきり分かれたチーム開発ではその真価を発揮しそうです。

しかしアクション機能を使うとなったら、アクションでできることはすべてアクションに寄せ、スクリプトからはアクションを含むキューの再生と一部の設定管理しかしない構成にするべきだと考えます。中途半端に数カ所だけアクションを使って...とやると、不具合が起きた時にどっちで起きているのか分からなくなるためです。