MidiTrail でテンポチェンジしたらInvalid Data Found というエラーに遭遇した ~ Retro Music Editorのmidi出力

音源のビジュアライザーにMidi Trailを利用しています。

Retro Music Editorからmidiファイルにエクスポートして、Midi Trailで読み込んで動画撮影しています。

しかし、もとの音源にテンポチェンジがあると
Midi Trailで読み込んだときに

Invalid data found.
FUNC: SMIDILib::SMFileReader::_ReadEvent
LINE: 467
INFO: 00000000 00000000



というエラーが発生します。

いろいろ調べて、しかたがないのかな、と思ったら、

メモ
55MCMDL1.MIDは、あるトラックに複数のチャンネルに対するイベントが含まれている。 標準MIDIファイルとしては、かなりグレイなデータにみえる。 たとえばdominoは、データ異常ありとして本データの読み込みを拒否する。

という記述を発見。

どうも生成されているmidiデータが規格に逸脱しているようです。

そこで、dominoで読み込んでみると、

確かにエラー表示されました。

dominoで読み込んでから、再度midiとして書き出して、MidiTrailで読み込むとちゃんとテンポチェンジして再生できました。

少々手間なのですが、無事に解決しました。

いちおう、掲示板に報告してしまったのですが、MidiTrailの問題ではないのかも。


追記(2020-05-28)

MidiTrailの制作者の方から回答いただきました♪

共有していただいたMIDIデータを確認したところ、データの一部が(私の理解では)MIDI規格書に沿っていない部分がありました。
このデータが存在することが原因で、読み取りエラーが発生しています。

以下、技術的な解説になります。
デルタタイムと呼ばれるデータが、最大4byteであるべきところ、5byteになっている部分がありました。
現状のMIDITrailの実装では、最大4byteで区切って次のデータの読み取りに進むため、
データが1byteずれてしまうことになり、次のデータの読み取りでエラーが発生します。

Dominoは、5byteのデルタタイムを許容して読み込んでいるのではないかと思われます。
TMIDI Playerでこのファイルを読み込ませたところ、ハングしました。
ということで、いただいたヒントを参考に
Midiフォーマットをざっと勉強して、ヘックスダンプを見てみました。
(原始的にエディタにコピペして、目で読んだ)


コンダクタートラックを読んで見る


異常がありそうなのは、コンダクタートラックに当たりをつけてみてみると、
確かにデルタタイムが5バイトになっているっぽいデータを発見しました。

このトラックは、テンポ指定と拍子指定がメインなので読みやすい。

ざっくりいうとmidiイベントは、「デルタタイム 中身」、という形式になっています。

デルタタイムは可変長で、最上位ビットがオフのものが出てくるまでつなげていきます。
正味のデータは7bit。

中身のデータは、1バイト目のイベント種類に応じて、後続するデータ長がわかります。

ということで、頭から読んでいきましょう。

はじめの 00FF 0300は、トラック名が空白ということを示してます。
00がデルタタイムで、「FF 03 len text」がバイト長と文字列データです。

次の「00[ff5103]07a120)」までがひとまとまりで、これはテンポ指定です。
テンポ指定は、「FF 51 03 tttttt」の形式です。
[ff5103]を囲んでみて、ttttttの末尾に閉じカッコをつけました。

始めのテンポを指定しているので、デルタタイムは0です。

次の「00[ff5804]04021808)」は、拍子の指定です。

エラーデータに遭遇

あとは、しばらく順当にテンポ指定が続いていくのですが、
「8f fffa c260[ff5804]04021808)」で長いデータがありました。

このデルタタイムが5バイトでエラーになっていたようです。
どうも曲が終わったあと、どっか遠くに拍子指定が残っているようです。

その後2回拍子を変更して、最後は「00[ff2f00]」でトラック終了です。
「FF 2F 00 」はトラックの終端を表しています。

この拍子指定はどこから来ているんだろう。

デルタタイムを計算する

「8f fffa c260」を計算してみます。
ビット列にすると
8F 1000 1111
FF 1111 1111
FA 1111 1011
c2 1101 0010 
60 0110 0000
ということになります。

 つなげてみると、
0001111 1111111 1111011 1010010 01100000

ちょっと桁分けが特殊ですが、7bitが4つと8bitが1つです。
これを8bit区切りにすると
0001 11111111 11111101 11010010 01100000(01 FF FD D2 60)

なんか、1ばっかり続いて怪しい(マイナス?)。

Retro Music Editorのテンポと拍子と見比べてみると、
こんな感じです。



どうも、いったんテンポのデータを全部出力してから、
拍子のデータを出力してるっぽい。

だから、途中のテンポ指定があると、
マイナスのデルタタイムが生じて、おかしなことになるんだろうなぁ。

もともと、Retro Music Editorのmidi出力は「おまけ」だろうし、しかたないのかな。

一応、報告してみよう。