ArduinoのUSB-MIDIのライブラリMIDIUSBでは、MIDIの送受信のための構造体が MIDIMIDIUSB_Defs.hに定義されています。byte1, byte2, byte3 はMIDIのイベントがそのまま 入ります。それではheaderには何が入っているのか調べてみました。
#pragma once #include <stdint.h> typedef struct { uint8_t header; uint8_t byte1; uint8_t byte2; uint8_t byte3; } midiEventPacket_t;
まず、MIDIを受け取りmidiEventPacket_tをシリアルモニターで書き出すようなプログラムを書きます。
#include "MIDIUSB.h" void setup() { Serial.begin(115200); } void loop() { midiEventPacket_t rx; char str[128]; do { rx = MidiUSB.read(); if (rx.header != 0) { sprintf(str,"%02x %02x %02x %02x\n", rx.header,rx.byte1,rx.byte2,rx.byte3); Serial.print(str); MidiUSB.flush(); } } while (rx.header != 0); }
次のようなMIDIデータをSendAndReceiveからArduino Microへ送ります。
Output MIDIの中に21バイトのデータを記述し、Sendボタンを押します。 これは、以下の9個のMIDIデータを連続して送信することを意味しています。
81 40 7F : Note On 92 3F 7F : Note Off A3 2E 43 : Polyphonic Key Pressure B4 3D 40 : Control Change C5 2D : Program Change D6 47 : Channel Pressure E7 3F 7F : Pitch Bend F8 : Timming Clock FE : Active Sensing
これを上のArduinoで受信すると、Serial Monitorには以下のように表示されます。
08 81 40 7f 09 92 3f 7f 0a a3 2e 43 0b b4 3d 40 0c c5 2d 00 0d d6 47 00 0e e7 3f 7f 0f f8 00 00 0f f8 00 00
上の結果を見ると、headerにはMIDIのステータス(byte1の上位4ビット)と同じ値がコピーされています。 それでは、以下のようなシステムエクスクルーシブメッセージを送って見ることにします。
以下のように、headerには4という数字と7という数字が書かれています。それを除けば、送信した システムエクスクルーシブメッセージと同じデータであることがわかります。
04 f0 01 02 04 03 04 05 04 06 07 08 04 09 0a 0b 04 0c 0d 0e 07 0f 10 f7
この4と7を理解するには、USB-MIDI1.0の仕様書を見る必要があります。
仕様書はUSBの規格団体からダウンロードすることができます。
https://www.usb.org/document-library/usb-midi-devices-
仕様書の「4 USB-MIDI Event Packets」にUSB-MIDIで送信される4つのバイトの説明が載っています。
BYTE 1,2,3はMIDIデータにあたり、BYTE 0がheaderにあたります。 BYTE 0には上位4ビットにケーブルナンバー(Cable Number)が、下位4ビットには コードインデックスナンバー(Code Index Number)が入ります、 先の4と7はこのコードインデックスナンバーにあたります。
コードインデックスナンバーの詳細は仕様書の 「Table 4-1: Code Index Number Classifications」に書かれています。 システムエクスクルーシブメッセージについて抜書きすると以下の表となります。
4 | システムエクスクルーシブ スタートと継続 |
5 | 1バイトのシステムコモンメッセージ もしくは残り1バイトでシステムエクスクルーシブで終了 |
6 | 残り2バイトでシステムエクスクルーシブ終了 |
7 | 残り3バイトでシステムエクスクルーシブ終了 |
上のシステムエクスクルーシブの例では、F7がBYTE 2に入っていて ちょうど3バイトでシステムエクスクルーシブが終わっていますので 最後ですのでコードインデックスナンバーが7になっています。
以下のシステムエクスクルーシブであれば最後は6になります。
F0 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
04 f0 01 02 04 03 04 05 04 06 07 08 04 09 0a 0b 04 0c 0d 0e 06 0f f7 00
以下のシステムエクスクルーシブであれば最後は5になります。
F0 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E
04 f0 01 02 04 03 04 05 04 06 07 08 04 09 0a 0b 04 0c 0d 0e 05 f7 00 00
さらに以下のシステムエクスクルーシブであれば最後は7に戻ります。
F0 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D
04 f0 01 02 04 03 04 05 04 06 07 08 04 09 0a 0b 07 0c 0d f7
上で調べた事を使ってArduinoでシステムエクスクルーシブを受信プロフラムを作ってみます。
unsigned char sysex[128]; uint16_t cnt=0; extern void procsysex(unsigned char *sysex, uint16_t cnt); void loop() { midiEventPacket_t rx; do { rx = MidiUSB.read(); if (rx.header != 0) { //send back the received MIDI command MidiUSB.sendMIDI(rx); switch(rx.header&0x0F){ case 0x4: if(rx.byte1==0xF0){ cnt=0; } sysex[cnt++]=rx.byte1; sysex[cnt++]=rx.byte2; sysex[cnt++]=rx.byte3; break; case 0x5: sysex[cnt++]=rx.byte1; procsysex(sysex,cnt); break; case 0x6: sysex[cnt++]=rx.byte1; sysex[cnt++]=rx.byte2; procsysex(sysex,cnt); break; case 0x7: sysex[cnt++]=rx.byte1; sysex[cnt++]=rx.byte2; sysex[cnt++]=rx.byte3; procsysex(sysex,cnt); break; } MidiUSB.flush(); } } while (rx.header != 0); }
procsysexはシステムエクスクルーシブを処理するルーチンで、 ここではシステムエクスクルーシブをシリアルで表示しています。
void procsysex(unsigned char *sysex, uint16_t cnt){ uint16_t i; char str[32]; for(i=0; i<cnt; i++){ sprintf(str,"%02x ",sysex[i]); Serial.print(str); } Serial.println(""); }