MIDIの仕様書が公開されていたので、ハマりそうな部分について書いておきます。タイムスタンプについてです。MIDIのデバイスやライブラリを自前で実装してみようかな、という方にとって参考になるかもしれません。MIDIのデータの形式はこんな感じです(仕様書より)。1.0なメッセージにタイムスタンプ情報が付いた形です。BLEの1パケットに収まらない場合は分割することもできます。上図はSysExというデータで、システムエクスクルーシブメッセージといい、機器の設定情報などをバイナリで送受信するためのものです。(最後の緑色背景のデータ)SysEx終端が来るまでが、データです。データの内容・長さは自由です。(水色背景のデータ)タイムスタンプは、下位7ビットと、ヘッダ内にある上位の6ビット分と組み合わせて13ビット(0〜8191、ミリ秒)の値になります。この値で通信のレイテンシを吸収します。タイムスタンプの精度タイムスタンプは送信側デバイスのクロック精度に依存するので、送信側のタイムスタンプの値が1000増えたからといって、受信側の時計でも正確に1000ミリ秒が経過しているとは限りません。単体のキーボードや音源など、マイコンで処理しているデバイスでは精度がわりと怪しくなります。前回のイベントからの間隔として扱うのが良さそうです。8192ミリ秒までの間隔しか測れないので気をつけます。タイムスタンプの上限値跨ぎ処理1パケットで複数のMIDIメッセージを受信することがあり、それらのタイムスタンプ下位が0xFFを跨いだ場合(図の例だと、SysEx開始時が0xFFで、SysEx終端が0x00のとき)や、タイムスタンプ全体の値が8191を跨いだ場合も、デバッグしていて微妙にハマります。8秒遅れてイベントが発火したり...。こちらは、前回のイベントのタイムスタンプとの差がマイナスなら8192を足す、みたいな対処で回避できるでしょう。SysExデータの末尾に現れるタイムスタンプ情報SysEx終端の直前にタイムスタンプ下位が入るので、その1バイトだけを除いたデータをSysExデータとする必要があります。先頭の0xF0と末尾の0xF7を含めたデータを返却することを前提としたAPIであれば、ちょっとだけ面倒な実装になりそうです。SysExデータが欠けるこれが一番デカい罠だと思います。SysExとタイムスタンプの仕様を見て、素直に「SysEx終端:0xF7が来るまでデータを読んだら、その直前の1バイトをタイムスタンプとして扱う」という解析処理を書いていると、仕様の罠にハマります。いう風に実装すると、イベントの発火タイミングが最大で127ミリ秒ズレて、その際にデータが欠損します。これはSysEx送受信の128回に1度の確率で発生します。こんなことになるかというと...タイムスタンプ下位7bitが0x77だった場合、送信されるバイト値は0xF7になります。0xF7を受信したからといって、この時点ではSysExをイベントキュー等に入れてはいけません。正しくは「0xF7を受信したら次のデータ1バイトをチェックし、次も0xF7なら次のデータまでがSysEx、それ以外ならこのデータまでがSysEx」という風に実装する必要があります。MIDIは様々なデバイス間で使われる通信プロトコルのため、送受信の実装が拙いデバイスについても、異常動作しないように対応する必要があります。具体的にはこの2つです。SysEx受信のときは、0xF7の2回受信を考慮して解析する。SysEx送信のときは、タイムスタンプの値として0xF7を送信しない。MIDIを実装する際のハマりポイントでした。