ゲーム開発
Unity
UnrealEngine
C++
ゲーム数学
ゲームAI
サウンド
アニメーション
GBDK
制作日記
3DCG
Houdini
Blender
USD
グラフィックス
テクノロジ
ツール開発
フロントエンド関連
サーバサイド関連
ソフトウェア設計
ハードウェア関連
おすすめ技術書
音楽
DTM
楽器・機材
ピアノ
その他
都会のエレキベア
ラーメン日記
四コマ漫画
おすすめアイテム
おもしろコラム
  • ゲーム開発
    • Unity
    • UnrealEngine
    • C++
    • ゲーム数学
    • ゲームAI
    • サウンド
    • アニメーション
    • GBDK
    • 制作日記
  • 3DCG
    • Houdini
    • Blender
    • USD
    • グラフィックス
  • テクノロジ
    • ツール開発
    • フロントエンド関連
    • サーバサイド関連
    • ソフトウェア設計
    • ハードウェア関連
    • おすすめ技術書
  • 音楽
    • DTM
    • 楽器・機材
    • ピアノ
  • その他
    • 都会のエレキベア
    • ラーメン日記
    • 四コマ漫画
    • おすすめアイテム
    • おもしろコラム
  1. ホーム
  2. 20240330_02_unity_wwise_practice

【Unity】第二回 Wwiseを使用したサウンド制御 〜インタラクティブミュージック編〜

サウンドUnityWwiseインタラクティブミュージック
2024-03-30

マイケル
マイケル
みなさんこんにちは! マイケルです!
エレキベア
エレキベア
こんにちクマ〜〜〜
マイケル
マイケル
前回の記事に引き続き、Wwiseを使用したサウンド制御について触れていきます! 今回はサウンドミドルウェアの醍醐味である「インタラクティブミュージック」の実装例について紹介します! 具体的には下記のようなサンプルになります。
【Unity】第一回 Wwiseを使用したサウンド制御 〜基本動作編〜
2024-03-30

▲前回の記事

20240327_01_unity-multi_audio_05
▲実装したインタラクティブミュージックのサンプル

エレキベア
エレキベア
おお〜〜〜 サウンドに合わせてオブジェクトが反応するのは見ていて楽しいクマね
マイケル
マイケル
サンプルプロジェクトのリポジトリと、CRI関連処理については下記になります! こちらも合わせてご参照ください!

GitHub - unity-multi-audio

▲サンプルプロジェクト

フォルダ
内容
Wwiseプロジェクト
APIを実行する処理
サンプルゲーム固有のオーディオ関連処理
サンプルゲームに関する処理
Wwiseプロジェクトから出力したサウンドデータ
エレキベア
エレキベア
中々ボリュームのあるサンプルクマ

参考書籍

マイケル
マイケル
今回実装するにあたり、下記書籍を参考にさせていただきました!

Unityサウンド エキスパート養成講座

マイケル
マイケル
Wwiseには触れていませんが、UnityAudioとCRIADXを使用した実装について紹介されているためサウンドミドルウェアを使用するイメージが掴めると思います!
エレキベア
エレキベア
Unityでのサウンド実装について幅広く知れる一冊クマね

インタラクティブミュージックの実装

マイケル
マイケル
それでは早速実装内容について見ていきます! インタラクティブミュージックの実装について、今回は下記について盛り込んでみました!
  • イントロループからのブロック遷移
  • オーディオ側からのイベント発行
  • ビート同期によるオブジェクト伸縮
  • AISAC値によるサウンド変化
エレキベア
エレキベア
いろいろ盛り込んでるクマね・・・
マイケル
マイケル
今回のために、サンプル実装がしやすい曲も作りました・・・ それぞれ見ていきましょう!

イントロループからのブロック遷移

マイケル
マイケル
最初に行ったのが「イントロループからのブロック遷移」処理です。 具体的にどういうことかというと、はじめはイントロをループしておき、プレイヤーが動き始めたらメインとなるブロックに遷移させるといった内容です!
20240327_01_unity-multi_audio_12
▲プレイヤーが動き始めるまでイントロをループさせる

エレキベア
エレキベア
なんかペルソナのダンジョン出発前とかで見たことがある気がするクマ
マイケル
マイケル
これを行うには、事前に曲を分割しておく必要があります。 今回は ・イントロ ・イントロループ ・メイン ・メインループ の4つのブロックに分けて定義しました。
マイケル
マイケル
これをWwiseで実現するために、MusicSwitchContainer等の仕組みを使用しました。 InteractiveMusicHIerarchyに、 Music Switch Container - Music Playlist Container - Music Segment といった構造で定義します。

Wwiseヘルプ - Music Switch Containerの中身と、再生方法の設定

20240330_02_unity_wwise_practice_02
▲MusicSwitchContainerの定義

20240330_02_unity_wwise_practice_04
▲Music Segment内ではループ等の再生方法を設定する

エレキベア
エレキベア
大きくイントロ、メインに分けて、その中で開始部分とループ部分を定義しているクマね
マイケル
マイケル
あとはMusicPlaylistContainer内でStateによってイントロとメインを切り替えれるように設定すれば準備は完了です。
20240330_02_unity_wwise_practice_03
▲StateでMusic Playlist Containerを切り替えれるようにする

20240330_02_unity_wwise_practice_01
▲Stateの定義

マイケル
マイケル
スクリプト側で任意のタイミングでStateを切り替える処理を実行すれば、曲が違和感なく遷移することが確認できるはずです。
        /// <summary>
        /// Stateの設定
        /// </summary>
        /// <param name="stateGroupName"></param>
        /// <param name="stateName"></param>
        public void SetState(string stateGroupName, string stateName)
        {
            AkSoundEngine.SetState(stateGroupName, stateName);
        }
▲Stateの設定
        /// <summary>
        /// ブロック遷移状態を設定する
        /// </summary>
        /// <param name="state">遷移状態</param>
        public void SetNextBlockState(IGameAudioService.NextBlockState state)
        {
            switch (state)
            {
                case IGameAudioService.NextBlockState.BgmAtomChainIntro:
                    _wwiseApiService.SetState(GameWwiseAudioSettings.Wwise.StateGroupName.BgmAtomChain,
                        GameWwiseAudioSettings.Wwise.StateName.BgmAtomChainIntro);
                    break;
                case IGameAudioService.NextBlockState.BgmAtomChainMain:
                    _wwiseApiService.SetState(GameWwiseAudioSettings.Wwise.StateGroupName.BgmAtomChain,
                        GameWwiseAudioSettings.Wwise.StateName.BgmAtomChainMain);
                    break;
            }
        }
▲遷移するブロックのStateを設定する
エレキベア
エレキベア
Wwiseでほぼ設定したからスクリプト側はシンプルクマね

オーディオ側からのイベント発行

マイケル
マイケル
次は曲がメインの部分に入ったらオブジェクトを表示&背景色を変更するという処理になります。
20240327_01_unity-multi_audio_05
▲メインの小節に入ったらオブジェクトと背景を表示する

マイケル
マイケル
これにはEventの中にコールバックを設定することで検知できるようにしました。 あとは設定したタグ名をスクリプト側で受け取ってコールバック登録すれば実装は完了です。

参考:WwiseSDK - 既存のMusic Segmentに、Custom Cueを追加する

20240330_02_unity_wwise_practice_05
▲CustomCueの設定

        /// <summary>
        /// 再生オプション
        /// </summary>
        public class SoundPlayOption
        {
            /// <summary>
            /// 再生中の音声を停止するか?
            /// </summary>
            public bool IsStopOther;

            /// <summary>
            /// フェード時間
            /// </summary>
            public int FadeTimeMs;

            /// <summary>
            /// ビート同期イベント コールバック
            /// </summary>
            public Action BeatSyncCallback = null;

            /// <summary>
            /// カスタムで追加したイベント コールバック
            /// </summary>
            public Action CustomEventCallback = null;
        }
▲コールバックオプションの定義
        /// <summary>
        /// Eventの再生
        /// </summary>
        /// <param name="soundBankName"></param>
        /// <param name="eventName"></param>
        /// <param name="gameObject"></param>
        /// <param name="option"></param>
        /// <returns></returns>
        public uint PlayEvent(string soundBankName, string eventName, GameObject gameObject, IWwiseApiService.SoundPlayOption option = null)
        {

・・・略・・・

            // Event再生
            uint playId = 0;
            if (option?.CustomEventCallback != null)
            {
                uint callbackTypeValue = default;
                if (option?.CustomEventCallback != null) callbackTypeValue |= (uint) AkCallbackType.AK_MusicSyncUserCue;
                AkCallbackManager.EventCallback eventCallback = (cookie, type, info) =>
                {
                    switch (type)
                    {
                        case AkCallbackType.AK_MusicSyncUserCue:
                            option?.CustomEventCallback?.Invoke();
                            break;
                    }
                };
                playId = AkSoundEngine.PostEvent(eventName, gameObject, callbackTypeValue, eventCallback, null);
            }
            else
            {
                playId = AkSoundEngine.PostEvent(eventName, gameObject);
            }

・・・略・・・

            return playId;
        }
▲シーケンスコールバックの登録
エレキベア
エレキベア
Wwiseでは再生時にコールバックを紐づけるクマね

ビート同期によるオブジェクト伸縮

マイケル
マイケル
次はBGMのリズムに合わせてオブジェクトを伸縮させる処理についてです。 こちらはHi-Fi Rush等でよく見られるような挙動ですね
20240328_02_unity_cri_practice_03
▲今回はSphereとBoxを対象とした

マイケル
マイケル
これを行うには、予めオーディオにBGMや小節等のビート同期情報を設定しておく必要があります。 あとはCustomEventと同様、再生時にコールバックを登録すれば実装は完了です。
20240330_02_unity_wwise_practice_06
▲BPM、小節等の設定

        /// <summary>
        /// Eventの再生
        /// </summary>
        /// <param name="soundBankName"></param>
        /// <param name="eventName"></param>
        /// <param name="gameObject"></param>
        /// <param name="option"></param>
        /// <returns></returns>
        public uint PlayEvent(string soundBankName, string eventName, GameObject gameObject, IWwiseApiService.SoundPlayOption option = null)
        {

・・・略・・・

            // Event再生
            uint playId = 0;
            if (option?.BeatSyncCallback != null
                || option?.CustomEventCallback != null)
            {
                uint callbackTypeValue = default;
                if (option?.BeatSyncCallback != null) callbackTypeValue |= (uint) AkCallbackType.AK_MusicSyncBeat;
                if (option?.CustomEventCallback != null) callbackTypeValue |= (uint) AkCallbackType.AK_MusicSyncUserCue;
                AkCallbackManager.EventCallback eventCallback = (cookie, type, info) =>
                {
                    switch (type)
                    {
                        case AkCallbackType.AK_MusicSyncBeat:
                            option?.BeatSyncCallback?.Invoke();
                            break;
                        case AkCallbackType.AK_MusicSyncUserCue:
                            option?.CustomEventCallback?.Invoke();
                            break;
                    }
                };
                playId = AkSoundEngine.PostEvent(eventName, gameObject, callbackTypeValue, eventCallback, null);
            }
            else
            {
                playId = AkSoundEngine.PostEvent(eventName, gameObject);
            }

・・・略・・・

            return playId;
        }
▲コールバックの登録
マイケル
マイケル
なお、SphereやBoxといった伸縮させるオブジェクトには、下記のようなインターフェイスを実装してビート数を受け取るよう実装しています。 こちらも気になる方はリポジトリの実装を参照してみてください!
namespace GameSample.Objects.BeatSync
{
    /// <summary>
    /// ビート同期オブジェクト
    /// </summary>
    public interface IBeatSyncBehaviour
    {
        /// <summary>
        /// ビート同期
        /// </summary>
        /// <param name="beatCount">ビート数</param>
        public void OnBeatSync(int beatCount);
    }
}

▲ビート同期オブジェクトのインターフェイス
エレキベア
エレキベア
CustomEventの実装とほぼ同じだったクマね

GameParameterによるサウンド変化

マイケル
マイケル
最後に味付けにはなりますが、ボスに近づくほどに別のギターパートの音量を上げるよう変化させてみました。 こちらはRTPCという機能を使用して、ゲームから設定したパラメータに応じてサウンド側のパラメータも編集させることで実現しています。
20240328_02_unity_cri_practice_06
▲ボスに近づくほどにギターパートの音量を上げるように変化させる

20240330_02_unity_wwise_practice_07
▲変化させるパートのRTPC処理を調整

        /// <summary>
        /// GameParameterの設定
        /// </summary>
        /// <param name="gameParameterName"></param>
        /// <param name="value"></param>
        public void SetGameParameter(string gameParameterName, float value)
        {
            AkSoundEngine.SetRTPCValue(AkSoundEngine.GetIDFromString(gameParameterName), value);
        }
▲GameParameterの設定
エレキベア
エレキベア
DSPエフェクトの実装時にも使用していたクマね 幅広く使えて便利クマ〜〜〜

おわりに

マイケル
マイケル
というわけで今回はWwiseによるインタラクティブミュージックの実装でした! どうだったかな?
エレキベア
エレキベア
CRIとはまた設定方法が違って面白かったクマ〜〜〜 どちらも機能は一通り用意されていて活用できそうクマね
マイケル
マイケル
長かったですが、これにてサウンドミドルウェアの学習は一通り終了です! 今後のゲーム開発で活用していく予定なので、また知見があれば記事にしようかと思います!
マイケル
マイケル
それでは今日はこの辺で! アデューーー!!
エレキベア
エレキベア
クマ〜〜〜〜

【Unity】第二回 Wwiseを使用したサウンド制御 〜インタラクティブミュージック編〜 〜完〜

【Unity】第一回 UnityAudioを使いこなす 〜サウンド再生処理編〜
2024-01-22
【Unity】第二回 UnityAudioを使いこなす 〜AudioMixer活用編〜
2024-01-22
【Unity】第一回 CRI ADXを使用したサウンド制御 〜基本動作、周波数解析編〜
2024-03-28
【Unity】第二回 CRI ADXを使用したサウンド制御 〜インタラクティブミュージック編〜
2024-03-28
【Unity】サウンドミドルウェアに依存しない設計を考える【CRI ADX・Wwise】
2024-03-27

サウンドUnityWwiseインタラクティブミュージック
2024-03-30

関連記事
【Unity】Timeline × Excelでスライドショーを効率よく制作する
2024-10-31
【Unity】Boidsアルゴリズムを用いて魚の群集シミュレーションを実装する
2024-05-28
【ゲーム数学】第九回 p5.jsで学ぶゲーム数学「フーリエ解析」
2024-05-12
【Unity】GoでのランキングAPI実装とVPSへのデプロイ方法についてまとめる【Go言語】
2024-04-14
【Unity】第一回 Wwiseを使用したサウンド制御 〜基本動作編〜
2024-03-30
【Unity】第二回 CRI ADXを使用したサウンド制御 〜インタラクティブミュージック編〜
2024-03-28
【Unity】第一回 CRI ADXを使用したサウンド制御 〜基本動作、周波数解析編〜
2024-03-28
【Unity】サウンドミドルウェアに依存しない設計を考える【CRI ADX・Wwise】
2024-03-27