n-yoda's blog

主にUnity3Dに関するあんまり技術的じゃないメモ的な何かを書いています。

UnityでMIDIを再生する

UnityでMIDI(Standard MIDI File)を再生する必要が生じたのでやってみました。 MIDIを再生して何がしたかったのかみたいなのもそのうち公開するかもしれません。 動く最小限のサンプルは以下のレポジトリに入っています。MaciOSで動きました。 github.com

C# Synth ProjectというC#で書かれたMIDIのライブラリが"ほぼ"そのままUnityでも動きました、というだけの話ですが、以下に手順を書いておきます。以下の手順を行った結果が上のレポジトリです。


追記:もっと良い方法を求めている人は:このQiita記事とかNativeAudioPluginsとかhttps://github.com/keijiroとかを参照。

1. C# Synth Project のソースをインポート

色々直したい部分があるのでソースをそのまま突っ込みました。Source/AudioSynthesisフォルダだけでOKです。

2. .NET 3.5対応

Unityの.NET frameworkは古いので、エラーが出た部分を書き直します。
Workarounds for .NET compatibility. · n-yoda/unity-midi@1a54828 · GitHub

3. Synthesizerクラスの修正

音の波形を合成してくれるSynthesizerクラスは、丁寧にbyte配列にエンコードしてくれます。 が、Unityの場合floatで欲しいので書き換えます。
Reveal float buffer. · n-yoda/unity-midi@443c91f · GitHub

4. MidiFileSequencer -> Synthesizer -> OnAudioFilterRead

MidiFileSequencerでmidiイベントを処理して、Synthesizerで音を合成し、OnAudioFilterReadで渡す、というコードを書きます。 OnAudioFilterReadはAudioSource.clipがnullでも使えるみたいです。
unity-midi/MidiPlayer.cs at master · n-yoda/unity-midi · GitHub

現状ここにいくつか問題があって、

  • 本当はAudioClip.Createが使いたいけどエディタがクラッシュする。
    • ググると結構前から報告されているバグのようです・・・
  • AudioSource.clipがnullの場合、OnAudioFilterReadのサンプリングレートが不明
    • チャンネル数もOnAudioFilterReadが初めて呼ばれるときまでわからない。
    • サンプリングレートはMac上では44100Hzと仮定したら上手く動いた。

動いたので満足してしまいましたが、Unityの中の方々に聞いたほうが良いかもしれません。

5. .bankと.midファイルを読み込んで再生

どちらもStreamingAssetsフォルダに入れて読み込むと良いと思います。

.bankファイルには音色データが入っているようです。バンクというのはMIDIの仕様にある概念みたいですが、フォーマットはC# Synth Project独自のものかも…?サンプルでは、C# Synth Projectに含まれるGMBank.bank(GMGeneral MIDI)を使っています。

.midは上のサンプルでは、The Mutopia Projectでダウンロードした「悲愴 第2楽章」(ここさけで流れた曲!)を指定しました。

あとは興味があればソースを見て頂ければと思います。