ADX2のループ再生、どの機能を使ったら良いの？


# 選択肢が多いからこそ
オーディオミドルウェア CRI ADX2には、目的のサウンド演出を手軽に実現するための機能が数多くあります。
同じ目的を達成しようとしても複数の手段が考えられる場合があり、どの手段を用いたら良いのか迷うことがあります。

そういった場合の判断基準として、例えば
* 実装の手軽さ
* 修正の手軽さ
* 演出結果の精度

などがあると思いますが、今回は特に手段の多いループ再生（繰り返し鳴らし続ける音）について、細かい違いと仕様変更があった場合の軌道修正のしやすさ、というものについて書いてみます。

## 繰り返し鳴らす手段あれこれ
例えば数字やゲージのカウントアップアニメーションや、リールや歯車などが回転するアニメーションのように、短い音を繰り返したくさん鳴らして表現したい演出を例として、ADX2の機能を用いた実装手段を考えてみましょう。

手段1:Cueに<font color="FireBrick">ワンショットのSE</font>を置き、アニメーションに合わせて<font color="MediumBlue">都度再生</font>する
手段2:Cueに置く<font color="FireBrick">波形ファイル</font>に<font color="MediumBlue">ループマーカー</font>を指定する
手段3:Cueに置いた波形ファイルの<font color="FireBrick">ウェーブフォームリージョン</font>に<font color="MediumBlue">自動繰り返し設定</font>をする
手段4:<font color="FireBrick">Cue</font>に<font color="MediumBlue">ループマーカー</font>を設定し、単音の波形を繰り返し鳴らす
手段5:Cueに<font color="FireBrick">ブロック</font>を指定し、<font color="MediumBlue">ブロックの繰り返し回数</font>を無限にする
手段6:Cueに<font color="FireBrick">アクショントラック</font>を追加し、<font color="MediumBlue">自身のCueを繰り返し呼ぶ</font>
手段7:Cueにループマーカーを設定し、ループ内で<font color="FireBrick">Cueリンク</font>を用いて<font color="MediumBlue">ワンショットのCueを繰り返し呼ぶ</font>


### 手段1:Cueに<font color="FireBrick">ワンショットのSE</font>を置き、アニメーションに合わせて<font color="MediumBlue">都度再生</font>する
![loopsound_case1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96688/3a30e34b-8eb4-9fef-140b-9037f1dec1b5.png)
サウンドデータ側ではワンショットの音だけを用意し、アニメーションに合わせて毎度再生イベントを呼ぶ、ある意味スタンダードな方法です。

サウンドデータ側はいたってシンプル且つ、Cueに設定できる各種ランダマイズ要素を扱う際に結果が分かりやすいというメリットがあります。

### 分解能に気をつけよう
注意したいのは音の鳴るタイミングの細かさ（以下、<font color="MediumBlue">分解能</font>と表記します）が<font color="FireBrick">**ゲーム内の単位時間に依存する**</font>点です。仮に60fpsで動作するものなら約16.67msec、30fpsなら約33.33msecです。今回、手段2〜7で作ったデータは80msec周期で音が鳴るように作ってありますが、同様の頻度で鳴らす場合に音の間隔が不自然になる場合もあります。
![可視化した発音タイミング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96688/a9e29dc9-b4c2-599e-b778-9c90b6c1b505.png)
上記の例では音の鳴る間隔が(5f→5f→5f→5f→4f→5f→)…や、(3f→2f→3f→2f→2f→)…と繰り返す形になり、等間隔とは言えません。聞こえ方が気にならない方も多くいらっしゃいますので妥協できるポイントでもあります。

そもそもフレーム単位で管理するパターンアニメーションで作られている場合はこのような問題になりにくいのですが、<font color="FireBrick">キーフレームアニメーションの補完</font>であったり、<font color="FireBrick">毎フレーム決まった角度の回転をさせる</font>…といった作り方の場合に起きやすいので、<font color="MediumBlue">プログラマーさんと相談しつつ進める</font>とよいでしょう。


### 手段2:Cueに置く<font color="FireBrick">波形ファイル</font>に<font color="MediumBlue">ループマーカー</font>を指定する
![loopsound_case2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96688/72efe67c-3654-1e90-98d8-a4a7705a730c.png)
波形にループマーカーを設定するため、分解能…というか繰り返しタイミングの精度はサンプリング周波数単位です。波形編集ソフトで設定するため、何か修正がある場合は波形編集ソフトに戻らないといけませんが、仮実装としての手っ取り早さはかなりポイント高いです。

### 手段3:Cueに置いた波形ファイルの<font color="FireBrick">ウェーブフォームリージョン</font>に<font color="MediumBlue">自動繰り返し設定</font>をする
![loopsound_case3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96688/7123ffce-c203-ad4c-2b42-3c6c365e64e0.png)
手順1と2のハイブリッド的な印象です。手軽さは2に次いで非常に楽です。
ワンショットの波形をタイムライン上に自動で繰り返し並べていくわけですが、間隔の調整が容易です。
分解能はmsec単位です。

### 手段4:<font color="FireBrick">Cue</font>に<font color="MediumBlue">ループマーカー</font>を設定し、単音の波形を繰り返し鳴らす
![loopsound_case4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96688/642f55a2-cd13-6c70-e30b-d3f98d1b5d6b.png)
手順3に近く、出音もほぼ同じです。分解能もmsec単位です。
細かい違いですが、手順3の場合は自動繰り返しのパラメーターとしてランダム要素があるので発音の間隔やニュアンスをわざとバラけさせるような演出のアレンジが可能です。
手順4では何か他のトリガー（アクションイベントやコールバックなど）を追加する事で、発音するたびに何かを行いたい場合に便利です。

### 手段5:Cueに<font color="FireBrick">ブロック</font>を指定し、<font color="MediumBlue">ブロックの繰り返し回数</font>を無限にする
![loopsound_case5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96688/18e79312-c502-0773-7f73-bc4f98ced51d.png)
手順4に近いです。仮演出として、今後その演出の前後に何か動きが追加されそうな場合はこの手段で実装するのもアリかもしれませんが…無理に使う必要はないでしょう。

### 手段6:Cueに<font color="FireBrick">アクショントラック</font>を追加し、<font color="MediumBlue">自身のCueを繰り返し呼ぶ</font>
![loopsound_case6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96688/c3899a88-241a-8377-5dfc-fe17b81f1981.png)
毎回トリガーされるので再生されるCueの数が手段1と同じです。
細かい理由は不明ですが、波形にループマーカーをつける手段2に次いで、繰り返しタイミングが正確です。
後ほど、比較画像を載せます。


### 手段7:Cueにループマーカーを設定し、ループ内で<font color="FireBrick">Cueリンク</font>を用いて<font color="MediumBlue">ワンショットのCueを繰り返し呼ぶ</font>
![loopsound_case7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96688/55fe0814-e103-bb2d-5254-ccdfaea347b3.png)
リンク先のワンショットCue側で色々と遊びを含む演出をしたい時に利用したら良さそうな手段です。
ゲーム内の状況に合わせて音色を変えたい、といった時には有効かと思います。

## プロファイラーによる比較
手段2から7の再生状況をプロファイラーで見たものを並べました。
結果は地味に違います。
![プロファイラーによる比較.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96688/e8f411c3-660a-a3e8-a4bf-56990855c0cf.png)
オレンジ色がCueの再生状態、水色がWaveformの再生状態を表します。手段1のワンショットは割愛していますが、手段7で大量に呼び出しています。

CueやWaveformを繰り返し呼ぶ系では発音数の上限に気を使う必要が出て来やすいことと、繰り返す手段によってはあ間隔に若干のバラつきが生まれる、という結果になりました。
手段6の周期の安定っぷりがちょっと意外な結果でした。
手段7で一度case1のCueが抜けているのにWaveformの再生が記録されているのは…プロファイラー側の取り零しでしょうか。

# 比較を終えてみて
どの実装手段がベスト、というのは状況次第なのですが
### 仕様が確定するまで
<font color="FireBrick">手段1、2、3が手堅い</font>のではないかと思います。
### 繰り返しタイミング最重視
手段2でしょう
### 繰り返しタイミング以外がFixしていて、Fix後にサウンドデータの差し替えだけ可能
手段3
QA中とかコード変更させてもらえないけどサウンドデータだけなら致命的なバグは起きにくいから差し替えが許されやすいみたいな状況
### 繰り返し前後に追加演出あり
手段1か手段5も良さそう
### 演出によって鳴らすCue（の内容）を変えたい
手段7 (ワンショットで鳴らすのはセレクタCueなど)

# 総括
ある程度、仕様が固まるまでは手段1〜3で様子を見て、その後の演出の幅を広げていく際に、作り込みたい要素によって4〜7の手段を使い分けていただければ良いのかなと思います。
もちろん手段1〜3のままでも良いかもしれません。
全ては目的次第という事で、実装例や判断基準の紹介でした。

最後までお読みいただき、ありがとうございました。