ADX2LEとUnity標準オーディオ比較

「ADX2LEとUnity標準オーディオ比較」の編集履歴(バックアップ)一覧に戻る
ADX2LEとUnity標準オーディオ比較」を以下のとおり復元します。
*目次
#contents()

*ADX2とUnityの標準オーディオの比較
回避策、解決策、限定された条件などにより捉え方は異なるかと思います。
ここでは、優劣を決めるようなものではなく、純粋に比較してどう違うかの理解を深めてもらえたら幸いです。

なお、ADX2とADX2LEの区別はしていませんが、一部ADX2のみの機能の紹介もまざっています。その場合は、ADX2LEと区別して表記しています。

**リッチなエフェクトがiOS/Androidで使える(Unity IOS/AndroidのPro版なしで)
Unityでリバーブなどエフェクトを使いたい場合Unity Pro版が必要ですが、iOS Pro/Android Proそれぞれでも必要だったりします。
→[[Unity Store>https://store-jp.unity3d.com/]]
ADX2はUnityエディタの都合上Unity Pro版(約15万)が必要ですが、iOS Pro/Android Pro版は必要ありません。
つまり、iOS/Androidでエフェクト付きの音を鳴らしたい場合にUnity iOS Pro/Android Pro版が要らない。(約30万くらいお得)
| - |ADX2|Unity標準(4.x)|Unity標準(5.x)|
|Unity Pro|必要|必要|不明|
|iOS Pro|不要|必要|不明|
|Android Pro|不要|必要|不明|

- Unity4.x
リスナーか、ソース側にエフェクトがつけられる。
- Unity5ではミキサーが登場する
UnityEditor上でミキサーツリーを作って、エフェクトをつけられるようになる。どのバス(カテゴリ?ストリップ?)に所属するかをソース側で指定することができるようになる。
バスのルーティングもダイナミックに変更が可能な様子。

-ADX2
バスエフェクトとして作成、スナップショットなども専用ツール側で作成する。どのバスを使うかはキュー側で設定する。
UnityEditor上では、Dspバス設定名の指定、スナップショット名の指定のみ。

**つなぎ目のないループ再生
| - |ADX2|Unity標準|
|ループ|簡単|面倒|

- Unity標準では全体ループは可能。
さらに、AudioSample数によるDelay再生など駆使するとイントロ付きループや、ビートに合わせるとかも可能なはず。
 sample_double = (int)((sources [clipName].audio [0].clip.samples - audio.timeSamples) % 88200);
 this.sources [clipName].audio [0].Play ((ulong)(sample_double));	// サンプル数遅延して再生開始される
オーディオソースを2つを交互に使うなど必要(clipを切り替えると音が途切れる、遅延でオーバーラップしている時一時的に2つになるなど)
波形のループサンプル数など何らかの方法でUnityの再生側に伝達する必要がある。 

また、mp3などのコーデック時は、ループにするとサンプルの先頭にループ分の情報が付与されるため、正確に連結再生させるにはそのサンプル数分考慮して再生リクエストをする必要がある。
→ちなみにごく短い波形であれば生wavを再生するとかもあり。BGMとか長いデータの場合はメモリを圧迫するので注意。
→Unity5になれば、ADPCMやOgg/Vorbis拡張があるので、そちらは素直にループができるかもしれない。


- ADX2の場合は、波形のループ再生(サンプル単位)が可能。
単純に波形側にループポイントがあるだけで、イントロ付きループも可能。(圧縮しても情報が保持される)

- シーケンスループによる1Shot波形のループ(余韻付き)といった事も可能。
ループかそうでないかは、データに設定されているので、プログラムからはただ再生を呼ぶだけで良い。

#ref(SeqLoop.png)シーケンスループの例

**オーディオソース
|-|ADX2|Unity|
|複数再生|可能|単音再生のみ|

- Unityの場合、複数再生をするには、PlayClipAtPoint()などの関数もあるが、AudioSourceが発音数分増えてしまうので、大量再生時は注意が必要。
 AudioSource.PlayClipAtPoint(audioClip_breakWall,pos);

例えば、呼び出し時にカウンタなどで制限したり、あらかじめAudioSourceを発音数分用意して空いているものを再利用するなどが考えられる。
 public AudioSource[] audio = new AudioSource[2]; //2個用意
 int playCount = 0;
 void Start(){
		for(int i = 0 ;i<crashSoundList.Length;i++){
			AudioSource crashSound = gameObject.AddComponent<AudioSource>();
			crashSound.clip = breakWall;
			crashSound.rolloffMode = AudioRolloffMode.Linear;
			crashSoundList[i] = crashSound;
		}
 }
 void Play(){
		crashSoundList[playCount%(crashSoundList.Length-1)].transform.position = pos;
		crashSoundList[playCount%(crashSoundList.Length-1)].pitch = pos.x;
		crashSoundList[playCount%(crashSoundList.Length-1)].Play();		
		playCount++;
 }

- ADX2の場合、発音数制限は、コーデック単位、カテゴリ単位、キュー単位、ウェーブフォーム単位で行う。
音に優先度を持たせる事で、発音数限界時に、優先度の高い音が鳴るように動作する。
ので、データ側でリミットをかけておくだけで、基本的に再生するだけで良い。

**オーディオクリップ
|-|ADX2|ADX2LE|Unity|
|オーディオクリップ|なし|なし|○|
|波形指定再生|○|なし|○|
- Unityは、wavやmp3,oggを直接再生可能。
- ADX2は、ACBという形のパッキングされた独自形式ファイルを持つ。
ファイル指定再生もサポート(Pro版)しており、wav,adx,hcaを直接再生可能。(一部機種ではmp3も対応)

**音楽的なピッチ指定方法
ここでいうピッチ変化は、アナログテープやレコードスクラッチのように変化する事。
速度を上げれば音程も高く、ゆっくりまわせば音が低くなります。1.0で等速(元波形の速度)
- Unityではピッチは、再生速度になる。2.0と入れればオクターブ上、-1.0と入れれば逆再生。
Unityでcent単位にするには以下のような計算をすると良い。
 ratio = Mathf.Pow(2,pitch/12.0f); // ピッチから再生速度
 pitch = 1200.0f*logf(ratio)/logf(2.0f); //再生速度からピッチ
- ADX2ではピッチをcent単位で指定する。100centが1半音なので、1200centでオクターブ上。逆再生は不可。
※ちなみに0を指定すると無音を無限に再生し続けます。(時間が進まない・・・)

**ACB(複数サウンドの再生定義ファイル+メモリサウンドのパッケージ)
|-|ADX2|Unity|
|パック|○|なし|
- Unityでは、波形単位、あるいはUnityPackage単位など波形の持ち方が考えられる。
- ADX2ではStreamingAseets以下にacbファイルとして圧縮済み波形データのパックとして置かれる。

**ACF(エフェクト、カテゴリ、発音数制限などの情報ファイル)
|-|ADX2|Unity|
|全体設定|○|なし|
- Unityでは、エフェクトやカテゴリ(タグなどで)、あるいは発音数制限などはスクリプトでといったようにファイルがバラバラになる傾向。(そもそもUnityはComponentの組み合わせが基本なので)。うまく扱うことで、プレファブ化してもったりといった事も可能かもしれない。
- ADX2では、StreamingAseets以下にacfというファイル1つに情報が収まった形となる。
**エフェクト(リバーブ)
|ADX2|Unity|
|○|○|
- Unityの場合、リバーブゾーンを指定する。Editor上で視覚的に分かりやすく配置が可能となっている。
- ADX2の場合、バスセンドエフェクトとして、音毎にバスセンド量の設定を行う。

**リバーブゾーン
|ADX2|Unity|
|なし|○|
- Unityの場合、リバーブゾーンを指定する。Editor上で視覚的に分かりやすく配置が可能となっている。
- ADX2の場合、AISACを使ってリバーブゾーンのようなものを構築する必要がある。
 float dist = 0.5f;
 source.SetAisac("Distance",dist);

**発音数制限
|-|ADX2|Unity|
|制限処理|○|なし|
- Unityはメモリがある限り発音可能。(発音数が増えると処理落ち、メモリ不足などが発生)
- ADX2はCriWareLibraryInitializer上で、あらかじめコーデック単位で最大発音数を設定可能。(初期化段階で固定でメモリ確保)
同時ストリーム数など細かい設定も可能。ただし、初期化時のみ(途中で変更できない、変更するには再初期化が必要)
#ref(criwareLibinitiallizer.png)CriWareLibraryInitializerの例
**3Dサウンド
|-|ADX2|Unity|
|3Dサウンド|○|○|
- Unityの場合、AudioClipで3Dかどうかを決め、AudioSource側で3Dの減衰距離、カーブ、ドップラーなど変更できる。
#ref(unit3dsound.png)Unity 3DSetting
- ADX2の場合、CRI Atom Craft側で3Dの減衰距離などを指定する。後からドップラーを強くといった設定変更はできない。データ側であらかじめ設定しておく形となる。

#ref(Pan3d.png)Pan3Dの例
**センター、LFE出力
|-|ADX2|Unity|
|センター/LFE出力|○|なし|
- ADX2ではセンター、LFEの出力を別途指定可能。ただし、5.1ch環境でないと音が出力されなくなる場合もある。ハード側でダウンミックスされて音が聞こえる(センターはL,Rから)といった事もあるので、扱う場合は注意が必要。
Pro版ではADX2側でソフトダウンミックスすることで差異を軽減するといったオプションあり。

**Sin生成などからの再生
|-|ADX2|ADX2LE|Unity|
|生成再生|△|なし|○|
- Unityの場合、AudioのCallbackを使う。OnAudioReadなどでメモリを渡す。
- ADX2の場合、BusのCallbackを使う。(エフェクトを掛けた再生が可能、マイク入力後や、音声合成音などにエフェクトをかける
△なのはUnityの場合Callback系が不自由なため、対応には若干ネイティブコード側の対応が必要。

**シーケンス再生
|-|ADX2|Unity|
|MOD再生|×|○|
|シーケンス再生|○|×|
- Unityの場合 Modファイルなどに対応していたりするらしい...
- ADX2の場合、キューそのものがシーケンス化可能。CRI Atom Craft上でタイムライン上に波形を並べて作成する。
 シーケンスか波形なのかは意識せず、ただ再生するだけで良い。

**エフェクト
- UnityはAudioSourcemまたはListener側にコンポーネントを追加し設定する。
#ref(unityReverb.png)UnityReverb設定の例
- ADX2はCRI Atom Craft側で設定する。
#ref(dspbus.png)DSPバス設定の例
 CriAtomEx.AttachDspBusSetting("DspBusSetting_0"); //バス変更
 float depth = 1.0f;
 int busNo = 1; //reverb
 atomSourceSe.SetBusSendLevelOffset(busNo,depth);

**エフェクトの種類(サウンド毎)
AudioSourceレベルで個別のサウンドごとに設定可能なエフェクトの種類です。
|-|ADX2|Unity|
|エフェクト種類|約10種|約3種|

|-|ADX2|ADX2LE|Unity|
|ボリューム|○|○|○|
|ピッチ|○|○|○(-2~2倍速)|
|パン2D|○|○|○|
|パン3D|○|○|○|
|センター/LFE/バスセンド|○|○|×|
|バイクアッドフィルタ|○|○|×|

- Unity:ボリューム、ピッチ、パン(2D,3D)
- ADX2:ボリューム、ピッチ、パン(2D,3D)、センター、LFE、バスセンド、バンドパス(ハイ、ロー)、バイクアッド(ローパス、ハイパス、ローシェルフ、ハイシェルフ、ピーキング、ノッチ)
UnityもADX2もSourceに対して、ボリュームやピッチ、パンの操作が可能。

**エフェクトの種類(Unity:AudioSourceコンポーネント系、ADX2:バス系)
|-|ADX2|Unity|
|バスエフェクト種類|約20種|-|
|AudioSourceコンポーネント|-|6種|

|-|ADX2|ADX2LE|Unity|
|ローパス|○|○|○|
|ハイパス|○|○|○|
|ローシェルフ|○|○|×|
|ハイシェルフ|○|○|×|
|ピーキング|○|○|×|
|ノッチ|○|○|×|
|エコー|○|○|○|
|ディストーション|○|○|○|
|リバーブ|○|○|○|
|コーラス|○|○|○|
|ディレイ|○|○|×|
|コンプレッサ|○|○|×|
|EQ|○|○|×|
|ピッチシフタ/フォルマント調整(FFT)|○|○|×|
|フランジャー|○|○|×|
|振幅解析器|○|○|×|
|サラウンダ|○|○|×|
|タイムストレッチ(グラニュラ系)|○|×|×|
|タイムストレッチ(FFT)|○|×|×|
- Unity:ローパス、ハイパス、エコー、ディストーション、リバーブ、コーラス
- ADX2:バンドパス(ハイ、ロー)、バイクアッド(ローパス、ハイパス、ローシェルフ、ハイシェルフ、ピーキング、ノッチ)、ディレイ、エコー、ディストーション、リバーブ(I3DL2)、コーラス、コンプレッサ、イコライザ(3Band)、ピッチシフタ、フランジャー、振幅解析器、サラウンダ

**エフェクトパラメータの操作
|-|ADX2|ADX2LE|Unity|
|エフェクトパラメータ操作|○|×|○|

- Unityでは、Componentに対して操作が可能。動的(プログラム上で)自由に付けたり外したりが可能。
- ADX2では、バスのエフェクトに隠蔽されているため直接操作できない。エフェクトアルゴリズムの変更や効果の掛け方などは、DSPバス設定であらかじめ決めておく必要がある。
また、DSPの設定パターン(パラメータ違い)はスナップショットの切り替えで行えるが今のところPro版のみ。
代わりにAISACなど経由してセンド先、センド量などを操作可能となっている。

**レベル解析
|-|ADX2|ADX2LE|Unity|
|レベル解析|○|○|○|
|FFT解析|○|×|○|
|ピッチ解析|○|×|×|
|BPM解析|○|×|×|

- UnityではFFT解析結果を取得できます。
 samples = audio.GetSpectrumData(128,1,FFTWindow.Triangle);
SourceまたはListenerのどれか1つのみ取得できます。

- ADX2ではバス(8個)のレベルをチャンネル(LR)毎に取得できます。
 CriAtom.SetBusAnalyzer(true); 					// バス解析器を有効化
 CriAtomExAsr.BusAnalyzerInfo lBusInfo = CriAtom.GetBusAnalyzerInfo(0);//	Lch
 level = lBusInfo.peakLevels[0];
※ADX2 Pro版ではFFT結果も取得できます。

**オーディオのルーティング変更
通常は、5.1ch(L,R,C,LFE,sL,sR,Ex1,Ex2)という出力固定ですが、
プレーヤー毎にチャンネルの出力ルーティングを変更する事ができます。
例えば、2ch*4(L1,R1,L2,R2,L3,R3,L4,R4)といった設定
   /* 音声データの0チャンネルと1チャンネルを他のスピーカーへルーティング */
   criAtomExPlayer_SetSendLevel(player, 0, CRIATOMEX_SPEAKER_FRONT_LEFT, 1.0f);            // 0ch->L
   criAtomExPlayer_SetSendLevel(player, 1, CRIATOMEX_SPEAKER_FRONT_RIGHT, 1.0f);           // 1ch->R
   criAtomExPlayer_SetSendLevel(player, 0, CRIATOMEX_SPEAKER_FRONT_CENTER, 1.0f);          // 0ch->C
   criAtomExPlayer_SetSendLevel(player, 1, CRIATOMEX_SPEAKER_LOW_FREQUENCY, 1.0f);         // 1ch->LFE
   criAtomExPlayer_SetSendLevel(player, 0, CRIATOMEX_SPEAKER_SURROUND_LEFT, 1.0f);         // 0ch->Ls
   criAtomExPlayer_SetSendLevel(player, 1, CRIATOMEX_SPEAKER_SURROUND_RIGHT, 1.0f);        // 1ch->Rs
   criAtomExPlayer_SetSendLevel(player, 0, CRIATOMEX_SPEAKER_SURROUND_BACK_LEFT, 1.0f);    // 0ch->Lb
   criAtomExPlayer_SetSendLevel(player, 1, CRIATOMEX_SPEAKER_SURROUND_BACK_RIGHT, 1.0f);   // 1ch->Rb
|-|ADX2|ADX2LE|Unity|
|ルーティング変更|△|×|×|
Unityの場合若干修正が必要です。ネイティブは対応済み。マルチチャンネルエフェクト(リバーブなど)バスエフェクトは正しく動作しません。
(最終出力のルーティングが切り替わるだけ)

*オーディオリソースの扱い方の違い
**そもそもオーディオの管理方法の違いについて
音は途切れると目立ちます。
3Dモデルは「パッ」と消えてもそれほど気になりませんが、音の場合、「プツッ」というノイズになります。
(プツっという音は、波形変化ではなくスピーカの振動が急激に0に戻る時に発生する事が多い)
オーディオリソースは、フェードアウトして消えるのが理想です。(フェードアウト:徐々にレベルを下げて行く)

少し遅延して消える仕組みを構築するのは、Unity上でも難しいです。

例えば、Unityでミサイルの飛翔音(ループの音:AudioSource)をつけたオブジェクト(プレファブ)を用意します。
この問題として、
ミサイルを消す(Destroy)すると、消した瞬間に音が停止する。「プツッ」となる。
これは、Audioのリソースをモデルに紐付けてしまう事により発生します。

さらに、ミサイルが数個なら良いが、100個くらい出た時には、AudioSourceが増えたり、減ったり、Destroy時の負荷も大変な事になります。
(オブジェクトやコンポーネントが100個分複製(インスタンス)化されたり破棄されたりするのです)

**ADX2では上記のリソース問題を解決する事ができます
まず、オーディオの管理を別のオブジェクトが行います。
シーン上にあるCriWareオブジェクトが、ACBという単位でオーディオリソースをまとめて読み込みます。

シーンに必要なオーディオアセットをあらかじめキューシートという単位でまとめ、キューという単位で再生を行います。

上の例では、100個のミサイルが鳴るとしても、オーディオリソースは1つで済みます。
また、そもそも、100個の音を判別できるでしょうか?
おそらく5~6個あれば十分です。というかそれほど音が鳴っていたら通常個々に音を判別できません。
ので、あらかじめキューリミットで5個までと決めておきます。
この時、後着優先がデフォルトとして機能するので、時間的に後発に鳴る音が、先に鳴っている音を止めてくれます。

さらに、この音を止める時、ウェーブフォームにエンベロープのリリースをつけておく事で、自動的にフェードアウト効果がかかります。
※このため、リリース時のオーバーラップしている間は実際のリソースは5個以上消費しています。

根本的に最大のリソース数というのがあり、これはCriInitializerが行っています。
ゲーム中に、発音数がどれだけ増減しても、メモリの確保量は一切変化しません。
メモリの解放でおこるガベコレのような事も発生しません。
(もちろん、発音数やInitializer自身を破棄、再構築する場合は発生しますが、頻度は相当低いはず。)

さらに音の演出にこだわるならば、50,100のミサイルが鳴った時用の音を別途用意し、
ミサイルの数に応じて付与音をならすといった事が可能になります。
これも、AISACなど使うことで、少ない手間で鳴らす事が可能になるでしょう。

復元してよろしいですか?