Unreal Engine 5.1でMIDIデバイスを使う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/837c98eb-a63c-474f-ffb1-fed5eeed9a99.png)

この記事は[ MIXI DEVELOPERS Advent Calendar 2022 23 日目](https://qiita.com/advent-calendar/2022/mixi)の記事です。

# はじめに
こんにちは！

株式会社MIXIのデザイン部署にて、Creative Directorをやっています。Sound Designerでもあります。非エンジニアですが、ゲーム制作の現場ではTechnical Sound DesignerとしてUnreal Engineに触れる機会が多かったこともあり、その延長で最近ではUnrealを使ったVirtual Productionにも少し手を出しています。

デザイン部署のノンゲーム分野におけるUnreal Engine活用事例は、「[MIXIにおける、デザイン職独自の評価指針をつくった狙いについて](https://cocoda.design/mixiyoshiyukiyokoyama/p/pa2254e9a77bb#%E6%96%B0%E3%81%9F%E3%81%AA%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8%E3%81%A7%E3%80%81%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E7%B5%84%E7%B9%94%E3%81%AE%E3%82%B1%E3%82%A4%E3%83%91%E3%83%93%E3%83%AA%E3%83%86%E3%82%A3%E3%82%92%E5%BC%B7%E5%8C%96%E3%81%99%E3%82%8B%E5%8F%96%E3%82%8A%E7%B5%84%E3%81%BF%E4%BE%8B)」の記事で軽く掲載されています。

# 概要

今回の記事は、Unreal Engine 5.1でMIDIデバイスを使えるようにする方法を紹介します。具体的には、MIDI対応のフィジカル・コントローラーをUE5で使えるようにします。実験的実装になるので、ノンゲーム領域で使うことをオススメします。

- 環境
    - Unreal Engine 5.1（UE4.27でも確認済み）
    - Windows PC

:::note
元々はせっかくUnrealを使ったVirtual Productionをやるなら、BGMや効果音の再生、音量の調整などのオーディオ処理もUnreal Engine側でやりたいなというのが出発点です。ある程度Unreal側で自動でBGMや音量調整などを出来るようにした上で、MIDIフィジカル・コントローラーを使って人間の手で微調整したり、臨機応変に介入できる仕組みを考えています。
:::

Unreal Engine 5のMIDIの扱いに関する公式ドキュメントはこちらです。

https://docs.unrealengine.com/5.1/ja/midi-in-unreal-engine/

# セットアップ
プラグインの、MIDI Device Supportをアクティブにします。繰り返しになりますが、Betaプラグインですので、ノンゲーム領域で比較的融通が効く環境で使用することを推奨します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/514266e3-15a0-0d80-369e-9319267b8c0d.png)

## 使用したMIDIデバイス
今回、使用するMIDIデバイスは「AKAI APC mini」（左）と「PreSonus FADERPORT2」（右）です。APC miniは、マトリックス状にパッド（ボタン）が並んでいるのが特徴で、FADERPORT2は、フェーダー（スライダー）が、モーター駆動のムービング・フェーダーになっているのが特徴です。
![PXL_20221219_051906906_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/6c06ab54-cacf-909c-5c05-fdf3a9406b0c.jpeg)

## Blueprintクラスの作成と、レベルへの配置
移植性なども考えてBlueprintクラスを新規作成して実装していきます。名前は任意ですが「MIDI_Control」という名前にしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/22519b68-e3fa-2e05-0b19-1dc94dfcca99.png)


# PCに接続されているMIDI機器の状況を確認する
セットアップで作った「MIDI_Control」に、Blueprintで実装していきます。

まず状況を把握するために、Print Stringを使ってMIDIデバイスの情報を確認したいと思います。パソコンには、「AKAI APC mini」「PreSonus FADERPORT2」に加えて、MIDI入出力機能を備えたオーディオ・インターフェイス「Steinberg UR-22mk2」の3つのMIDIデバイスが接続されています。今回UR-22mk2は使用しません。

Blueprintを使って下記のようなDebug表示を実装していきたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/9623ee9a-6ca3-f0c8-1e8b-c66d06ad4839.png)

## MIDIデバイス情報をBlueprintで表示する
これらの表示はPrint Stringを使った、とても簡単な実装になっています。

下記は「Get Default MIDI Input Device ID」ノードを使って、デフォルトMIDIデバイスのIDを表示しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/ef76821c-bbc1-ed79-1b4a-7dcf5a6bb548.png)

次に接続されているすべてのMIDIデバイスの情報を表示します。「Find MIDI Device」を使います。「Find MIDI Device」は構造体になっているので、「For Each Loop」を使って要素を取り出しつつ、順番にPrint Stringを使って表示することにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/e254ee9a-4229-fc4c-7ed3-8ed9c0372ccc.png)

MIDIデバイスは、MIDI Input、MIDI Outputで異なるDevice IDが割り振られるようです。「Array Element Can Receive From」と「Array Element Can Send To」のBool値で、そのMIDI Device IDがINとして使えるか、OUTとして使えるかを判別することができます。Receiveじゃないってことは、Sendであると言えそうですが、ここでは念のために両方の値を参照してブランチしています。

これで、どのDevice IDがどのMIDI機材か、またInかOutかということがわかりました。このDebug表示するフロー自体は必須ではありませんが、状況を確認できるので実装してみました。

# MIDIデバイスを変数に格納
では、「AKAI APC Mini」と「Faderport」をUnrealで使えるようにしていきたいと思います。その為には、各MIDIデバイス用のObject変数を作成します。先ほど調べたDevice IDを使います。

## MIDI Inputの設定
「Create MIDIDevice Input Controller」ノードの、Deveice ID項目に先ほど調べた番号を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/2c90ae33-eef3-22e6-2f18-223a0ac933cd.png)

:::note
**TIPS**
Blueprintではノードを折りたたむことができます。折りたたむ、マクロ化、関数化というのもありますが、今回は単に見た目をすっきりさせたいという理由で折りたたんでいます。
　⇒ https://docs.unrealengine.com/4.27/ja/ProgrammingAndScripting/Blueprints/BP_HowTo/CollapsingGraphs/
:::

変数は「Create MIDIDevice Input Controller」のReturnValueから線を引っ張ってきて、変数へ昇格させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/e7e7b6d5-53f3-7891-1cfc-be739aee781c.png)

## MIDI Outputの設定
Inputと同じですが、Outputは「Create MIDIDevice Output Controller」を使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/db6006ca-f91b-0cc7-0f9c-e57d84d09071.png)

:::note warn
**補足**
一旦、ここでは上記のスクリーンショットにある「MIDIOutput Device Interface」は無視してください。後述する「Blueprint Interfaceについて」で軽く触れます。
:::

# MIDI信号を、イベントにバインドする
MIDIデバイスから、MIDI信号が来た時にイベントが実行されるようにバインドします。ここではMIDI信号の仕様やフォーマットについては割愛します[^1]。今回、使用するAPC miniでは、パッド部分がNote情報、スライダー部分はControl Change（略してCCと良く言われます）を使っています。


[^1]:M I D I 1.0 規格書 - 音楽電子事業協会
https://amei.or.jp/midistandardcommittee/MIDI1.0.pdf

Faderportは、Pitch Bend情報を使用しています。CCが8bitで0-127の128段階しか扱えないのに対して、Pitch Bendはより細かく音程を滑らかに表現できるように、2バイトの情報になっており-8,192～8,191の16,384段階扱うことができます。Faderportは、これを実際にはピッチ（音程）ではなく音量制御で利用しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/24a3f917-247f-6246-65db-ce85ee4d5580.png)

## イベントをバインドする
前の工程で作ったMIDIデバイスの変数を配置し、そこから線を引っ張ってきて「On MIDINote onにイベントをバインド」を選択します。ちなみに、カスタムイベントを即座に作って直接結びたいときは、「On MIDINote onを割り当てる」を選択すると、カスタムイベントも同時に作成されます。処理の違いまでは判らないのですが、今回は「On MIDINote onにイベントをバインド」の方法でやりたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/d327f52b-3e3c-3679-3779-c1aa076f59e8.png)

赤い四角の<font color="red">□</font>イベントコネクタから線を引っ張ってきて、「Create Event」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/6bb8042e-ade6-67cd-f701-9d80facd7818.png)

次にCreate Eventから「一致するイベントの作成」を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/f62eb616-9b10-7f65-6425-92fc0bd4438f.png)

するとカスタムイベントが作成されます。このカスタムイベントからはTimestamp、Channel、Note、Velocityの項目があります、カスタムイベントの名前は任意で付けることができます。今回は、わかりやすく「MIDI_APC_NoteOn」にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/9c16b4a1-77a2-3797-5473-ea956f22f674.png)

これで、MIDIデバイスからNote On信号が来たときにカスタムイベントが実行されます。

:::note
**TIPS**
ちなみにVelocityは速度をイメージしますが、音楽制作では打鍵した時の強弱を意味します。鍵盤が押し込まれる速度を、鍵盤を打鍵する時の強弱情報として扱っていると捉えていただければと思います。
:::

## 確認
確認のために、下記のようなシンプルなBlueprintを実装してみます。APCのパッドを叩くと、Noteナンバーを表示するという実装です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/7649435b-5a23-3132-d669-59a9a63677a2.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/322deb5d-acf8-1f70-1a16-16387fa46b82.png)

ここまでできれば、あとはこれを応用して様々なことができます。UE5でMIDIデバイスを使えるようにする方法は以上となります。UE4.27でも全く同じ方法で可能です。

# Appendix. 使用例
使用例として、効果音やBGMを再生したり、音量を変更したりすることが出来ます。また、Unreal Engine側からMIDI信号をMIDIデバイス側に送ることも可能なので、パッドの光やムービングフェーダーといった、フィジカル・コントローラー側をUnreal Engine側から制御することも可能です。

下記の動画はその一例です。
<iframe width="100%" height="400" src="https://www.youtube.com/embed/Yl8miipv1E4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


## 概要
Noteの値は整数なので、「整数でスイッチ」ノードを使って音を鳴らし分けています。ちなみに下記の「APC Audio PlayOnOff」と「APC Audio PlayOneShot」はマクロで、APCMiniの音の制御と、パネルの光り方の処理をマクロ化したものです。再生したいSound Cueと、Note On/Offの値を入力してやると動作するように実装にしてます。

Note Offはパッド（鍵盤[^2]）から指を離した時に送られるMIDI信号なので、パッドを押してる間は緑に、ボタンを離すと元の黄色に戻るといった制御が可能です[^3]。これらを使って、BGMのように一度押すと再生を開始し、もう一度押すと再生を停止するタイプと、効果音のように押したら1回だけ再生、または押してる間だけ再生されるといった、オルタネイト（ラッチ）／モーメンタリ（アンラッチ）制御が可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/b87bf9f8-dea8-101b-76ba-89386f6e7a77.png)

[^2]: APCminiは打楽器の演奏に向いたパッド型のMIDIデバイスですが、最も一般的なMIDIデバイスはMIDIキーボードです。そして、Note情報は鍵盤のド・ド♯、レ、レ♯、ミ、ファ……といった感じに、音階を整数で示したものになります。
[^3]: 製品ごとのMIDI信号の扱いは、製品マニュアルの巻末に記載されている場合が多く、一般には「MIDIマッピング」と呼ばれます。ですが、AKAI APCminiはAbleton Liveという音楽制作ソフトとセットで使用する前提のMIDIデバイスなせいか、既に公式サイトからはMIDIマッピング情報が入手できません。「AKAI APC MIDI Mapping」でGoogleやYouTubeを検索すると見つかると思います。

## Blueprint Interfaceについて
「MIDI CC Interface」というノードがありますが、こちらは元から用意されておらず、Unreal EngineのBlueprint Interfaceを使っています。名前も私が適当に付けたものです。

https://docs.unrealengine.com/5.1/ja/blueprint-interface-in-unreal-engine/

このBlueprint Interfaceを使うと、別のBlueprintと値のやり取りができます。今回は、ミキサーのようなスライダーを実装した「MIDI_Mixer」というWidget Blueprint(UMG)に、MIDI信号を渡しています。「MIDI_Mixer」も、私が適当につけた名前です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/9e61b6af-36e3-a3ed-3eb6-85ae7ccdee8e.png)

## MIDI_Mixer（Widget Blueprint）で実装しているボリューム制御
「MIDI_Mixer」に渡されたControl Changeの値は、Sound Mix Class でボリュームを制御しています。また同じ値を使用してUMGのスライダーの値も更新しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/5e46bdf4-4988-ad05-473d-eab8472dfd34.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/eff9deef-e869-791a-869f-cb73a98ed115.png)

:::note
**TIPS**
Unreal EngineではVolumeを完全にゼロにすると再生中の音を停止してしまいます。何が起こるかというと、フェーダーを下げきると再生されていた音が停止され、再びフェーダーを上げてもBGMが聞こえてきません。音量をゼロにしても流れ続けてほしい場合は、Sound Cueのボイス管理の設定で「Play when Silent」に変更しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/ab854f50-6112-6397-6619-bc8db4d66b97.png)

⇒ https://forums.unrealengine.com/t/setting-sound-mix-class-override-to-0-volume-stops-sound-from-playing/436877
:::

:::note
**TIPS**
CCやPitch Bendの値を、Sound Mixなどでボリュームの値として使う場合、0～1に正規化します。Normalize to Rangeを使用しています。いろんな場所で使えるようにマクロ化しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2976099/9346c97c-e4b6-5f01-4a57-1d22fa7c6fef.png)
:::

# さいごに
MIDI信号は、Unreal Engineに入った段階で音に関するものだけでなく、如何様にも活用できます。例えばVirtual Productionでスライドを切り替えたり、ギミックを発動させたりと用途は様々です。現在、私はキーボード・ショートカットとStream Deckを駆使していますが、MIDIデバイスはNoteやChannel[^4]といった整数であれやこれやとフローに落とし込んで扱えるのが、一つ面白いところかなと思います。

1982年に誕生したMIDIは、そもそも異なる楽器同士を繋いで演奏するためのに作られたプロトコルで、良い意味で枯れた技術です。ユニークなMIDI入力デバイスも多数あります。これらを使って、音楽や演奏に合わせたリニアな表現や、インタラクティブな表現も手軽試すことが出来ると思います。単に機能性だけでなく、なにかおもしろい事に使えないかなーってな感じで遊んでみるのもよいのではないでしょうか。

今回は割愛しましたが、特定のオブジェクト制御するにはRemote Control機能を使うともっと簡単に実装できます。それは、また機会があれば書いてみたいと思います。

[^4]:MIDIはChannelが、16 Channelあります。16 Channelを扱えるMIDIデバイスのことを「マルチティンバー」と呼んだりします。マルチティンバー音源は1台で16種類の楽器を個別に扱えます。例えば、Channel 1にはピアノ、Channel 2はギター、Channel 3はベースといった感じで使えます。

[^5]:テンポや小節や拍、音符の長さといった音楽的考えで時間を扱うこと。Steinberg Cubase/Nuendo用語で一般的に使われる用語ではないですが、説明しやすいので使ってます。最近、Unrealもこうした音楽時間で制御することが可能になってきています。