
マイケル
みなさんこんにちは!
マイケルです!

エレキベア
こんにちクマ〜〜

マイケル
最近はサウンドミドルウェア周りを学習していまして、
CRI ADXとWwiseについて大方使える状態になりました!

エレキベア
おぉ〜〜どちらもよく聞く定番のミドルウェアクマね

マイケル
その中で学習した内容の総まとめとして、オーディオ処理のサンプルを各ライブラリで切り替えできるUnityプロジェクトを作成しました。
今回はこちらを実装するにあたっての設計についてご紹介します!

▲オーディオライブラリを切り替え可能なプロジェクトを作成した

エレキベア
ほぅ・・・一度使い始めると中々変更が難しそうな印象があるクマから
切り替えれるのは大きいクマね

マイケル
実際にやってみると苦戦した点がいくつかあったので、その辺りを含めて記載していこうかと思います!
作成したサンプル

マイケル
実際に作成したサンプルプロジェクトは下記の3つで、GitHubリポジトリに格納しています。

▲サンプル1:基本機能

▲サンプル2:オーディオスペクトラム

▲サンプル3:インタラクティブミュージック

マイケル
実装したライブラリは UnityAudio、CRI ADX、Wwiseの3つ で、各サンプルの実装状況は下記のようになっています。
周波数データの取得がWwiseではデフォルトで対応していなかったため、オーディオスペクトラムの実装は省いています。
各機能の実装状況
機能 | UnityAudio | CRI ADX | Wwise |
---|---|---|---|
基本再生 | ○ | ○ | ○ |
オーディオスペクトラム | ○ | ○ | × |
インタラクティブミュージック | × | ○ | ○ |

エレキベア
Wwiseで周波数データの取得ができないのは以外クマね

マイケル
調べたらカスタムプラグインを作って回避する方法は出てきたけど
Unity標準でも対応してるし、導入してほしいね・・・
サウンドミドルウェアの依存

マイケル
これらのライブラリを切り替えれるよう汎用化するにあたり、下記のような問題がありました。
通常の方法で使用すると サウンドミドルウェアのプロジェクトへの依存が強い 状態になってしまいます。
グローバルオブジェクトの存在

マイケル
1つ目はグローバルオブジェクトの存在です。
CRI、Wwiseではそれぞれ初期化するために独自のグローバルオブジェクトをシーンに生成しておく必要があります。

▲CRIADXのグローバルオブジェクト

エレキベア
ミドルウェアの管理オブジェクトが必要になるのクマね
独自コンポーネントの存在

マイケル
そしてオーディオの再生元とするためのSourceコンポーネント、Listenerコンポーネントなど独自のコンポーネントをオブジェクトにアタッチしておかなければなりません。

▲ライブラリ独自のコンポーネントをアタッチする必要がある

エレキベア
これはUnityAudioでも同様クマね
実装方法の違い

マイケル
最後にこれは仕方がないですが、ライブラリごとに実装方法が異なります。
この辺りを上手く汎用的に書かなければいけません。
▲CRIの例、再生処理の後に別途コールバックを追加している
▲Wwiseの例、再生時にコールバックを渡している

エレキベア
中々一筋縄ではいかなそうクマね・・・
最終的な設計
設計方針

マイケル
これらの問題を解決するため、下記のような方針で実装を行いました。
- オーディオ設定は各ライブラリごとに定義するが、汎用で使える変数も用意する
- グローバルオブジェクトの生成、コンポーネントのアタッチはスクリプト内で行う
- API実行処理、ゲーム固有のオーディオ処理は別クラスに分ける
- ゲーム側からはインターフェイスを参照する

マイケル
オーディオ関連の処理をAPI実行クラスとゲーム固有の処理実行クラスに分割し、
ゲーム側からはインターフェイスを参照することで使用ライブラリを意識しない構成です。

▲パッケージ間の依存関係

▲最終的なクラス設計

▲右:オーディオライブラリのAPI実行クラス

▲左:ゲーム固有のオーディオ処理クラス

エレキベア
サービスロケータを使ってクラスを切り替えるクマね

【Unity】ServiceLocatorを使ってサービスクラスをまとめる
2022-02-27
オーディオの固有設定と汎用化

マイケル
各ライブラリの構成は下記のようになっていて、
名称は異なりますが大方似たような構成になっています。
各ライブラリの構成
UnityAudio | CRI ADX | Wwise | |
---|---|---|---|
再生の分類 | - ※AudioMixer単位での制御は可能 | CueSheet | Soundbank |
再生の対象 | Audio | Cue | Event |
ゲームとやり取りするパラメータ | - | AISAC | GameSync (Switch, State, GameParameter) |
Listenerコンポーネント | AudioListener | CriAtomListener | AkAudioListener |
Sourceコンポーネント | AudioSource | CriAtomSource | AkBank |

マイケル
そのため各ライブラリ固有の設定を定義するのに加えて、
下記のような共通の変数を定義して実装しました。
汎用化するための定義
汎用の定義 | |
---|---|
再生の分類 | SoundSheet |
再生の対象 | SoundEvent |
ゲームとやり取りするパラメータ | GameParameter |
▲ライブラリ固有の設定と共通設定を定義する

エレキベア
ゲーム側からは使用ライブラリに関わらず共通の変数を使用するクマね
グローバルオブジェクトの生成とコンポーネントのアタッチ

マイケル
そしてグローバルオブジェクトや独自コンポーネントに関しては、各ライブラリのクラス内で生成するようにしました。
▲グローバルオブジェクトの生成(CRI)
▲コンポーネントのアタッチ(CRI)

エレキベア
これでオブジェクトやシーンの状態は汚さずにすむクマね
ゲームからはインターフェイスを参照する

マイケル
最後に、ゲーム側からはServiceLocatorを通じてインターフェイスからサービスクラスを取得するようにします。
ライブラリ切り替え時にはDefine定義も差し替えることで処理を分けています。
▲ゲームからはインターフェイスを参照する

▲メニューからライブラリを切り替える
▲サービスロケータへの登録

エレキベア
これでだいぶ綺麗にまとまったクマね
おわりに

マイケル
というわけで今回はサウンドミドルウェアの依存を減らしつつオーディオ処理を実装する方法についてでした!
どうだったかな?

エレキベア
中々面倒だったクマがなんとか汎用的にできたクマね

マイケル
ライブラリを切り換えることはそうそうないと思うけど、
普段から依存を減らすよう実装には気をつけたいね・・・

マイケル
次回以降、CRIとWwiseの実装内容についても軽く執筆する予定です!
お楽しみに!!

エレキベア
クマ〜〜〜〜〜
【Unity】サウンドミドルウェアに依存しない設計を考える【CRI ADX・Wwise】〜完〜