🎹

UE5 (EarlyAccess) + MetaSounds で曲演奏をしてみる

2021/06/15に公開

はじめに

先日公開された Unreal Engine 5 Early Access 。 Nanite や Lumen といったグラフィックスの新機能に注目が集まっていますが、私的にはサウンドの新機能である "MetaSounds" がかなり気になりまして、ちょっと試してみました。

MetaSounds はノートベースで要素をつないで音を作り、外部からパラメーターを与えることでリアルタイムに音を変化させる事ができる機能です。 "DAW の代わりになるのでは?" みたいな話を見かける一方、 Early Access では今のところそういった打ち込んだシーケンスを元に演奏する機能はなさそうでした。

で、なんとか組み込みの機能だけで曲の演奏をしてみようとしてみたので、その手順をまとめました。

MetaSounds の導入

MetaSounds は初期状態では使えないのでプラグインを有効化、再起動をします。

プラグインが有効化されたらコンテンツドロワーの追加で MetaSound を新規作成します。

音を作る

Quick Start Guide 通りに進めるのもよいのですが、音を出すまでがちょっと長いので手っ取り早く音を出すことを試しながらやっていく方がよいかなと思います。

基本

  1. MetaSounds のグラフ内で右クリックしてメニューを出して、検索窓に "sine" と入力して "正弦波" (Sine) を選択します
  2. Audio ピンを Output ノードの Audio ピンに接続します
  3. プレイを押します

すると 440Hz の正弦波が再生されます。

ソースとなるこれらの波形は正弦波の他、矩形波 (Square) 、三角波 (Triangle) 、のこぎり波 (Saw) があり、 Wav ファイルを入れることもできます。

さらに

  1. 同様にして検索窓で "delay" と入力して "レイトディレイ" (Late Delay) を選択します (ただの "ディレイ" はエフェクトなので注意。レイトディレイはイベント)
  2. OnPlay - レイトディレイ - OnFinished でノードを接続します。

とするとレイトディレイ指定時間で再生が停止するようになります。 On Play はグラフ再生開始のトリガーで、 On Finished にイベントを流すと再生が停止します。

ノート、エンベロープ

"MIDI から周波数 (Float)" の MIDI in ピンは MIDI のノート番号を入れます。 60 = c5 (MML 的には一般的に o4c) です。ノート番号に応じた周波数値が出力されるので、その値を波形ソースに接続すると任意のノートの音が出せるようになります。

エンベロープは "Trigger Attack" が Key On 、 "Trigger Release" が Key Off に対応し、 Trigger Release から鍵盤を放した後の減衰が始まります (ので "On Trigger Release" で止めてはならない) 。 "On Done" で完全な鳴り終わりになるので、この通知を On Finished に接続しています。

エンベロープは 0.0~1.0 (比率) の変化なのでソース (ここではサイン波) と乗算し、出力します。

Audio と Float

MetaSounds のノード/ピンでは "Audio" と "Float" の二種類の値を扱います。

"Audio" は波形グラフの縦軸方向の数値で音量を表すものです。一方、 "Float" は浮動小数点値そのもので汎用的に使われます。 Audio と Float 間での演算は制限されていますが、相互のキャストも容易です。
Audio もおそらくは浮動小数点値だと思うのですが、 "音声として出力してよい値" と明示的に区別するためのものと思われます。

LFO

LFO は LFO ノードを追加し、元のパラメーター (周波数など) に対して加算、乗算をして適用します。周波数に関しては乗算で適用した方が音の高さによる係り方のばらつきが少なくなるのではないかなあと思います。

乗算としているので範囲を 0.95~1.05 としています (加算だったら -2.0~2.0 など)。

LFO をビブラート的にかける場合、発音してから一定時間経過後に LFO がかかるようにしたいところですが、 MetaSounds の LFO は常に LFO がかかっている状態なので、そのような調整ができません。が、 MetaSounds はノードベースで自由に組み合わせができるのが特徴。ちょっとした工夫で対応が可能です。

ここでは Trigger Route ノードを使ってトリガーに応じて定数か LFO の値かのどちらを使うか切り替えるようにしてみました。

変調

サイン波、矩形波、三角波、のこぎり波は "変調 (Modulation)" の入力ピンがあるので周波数変調をかける事ができます。つまり FM 音源です。いわゆる実チップのエミュレーションにはならないと思いますが、サイン波以外もかけられたり実質無限の数のオペレーターを好きにつなぐ事ができるので、かなり自由な音作りが可能ではないかなあと思います。

フィードバックは "Audio を送信" と "Audio を受信" を組み合わせる事で実現できます。

https://twitter.com/TANY_FMPMD/status/1401527795868594176?s=20

シーケンスを入力してみる (Early Access 版)

ここからシーケンス入力に挑戦してみます。

Early Access では MetaSounds 上で SMF や MML といった一般的な音楽のシーケンスデーターをソースにする方法が用意されていないようなので、 Blueprint のインターフェースを利用して外部から MetaSounds を制御して曲を鳴らしてみようと思います。

注意点ですが、

The MetaSound Blueprint interface is under active development and is expected to change prior to Unreal Engine 5's full release.

とあるように、 Blueprint とのインターフェースは今後おそらく変更されるのと、おそらく MetaSounds 上で SMF などを入力する手段が用意される (か誰かえらい人が作ってくれる) と思うので、本項の内容の多くは実質現時点のみ通用する半分ネタみたいなものになると思います。その辺りはご理解ください。

MetaSounds のパラメーターを外部から変更できるようにする

まず MetaSounds のノードの値を外部から変更できるようにします。対象のピンをドラッグして "グラフ入力に昇格 (Promote to Graph Input)" を選択。名前は適切なものに変更します。

  • "MIDI から周波数 (Float)" の "MIDI in" ピン (→ グラフ入力名 "Note")
  • エンベロープの "Trigger Attck" (→ グラフ入力名 "Key On")
    • "On Play" からの接続は削除
    • "On Play" から接続していたピンは "Key On" につなぎなおす
  • エンベロープの "Trigger Release" (→ グラフ入力名 "Key Off")
    • 元々つないでいたレイトディレイは削除
  • エンベロープの "On Done" から "On Finished" への接続は削除 (MetaSounds が止まるのが困るので)

LFO は 0.99~1.01 に調整しています。

必須ではないですが、 "出力" の前に定数との乗算ノードをはさんで音量を絞っています (これも外部から変更できるようにするとよいでしょう) 。

この状態で再生テストをしても音は鳴りませんが、 "Key On" の (↓) をクリックするとイベントが発生して鳴ります。同様に "Key Off" でエンベロープの Release が確認できます。

Sequencer の準備をする

曲データの打ち込みに "Sequencer" を利用します。

UE の Sequencer は通常はグラフィックスのアニメーションに利用するものですが、 "決められたタイミングで指定した音を発声する = 曲の演奏" ということで、今のところ他に適切な方法はないと思うのでこれでいきます。

とりあえずコンテンツドロワーで新規のレベルシーケンスを作り、開きます。

まず fps を決定します。 fps は曲のテンポ及び分解能に直結します。例えば "♩ = 60" というテンポで入力する曲で一番細かい音符が四分音符であれば "1 fps" ということになります。 fps を上げておけばそれだけ細かい制御が可能になりますが、数えるのも面倒になるので適切な値を設定するようにしましょう。今回は "♩ = 120" の四分まで想定で 2fps を設定します。

トラックを追加する

レベルに先ほど準備した MetaSounds を D&D して追加します (もしくは Actor に適切に Audio Component と Sound ソースに MetaSounds を設定) 。名前はとりあえず "SoundSource 1" としました。

シーケンスのトラック追加で "シーケンサへのアクタ → 追加した MetaSounds のアクタ" を指定して追加します。

追加したトラックの "+ トラック" で "イベント → トリガー" をします。

曲の打ち込みをする

後は任意位置にイベントをおいていきます。とりあえず 0, 2 フレーム目の位置に起きました。また、シーケンスの開始位置 (緑線) を 0 フレームにしていると 0 フレーム目のイベントが発行されない (?) ようだったので -1 フレームから開始するようにします。

次に置いたイベントをダブルクリックするとイベントグラフを実装するためのブループリント画面が開きます。両方ダブルクリックして 2 つ準備します。

ここからが Blueprint で MetaSounds を制御する (今のところの) やり方です。

  • パラメーターを変更する
    1. イベントピンからドラッグして "Set Float" 関数を出します。
    2. イベントのアクターのピンからドラッグして "Get Paramter Interface" 関数を出し、 "Return Value" を Set Float のターゲットに接続します。
    3. Name に MetaSounds で設定したグラフ入力名をセット。ここでは "Note" 。
    4. Value に設定した値を指定します。ここではとりあえず "67" を指定します。初期値の 60 以外がよいでしょう。
  • イベントを発行する
    1. イベントピンからドラッグして "Trigger" 関数を出します。
    2. 同様に "Get Paramter Interface" 関数から "Return Value" を Trigger のターゲットに接続します。
    3. Name はここでは "Key On" 。

これで "音程 67 に設定してから発音" という処理になります。同様に次のイベントで "Key Off" トリガーを叩いて発音を止めるようにしてみます。すると次のようになります。

最後にシーケンスを再生するように仕込みます。

これで Editor のプレイボタンを押すと 1 秒 ("♩ = 120" で 2 拍) 音を鳴らして止まる、という再生になりました。

・・・あとはもう力技で沢山並べていくだけです。が、音を鳴らしたり止めたりする度にノードを組むのは (コピペするとしても) あまりにも不毛なので関数を定義した方がよいでしょう。

シーケンスのプループリントの "関数" の (+) ボタンを押して追加し、次のような関数を定義します。

  • Key On
  • Key Off

と定義をした上でイベントのプループリントを書き直すと幾分か見やすくなります。

トラック (同時発音数) を増やす

"トラックを追加する" から同じようにソース (Audio Component) と制御するトラックを追加していくことで同時に鳴らす音を増やしていくことができます。

同じようにイベントを追加していって、イベント毎に Key On / Key Off の関数を関連付けていきます。

左からトラック 1, 2, 3, 4 で縦方向が時間方向に並べてます。
本当に力技です。

https://twitter.com/TANY_FMPMD/status/1404558724824387590?s=20

おわりに

MetaSounds は一つ一つの要素は非常にシンプルなものですが、それらを柔軟に組み合わせる事で自由な音作りをすることができるかなりすごい機能だと思います。

ただ、これで音楽を演奏するにはやはり SMF 入力 (かそれに類する機能) がないとどうにもならないかなあという感じはします。プロシージャルで生成するにしても限度があるでしょうし。 SMF で複数のフレーズの断片を入力し、状況に応じて音色と合わせて切り替えていく、みたいな使い方ができると結構よいかなあと思いました。

まだ初期段階ですし、これからの進化に期待しています。

Discussion