8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ADX+UE5で作る、インタラクティブミュージック中のクォンタイズ機能(改訂版)

Last updated at Posted at 2021-10-14

はじめに

ADXアンバサダーとして執筆しておりますSigと申します。
この記事ではアンリアルエンジンとサウンドミドルウェア「ADX for UE」を連携させ、インタラクティブミュージックの要素である「クォンタイズ」を実装してみます。
自分で音楽を奏でられる遊びや、ゲーム内の演出や音をBGMのタイミングに合わせたりといった演出を作ることができます。

当記事ではUE5.2を使用しています。
基本的にブループリントのみでの実装を想定しています。
ADXはインディー向けの「LE版」であれば、無料で使用できます。
https://game.criware.jp/products/adx-le/

なお、ADX2はADXへ名称が変更になりましたが、ツール構成は変更ありません(2がないから古いほう、というわけではありません)。

記事執筆時点のADX for UEのSDKバージョンは「ADX LE UE SDK(2.00.00.00)」です。

前提

ADX for UEの導入や基本的な使い方は以下の記事にあります。必要に応じて参照してください。
ADX for UEの導入で、一歩上のサウンド表現を(導入編)
https://qiita.com/SigRem/items/4250925f6d66a4fd287a
ADX for UEの導入で、一歩上のサウンド表現を(実践編)
https://qiita.com/SigRem/items/c089b71c42e898980a46

クォンタイズとは

楽曲制作において、クォンタイズはばらばらに配置された音符(ノート)を楽曲に合わせたテンポに配置する機能のことです。
本来無段階に鳴らすことのできるサウンドに最小単位を設け、それに沿って再生することで音楽として成立させます。

ImageA.png

インタラクティブミュージックにおいてもクォンタイズは有効です。
ゲーム中に再生するサウンドを保留しキューに入れておき、BGMのテンポに合わせて実際に再生を開始することで両者を統一させ、まるで最初からひとつのサウンドだったかのように聞かせることが可能です。

ImageB.png

今回の記事の実装を試したいけど手頃な音声素材がない……という方のために、1フレーズではありますが素材を用意しましたのでご利用ください。
https://github.com/SigRem221/adx2forue4-booksample/tree/master/ADX_QuantizeSample

https://drive.google.com/file/d/1-PhYlpIMZRkZgW1XaM_95IGsI4RTCeK0/view?usp=share_link
(どちらのリンクも内容は同じものです)

実装

AtomCraftでサウンドをセットアップする

マテリアルのインポート

AtomCraftにサウンド素材となるマテリアルをインポートします。
扱うファイルが多くなるため、用途に合わせてフォルダ分けしておくと便利です。
「マテリアルルートフォルダー」を右クリックし、「新規オブジェクト」→「マテリアルフォルダーの作成」でフォルダが作成できます。
A00.png
画像ではドラムループ、ピアノパート、リード、ストリングスに分けてあります。

A01.png
フォルダごとに素材を振り分けてインポートしました。
A02.png
ループする素材についてループ情報の上書きを行います。
マテリアルを選択し、インスペクターにてループ情報の上書きを「True」に、ループタイプを「ループ」にします。
A03.png
これでドラムループが自動的にループ再生されるようになります。

ドラムループパートの作成

楽器パートごとにキューを作成します。
まずはドラムループです。
キューシートのワークユニットを右クリックし、「新規オブジェクト」→「キュー『ポリフォニック』の作成」を選択します。
A04.png
オーソドックスなキューが作られるので、ドラムループ素材をキューに入れます。

次にビートのタイミングをUE側で取得できるよう、ビート同期情報を設定します。
トラックリストの空欄で右クリックし、「新規オブジェクト」→「ビート同期情報の作成」を選択します。
A05.png
「BeatSync」という表示が追加されました。
A06.png
ビートの情報を設定するには、楽曲のBPMの値が必要です。
BPMが分からない場合、対象のマテリアルを右クリックして「BPM解析」を選択します。
A07.png
ログに「BPM "142"」という表示がされ、楽曲のBPMが142であることが分かりました。
A08.png
キューの「BeatSync」を選択し、インスペクターにてBPMに「142」を入力します。
A09.png

必須ではありませんが、分かりやすいようタイムラインの表示単位も変えておくと役立ちます。
トラックリストの上にある時計の右の逆三角をクリックし、「タイムベースの編集」を開きます。
A10.png
ここのBPMにも「142」を設定しておきます。
A11.png
タイムライン表示が楽曲のテンポに合わせられました。
次の画像ではちょうどいい場所で曲がループしているのが分かります。
A12.png

クォンタイズする楽器パートの作成

次にピアノやリードなどの楽曲パートのキューを作成します。
キューシートを右クリックし、「新規オブジェクト」→「キュー『ランダム』の作成」か「キュー『ランダムノーリピート』の作成」を選択します。
これらの違いは何度もランダムなトラックを再生した際に、「同じトラック」を続けて再生するかどうかです。
A13.png
作成されたキューに対して、1トラックにひとつずつマテリアルから対応する素材を入れていきます。
A14.png
試しに再生してみましょう。毎回違うトラックがランダムで再生されるはずです。
A15.png
リード、ストリングパートに対しても同じようにキューを作成します。
A16.png
これらもマテリアルの数だけトラックを持つことになります。
A17.png

キューシートのビルド

ここまででひとまずAtomCraftでの作業は完了です。
ツールバーからキューシートをビルドします。
A18.png
複数のキューシートを作成した場合、すべてのキューシートにチェックがついていることを確認してください。
チェックがついていないキューシートはビルドされません。
A19.png

UE5でクォンタイズを実装する

キューシートのインポート

AtomCraftでビルドしたacf、acbファイルをUE5のコンテンツブラウザ(またはコンテンツドロワー)にドラッグアンドドロップし、インポートします。
ワークユニットやキューシートが複数ある場合、acbファイルも複数出力されています。すべてインポートしてください。

acfファイルのインポート時のダイアログではどちらも「Yes」を選択します。
A01.png
A02.png
これにより、このプロジェクトで使用するAtom Configファイルが自動的に設定されます。

acf、acbファイルをインポートすると、コンテンツブラウザにアセットとして追加されます。
A03.png
キューシートを開き、正常に再生できるか一度確認しておきましょう。
A04.png

サウンドの配置

ドラムループのキューをレベル上にドラッグアンドドロップして配置します。
A05.png

配置したキューを選択しておき、「Blueprint」→「Open Level Blueprint」でレベルブループリントを開きます。
A06.png

ブループリントからビート情報を取得する

イベントグラフ上で右クリックして「Create a Reference to (キュー名)」を選択し、リファレンスノードを作成します。
B01.png

リファレンスノードから線を伸ばし、Get Atom Componentを選択して配置します。
B02.png

Get Atom Componentからさらに線を伸ばし、「assign beat」と検索して出てくるAssign On Atom Beat Sync Callbackを選択すると、ふたつのノードが配置されます。
B03.png
B04.png

自動的に作られたカスタムイベントに適当に名前をつけておきます。
B05.png

これでビートごとにイベントが走るようになりました。
テスト用に文字を表示してみます。
カスタムイベントから線を伸ばし、Print Stringノードでデバッグメッセージを出します。
B06.png
実行してみると、ウィンドウ左上にドラムのテンポに合わせてメッセージが表示されます。
B07.png

合わせてサウンドも鳴らしてみましょう。
「atom 2d」と検索し、出てきたPlay Sound 2Dノードを配置します。
B08.png
B09.png

再生するキュー(サウンド)を指定するために、新規に変数を用意します。
「My Blueprint」パネルの「VARIABLES」で+ボタンを押し、変数を追加します。
B10.png
適当に名前をつけます。変数の型は「Atom Cue Sheet」型の「Object Reference」です。
B11.png
コンパイルすると初期値が設定可能になるので、Detailsパネルでキューシートを指定します。
B12.png
変数をイベントグラフにドラッグ&ドロップし、Get CueSheet_IMQノードを配置します。
B13.png
Get CueSheet_IMQノードから線を伸ばし、Get Sound Cue by Nameノードを配置します。
名前を指定してキューシートからキューを取得するものです。
「Cue_A_Piano」を指定してピアノのサウンドのキューを取得します。
B14.png

この状態でゲームを実行してみましょう。音楽のテンポに合わせて、絶え間なくピアノのサウンドが再生されるはずです。

サウンドのクォンタイズ

各楽曲パートをゲーム中にクォンタイズし、再生する処理を作っていきます。
パートごとに入力を受け取れるよう、変数を追加しましょう。
今回はシンプルな例として、Bool型変数をパートごとに作成しています。
C01.png

Input Keyイベントノードで1,2,3キーが押されたことを感知し、対応する変数をTrueにします。
C02.png

カスタムイベントから線を伸ばし、入力によって変数がTrueになっていた場合、サウンドを再生して変数をFalseに戻す処理を書きます。
これでビートごとに楽器キーの入力判定と再生が行われることになります。

パートごとに同じ処理を作ります。Sequenceノードを使うと処理を順番に書けるため、グラフが分かりやすくなるのでおすすめです。

C03.png

変数「bPlayPiano」が「True」の場合(つまり、直前に1キーが押されていた場合)、ピアノのサウンドを再生して「bPlayPiano」を「False」に戻します。
C04.png

これで、1キーを押した直後のビートのみピアノのサウンドが再生されることになります。

同じように、他のパートについても処理を作ります。ほぼコピペでOKです。
C05.png

さて、ここで一度テストプレイしてみましょう。1,2,3キーを押すと次のビートタイミングで楽器が演奏されるはずです。
しかし、サンプルのストリングスパートは少し尺が長いため、連続で押すと重なって演奏されてしまい、不自然に感じます。

演奏タイミングをパートごとに設定する

解決方法は簡単です。
カスタムイベントの「Beat Sync Info」から線を伸ばし、Breakノードをつなげるとビート同期情報の分解ができ、詳細な情報を取り出すことができます。
D01.png

Break Atom Beat Sync Infoノードの「Beat Count」からは小節内で現在何ビート目のタイミングかを受け取れます。
試しに「Beat Count」をPrint Stringノードにつなぎ、メッセージとして出力してみます。
D02.png

ビートのカウントは0から始まり、4つめのタイミングでまた0に戻ります。小節内のビート数が正しく取得できているのが分かります。
B22.png
これを踏まえて、ストリングスの再生処理にBranchノードを噛ませます。
条件を**「Beat Cnt == 0」**とすると、各小節の始めのみにストリングスの演奏判定が行われることになります。
D04.png

この状態でテストプレイすると、ストリングスの音は重ならずに演奏されるようになっているはずです。

さらに演出を追加する場合や、ユーザーの入力体験を高める方法もまとめていますのでこちらの記事も参照してください(こちらは前バージョンで書かれた記事になります)。
ADX2 for UE4でつくるクォンタイズ(テクニック補完編)
https://qiita.com/SigRem/items/207ef9c8b70c1cc798b0

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?