USB-MIDI (12)

今回は USB-MIDI コンバータの MIDI OUT 側の処理の話です。
USB-MIDI イベント・パケットから直接に内蔵音源をドライブするのではなく、MIDI のシリアル・データに変換して MIDI 端子から出力するという機能に限れば、(MIDI IN 側に比べて) その処理は非常に簡単です。
出力エンドポイントから UART 出力までのブロック・ダイアグラムを下に示します。 (ケーブル・ナンバー処理は省略)

固定長の 1 〜 3 バイトの MIDI メッセージはイベント・パケットの 3 バイトのペイロード部に「完全」な形で格納されて送られてくるので、MIDI 出力側の処理としては、

  • MIDI パケットの CIN (Code Index Number) からメッセージ長を求める
  • ケーブル・ナンバー (CN: Cable Number) を参照して UART 出力先を決め、対応する FIFO (リング・バッファ) に 1 〜 3 バイトの MIDI メッセージを書き込む
  • 割り込み駆動 UART 出力ルーチンでは FIFO から 1 バイトずつ取り出し (必要があればランニング・ステータス処理をして) UART 送信レジスタに書き込む

となります。
不定長であるシステム・エクスクルーシブ・メッセージも 3 バイト単位に分割されて MIDI パケットに格納されているだけなので、順にバッファに書き込めば UART 出力段階でつながります。
システム・リアルタイム・メッセージの特別扱いはパケットのエンコード時に行われているので、MIDI 出力時には気にせず他のバケットと同様に扱えばすみます。
エンコード時に固定長の 1 〜 3 バイトの MIDI メッセージとシステム・リアルタイム・メッセージとは分離されているので、 2 〜 3 バイト・シーケンスのバイト間にシステム・リアルタイム・メッセージが挟み込まれることはありませんが、不定長のシステム・エクスクルーシブ・メッセージではメッセージ・シーケンスの間に挟み込まれる可能性があります。
これは、システム・リアルタイム・メッセージの元々の性質である、どこにでも表れることが可能ということに戻るだけなので特に配慮する必要はありません。
プログラムのデバッグ時には、OUT エンドポイントから読み出された USB-MIDI イベント・パケットの内容を確認したい場合もあるので、上の図ではパケットをそのまま出力するようなスイッチを設けてあります。
USB 1.1 のフルスピード (12 Mbps) では、バルク・エンドポイント・サイズは、8、16、32、64 のいずれかですが、最小の 8 でも 4 バイトの USB-MIDI イベント・パケットが 2 個入ることになります。
MIDIStreaming の規格書では、複数の MIDI パケットを 1 回のバルク転送で送る場合の方法にういて言及がありません。
実際に確かめてみたところ、Windows XP では、常にエンドポイント・サイズ分のデータが送られてきて、使用されていない部分にはゼロが詰められていました。
たとえば、エンドポイント・サイズが 64 で送るパケットが 1 個の場合、最初の 4 バイトに MIDI パケットが詰められていて、残りの 60 バイトは「ゼロ」になっていました。
Windows Vista の場合には、有効な MIDI パケットのサイズ分だけのデータだけを送るようです。
たとえば、エンドポイント・サイズが 64 でも送るパケットが 2 個の場合、8 バイトのデータのみが送られてきました。
現状では CIN = 0x00 のパケットは未定義で、意味あるデータとしては決して送られてこないので、MIDI パケットの最初のバイト (CN/CIN バイト) が「ゼロ」であれば、それ以降には有効な MIDI パケットはないということが判断できます。
したがって、エンドポイントから有効な MIDI パケットをすべて取り出したことを判断するには、

  • データの終わりに達した
  • CN/CIN バイトがゼロ

のいずれかが成り立てば良いことになります。