基本仕様
開発当時の構想
当初の開発目標として、
- MIDIコネクタ:4IN / 4OUT
- USB-MIDI:4IN / 4OUT
- USBとMIDIのルーティング:CableNumber<>PORTスルー
- MIDI間のルーティング:ディップスイッチ
としていました。
MIDI間のルーティングがなかったら、世間で売られている安価なUSB-MIDIインターフェースと何ら変わりがありません。
ディップスイッチでルーティングを変えられることがメリットで、違うMIDI入力で同じ出力先を選んだ時は、ミキシング(マージ)処理もします。
これで安価なUSB-MIDIインターフェースとは差別化できます。
ルーティング設定やイベントフィルタを自由に設定できるようにする
しかし、海外製のUSB-MIDIインターフェースには、USBを使わないときは簡易的なルーティングができたり、ミキシング機能を持っているものもあります。
そこで、ファームウェア更新用にUSBメモリを使えるようにしてあるので、USBメモリの中にルーティング設定やイベントフィルタ設定を入れておいてUSBコネクタに挿し、設定を読み出して内蔵フラッシュに保存します。
ルーティング設定、イベントフィルタの設定は単純なバイナリファイルなので、バイナリエディタで作ることができます。
設定は合計32持たせることができます。
32あれば、1ライブの曲全てで設定を変えるとしても十分でしょう。
実際はメモリ容量の制限で32程度になります。
バイナリエディタで作るのは流石に面倒なので、このデータを作るための専用アプリを開発しました。
専用エディタは便利だけど...
確かにバイナリエディタよりは圧倒的に便利です。
しかし、設定は机上で作るので、実際に設定をUSB-MIDIで使ってみると間違ってたとか、もうちょっとこうしたい...となると、また机上でのデータ作成...
意外に実践的ではないと感じました。
ベストはUSBで直接設定を編集できること
昔使っていたMOTU社のMIDI Time Pieceシリーズは専用のエディタがあって、それは直接MIDI Time Pieceシリーズのメモリを編集していました。
RS422シリアル通信タイプのMIDI Time Pieceなら、通信フォーマットを独自に開発することで、割と容易に直接MIDI Time Pieceのメモリ編集をすることができます。
後にUSBタイプのMIDI Time Pieceが発売されましたが、専用のドライバを入れる必要がありました。
自作USB-MIDIインターフェースはUSBクラス・コンプライアントで開発しているので、追加で独自のUSB通信ラインを設けることはできません。
専用ドライバを開発するのも流石に大変です。
USBクラス・コンプライアントでもできる妙案
買い物を兼ねた散歩をしている時、ふと思いつきました。
MIDIにはシステム・エクスクルーシブ・メッセージという、メーカー(ユーザー)が自由に仕様を決められるものがあります。
具体的には0xf0から始まって、0xf7で終わるメッセージで、この間に挟まれるデータのフォーマットは自由です。
これを利用すれば、メモリ編集だろうが何でもできるわけです。
ただし、システム・エクスクルーシブ・メッセージは多くのメーカーがシンセサイザー類の設定や、特別な演奏効果を出すために利用しています。
そのため、むやみに楽器類に送るわけにはいきません...
そこで思いついたのが、USB-MIDIを5IN / 5OUTに仕様変更することです。
USB-MIDIの5IN / 5OUTでどうやってUSB編集を実現する?
実際のところ、USBで受け取ったデータをどうするかはファームウェア次第です。
USB-MIDIインターフェースの機能として、USBで受け取った演奏データはUARTで楽器に出力するというのは絶対必要です。
そして、USBで受け取ったデータをどのUARTに出力するか...もファームウェア次第で、通常はUSBのCableNumberに対応したMIDIコネクタに割り振ります。
極端なことを言えば、USBで受けたデータをUARTに出力せず、捨ててもいいのです。
そこで、USB-MIDIのCableNumber0-3の4つは今まで通りUARTへ出力し、5番目のCableNumber4はUARTへ出力せず、内部のメモリ編集用として利用すればいいんです。
これなら、USBクラス・コンプライトでありながら、メモリ編集という特別なこともできます。
MIDIならではの制限
例えばメモリダンプであれば、0xf0と0xf7の間に指定サイズのメモリ内容を入れ込めばいいですよね。
しかし、ここはMIDIの規格に合わせてデータを整形しなくてはいけません。
MIDIは8ビットデータのうち、最上位ビットが1の時はステータス・バイトという特別な情報を持つものです。
この後に続くデータは必ず最上位ビットが0でなくてはいけません。
そして、システム・エクスクルーシブ・メッセージ内には最上位ビットが0のデータしか含むことができません。
MIDIは数値情報は7ビットで表現します。
そのため、127までは0x7fで表せますが、128は0x0100という2バイト表現にしなくてはいけません。
このほかにも、上位4ビットと下位4ビットで2バイトに分けるという方法もよく使われます。
これなら、上位4ビットは常に0なので、MIDIの規格にも合います。
こっちの方が変換と復元も簡単です。
0xf0と0xf7がシステム・エクスクルーシブ・メッセージを区切るためのものですが、メモリの中には0xf0と0xf7が存在する可能性はあります。
メッセージ区切りとメモリ内容をしっかり区別できなくてはいけないですね。
ここさえ守れば、0xf0と0xf7の間にメモリの内容をMIDIの規格に合わせた表現に変換すれば、メモリの内容を送ることができます。
USBで自作USB-MIDIインターフェースを操作するための仕様
USB部分を5IN / 5OUTに変更し、5番目のCableNumber4は独自処理に利用し、UARTには出力しません。
専用ドライバも不要です。
Mac上でのUSB-MIDIインターフェースの見え方
Mac上では5番目のCableNumber4も認識されますが、MIDIコネクタには出力されないのと、5番目のMIDIコネクタもありません。
若干ユーザーは混乱するかもしれませんが、ドライバレスのメリットを考えれば、ここは目をつぶってもいいかと思います。
専用アプリでのアクセス
専用アプリではCableNumber4、Mac上での表現ではポート5を指定します。
当然MIDIデバイスとしてアクセスが可能です。
様々なメモリ編集の内容を、うまく0xf0と0xf7に挟んで送ります。
主にメモリリード、メモリライトを使います。
これ以外にも32ある設定のどれを編集するかを指定したり、それをUDB-MIDIインターフェース内のテンポラリメモリにコピーしたり、テンポラリメモリの内容をメモリーに保存したり、内蔵フラッシュへの読み書きのコマンドのようなものも同じように0xf0と0xf7に挟んで送ります。
そして、メモリリードを応用して32全ての設定データを読み出して保存すれば、データのバックアップにもなりますし、32の設定を丸ごと違うものに入れ替えるのも簡単にできます。
USB-MIDIインターフェースのファームウェア側の対応
ファームウェアでは、CableNumber4ではシステム・エクスクルーシブ・メッセージだけを受け取り、それ以外のメッセージは捨てます。
また、受信したシステム・エクスクルーシブ・メッセージがメモリ編集のためのメッセージかどうかも判断しなくてはいけません。
そのため、0xf0と0xf7で挟むデータにヘッダ領域を設け、ヘッダがメモリ編集のメッセージで決められたものと一致すれば受信して処理します。
万が一DAWなどで間違えてCableNumber4を指定された場合、演奏データや指定以外のシステム・エクスクルーシブ・メッセージは弾かなくてはいけません。
UARTでのMIDIと違って、USBでの送受信なので、大容量のデータ転送はめっちゃくちゃ速いです!
USB-MIDIでは制限はなさそうですが、システム・エクスクルーシブ・メッセージで送るのは128バイト以下にしておくのがしきたりです。
今回はヘッダを入れると128バイトを数バイト超えますが、ひとまずmacOS26では送受信に影響はなく、無事やり取りができています。
STM32F407のCCMRAM(64KB)の中身を全てダンプするのも一瞬です。
最後に
USB接続で使えるエディタが実現できたことで、自作USB-MIDIインターフェースの本領発揮といったところです。
実際にMIDIキーボードやコントローラを操作しながらルーティングやフィルタを変えたり、特にキーレンジを設定してスプリットを作るときは確認しながら作業できるので、めちゃくちゃ便利になりました。
ライブでも十分使えそうです。