ADX2LE情報

adx2leウィキ、adx2le wiki
ADX2 LE情報(facebook ADX2ユーザー助け合い所からコピー)

検索にひっかかるようにwikiにADX2LEでのスクリプトのヒント集をwikiにまとめたページになります。

ゲームサウンドを強力にサポートする
ADX2LEダウンロードはこちら→ADX2 LE公式サイト
ADX2用語集→ADX2用語集
オンラインマニュアル→オンラインマニュアル
ADX2UnityPluginオンラインマニュアル→ADX2UnityPluginオンラインマニュアル
AtomCraftマニュアル→Craftマニュアル

ADX2に限らずゲームサウンドチャット場➡︎ゲームサウンド制作よろず

Atom? エディターじゃないよ CRIAtomといってADX2の下で動いているモジュール名

ADX2ポータルはこちら→ADX2ポータル
ADX2 LE採用タイトルはこちら→ADX2 LE採用タイトル


なお、ここに書いてある情報はADX2とADX2LE両方の情報になります。一部LEでは未実装な機能もあるかもしれません。(わかる範囲で書いています)
Unity向けの場合は一部の機能に制限されている場合があります。(一部のDSP関連のCallback(フィルターやシームレス連結コールバック)など)

目次


トラブルシューティング

古いツールで開けない

CRFATは基本的に新しいツールでデータを作ってしまうと古いツールで開けなくなります。
この場合、最悪目コピーで復元する必要がでてきますが、キューシートの情報であれば、CSVインポートエクスポートが使える場合があります。

DSPバス設定が今までと違う

今までと同じように使いたい場合
1.BUSを8個追加し
2.バスマップのBusMap_Defaultのバス名のところを全て設定する。
3.AISACオートーメーション用バスマップのバス名のところを全て設定する。

バスにセンドした音がでない

DSPBusSettingのバスのセンドにMasterOutを追加する。

カスタムプラグインに何もでてこない

エフェクトプラグインマネージャーでプラグイン検索パスを追加する

カスタムプラグインの影響でツールが起動しない

iniファイル

C:\Users\ユーザ名\AppData\Local\CRIWARE\Adx2\CriAtomCraft\
CriAtomCraft.iniの記述
vstPath=C:\\Program Files\\Common Files\\Steinberg\\VST2

を空フォルダにパスに置き換えて回避する


AtomWindowが開かない

Qiita記事「AtomWindowが開かない」➡︎https://t.co/QLsXLdQSTR

うまくアップデートできない

UnityEditor上で関連するコンポーネントなどが認識されている状態だとうまくImportができないようです。
ので
まず、空のシーンを作る。
Unityを閉じる。
Unityを開いてcriware_unity_plugin.unitypackageをAssetsにドロップしインポートする。
とするとうまくいくはず。


MonoDevelopでビルドするとエラー

エラーのでるProjectを右クリックしOptionsを選択、Build>GeneralのTargetframework:を「Mono/.Net 4.0」を選択する。
※SolutionリストのAssembly-CSharp_Editorとかの右クリックです。(よくSolutionのOptionをみて項目が無くて焦るので)


PCでビルドしようとしたらエラー

Assets/Plugins/CriWare/CriHcaDecoder.cs(45,36): error CS0117: `System.IO.File' does not contain a definition for `ReadAllBytes'
がでてるけど?
Unity EditorのPlayerSettingがiOSになっていると出ます。(Macで作業したプロジェクトなど)
WindowsではiOSがビルドできないため、Unity EditorのPlayerSettingでiOS以外(PCなど)にSwitchPlatformして下さい。


The number of Field exceeds the number of MAX Field.とエラーになる

もしくは、
[CRIWARE] Error:E2012113003:Invalid parameter.
など。

これはデータフォーマットが不正な場合に起こります。ツールとランタイムのバージョンが合っているかどうか確認してください。
(ランタイムが古く、データが新しいフォーマットの場合に起こりやすいです)


CRI runtime library is not compatible. Confirm the version number.

これもデータの不整合が考えられるのですが、他に、
unity実行後に「criware_unity_plugin.unitypackage」をインポートした場合、
一部のオブジェクトが正しくインポートできない(実行中のファイルの上書きなどに失敗)している可能せがあります。

「criware_unity_plugin.unitypackage」を確実に再インポートするには、
ファイルメニューから、「New Scene」 を選択。
Unityを一度終了する。
Unityを起動する。
「criware_unity_plugin.unitypackage」をダブルクリックしてインポートする。

これで、確実にインポートができます。
Unity側で、一度でもシーンが実行されてしまう(Editor上でも)と、ファイルがロックされてしまうので、
空のシーンにしてから再起動する必要があります。


CriWareLeStub.csでエラー

これは、ADX2LEを動かすためのソースです。ADX2プロ版の場合は不要ですので削除してください。


[CRIWARE] Error:E2010040102:Can not find specified cue name. (Specified cue name is 'Beat1'.)

これは、キュー名「Beat1」が見つからないというエラーです。正しくacbがロードされていない場合に起こります。
キューが見つからない場合にも起こります。


Windows7 Windows8でUnityでエラー?XAudio2がなんとかで音が出ない場合

これでWindows7 ADX2LE動いた→ DirectX エンド ユーザー ランタイム Web インストーラ
という報告があります。
参考→http://watery.dip.jp/slash/archives/2118

なお、最近のバージョンではWASAPIに対応しているため、上記の問題が起こらないかもしれません。


ACBHnでランタイム時に管理されいてるもの

  • ランダムやシーケンシャル、シャッフルなどのキューごとの状態(どのトラックを最後に再生したかなど、再読み込みするとリセットされる。
  • キューリミット、キューシートキューリミット

  • 関連情報

対戦などで、2人が同じキャラを選んだ場合の動作

例えば、
対戦などで、2人が同じキャラを選んだ場合に、
それぞれ固有のランダムやリミットをしたい場合は、 ACBHnを別にして処理することで、それぞれで個別にできます。

(それぞれでランダムとかなので、同じセリフが連続するといったことも発生します。)

上記とは別に、
似たような機能で、1つのACBでも、サウンドオブジェクトの機能で、影響の範囲(スコープ)を全体か、オブジェクトごとかといった違いをつけるといったこともできます。

(全体で制御したいか、サウンドオブジェクトに関連するプレーヤー単位で制御したいかといった制御、例えば、二人くらいならACBロードでもよいけど、大量にでてくる敵キャラごとに個別にしたいといった場合など)


仮想環境でCRIAtomCraftを動かす時の注意

Macで作業する場合、ParallelsやVMWareなどの仮想環境でAtom Craftを動かす事になる。

このときビルドの出力先は通常のWindowsが認識出来るフォルダに設定する必要がある。
ほとんどの場合デフォルト設定のままで良いのですが、
仮想環境がファイルを同期するような特殊なフォルダの場合正しく出力できない場合があります。
(例:マイドキュメントがMacのドキュメントと共有されている等)
ドライブレター(C:とか)が含まれるフォルダであれば問題ありません。(\\から始まるパスだとうまくいかない)

UnityではMac側で認識可能な共有フォルダを指定すると良い。(稀に共有にラグが発生するので日付など確認するとなお良い)

CRIAtomCraftをAssetsフォルダ以下に配置してはいけない理由


Assetsを共有したい目的で、Assetsフォルダ以下にCRIAtomCraftのプロジェクト(.atmcproj)を置くと、
元素材の波形やビルド時に生成されるキャッシュファイルや生成されたcsファイルが多重にUnityに認識されて問題が発生します。
波形や関連ファイルが多いとUnityのロードに時間がかかります。

AtomCraftのファイルはAssetsフォルダの外側(Assetsと同階層または一つ上の階層にAtomCraftフォルダを作ってその中とか)
で作成/管理し、生成物(.cs,acb,acf,awb)のみAssetsフォルダ内にコピー(CRI Atom WindowでUpdate)すると良いです。


突然爆音になる?

以下の操作時
  • コーデックがADXでシーク再生を行う
  • ツールで再生位置を変えてプレビューした

原因として以下のものが考えられます。
  • ADXでのシーク再生は推奨されません。(ADXの場合、ADPCM的な予測値が不明になるため、無音部分以外のシークは問題が起こる場合があります。)
HCAでは問題が起こらないため、ターゲットコンフィグのデフォルトコーデックをADXからHCAなどに変更すると良いです。

  • 他、LEのみの使用では通常起りませんが、ADX2LEではないプロ版のデータを再生しようとした場合にも正しく発音されない場合があります。
爆音については、スピーカやヘッドフォン、耳を痛めてしまう恐れがありますので、ご注意ください。

  • 暗号化のかかったデータの場合なども同様に爆音になる可能性が高いです。


突然音が鳴らなくなった

➡︎プレビュー再生で、「AWBのビルドに失敗しました」となった場合、previewCacheフォルダ内のAWB名のファイル(.awb,.TmpAwb,.oldなど)を削除すると復活する場合があります。


AtomWindowにキューが表示されない

➡︎UnityのCriAtomWindowにキューの情報が表示されていない場合、一度アプリを実行して実行中にGetInfoボタンを押すとリストが得られる。


突然エディタが終了する

➡︎ADX2LEはネイティブプラグインで動作しています。そのため、初期化などが正しく行われていない場合にCri〇〇といった関数にアクセスが行われるとUnityEditorごと落ちてしまいます。
  • もし、複雑な処理で落ちてしまうような場合、まずCri〇〇の呼び出しをコメントアウトし安定して動作するか確認し、
  • もしCri〇〇の呼び出しが原因と分かった場合、次にどのタイミングで落ちてしまうかをチェックします。
  • チェックは地道にコメントアウトを少づつ外して行くといった方法になります。


アップデートがうまくいかない

「CRIWARE Unity Plug-in」をアップデートする場合、プロジェクトを開いた後、まだシーンをロードしていない状態で、新しいカスタムパッケージをインポートしてください。
変更があるファイルのみ上書きされます。
いったんシーンをロードしてしまうと、パッケージのインポートに失敗する場合がありますので注意してください。

  • 発音数が足りない
Cri Ware InitializerのStandard Voice Poolの数を増やす


あと、VirtualVoice(仮想ボイス)も合わせて増やす。

ストリーム数を増やす場合はFileSystemのストリーム数も増やす。

  • 発音数の確認スクリプト(デバッグ用途)
TextVoices.text = string.Format("{0} vocies", 
				CriAtomExVoicePool.GetNumUsedVoices( CriAtomExVoicePool.VoicePoolId.StandardMemory).numUsedVoices 
				+ CriAtomExVoicePool.GetNumUsedVoices( CriAtomExVoicePool.VoicePoolId.HcaMxMemory).numUsedVoices);

発音数はボイスプールごとにある。ボイスプールの最大発音数もとれる。
CriAtomExVoicePool.GetNumUsedVoices( CriAtomExVoicePool.VoicePoolId.StandardMemory).numPoolVoices

  • iPhone/Android同時開発で同じビルドデータを使いたい
iPhoneとAndroid共有したい場合、Androidで出すといい。

理由は、低遅延再生のためのパラメータパレット設定(Native)がAndroidでのみ出力されるから。
Androidの設定の初期設定では44100でリサンプリングされてしまう。
これを避けるには強制リサンプリングレートフラグをfalseにする。
ただし、気をつける点として、低遅延再生(Native)を使う場合に44100でないとエラーになる。

低遅延再生(Native)を使うとBusエフェクトは効かない。
フィルターも使えない。あくまで、そのまま再生する用として使う。

低遅延再生は、音ゲーなどでのタップ音などにのみ使う。
低遅延再生(Native)はいろいろ制限があるので注意。(Androidの機種やバージョンなどによって発音負荷や動作が異なる)

あと、iPhone/Androidはデフォルト設定だとADXコーデックなので、HCAに変更する。

ループ再生で音がループしない

➡︎タイムラインでのループマーカーでは波形の途中に戻るようなループはできません。ループ区間内に波形の出だし部分があるもののみ再度再生されます。
  • 他にマテリアルの設定でループをつけるとサンプルレベルの精度でループが可能です。
  • 他に「自動繰り返し間隔」を指定することでオーバーラップや間を入れてループといったこともできます。


トラックで音が重なって鳴ってしまう

➡︎トラックの設定の「トラックMonoフラグ」をオンにすると、重ならないようになります。


ブロックの再生がまれにずれる

➡︎サーバー周期が低い場合に起こります。サーバー周期をあげることで改善する場合があります。


ビート同期再生で音が重ならない

➡︎ビート同期再生は、次の音へ切り替わるような動作のため、複数の音をリクエストした場合に最後のリクエストした音のみが再生されます。
  • 複数の音を鳴らすキューをアクションで呼び出すなどの工夫が必要です。


セレクタを設定したキューを鳴らそうとしても鳴らない

ADX2(LEはまだ)セレクターの設定に「グローバル参照セレクターラベル」というのがあり、これを設定しておくことで、指定したセレクタの音が再生できる。
「グローバル参照セレクターラベル」はプログラムで変更が可能。

キュー固有で特定のラベルを指定したい場合は、キューの「デフォルト参照セレクターラベル」を設定しておく。
こちらを設定した場合、プログラムで「グローバル参照セレクターラベル」を変更しても影響を受けないようにもできる。


シーケンスマーカーいろいろ


曲の途中から再生する音にする

1.キューを作る
2.BGMをキューにドロップしてトラックを作る
3.キューに「シーケンススタート」マーカーを作成する
4.マーカーの位置を適宜ずらす
5.適当にウェーブフォームのエンベロープのアタックなどをいじってフェードインっぽくする

曲の途中で終わらせる

1.キューを作る
2.BGMをキューにドロップしてトラックを作る
3.キューに「シーケンスエンド」マーカーを作成する
4.マーカーの位置を適宜ずらす
5.適当にウェーブフォームのエンベロープのリリースなどをいじってフェードアウトっぽくする


曲の開始位置をランダムに再生する音にする

1.キューを作る
2.BGMをキューにドロップしてトラックを作る
3.キューに「シーケンススタート」マーカーを二つ以上作成する
4.マーカーの位置を適宜ずらす
5.適当にウェーブフォームのエンベロープのアタックなどをいじってフェードインっぽくする

シーケンススタートが複数あると、ランダムにどれかから再生されます。


AISACいろいろ


BGMをハイパスエフェクトを通した音にする

1.キューを作る
2.BGMをキューにドロップしてトラックを作る
3.トラックにAISACを追加し、「バンドパスフィルター-低域」を作る。
4.AISACのカーブを右肩上がりにする。
5.AISACを動かすとハイパスになる。

下記にあるアクションでAISACを動かしたり、REACTでAISACを動かしたりすることができる。


アクションいろいろ


特定キューを止めるキュー

キューをリクエストすると、再生中の特定のキューのみを停止するキューの作り方
1.キューを作る
2.アクショントラックを作る
3.アクショントラックのトラックヘッダーに止めたいキューをドロップ
4.アクショントラックに「停止」アクションを追加する。

キューにつけたAISACを動かすキュー

キューをリクエストすると、AISACを一定時間かけて変更するキュー
1.キューを作る
2.アクショントラックを作る
3.アクショントラックのトラックヘッダーにAISACを動かしたいキューをドロップ
4.アクショントラックに「再生パラメータアクション」アクションを追加する。
5.「パラメータ変更」アクションのタイプをAISAC0、変更値、変更時間を設定する

カテゴリにつけたAISACを動かすキュー

キューをリクエストすると、カテゴリにつけたAISACを一定時間かけて変更するキュー
1.キューを作る
2.アクショントラックを作る
3.アクショントラックのトラックヘッダーにカテゴリをドロップ
4.アクショントラックに「再生パラメータアクション」アクションを追加する。
5.「再生パラメータタイプ」をAISACコントロール0、目標パラメータ値、目標への速度を設定する

キューにつけたセレクタを動かすキュー

キューをリクエストすると、特定のキューのセレクタを変更するキュー
1.キューを作る
2.アクショントラックを作る
3.アクショントラックのトラックヘッダーにキューをドロップ
4.アクショントラックに「セットセレクタラベル」アクションを追加する。
5.「セレクタラベル」を設定する

プレーヤーのフェードパラメータを変更するキュー

1.キューを作る
2.プレーヤーアクショントラックを作る
3.プレーヤーアクショントラックに「プレーヤーフェーダー」アクションを追加する。
4.「フェードイン時間」「フェードアウト時間」「カーブタイプ」を設定する

なお、フェーダーは別途、ランタイムでつけておく必要がある。

BGMのピッチを下げつつ音を止める

1.キューを作る
2.アクショントラックを作る
3.アクショントラックのトラックヘッダーにカテゴリをドロップ
4.アクショントラックに「再生パラメータアクション」アクションを追加する。
5.「再生パラメータタイプ」をピッチ、目標パラメータ値を-1200、目標への速度1.0を設定する
6.「停止」アクションを追加する。

複合技いろいろ


「飛ばし」みたいな演出をする

1.DSPバス設定にバスを追加する(飛ばし用のバス)
2.バスにエフェクト(リバーブ)をつける。
3.バスのセンド先をMainにつなぐ
4.バスマップで、飛ばし用バスを追加する
5.BGMのキューを作る
6.BGMのキューの飛ばし用バスを最大出力にする

これで、エフェクトのかかった音が準備できたので、今度はこれらをコントロールキューを作る

1.キューを作る
2.アクショントラックを作る
3.アクショントラックのトラックヘッダーにBGMキューをドロップ
4.アクショントラックに「再生パラメータアクション」アクションを追加する。
5.「再生パラメータタイプ」をバスセンド(飛ばし)、目標パラメータ値を0、目標への速度10.0を設定する
6.「再生」アクションを追加する。

これで、エフェクトが抑えられた状態でBGMが鳴らせる。

次に飛ばしつつ止めるキューを作る

1.キューを作る
2.アクショントラックを作る
3.アクショントラックのトラックヘッダーにBGMキューをドロップ
4.アクショントラックに「再生パラメータアクション」アクションを追加する。
5.「再生パラメータタイプ」をバスセンド(飛ばし)、目標パラメータ値を1、目標への速度10.0を設定する
6.「停止」アクションを追加し、適宜後ろへずらす。(止まるまで少し時間かかる分の音だけエフェクトへ飛ばす)

「飛ばし」みたいなのの別回答

1.通常の音楽と、
その音楽にめっちゃリバーブのかかった音を用意する。
2.トラックにそれぞれ音を追加する

これで、両方が同時に鳴っているキューができる。

次にこれを制御するキューを用意する。まずドライ音用キュー

1.キューを作る
2.アクショントラックを作る
3.アクショントラックのトラックヘッダーにBGMキューをドロップ
4.アクショントラックに「ミュートアクション」を追加する。
5.「トラックインデックス」を0、ミュート状態を「ミュート解除」
6.アクショントラックに「ミュートアクション」を追加する。
7.「トラックインデックス」を1、ミュート状態を「ミュート」

次にWet音用キュー

1.キューを作る
2.アクショントラックを作る
3.アクショントラックのトラックヘッダーにBGMキューをドロップ
4.アクショントラックに「ミュートアクション」を追加する。
5.「トラックインデックス」を0、ミュート状態を「ミュート」
6.アクショントラックに「ミュートアクション」を追加する。
7.「トラックインデックス」を1、ミュート状態を「ミュート解除」

メリットとしては、DSPエフェクト使わずお気に入りのかかった音を用意できる。 デメリットとしては2音常に再生し続けている状態になっている。

「飛ばし」みたいなのの別回答2(ビート頭で飛ばす)

1.通常の音楽と、
その音楽にめっちゃリバーブのかかった音を用意する。
2.トラックにそれぞれ音を追加する

1.セレクタによるトラック遷移キューを作る
2.トラックを2つ用意し、それぞれ波形を配置
3.セレクタを用意する。セレクタラベルを2つ用意する
4.トラックにセレクタラベルをセットする。
5.「ビート同期マーカー」を追加する(適宜BPMを設定する)

次にセレクタを切り替えるキューを用意する

1.キューを作る
2.アクショントラックを作る
3.アクショントラックのトラックヘッダーにBGMキューをドロップ
4.アクショントラックに「セットセレクタラベル」を追加する。
5.「セレクタラベル」をセットする

これをトラックの数用意する。
(止める場合は、「停止」のアクションも追加する)

これの良いところは、発音数が1で、クロスフェードする瞬間だけ2音になる。(すごく少ない発音数で済む)且つ、サンプルレベルで同期している。

さらに、
全体の尺が同じであれば、BPM違いのBGMを用意することもできる。
(トラックにBPM設定をする)

サイドチェインコンプ

DSPバス設定に「振幅解析機」と「コンプレッサー」を用意して、声とかバスドラ(?)を聞こえやすくするような効果を作る。

1.バスを用意、トリガーとなるバス、影響を受けるバス(BGMとか)
2.トリガーのバスに「振幅解析機」をつける
3.受けるバス(BGMとか)に「コンプレッサー」(こちらはセンド先をMasterOutにする)
4.バスマップを用意する(トリガー、BGMなど)

トリガーのキューの設定

5.キューで、トリガーバスを指定し1.0をバスセンドしておく。

BGMのキューの設定

5.キューで、BGMバスを指定を指定し1.0をバスセンドしておく。MasterOutは0にする。

BGM再生中に、トリガーのキューを鳴らすとBGMにコンプがかかる。


はじめに


効果音を作りたい

スライドの33ページから「爆発音」「レーザー音」「サイレン音」など作ってみましょう。
↑チップチューン風の音が作れます。
ツールの基本的な使い方動画


シーンの初期手順

UnityでPluginをインストールした後に以下の手順でシーンに最低限必要なオブジェクトを作成します。
①「CRI」メニューからCreate CRIWARE Libraly Initializerを選択し、ADX2システム初期化の為のオブジェクトをシーンに追加する。
②「CRI」メニューからCreate CRIWARE Error Handlerを選択し、エラーハンドラをシーン追加
③「CRI」メニューからOpen CRI Atom Window ...でCRIウィンドウを開きそのウィンドウ内の
Select Assets Rootボタンで[Atom Craftの出力したAssetsフォルダ]を指定します。
Update Assets of "CRI Atom Craft"ボタンでACF,ACBを更新します。

この手順でツール「CRI Atom Craft」で作ったデータを更新する事ができます。

AtomCraftの(cs,acf,acb,awb)ファイルが正しく認識できたら
④「CRI Atom Window」の「CreateGameObject」ボタンを押してAtomSourceのついたオブジェクトを作成します。
この時、同時にCRIWAREオブジェクトが生成されます。
生成されたオブジェクトの「Play on Start」をチェックし再生確認をする。

ACFはどこで指定するの?

CriWareInitializerのInitialize Atomの項目にあるACF File Nameに
NewProject.acfといった名前で設定します。
または
CRIWAREのCRI Atom(Script)で設定します。

CriAtomスクリプトにもACF Fileの項目がありますが、こちらは特に指定しなくても問題ありません。
逆に両方指定してしまうと2回初期化しようとしてエラーが発生します。

スクリプトはじめ


ADX2LE用の音を鳴らす為のSoundManager.csを作る

①シーンに空のGameObjectを生成し、SoundManagerと名前をつける。
②プロジェクトにC#スクリプトを作成し、SoundManager.csと名前をつける。
③ ①で作ったオブジェクトに②で作ったcsをドロップし、コンポーネントとしてくっつける。
あとはこのcs内でAtomSouceを生成しても良いし、くっつけたコンポーネントを操作するも良い。
AtomSourceのスクリプトでの作り方は次に書いてある。



CriAtomSourceコンポーネントの追加(スクリプトから追加)

atomSourceSe = gameObject.AddComponent<CriAtomSource> ();
atomSourceSe.cueSheet = cueSheetName; //キューシート名指定

AtomSourceコンポーネントをスクリプトで作りたい場合はStart()内などに上記のスクリプトで追加すると、
実行時にCriAtomSourceが追加されます。

複数のAtomSourceをつけたい場合など上記のようなやり方もできるという例になります。



CriAtomSourceコンポーネントの取得

atomSourceSe = gameObject.GetComponent<CriAtomSource> ();

ゲームオブジェクトにくっついてるAtomSourceコンポーネントを取得します。
スクリプトで制御したい時にこれを使って取り出す。



再生/停止/ポーズ/ポーズ解除 (Unity AtomSourceの関数)


atomSourceSe.Play(4); // キューID指定再生
atomSourceSe.Play(“orchehit”); //キュー名指定再生
atomSourceSe.Stop();
atomSourceSe.Pause(true);
atomSourceSe.Pause(false);

再生関数には、番号(ID)指定と名前(ラベル)指定の二種類があり、どちらでも好みのものを利用できます。


スクリプト特殊


特殊な再生開始(時間指定して、フェードイン、フェードアウト設定を上書き) (Playerの関数)

atomsourceSelect.startTime = 30*1000; //30秒目から
atomsourceSelect.Player.SetEnvelopeAttackTime(2000f); //2秒フェードイン
atomsourceSelect.Player.SetEnvelopeReleaseTime(2000f); //2秒フェードアウト
atomsourceSelect.Play(); //再生

Pitch/Volume変更 (Unity AtomSourceの関数)

atomSourceSe.pitch = 100; // cent(100で半音)
atomSourceSe.volume = 1.0f;   // 1.0で原音と同じ振幅レベル


【即時反映】
ピッチやボリュームは変更したらすぐに反映します。
これは、同じatomSouceSeで複数の音を再生している場合、全ての音に反映します。

再生中の音に反映させたくない場合はピッチベンドの項目を参考にしてみてください。

Pan変更 (Unity AtomSourceの関数)

パンは360度のパンになっており、ITU5.1chに合わせ
LRの角度は30度、サラウンド(後ろ側)は120度の範囲で指定します。

atomSourceSe.pan3dAngle = -30; // Lスピーカから再生 


2Dゲームであれば、-30~+30の範囲をL~Rとみなして操作することができます。
なお、後ろ側へパンをした場合、音が消えてしまうタイプと、ダウンミックス(4ch->2chにダウンしてミックスされる)が行われる
場合があり、ハードウェアやプラットフォームに依存します。
(ダウンミックスされる場合は-3dBほど下がってフロントスピーカへ出力される。)

パンの奥行き感をだす



pan3dDistanceは初期値は1.0で
値が小さくなると他のスピーカから漏れていくようになり、0.0で完全に定位がなくなります。

1.0がスピーカの配置の円周上、0.0が全スピーカの中央となります。


atomSourceSe.pan3dAngle = 0.80; // 若干音像がぼやける (ステレオだと中央に寄る) 


例えば、
画面の手前にいるキャラクタはしっかりと音の定位を動かし、遠い側にいるキャラは0.5くらいにして定位をぼかすといったことができます。
画面構成によってはまったく別パターンもあり
ある距離無いは定位をぼかし、ある距離が一番定位がしっかりし、さらに遠くは音量が下がりつつまたぼかすといった形になります。

(カメラのフォーカス、マイクのフォーカスなどのイメージになり、画角が広い、狭い、望遠か近距離かなどでも演出方法が変わります)

また、ゆっくりと音が頭上を通り抜ける場合(対角線上のスピーカへの移動)などにもこのパラメータを使うことで、スピーカ感の音のジャンプを防ぐことができます。

他にも、メニュー画面に遷移した時に0.0にしてモノラル風にし、ゲーム開始で1.0に変化させることで、
空間の広がり感の変化のメリハリをつけるといった効果も考えられます。

単純に音源までの距離とは違う場合があります。例えば、音源の大きさで考えることもあります。
大きな噴水の近くでは音像がつつまれる感じになるため0.0に近くなり、蚊や蜂などが30cm以内で飛ぶような音の表現は1.0になります。

3Dポジショニング


3Dポジショニングは毎フレームアップデートしつつ、CRI ListenerとのCRI SoundSourceの位置関係から音の定位をします。
さらに、距離減衰やドップラー、音源コーンなどの効果をもたせることができます。
トレードオフとして演算量や設定の手間が増えますが、距離AISACなどと組み合わせることで、自動化しつつ音の変化の表現を豊かにすることも可能です。
例えば、サラウンド側にまわった音はAISACでローパスフィルタの周波数をさげるなど。
注目させたい、ここぞという音につけていくのが効果的です。

[トラブルシュート]3D Positioningをチェックしても音の位置が変化しない

AtomCraft側で
[ウェーブフォームのPanTypeをオート]
[キューの距離減衰を設定]
にする必要がある

[トラブルシュート]PanTypeを変えても音の位置が変化しない (AtomPlayerの関数)


 atomPlayer = new CriAtomExPlayer(); // AtomExPlayer()作成
atom3dSource = new CriAtomEx3dSource();
atomPlayer.SetPanType(CriAtomEx.PanType.Pos3d);		
atomPlayer.SetCue(null,"synth");
atomPlayer.Set3dSource(atom3dSource);
atomPlayer.Set3dListener(CriAtomListener.instance.internalListener);//リスナーもセット
void Update () {	
atom3dSource.SetPosition(this.transform.position.x,this.transform.position.y,this.transform.position.z);
atom3dSource.Update();
}

[トラブルシュート]リアスピーカの音がしない


正確には、iPhoneなど2ch出力の機種で、サラウンド側にある音が聞こえない場合の対処です。
マトリクスのエフェクトをつかってスピーカ出力のルーティングを変えることで、フロントへまわします。


これだと音量が1.5倍になるからヘッドルーム(音量の最大に達しないように音量を小さくし余裕をもつ事)を多めにしておく必要あり


他にも前後で音の質感を変えたい場合などにもマトリクスを使う方法もあります。

サンプルソース:ADX2LE3DPosTest



AISAC変更 (Unity AtomSourceの関数)

atomSourceSe.SetAisac(aisac_id,value);//AISACコントロールID指定
atomSourceSe.SetAisac(“Any”,value); //AISACコントロール名指定

AISACはゲームの状況を音に影響させたい場合に使います。ピッチやボリューム変更と同じようなコントロール値という0.0~1.0の値で、ツールで作成したAISAC変化をプログラムから呼び出す事ができます。

持続音などの変化(エンジン音)やBGM、環境音に対するフィルター処理など様々な用途に使う事ができます。

カテゴリボリューム変更 (Atomの関数)

CriAtom.SetCategoryVolume("BGM",bgmVolume);

カテゴリはツールでキューに設定しておくことができます。
キューに適切にカテゴリを設定することで、ゲーム中のサウンドコンフィグとして使う事ができます。

カテゴリとは、BGM、SE、Voice、Ambientなど大まかな分け方と
CutScene、MainChara、SubChara、Enemy、Weaponなどの分類
System、InGame、UI、Areaなど
Shoot,Throw,Explosionなど
一つのキュー(音定義)に対して複数のカテゴリを持たせる事ができます。(タグのようなイメージ)

カテゴリにつけたAISACの変更 (Categoryの関数)

CriAtomExCategory.SetAisac(0,0,0); //カテゴリID 0のAISACControlID0にAISAC値0をセット
CriAtomExCategory.SetAisac(1,0,0); //カテゴリID 1のAISACControlID0にAISAC値0をセット
CriAtomExCategory.SetAisac(2,0,0); //カテゴリID 2のAISACControlID0にAISAC値0をセット
CriAtomExCategory.SetAisac(3,0,0); //カテゴリID 3のAISACControlID0にAISAC値0をセット

バスについて

最近バスの仕様が変更になって、AtomCraftでバスを追加しないとうまく動かないかもしれない。気をつけて。

バスセンド(リバーブ量変化等) (Unity AtomSourceの関数)

これは個々のプレーヤーせ再生するキューのバスセンド量を調節する場合に使用します。

float depth = 1.0f;
int busNo = 1; //reverb
atomSourceSe.SetBusSendLevelOffset(busNo,depth);

センドエフェクトは比較的重いDSP処理を行う目的で使用します。上記の関数はデータ設定に対して加算します。
トンネルに入った時にdepthを大きくするという使い方ができます。
ツールで他のバス(バスは0~7まで)にエフェクトを追加しておく事で、音に変化を与える事ができます。

【応用的な使い方】
  • バスセンドを動的に変えて、一部の音の振幅レベルだけを取り出す

DSPバスのボリューム変更 (Asrの関数)

これは、DSPバス設定のバスのボリュームを変更する場合に使用します。

void CRIAPI criAtomExAsr_SetBusVolume	(	CriSint32 	bus_no,
CriFloat32 	volume 
)	


ASRって何?

AtomSoundRendererの略 サウンドのレンダリングを主に行う。

ASRラックって何?

AtomSoundRendererはミキサーを持っていて、それの収まっているラック(入れ物)のこと。

スクリプト【状態取得】


再生時刻の取得 (Unity AtomSourceの関数)

GUILayout.Label(atomSourceBgm.time.ToString());
上記のはOnGUI()なっで呼ぶと再生時刻を表示します。


音楽のタイミングに合わせて何かしたい場合 (Playerの関数)

より厳密に時刻を撮りたい場合、GetTimeSyncedWithAudioを使うと、上記のTimeよりも正確に時間がとれます。

例えば、ポーズ、ポーズ解除や、iOSなどスプリングボードに出入りするなど、サウンドのタイミングが乱される場合があります。(時刻取得がフレームスキップするなど)
この関数は、サウンドの再生サンプル数から時刻を返すため極めて正確な時刻を得られます。
反面、ピッチを変えられません。また、内部処理の都合で同一フレームで度々呼ぶようなコードにしないことをお勧めします。(負荷がかかる)

GetTimeSyncedWithAudioを使うには、対応したCriAtomExPlayerを用意し、再生する必要があります。
CriAtomExPlayer(bool enableAudioSyncedTimer)
サンプル数を基準とするため、ピッチの変更ができません。
また、波形再生に依存するため、波形が存在しない区間のあるシーケンスでは正しく時刻をとれません。

音ゲーなど、必ず鳴り続けてる音があるものにピンポイントで使用するような感じになります。

シーケンスの時刻を得る (Playbackの関数)

GetSequencePositionを使うとシーケンスの時刻を得ることができます。
シーケンスループやブロック再生、シーケンス再生レートの影響を受けた時刻が得られるため、ブロックの再生位置監視などに使うことができます。


再生状態の取得 (再生中かどうか) (Unity AtomSourceの関数)

CriAtomSource.Status status = atomSourceBgm.status;
  if ((status == CriAtomSource.Status.Stop) || (status == CriAtomSource.Status.PlayEnd)) {//停止かエンドか
      this.playbackBGM = atomSourceBgm.Play(100);
}

上記の例では停止かエンド時に再度トリガーします。

振幅レベルをとりだす(プレーヤーから)(音量チェック、ピークメータ表示、口パク等) (PlayerOutputAnalyzerの関数)


CriAtomSource atomSource;
//	プレーヤー出力の解析
CriAtomExPlayerOutputAnalyzer criAtomExPlayerOutputAnalyzer;
void Start () {
	atomSource = this.gameObject.AddComponent<CriAtomSource>();
	// 解析モジュールの作成
 	 CriAtomExPlayerOutputAnalyzer.Type[] type = new CriAtomExPlayerOutputAnalyzer.Type[1];
	 type[0] = CriAtomExPlayerOutputAnalyzer.Type.LevelMeter;
	 // コンフィグでバンド数を指定
	 CriAtomExPlayerOutputAnalyzer.Config[] config = new CriAtomExPlayerOutputAnalyzer.Config[1];
	 config[0] = new CriAtomExPlayerOutputAnalyzer.Config();
	 // 出力データ解析モジュールを作成
	 criAtomExPlayerOutputAnalyzer = new CriAtomExPlayerOutputAnalyzer(type, config);
	//	ソースに解析をアタッチ
	atomSource.AttachToAnalyzer(criAtomExPlayerOutputAnalyzer);
}
void Update () {
	Debug.Log("Player Level " + criAtomExPlayerOutputAnalyzer.GetRms(0).ToString());
}
	void OnDestroy()
	{
 	//	ソースに解析をデタッチ
 	 atomSource.DetachExPlayer();
 }

振幅レベルをとりだす(バスから)(音量チェック、ピークメータ表示、口パク等) (Atomの関数)

void Start () {
   CriAtomEx.AttachDspBusSetting("DspBusSetting_0"); //バス変更
   CriAtom.SetBusAnalyzer(true); // バス解析器を有効化
}
void Update () {
   CriAtomExAsr.BusAnalyzerInfo lBusInfo = CriAtom.GetBusAnalyzerInfo(0); //バス0
   Debug.Log("level:" + lBusInfo.peakLevels[0].ToString()); //チャンネル0(Left)
}
8個あるバスのうちバス0はマスターアウトのバスで、全ての音がそのバスを経由します。
特定の音のみの振幅を検出したい場合は、専用のバスへもセンドして検出する事も可能。(声専用バス等)

GetBusAnalyzerInfo()はUpdate()などで定期的に呼び出すことで、リアルタイムの変化が取り出せます。

他にも
Debug.Log("level RMS:" + lBusInfo.rmsLevels[0].ToString()); //RMS
Debug.Log("level PeakHold:" + lBusInfo.peakHoldLevels[0].ToString()); //RMS
もあります。
デフォルトではRMSは50msec,ホールドは1000msec
RMS、ピークホールドの時間設定は、AttachBusAnalyzerの引数で設定を変える事もできます。

各チャンネル0~7(L,R,C,LFE,Ls,Rs,Ex1,Ex2)のレベルが確認できるので、音量のチェックなどにも利用できます。
(使用しない時は負荷軽減になるのでCriAtom.SetBusAnalyzer(false); を呼んでおきましょう。)



バスの波形フィルターコールバックを使って波形を参照したり直接加工する  (AsrBusFilterCbの関数)

CriAtomExAsrBusFilterCbFunc(void *obj, CriAtomPcmFormat format, CriSint32 num_channels, CriSint32 num_samples, void *data[])


これ使うとゲーム側でバスの音を変化させるDSP処理が書けたりする

プレーヤーの波形フィルターコールバックを使って波形を参照したり直接加工する  (PlayerFilterCbの関数)

CriAtomExPlayerFilterCbFunc(void *obj, CriAtomExPlaybackId id, CriAtomPcmFormat format, CriSint32 num_channels, CriSint32 num_samples, void *data[])

これ使うとゲーム側でプレーヤーの音を変化させるDSP処理が書けたりする

たとえば、ボイスチャットや別のサウンド処理へ流したり、サンプリングしたりといったことにも使える


ACF情報(カテゴリ、ゲーム変数、AISACコントロール)の取得 (Acfの関数)

	// カテゴリ情報の取得数
	int categoryNum = CriAtomExAcfDebug.GetNumCategories();
	Debug.Log("categoryNum " + categoryNum.ToString());
	CriAtomExAcfDebug.CategoryInfo categoryInfo;
	for(ushort categoryNo = 0; categoryNo < categoryNum; categoryNo++){
		bool ret = CriAtomExAcfDebug.GetCategoryInfoByIndex(categoryNo,out categoryInfo);
		if(ret){
			Debug.Log("CategoryName \"" + categoryInfo.name + "\" GroupNo " + categoryInfo.groupNo.ToString());
		}
	}

	// ゲーム変数の取得
	int gameVariablesNum = CriAtomEx.GetNumGameVariables();
	Debug.Log("gameVariablesNum " + gameVariablesNum.ToString());
	CriAtomEx.GameVariableInfo gameVariableInfo;
	for(ushort gameVariablesNo = 0; gameVariablesNo <gameVariablesNum;gameVariablesNo++){
		bool ret = CriAtomEx.GetGameVariableInfo (gameVariablesNo,out gameVariableInfo);
		if(ret){
			Debug.Log("GameVariablesName \"" + gameVariableInfo.name + "\"");
		}
	}

	// AISACコントロール情報の取得
	for(uint aisacControlId = 0;aisacControlId<32;aisacControlId++)
	{
		string aisacControlName = CriAtomExAcfDebug.GetAisacControlNameById(aisacControlId);
		if(aisacControlName.Length != 0){
			Debug.Log("AISAC Control ID " + aisacControlId.ToString() + " Name \"" + aisacControlName + "\"");
		}
	}

ACB(キューシート)情報の取得

CriAtomExAcb acb = CriAtom.GetAcb (cueSheetName);

キュー情報一括取得 (Acbの関数)

string cueSheetName = “Pinball”;
CriAtomExAcb acb = CriAtom.GetAcb (cueSheetName);
CriAtomEx.CueInfo[] cueInfoList = acb.GetCueInfoList ();
キューにはツールで設定された様々な情報があります。これを再生前に取得する場合上記の関数を使います。名前やID、ユーザーデータ、カテゴリやAISAC使用有無、キューの長さなど取り出す事ができます。
たとえば、サウンドテスト用に再生ボタンを並べる時、キュー名一覧が欲しい場合や、キューがループ(長さが-1)かどうかの判定に使います。

キュー名とキューID一覧を得る (Acbの関数)

以下のソースを参考にしてacbから情報を取得する事ができます。

// ACB(キューシート)情報の取得
string cueSheetName = "CueSheet_0";
CriAtomExAcb acb = CriAtom.GetAcb (cueSheetName);
// キュー情報の一括取得
CriAtomEx.CueInfo[] cueInfoList = acb.GetCueInfoList ();

// キュー名とキューIDをデバッグ出力
foreach(CriAtomEx.CueInfo cueInfo in cueInfoList){
 Debug.Log("cueName:"+cueInfo.name + " cueId:"+ cueInfo.id);
}


キュー情報取得(キュー名指定) (Acbの関数)

CriAtomExAcb acb;
CriAtomEx.CueInfo cueInfo;
int GetNumBlocks(string cueName){
 acb = CriAtom.GetAcb (cueSheetName);
 acb.GetCueInfo (cueName, out cueInfo);
 return cueInfo.numBlocks;  // ブロック数を得る
}

string GetUserData(string cueName){
 acb = CriAtom.GetAcb (cueSheetName);
 acb.GetCueInfo (cueName, out cueInfo);
 return cueInfo.userData;  // ユーザーデータを得る
}
ACBの情報をキューシート名で取得し、acbからキューの情報をキュー名で取り出します。ここでは。ブロック数を取得しています。
例)現在の再生時刻と組み合わせて、シークバー(どこまで再生したか)などのような表現などに使えます。

atomsourceBgm = gameObject.GetComponent<CriAtomSource>();
 if(atomsourceBgm != null){
  CriAtomExAcb acb;
  CriAtomEx.CueInfo cueInfo;
  acb = CriAtom.GetAcb (atomsourceBgm.cueSheet);
  if(acb.GetCueInfo (atomsourceBgm.cueName, out cueInfo)){
   totalTime = cueInfo.length;
  }
 }
キューの長さを取得する例。ここではCriAtomSourceから取り出している。



DSPバス設定のスナップショット切り替え (AsrRackの関数)

criAtomExAsrRack_ApplyDspBusSnapshot	(	CriAtomExAsrRackId 	rack_id,
const CriChar8 * 	snapshot_name,
CriSint32 	time_ms	 
)	

時間指定でDSPバスエフェクトのスナップショットを切り替える
エフェクトパラメータ設定の違うスナップショットをあらかじめツールで用意し名前をつけておくことで、その設定に変更することができる。

スクリプト【ブロック再生】

ブロック再生は、キューの一部の再生区間(ブロック)の遷移情報をもたせたキューをインタラクティブにコントロールする場合に使用します。
音楽的な変化として、ビートを崩さないで再生を連結するといった要望があるのですが、その解決の一つになります。
データ側で明示的なブロック(音楽的な区切り、Stem、小節、楽章(イントロ、サビ、アウトロ)など)を作成し、
そのブロックの再生中に別のブロックへの変更を行う際に
再生リクエストを音楽的な区切り目(ブロック終端または分割数区切り)まで自動遅延(待機)させたり、
指定回数ブロックをループした後に「次ブロックへ」の遷移指定ができます。


再生中のブロックインデックスの取得(ブロック再生)(Playbackの関数)

CriAtomExPlayback playbackBGM;
playbackBGM = atomSourceBgm.Play(100);
int cur = this.playbackBGM.GetCurrentBlockIndex();
↑現在再生中のブロック番号を確認する方法。どのブロックが再生されているか、確認する用途で使用します。

再生中のブロックインデックスの指定(ブロック再生)(Playbackの関数)

playbackBGM.SetNextBlockIndex(cur % this.cueInfo.numBlocks);
再生中のブロックを含むキューに対して上記の関数を呼ぶと、ツールでブロックをクリックした時と同じような動作になります。
例えば、ブロックを無限ループ(ループ回数-1)にしていたブロック再生中に、別のブロックへ遷移を指定したい場合に使用します。
遷移を指定しても即時に切り替わるのではなく、データ側で定義したブロックの遷移ルールに従って遷移します。

即時に切り替えたい場合は
  • データ側の「分割数」を細かくする
  • 一度停止して、ブロックセットしてから再生する。 

再生開始前にブロックをセットして再生(ブロック再生) (Playerの関数)

atomSourceBgm.cueName = "mainBgm";
atomSourceBgm.Player.SetFirstBlockIndex(1);
atomSourceBgm.Play();
再生開始前にセットする方法。
複数のイントロ(再生開始位置)がある楽曲などで使用します。

シーケンスコールバックを得る (Sequencerの関数)

シーケンスコールバックは、AtomCraft側で、シーケンスコールバックマーカーを設定したデータを用意することで実現します。
楽曲のタイミングに合わせた演出を行いたい場合などに使います。
シーケンス上の任意の位置にコールバックイベントを埋め込むことで、
そのタイミングで、SequencerEventCallback関数が動作します。

void Start() {
 CriAtomExSequencer.SetEventCallback(SequencerEventCallback); //シーケンスコールバックの関数をセット
}
void SequencerEventCallback(string eventParamsString)
{
 string[] strList = eventParamsString.Split('\t');
 Debug.Log(strList[4]);  // Callbackの文字列をログに表示
 int tagNo = int.Parse( strList[4]);	// CallbackのIDを取得
 //GameObject go = Instantiate(itemPrefab,new Vector3(posX,9,0),Quaternion.identity) as GameObject;
 //GameObject.Destroy(go,4);
}
strListの4番目はコールバックのタグの内容が文字列で渡ってくるので、これをゲームの演出などに応用することができます。
例えば、出現位置とかに利用できます。
再生位置に連動した演出が簡単にできます。

スクリプト【ビート同期】


BGMのビートを取り出す(ビート同期する処理)

void Start () {
   evBeatUpdate += beat; //(デリゲート)
}
void beat ()
{
   Debug.Log("beat" + beatNo.ToString());
}
static int beatNo = 0;
static int lastBeatNo = 0;
public delegate void BeatUpdate ();
static public BeatUpdate evBeatUpdate;
void Update () {
   beatNo = (int)(0.001f*(atomSourceBgm.time*82f/60f)); //BPM82
   if(lastBeatNo != beatNo){
       evBeatUpdate();
       lastBeatNo = beatNo;
   }
}
再生時間を元楽曲のテンポ(あらかじめ知っている)で割って拍を取り出し、デリゲートを使ってビートに合わせる処理。
拍に合わせた処理をする(音ゲーなど)に使えるかも。
timeは再生中の時刻(msec)が入ります。
1000msec/60で1分(Minite)あたり何ビート(Beat)数の基準(60BPM)が取り出せます。
1BPM = 60000msec 2BPM = 30000msec 10BPM = 6000msec 60BPM = 1000msec 120BPM = 500msec
テンポが早ければ、ビートの間隔は短くなり、遅ければ長くなります。

レイテンシー

【遅延について】
音の再生タイミング(レイテンシー)はオーディオサーバー周期とも密接に関連します。
周期が60FPSの場合、約16.6msecの単位で一括処理が行われます。(クォンタイズがかかったような状態)

タイミングがシビアな音ゲー等の場合、4~6msecほどの精度をもたないと音がずれる(もたったり食った状態)などに
感じます。

音で確認

latency200_100_50_25_10.wav
200msec,100msec,50msec,25msec,10msecの違いを聞けます。
200「ツ、タン」,100「ツタン」,50「ツタ」,25「チャ」,10「タ」といった感じ。

ゲームの画面更新が16msecや32msecだとすると「チャ」「タ」くらい出て欲しい。

バッファサイズ(サンプル数)とレイテンシー


128,256sampleなどが処理単位となる。ADX2LEではボリューム値はリニアに補間するが、ピッチやフィルターなどはこの最小単位で処理される。
なめらかなピッチベンドなどを行うつもりでもこの最小単位msecの階段状に変化する。ドップラーなども影響受けるので、あまりに高速な音の変化を期待する時に気にかけておくと良い。(奇麗な変化を別サンプルで用意するとか)

最終出力が22050の場合
1000msec = 22050 sample
0.045351msec = 1 sample
5.804989msec = 128 sample
11.609978msec = 256 sample
16msec = 約352.8sample
32msec = 約705.6sample
高域がこもって聞こえる。

最終出力が32000の場合
1000msec = 32000 sample
0.03125msec = 1 sample
4msec = 128 sample
8msec = 256 sample
16msec = 512sample
32msec = 1024sample
処理負荷低い、切りが良い。CD品質より劣る。

最終出力が44100の場合
1000msec = 44100 sample
約0.022676msec = 1 sample
約2.902494msec = 128 sample
約5.804989msec = 256 sample
16msec = 約705.6 sample
32msec = 約1411.2 sample
CD品質。

最終出力が48000の場合
1000msec = 48000 sample
0.020833msec = 1 sample
2.66667msec = 128 sample
5.33333msec = 256 sample
16msec = 768sample
32msec = 1536sample
処理負荷が上がるけど時間方向に細かい変化になる。

ADX2で音が遅れる一般的な要因と回避策

  • ストリーム再生を使っている。メディアから読み込むため再生開始に時間がかかる。
 【回避策】
 →メモリ再生をする。
 →prep (一時停止状態で読み込み)pause解除で再生開始する。
  • ボイスリミットに達している音を発音している。

 【回避策】
 →ボイスリミットを多めにする。
  ボイスリミットの確保の処理は早いのですが、ボイス開放処理は遅めなため、短時間で多くのリクエストをすると処理が滞る場合があります。
  (ボイス開放待ちになる)
 →キューリミットを使う
  キューリミット、またはカテゴリの
   キューリミット数を、制限したい発音数
   ボイスリミット数を、制限したい発音数+数音にしておく。
  後着優先時の動作として、
  キューリミットではリリースのある音を止めないため、実質の発音数はオーバーラップ分リミットを超える場合があります。
  ボイスリミットでは、リリースを停止してボイスを取得しに行くため、ボイスの停止に時間がかかる場合、次のボイス取得が遅延します。
  ボイスにゆとりをもたせて、リミットはキュー側で行うと処理として都合が良くなります。
  • シーク再生

 【回避策】
 →2つボイスを用意し、交互に扱うなど。
  • ブロック再生
 シーケンスの精度の問題でサンプルレベルでの連続再生はできない。
 【回避策】
 →少し長めの余韻つき波形を、次の波形の頭にオーバーラップするように再生し誤摩化す。
  • Android

 【回避策】
 →低遅延再生を試みる。
CRIWARE Library Initializer コンポーネントにて低遅延再生標準ボイスプール数を指定
CriAtomSourceコンポーネントの「Low Latency Playback」チェックをオンにして再生開始
スクリプト上でCriAtomSourceを操作する場合は、CriAtomSource.androidUseLowLatencyVoicePoolプロパティに true をセットしてください。ただし、低遅延音声再生ボイスプールから音声を再生する場合、以下のような制限事項があります。
本機能はSE再生など遅延を少しでも減らした音声のみ使用し、BGMやエフェクトを使用したい音は通常再生を行ってください。
注意:•低遅延再生標準ボイスプールの最大数はメモリ再生・ストリーム再生あわせて27まで。
•音声データのサンプリングレートは44100Hz/22050Hz以外は再生できません。
•2Dパン、ボリューム調整のみ可能。ピッチ調整やリバーブなどのエフェクト機能などは使えません。
•本機能はAndroid OS 2.3以降の端末のみ有効です。 

オーディオサーバーの周期

理想的にはオーディオサーバー処理を240FPSの処理になるのですが、
デフォルトの30FPSと比較して8倍の負荷になる計算。(実測値は環境や処理内容依存で変化します)
ゲームの場合、他の処理の為に負荷を軽減する必要が多く
これらの設定は大きなトレードオフが発生します。
オーディオサーバー周期はCriAtomInitializerで設定することができます。

※実際には別の要因でボトルネックが発生する場合もあり、ある一定量以上は効果がでなくなります。

処理負荷

ハイエンド機やPCなどではほとんど問題ないのですが
携帯機では
「処理負荷が上がる」=「電池の減りが早く」なります。
CPUクロック等待機状態からの復帰に時間がかかるような処理では、
再生の供給が間に合わず音が途切れたりする事もあります。
(想定しているサーバー周期で動作しないし、システムの保証がない)
おそらく、音の途切れをなくすための膨大なレイテンシー(100~300msec)のある端末やOS、ハードウェアの組み合わせがあるようで、
電話やメッセージの着信、カメラのシャッター音など、システムレベルのサウンドとのミキシングなど公開されていないレイテンシーもあります。
同じ内容のものでも端末によって気持ちよさが変わってしまいます。

例えば
300msecは200BPMで1拍(beat)音楽的に4分音符分の遅れということになります。
150msecで8分音符 75msecで16分音符 32.5msecで32分音符

16分音符のずれはほとんどの人が知覚できるレベルでずれに感じます。

これらのシビアなタイミングが気持ちよさにダイレクトに繋がるような
音ゲーを作る場合には重要な問題となります。

【for Unity iOS で遅延を減らしたい】

プロジェクトセッティングのAudioManagerからDisable Audioをチェックする。
iOS ConfigのBuffering Timeを100から16にする。
メモリ再生にする。


【for Windowsで遅延を減らしたい】

 criAtom_SetSoundBufferSizeを小さくする。(あまり小さくすると音途切れなどの原因になります)

【ADX2LE iOSで遅延を減らしたい】

楽器アプリを作っていて気がついたのですが
[CriWareInitializer]の[iOS Config]というところの[Buffering Time]という項目がデフォルト100msecとなっています。
これを50msecに変更する
と少し改善します。
「ツタン」から「ツタ」くらいに変わる。
※ただしこの設定を下げるとGC(ガベコレ)時に音途切れが発生する可能性があります。発音中にGCが発生するような作りにしない工夫も必要です。(シーン切り替え時に無音部分を用意するなど)

ちなみによくあるBPM120で
4分音符 500msec 8分音符 250msec 16分音符 125msec 32分音符 62.5msec
なので、32分音符分ずれていたらこれが原因。

iOSの画面を爪でコツンと叩くような感じで、音を鳴らした時にこれくらいずれていたら
設定を疑うと良い。
「ツ、タン」(120~200msec)が「ツタン」(60msec)くらいになります。(鳴らし開始と音が出るまでの時間が短縮する)
楽器レベルでは(10msec以内に押さえたいところ)


  • 解像度的な乱れ(密度がばらつく)の改善
定期的に
32分音符で叩いていて、たまに動作が乱れる場合は
[CriAtomInitializer]の[InitializeAtom]の[Server Frequency]をデフォルト30から
60または120にします。
「タタッタタタ」とかが「タタタタタタ」と改善するはず。(サーバーの鳴らす処理の入るタイミングの解像度が上がる)
30FPS 約32msec 60FPS 約16msec 120FPS 約8msec
※ただし、負荷も上がるので、携帯機などでは電池の減りが早くなる等別の問題が発生します。
※また、処理量も増えるため大量のサウンドを同時再生しているなど負荷の増加に注意が必要です。

音の停止判定は遅い?

サウンドの発音までの処理は早いのですが、停止の処理は精度が低いようです。(エンベロープのリリース処理や解放処理など)
リミットがかかった場合なども若干の停止待ちが発生するため、
発音を優先するのであれば、多めのボイスを確保するようにしておくことが良いです。

スクリプト【テクニックアラカルト】


サンプルディレイみたいなのはありますか? (Playerの関数)

サンプル単位ではなくミリ秒単位で以下のような方法が可能です。
[データ]
キューにプリディレイ用のAISAC「PreDelay」を作る。カーブに「プリディレイ」を設定し
AISAC(0.0~1.0)をmsecにマッピングする。例えば、0~100msec。


ただし、波形の再生だけが遅くなるだけなので、オートメーションとかシーケンスのタイミングは元のままで再生されます。
また、PreDealy中も発音カウントは増えるので、リミット処理などが行われます。(PreDelay時間時に無音が再生されているイメージ)

プログラムで以下のように呼び出す
atomSourceBgm.SetAisac("PreDelay",msec/100.0f);
atomSourceBgm.Play("hit");
これでとりあえずディレイ再生が可能です。

再生開始位置をずらす

criAtomExPlayer_SetStartTimeを使う

XYでAISACを変更する(カオシレータ風) (Playerの関数)

// TapPos(new Vector2(x/Screen.width,y/Screen.height));
static public void TapPos(Vector2 tapPos)
{
   atomSourceBgm.SetAisac("y",tapPos.y);
   atomSourceBgm.SetAisac("x",tapPos.x);
}
AISACを2つ使って音を面(2軸)で操作する。AISACは一つのキューで最大8個まで別のコントロールを持たせる事ができる。
例えば
カオシレータ風にするならば
  • スケール用のピッチの階段上のグラフ(AISAC)
  • エフェクト用のバスセンドのグラフ(AISAC)
といった形にもできます。
エンジン音ならば
  • RPM(回転数)
  • Laod(エンジン負荷)
環境音なら
  • 天候
  • 群衆の人数
ゲーム状況をインタラクティブに反映するならば
  • ゲームの進行具合
  • メインキャラの体力ゲージ
による音の変化など。




【Unity機能】
Unityの標準再生などの再生速度指定系でピッチを指定したい場合に使います。ADX2LEでは再生速度指定AISACなどで使うかも。

iOSなどバックグラウンドになった時にBGMを一時停止/復帰する

void OnApplicationPause(bool pause)
{
   atomSourceBgm.Pause(pause);
}
iOSなどスプリングボードへ移動する瞬間などの若干のフェードアウトしている間も音は再生されています。これを使うことでほんの少し抑制できます。

Androidなどバックグラウンド動作を許す端末などでは、
void OnApplicationFocus(bool focusFlag)
{
 atomSourceBgm.Pause(!focusFlag);
}
でフォーカスが当たっていない時に音を止めたりします。



AtomSourceからCriAtomExPlayerを得る(CriAtomExPlayerを呼び出す改良)

CriAtomExPlayerはpitchの変更やtimeの設定など低レベルな隠されたリアルタイム処理を使用する場合に取得します。
いろいろな事ができる反面、状態や動作をよく理解しておかないと混乱(意図しない再生など)する可能性のある機能もあるので注意。

Plugins/CriWare/CriWare/CriAtomSource.csに以下の行を追加

public CriAtomExPlayer player { private set; get; }

一度も再生をしていないと不定な場合があるため、初回呼び出し前に下のリセットを呼び出すと少し安定する?

AtomSourceからCriAtomExPlayerを初期設定に戻す(リセット) (Playerの関数)

Playerに対して様々なパラメータをセット(ピッチ等)してしまった後にもとに戻したい場合リセットをすると最初の状態に戻ります。
atomsourceSelect.Player.ResetParameters();
atomsourceSelect.Stop();



シーケンシャルを最初に戻す (Acbの関数)


キューが、シーケンシャルに複数のトラックを切り替えて再生する時に、意図的に最初のトラックの再生に戻したい場合があります。

シーケンシャルなキューの再生を最初の状態に戻したい場合は、

criAtomExAcb_ResetCueTypeStateByName
criAtomExAcb_ResetCueTypeStateById

を使います

Unityだと後ろの方が省略されて、引数違いの関数になります。



そのほかのリセット的な処理

関数リファレンスで「Reset」などで検索するといろいろでてきます。



シークして再生(シーク再生、途中から再生)(Playerの関数)

次回再生の再生開始時刻を指定する
atomsourceSelect.startTime = 30*1000; //次回再生音は30秒目から
atomsourceSelect.Play();	
atomsourceSelect.startTime = 0; //次回再生音を0秒目からに戻す

プレーヤに直接指定する場合
atomSourceSe.Player.SetStartTime((long)settime);   
atomSourceSe.Stop();
atomSourceSe.Play(cueNo);  
CriAtomExPlayerのSetStartTimeを呼び出すため、CriAtomExPlayerを呼び出す改良を施しておいて下さい。
SetStartTimeには開始msecを指定します。次回再生時に指定時刻から再生します。

再生中の音をピッチベンドする (Playbackの関数)

CriAtomExPlayback playback;
void Playback(int cueNo)
{
 playback = atomSourceSe.Play(cueNo);
}
void PitchBend(float pitch){
 atomSourceSe.Player.SetPitch(pitch);   
 atomSourceSe.Player.Update(playback);
}
CriAtomExPlayerのSetPitchを呼び出すため、CriAtomExPlayerを呼び出す改良を施しておいて下さい。SetPitchにはcent値(100で半音、1200で1オクターブ)を指定します。
playbackを取得して、Updateしたタイミングで再生中の音に反映します。

Updateで更新されるパラメータについて

音が変化しないといった時は、Update系の処理を呼ぶ必要を検討します。


playerに対してSet系や Attach系で指定したパラメータは、その後のPlayerで再生した音にのみ影響を与えます。

これは、
「再生中の音」に影響を与えたい場合は、Play時のPlaybackIDを利用するか、 
UpdateAllなどの関数を呼び、そのプレイヤーで再生中の全ての音に 
現在のPlayerのパラメータ設定を影響させるといった操作が必要です。


パラメータのセットと、再生のリクエストのタイミングについて


通常は、パラメータをセットしてから、音を鳴らすという操作になります。

もし、音がなってから、ボリュームやピッチを変更すると、
最悪一瞬だけ音が鳴ってから変化したり、たまたま音の出だしが遅いなどのタイミングが間に合って、
正しく鳴ったりといった不正確な動作になります。

もっとなめらかな変化が欲しい場合

Updateにしても、オーディオの処理フレームとはタイミングの操作になるため、
変化の解像度は階段状になったり、更新タイミングも不正確で音の鳴り方が不定になりがちです。

基本的には、エンベロープの設定やフェーダーなどを利用して、影響が少ないようにした方が良いです。


AtomExPlayerを使用した再生 (Playerの関数)

より低レベルなサウンド処理を行う場合の再生方法です。

CriAtomExPlayer atomPlayer = null;
void Start()
{
 atomPlayer = new CriAtomExPlayer(); // AtomExPlayer()作成
}
void Play(string cueName)
{
 atomPlayer.SetCue(null,cueName);
 atomPlayer.Start(); // 再生開始
}
void OnDestroy()
{
 if(atomPlayer != null){
  atomPlayer.Dispose(); // 破棄
  atomPlayer = null;
 }
}

selectorLabelを設定する (Playerの関数)

CriAtomExPlayerの関数を呼ぶ

audioSource.player.SetSelectorLabel(”Ground”,"concrete"); //床セレクタのコンクリートのラベル指定

スクリプト【Unityの物理とかで再生制御】

キューブをクリックすると再生/停止をする

クリックの判定にRaycastHitを使う方法を紹介。
  • CubeにCriAtomSourceをつけて、cri/unity/samples/criatom/script/Unity3Project/ScriptSample01_ClickToPlay/Assets/Scripts/PlayAndStopSoundOnClick.csを使う。
   void Update () {
       if (Input.GetMouseButtonDown(0)){
           Ray clkRay = Camera.main.ScreenPointToRay(Input.mousePosition);
           RaycastHit rh;
           // Collision Dectection
           if (Physics.Raycast(clkRay, out rh, 20)) {
               GameObject target = rh.collider.gameObject;
               if (target == this.gameObject) {
                   // Play Cue
                   CriAtomSource atom_src = target.GetComponent();
                   if (atom_src != null) {
                       CriAtomSource.Status status = atom_src.status;
                       if ((status == CriAtomSource.Status.Stop) || (status == CriAtomSource.Status.PlayEnd)) {
                           atom_src.Play();
                       } else {
                           atom_src.Stop();
                       }
                   }
               }
           }
       }
   }

キューブに触れると再生/停止する



スクリプト【初期化、ロード関連】


スクリプトでのacbロードと解放の仕方

if(GUILayout.Button("Remove")){
      CriAtom.RemoveCueSheet("PinballMain");
}
if(GUILayout.Button("Add")){
      CriAtom.AddCueSheet("PinballMain","PinballMain.acb","");
}
ACBを動的に切り替えたいなどの特殊用途に使用します。
具体例をいくつか
  • ダウンロードコンテンツ(DLC)
    • キャラクターダウンロード(読み上げる声優の切り替え)
    • アイテムのダウンロード
  • プログラム上の差し替えでリクエストに対する音が切り替わる等を表現したい場合など。
    • 対戦格闘におけるキャラ選択後のパンチやキックの音の変化
    • レースゲーム等で車選択による音の切り替え
    • 音ゲーでの楽曲選択による音の切り替え
    • ステージ切り替えによるアンビエント変化等

なお、あらかじめInitializerオブジェクト、CriAtomオブジェクトが必要です。

CRIAtomオブジェクトを用意する


CRI Atomのインスタンスが無い状態で、関数を呼び出そうとするとnullアクセスになります。

//  CRI Atom作成
var criAtom = new GameObject("CRIAtom");
criAtom.AddComponent<CriAtom>();

といった感じで、CriAtomのコンポーネントを先に作っておくと良いです。


より簡単にStreamingAssets以外のパスから読む方法(New)

AddCueSheet関数にフルパスを指定するだけ。
if(GUILayout.Button("Add")){
      CriAtom.AddCueSheet("PinballMain","C:/PinballMain.acb","");
}
AddCueSheetはパスが相対パスの時はStreamingAssetsから読むようです。

ACFの登録をスクリプトから行う

CriAtomEx.RegisterAcf
CriAtomEx.UnregisterAcf
を使う。

イニシャライザとか別オブジェクトだけど、スクリプトからできない?

Unityは初期化順序や、永続性がGameObjectに依存するので、
CRI Initializerを別オブジェクトで追加するのが簡単です。

もし何らかの理由で、自前で行いたい場合は、CRI Initializerの中と同様の処理を行うことでできますが、
初期化順序や破棄なども注意深く行う必要がでてきます。

例えば、
  • Unity Execution orderで初期化を早めに呼ぶ。
  • セットアップシーンを用意して、初期化を済ませておく。

ADX2LEはApplication.temporaryCachePath等に保存してあるオーディオファイルを再生する・・・的な事は出来ますか?

Assets以下のフォルダにあるACBをロードして、再生するサンプルの動画作ってみました。
ここでは、無関係なゲームジャムのELISEのacbを読み込んで再生しています。http://www.youtube.com/watch?v=DyhujH43ozI&feature=youtu.be

通常のCriAtomSourceで指定したキューシート名のロード先はStreamingAssets以下から読み込みますが
外部デバイス(SDカード)、URLでサーバーからACBをダウンロードなど、
UnityのAsset管理外のフォルダから直接acbファイルを指定して再生する場合に使用します。

CriAtomExACB acb = null;
void LoadACB(string loadAcbPath)
 if(acb != null){
  acb.Dispose(); // ロード前に既にあったら破棄
  acb = null;
 }
 acb = CriAtomExAcb.LoadAcbFile(null,loadAcbPath,null); // ロード
}
void OnDestroy()
{
 if(acb != null){
  acb.Dispose(); // 破棄
  acb = null;
 }
}

スクリプト【サウンド関連パラメータ変換】


MIDIノートNoから音程を設定(0~127 -> cent値)

static public void SetMidiNote(float note)
{
   atomSourceSe.pitch = (note-69)*100; // cent(100で半音,ベースノート A4=69)
}
セント値への変換

MIDIベロシティから音量を設定(0~127 -> 0.0~1.0)

static public void VelocityToVoluem(float velocity)
{
   atomSourceSe.volume = velocity/127f; // 0.0~1.0の正規化ボリューム指定
}

周波数からMIDIノートの変換(Hz -> MIDINoteNo)

static public float Ftom(float freq)
{
   return (69f + (1f/.057762265f) * Mathf.Log(freq/440f));
}

(MIDIノート)から周波数の変換(MIDINoteNo -> Hz)

static public float Mtof(float note)
{
   return (440f * Mathf.Exp(.057762265f * (note - 69f)));
}

CRI Pitchから再生速度へ変換(cent値 -> 0.0~4.0)

static public float PitchToSpeed(float pitch)
{
   return Mathf.Pow(2,pitch/1200.0f);
}

BPMから一拍の長さ(msec)に変換

beat per minute
1分で何拍打つかという指定なので、
BPM120は1分(60*1000msec)で120回。
一拍の長さは、60000/120で求められる。
beatLength = 60000/bpm

BPMから再生速度に変換

ピッチの変化を上記の再生速度にしてしまえば、1.2倍速とかの指定ができる感じになります。
(目的のBPM/元のBPM)をスピードとして指定するといったBPM変換も可能です。
speed = DstBpm/SrcBpm; // 元のBPMが100で、120にしたい場合、120/100 = 1.2倍

再生速度からCRI Pitchへ変換(0.0~4.0 -> cent値)

//pitch = 1200.0f*logf(ratio)/logf(2.0f);
pitch = 1200.0f*Mathf.Log(ratio)/Mathf.Log(2.0f);

dBからCRI Volumeに変換(-96dB~+6dB -> 0.00 ~ 2.00)

volume = Mathf.Pow(10.0f,dB / 20.0f);

CRI VolumeからdBに変換(0.00 ~ 2.00 -> -96dB~+6dB )

db = 20.0f * Mathf.Log10(volume);

インゲームプレビュー(他のマシンへ接続)

MacでParallelsなど使用している場合、MacのIPを「ツールメニュー>プロパティ>ターゲット>PC>リモートPC IP アドレス」に指定し、チェックします。
Unity側「CriWareLibraryInitializer」のUses In Game Previewのチェックも忘れずに。
Unityの動作がバックグラウンドで止まってしまう場合は、PlayerSettingsの「Run In Background」をチェックすると良いです。



PCでオーディオデバイスを切り替える関数

 criAtom_SetDeviceId_WASAPI を使う

エフェクトパラメーターを直接いじる

SetEffectParameterと
UpdateEffectParameterを使う。


バス1につけたリバーブの残響時間を操作

CriAtomExAsr.SetEffectParameter	(	"BUS1",
CRIATOMEXASR_I3DL2_REVERB_NAME ,
CRIATOMEXASR_I3DL2_REVERB_PARAMETER_DECAY_TIME,
3
);		

エフェクトの設定を取得する


 // バスの数を得る

           CriSint32 dspSettingNum = criAtomExAcf_GetNumDspSettings();

//	DSP設定の数だけループ
               for(int dspSettingNo = 0; dspSettingNo <dspSettingNum;dspSettingNo++){
                   const CriChar8* dspSettingName = criAtomExAcf_GetDspSettingNameByIndex(dspSettingNo);
                   {
                       CriAtomExAcfDspSettingInfo setting_info;
                       // DSP Setting情報の取得
                       criAtomExAcf_GetDspSettingInformation(dspSettingName, &setting_info);
                    }
                }


// スナップショット情報
CriAtomExAcfDspSettingSnapshotInfo settingSnapshotInfo;
criAtomExAcf_GetDspSettingSnapshotInformation(snapShotIndex,&settingSnapshotInfo);

// バスリンク情報
CriAtomExAcfDspBusLinkInfo criAtomExAcfDspBusLinkInfo;
criAtomExAcf_GetDspBusLinkInformation(startBusLink+num_buslink,&criAtomExAcfDspBusLinkInfo);

// FX情報
criAtomExAcf_GetDspFxType(bus_infoList[num_buses].fx_indexes[num_fxes]);



スクリプトでACFからとれる情報

スクリプトでACBからとれる情報



その他


ADX2Web版でありそうな対処

  • 他のサーバーからロードする場合 CORSの設定も必要
  • AACエンコーダが別AddOnで別パッケージになっている
  • Mac版UnityEditorなら以下の手順でAACもならせる。
 1.CriWareLibraryInitializer>Initialize Atom>Max VirtualVoicesを増やす。(32->64など)
  • 一部のエフェクトが機能しない。リバーブやディレイは実装が少し異なる(音が変わる場合がある)
  • ACFやACBのLoadを完了してから呼ぶ
  • UnityのResourcesからロードもできる(サーバーにacf,acbを置かない方法もある)
  • Loadしたデータもガベコレされないようにしておく
```
byte[] raw_dataAcf;
byte[] raw_dataAcb;
IEnumerator Start () {
	// ----
	// テキストアセットとしてACFを読み込む。NewProject.bytesはResourcesフォルダに配置する。
	// ----
	TextAsset text_assetAcf = Resources.Load<TextAsset> ("NewProject");
	raw_dataAcf = text_assetAcf.bytes;
	// ----
	// テキストアセットとしてACBを読み込む。CueSheet_0.bytesはResourcesフォルダに配置する。
	// ----
	TextAsset text_assetAcb = Resources.Load<TextAsset> ("CueSheet_0");
	raw_dataAcb = text_assetAcb.bytes;
	// ----
	// ACF登録
	// ----
	CriAtomEx.RegisterAcf(raw_dataAcf);
	
	// ----
	// CriAtomを作成しゲームオブジェクトに追加
	// ----
	this.gameObject.AddComponent<CriAtom>();
	// ----
	// キューシートを追加
	// ----
	var cuesheet = CriAtom.AddCueSheet("CueSheet_0", raw_dataAcb, null);
	// ----
	// キューシートのロード完了まで待つ WebGL版はロードに時間がかかる(ロード前にAtomにアクセスしないようにここで待つ)
	// ----
	while (cuesheet.IsLoading) {
		yield return new WaitForEndOfFrame();
	}
    // ----
	// DSPバス設定
	// ----
	CriAtom.AttachDspBusSetting ("DspBusSetting_0");
}
```
  • ブラウザの開発メニューからエラーメッセージなどが確認できる



ご意見はこちら

名前:
コメント:
最終更新:2019年10月25日 11:36