USB-MIDI (8)

MIDIStreaming サブクラスの規格書[*1]の付録 B に示されているディスクリプタを元に解説を加えます。
規格書は、「usb.org midi」 を検索キーワードとしてググればすぐに見つかります。
ここで示すディスクリプタは、 2 箇所を除いて規格書の付録 B と同じです。
その 1 箇所は、元の文書ではディスクリプタ全体のサイズを示す wTotalLength に値が指定されていなかったのを実際の数値に置き換えました。
もう 1 箇所は、クラス固有 MS インターフェース・ディスクリプタ内の wTotalLength で、規格書本文の説明に沿えば、後続のエンドポイント・ディスクリプタは含まれないはずですが、付録 B の例では、エンドポイント・ディスクリプタを含む値となっています。
具体的には、エンドポイント・ディスクリプタを含まない場合には 0x0025 = 37 バイト、含む場合には 0x0041 = 65 バイトとなります。
ここでの説明では、エンドポイント・ディスクリプタを含まない値としています。
ソースが公開されている USB-MIDI 関連のプログラムを調べると、付録 B の例のエンドポイント・ディスクリプタを含む値 0x0041 を使用しているケースが多いようです。
私の持っている MIDI 機器の中で、標準 USB クラスに準拠しているのは KORG microKEY-37 だけなのですが、そのディスクリプタを調べるとエンドポイント・ディスクリプタを含まない 0x0025 でした。
EZ-USB (AC2131S) で作成した USB-MIDI プログラムで試して見ると、対象 OS が Windows の場合には 0x0025 でも 0x0041 でも変わらず動作しました。
他の OS の場合については調べていません。
以下に、各ディスクリプタごとに説明します。 これらを順につなぎ合わせていけば「動作する」ディスクリプタが得られます。
ディスクリプタは「リトル・エンディアン」で記述するという「お約束」なので、以下の表で 2 バイトの「ワード値」で表現されている部分は下位バイトを先、上位バイトを後に記述する必要があります。
たとえば、ワード値が 0x0065 なら、0x65, 0x00 の順番でバイト値の列に直します。
まず最初は、先頭に位置するコンフィギュレーションディスクリプタです。



表 B-2: MIDI アダプタ コンフィギュレーションディスクリプタ

Offset フィールド Size 説明
0 bLength 1 0x09 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x02 ディスクリプタ・タイプ
(0x02=CONFIGURATION)
2 wTotalLength 2 0x0065 このディスクリプタを含む
ディスクリプタ・サイズ
(0x0065 = 101 バイト
= 9 + 9 + 9 + 9 + 7
+ 6 + 6 + 9 + 9 + 9
+ 5 + 9 + 5)
4 bNumInterfaces 1 0x02 全インターフェース数
(AC と MS で計 2 個)
5 bConfigurationValue 1 0x01 コンフィギュレーション番号
6 iConfiguration 1 0x00 コンフィギュレーション
ストリングのインデクス
(0x00 = 不使用)
7 bmAttributes 1 0x80 属性
(バスパワーのみ、
リモード・ウェイクアップなし)
8 MaxPower 1 0x32 最大電流
(0x32 = 100 mA)



これはクラス固有ではない「標準」のものなので、難しい部分はありませんが、オフセット 4 の bNumInterfaces フィールドの値は、AudioControl インターフェースと MIDIStreaming インターフェースの、計 2 個となります。
規格からは外れますが、AC インターフェースを省略して MS インターフェースだけにするなら、当然この値は「1」にする必要があります。
オフセット 2 の wTotalLength には全ディスクリプタのサイズを指定します。
元の文書には数値が入っていませんが、実際の値は 0x0065 = 101 バイトとなります。 上の表には、その内訳も示してあります。

表 B-3: MIDI アダプタ 標準 AC インターフェース・ディスクリプタ

Offset フィールド Size 説明
0 bLength 1 0x09 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x04 ディスクリプタ・タイプ
(0x04 = INTERFACE)
2 bInterfaceNumber 1 0x00 このインターフェースの番号
3 bAlternateSetting 1 0x00 オルタネート設定の番号
4 bNumEndpoints 1 0x00 エンドポイント数
(デフォルト・パイプ (EP0)
含まず)
5 bInterfaceClass 1 0x01 インターフェース・クラス
(0x01 = AUDIO)
6 bInterfaceSubClass 1 0x01 インターフェース・サブクラス
(0x01 = AUDIO_CONTROL)
7 bInterfaceProtocol 1 0x00 インターフェース・プロトコル
(0x00 = 指定なし)
8 iInferface 1 0x00 インターフェース名
ストリングのインデクス
(0x00 = 不使用)



AudioControl インターフェースでは、コントロール操作はデフォルト・パイプ (エンドポイント 0) のコントロール転送のクラス拡張リクエストを使うので、コントロールだけなら (追加の) エンドポイントを使う必要はありません。
AC インターフェースでは、ステータス報告のためにインタラプト IN エンドポイントを 1 つだけ追加することができます。 これを使わないならば、bNumEndPoints の値は「0」に設定しておきます。

表 B-4: MIDI アダプタ クラス固有 AC インターフェース・ディスクリプタ

Offset フィールド Size 説明
0 bLength 1 0x09 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x24 ディスクリプタ・タイプ
(0x24 = CS_INTERFACE)
2 bDescriptorSubType 1 0x01 ディスクリプタ・サブタイプ
(0x01 = HEADER)
3 bcdADC 2 0x0100 Audio Device クラス定義の
リリース番号
(0x0100 = rel. 1.0)
5 wTotalLength 2 0x0009 このディスクリプタを含む
CS ディスクリプタ・サイズ
7 bInCollection 1 0x01 属するストリーミング・
インターフェースの個数
(MS だけなので 0x01)
8 baInferfaceNr(1) 1 0x01 属するストリーミング・
インターフェース番号(1 番目)
(0x01 = MSインターフェース
の番号)



AC インターフェースからコントロール可能なエレメントがない場合には、クラス固有の AC インターフェース記述は上のヘッダ部分 1 個だけとなり、前の標準 AC インターフェース・ディスクリプタと合わせて。18 バイト分のディスクリプタは常に固定パターンとなります。

表 B-5: MIDI アダプタ 標準 MS インターフェース・ディスクリプタ

Offset フィールド Size 説明
0 bLength 1 0x09 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x04 ディスクリプタ・タイプ
(0x04 = INTERFACE)
2 bInterfaceNumber 1 0x01 このインターフェースの番号
3 bAlternateSetting 1 0x00 オルタネート設定の番号
4 bNumEndpoints 1 0x02 エンドポイント数
(デフォルト・パイプ (EP0)
含まず)
5 bInterfaceClass 1 0x01 インターフェース・クラス
(0x01 = AUDIO)
6 bInterfaceSubClass 1 0x03 インターフェース・サブクラス
(0x03 = MIDI_STREAMING)
7 bInterfaceProtocol 1 0x00 インターフェース・プロトコル
(0x00 = 指定なし)
8 iInferface 1 0x00 インターフェース名
ストリングのインデクス
(0x00 = 不使用)



この例では、MIDI IN / OUT にそれぞれエンドポイントを 1 つずつ割り当てるので、上記の標準 MS インターフェース・ディスクリプタのオフセット 4 の bNumEndPoints フィールドの値は「2」となります。

表 B-6: MIDI アダプタ クラス固有 MS インターフェース・ディスクリプタ

Offset フィールド Size 説明
0 bLength 1 0x07 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x24 ディスクリプタ・タイプ
(0x24 = CS_INTERFACE)
2 bDescriptorSubType 1 0x01 ディスクリプタ・サブタイプ
(0x01 = HEADER)
3 bcdMSC 2 0x0100 MIDIStreaming サブクラス
定義のリリース番号
(0x0100 = rel. 1.0)
5 wTotalLength 2 0x0025 このディスクリプタを含む
CS ディスクリプタ・サイズ
(0x0025 = 37 バイト
= 7 + 9 + 9 + 6 + 6)



上のクラス固有 MS インターフェース・ディスクリプタのオフセット 5 の wTotalLength フィールドにはクラス固有ディスクリプタ・サイズを設定する必要がありますが、前述のように、ここではエンドポイント・ディスクリプタを含まない値としています。

表 B-7: MIDI アダプタ MIDI IN ジャック・ディスクリプタ (埋め込み)

Offset フィールド Size 説明
0 bLength 1 0x06 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x24 ディスクリプタ・タイプ
(0x24 = CS_INTERFACE)
2 bDescriptorSubType 1 0x02 ディスクリプタ・サブタイプ
(0x02 = MIDI_IN_JACK)
3 bJackType 1 0x01 このジャックのタイプ
(0x01 = EMBEDDED)
4 bJackID 1 0x01 このジャックの ID 番号
(ID = 1)
5 iJack 1 0x00 このジャック名の
ストリング・インデクス
(0x00 = 不使用)



MIDI IN ジャックには入力ピンがなく、また出力ピンは 1 個だけなので特に指定する必要はなく、ディスクリプタには入出力ピンに関するフィールドはありません。
オフセット 4 の bJackID フィールドで ID 番号を割り当てるのが主な機能です。

表 B-8: MIDI アダプタ MIDI IN ジャック・ディスクリプタ (外部)

Offset フィールド Size 説明
0 bLength 1 0x06 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x24 ディスクリプタ・タイプ
(0x24 = CS_INTERFACE)
2 bDescriptorSubType 1 0x02 ディスクリプタ・サブタイプ
(0x02 = MIDI_IN_JACK)
3 bJackType 1 0x02 このジャックのタイプ
(0x02 = EXTERNAL)
4 bJackID 1 0x02 このジャックの ID 番号
(ID = 2)
5 iJack 1 0x00 このジャック名の
ストリング・インデクス
(0x00 = 不使用)





表 B-9: MIDI アダプタ MIDI OUT ジャック・ディスクリプタ (埋め込み)

Offset フィールド Size 説明
0 bLength 1 0x09 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x24 ディスクリプタ・タイプ
(0x24 = CS_INTERFACE)
2 bDescriptorSubType 1 0x03 ディスクリプタ・サブタイプ
(0x03 = MIDI_OUT_JACK)
3 bJackType 1 0x01 このジャックのタイプ
(0x01 = EMBEDDED)
4 bJackID 1 0x03 このジャックの ID 番号
(ID= 3)
5 bNrInputPins 1 0x01 このジャックの入力ピン数
6 baSourceID(1) 1 0x02 1 番入力ピンと接続する要素の
ID 番号
(0x02 = Ext MIDI IN Jack)
7 baSourcePin(1) 1 0x01 1 番入力ピンと接続する要素の
出力ピン番号
(0x01 = 1 番ピン)
8 iJack 1 0x00 このジャック名の
ストリング・インデクス
(0x00 = 不使用)



MIDI OUT ジャックでは入力ピンを複数持てるので、ディスクリプタでその接続先のエレメントの ID 番号と出力ピン番号を記述します。 ディスクリプタ・サイズは入力ピン数により変化します。
オフセット 5 の bNrInputPins フィールドで入力ピン数を指定します。
この例では MIDI IN ジャックひとつと接続するだけなので、入力ピン数は「1」です。
オフセット 6 の baSourceID(1) フィールドが 1 番入力ピンと接続するエレメントの ID 番号、オフセット 7 の baSourcePin(1) フィールドがピン番号の指定です。
入力ピンが複数ある場合には、
baSourceID(2),baSourcePin(2),baSouceID(3),baSourcePin(3), ...
のように繰り返します。
「エレメント」の場合には出力ピンを複数持てるのでピン番号を区別する必要がありますが、MIDI IN ジャックの場合には出力ピンは 1 番ピンの 1 つだけなので、baSoucePin(1) フィールドに指定する値は常に「1」となります。

表 B-10: MIDI アダプタ MIDI OUT ジャック・ディスクリプタ (外部)

Offset フィールド Size 説明
0 bLength 1 0x09 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x24 ディスクリプタ・タイプ
(0x24 = CS_INTERFACE)
2 bDescriptorSubType 1 0x03 ディスクリプタ・サブタイプ
(0x03 = MIDI_OUT_JACK)
3 bJackType 1 0x02 このジャックのタイプ
(0x02 = EXTERNAL)
4 bJackID 1 0x04 このジャックの ID 番号
(ID= 4)
5 bNrInputPins 1 0x01 このジャックの入力ピン数
6 baSourceID(1) 1 0x01 1 番入力ピンと接続する要素の
ID 番号
(0x01 = Emb MIDI IN Jack)
7 baSourcePin(1) 1 0x01 1 番入力ピンと接続する要素の
出力ピン番号
(0x01 = 1 番ピン)
8 iJack 1 0x00 このジャック名の
ストリング・インデクス
(0x00 = 不使用)





表 B-11: MIDI アダプタ 標準バルク OUT エンドポイント・ディスクリプタ

Offset フィールド Size 説明
0 bLength 1 0x09 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x05 ディスクリプタ・タイプ
(0x05 = ENDPOINT)
2 bEndpointAddress 1 0x01 エンドポイント・アドレス
(OUT EP 1)
3 bmAttributes 1 0x02 エンドポイント属性
(0x02 = Bulk, not shared)
4 wMaxPacketSize 2 0x0040 エンドポイント・サイズ
(0x40 = 64 バイト)
6 bInterval 1 0x00 バルク・エンドポイント
では無視される
7 bRefresh 1 0x00 未使用
8 bSynchAddress 1 0x00 未使用



MIDIStreaming ではバルク転送を行うことが規格で決まっているので、バルク・エンドポイントを指定します。
「標準」とは言いながら、AudioStreaming で使うアイソクロナス・エンドポイントに合わせて、バルク転送には不必要なフィールド bRefresh, bSynchAddress が追加されているので、「0」にしておきます。
エンドポイント・アドレスやエンドポイント・サイズが上の表の値で都合が悪ければ都合の良い値に変更します。

表 B-12: MIDI アダプタ クラス固有バルク OUT エンドポイント・ディスクリプタ

Offset フィールド Size 説明
0 bLength 1 0x05 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x25 ディスクリプタ・タイプ
(0x25 = CS_ENDPOINT)
2 bDescriptorSubType 1 0x01 ディスクリプタ・サブタイプ
(0x01 = MS_GENERAL)
3 bNumEmbMIDIJack 1 0x01 関連付ける埋め込みジャック数
4 baAssocJackID(1) 1 0x01 1 番出力 (CN = 0) と関連
付けるジャックの ID 番号
(1 = Emb MIDI IN JACK)



クラス固有エンドポイント・ディスクリプタでエンドポイントと埋め込み MIDI ジャックとの間の「関連付け」(association) を行います。
1 つのエンドポイントに複数の埋め込み MIDI ジャックを関連付けることができます。
1 番目に指定した埋め込み MIDI ジャックにはケーブル・ナンバー 0 の MIDI パケットが割り振られ、2 番目に指定した埋め込み MIDI ジャックには CN = 1 のパケットが割り振られ、以下同様に CN = 15 のパケットまでがサポートされます。
ホスト PC からは CN が付加されて出力エンドポイントに送られてきますが、それを実際に振り分けるのは USB-MIDIファームウェアの責任です。
同様に、USB-MIDIファームウェアではケーブル・ナンバーを付加した MIDI パケットを作成して入力エンドポイントに送る必要があります。
この例では、関連付ける埋め込み MIDI ジャックは 1 つだけなので、ホスト PC のソフトウェアからは MIDI IN ポート 1 つ、MIDI OUT ポート 1 つに見えます。

表 B-13: MIDI アダプタ 標準バルク IN エンドポイント・ディスクリプタ

Offset フィールド Size 説明
0 bLength 1 0x09 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x05 ディスクリプタ・タイプ
(0x05 = ENDPOINT)
2 bEndpointAddress 1 0x81 エンドポイント・アドレス
(IN EP 1)
3 bmAttributes 1 0x02 エンドポイント属性
(0x02 = Bulk, not shared)
4 wMaxPacketSize 2 0x0040 エンドポイント・サイズ
(0x40 = 64 バイト)
6 bInterval 1 0x00 バルク・エンドポイント
では無視される
7 bRefresh 1 0x00 未使用
8 bSynchAddress 1 0x00 未使用





表 B-14: MIDI アダプタ クラス固有バルク IN エンドポイント・ディスクリプタ

Offset フィールド Size 説明
0 bLength 1 0x05 このディスクリプタのサイズ
(バイト単位)
1 bDescriptorType 1 0x25 ディスクリプタ・タイプ
(0x25 = CS_ENDPOINT)
2 bDescriptorSubType 1 0x01 ディスクリプタ・サブタイプ
(0x01 = MS_GENERAL)
3 bNumEmbMIDIJack 1 0x01 関連付ける埋め込みジャック数
4 baAssocJackID(1) 1 0x03 1 番入力 (CN = 0) と関連
付けるジャックの ID 番号
(3 = Emb MIDI OUT JACK)


*1:"Universal Serial Bus Device Class Definition for MIDI Devices Release 1.0", Nov 1, 1999, USB Implementers Forum