ゲーム開発
Unity
UnrealEngine
C++
Blender
Houdini
ゲーム数学
ゲームAI
グラフィックス
サウンド
アニメーション
GBDK
制作日記
IT関連
ツール開発
フロントエンド関連
サーバサイド関連
WordPress関連
ソフトウェア設計
おすすめ技術書
音楽
DTM
楽器・機材
ピアノ
ラーメン日記
四コマ漫画
その他
おすすめアイテム
おもしろコラム
  • ゲーム開発
    • Unity
    • UnrealEngine
    • C++
    • Blender
    • Houdini
    • ゲーム数学
    • ゲームAI
    • グラフィックス
    • サウンド
    • アニメーション
    • GBDK
    • 制作日記
  • IT関連
    • ツール開発
    • フロントエンド関連
    • サーバサイド関連
    • WordPress関連
    • ソフトウェア設計
    • おすすめ技術書
  • 音楽
    • 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