LoginSignup
23
22

More than 5 years have passed since last update.

JavaScriptでMIDIファイルを解析してみる 3

Last updated at Posted at 2015-06-17

JavaScriptでMIDIファイルを解析してみる 2
でトラックチャンクについて説明しました。

ここでは実際のデータを見てみたいと思います。
JavaScriptでMIDIファイルを解析してみる 1では、MuseScoreという楽譜作成ソフトからMIDI出力したファイルをサンプルに使いましたが、サンプルとしては微妙でした。
ここではフリーのシーケンサーソフトDominoで作成したMIDIファイルをサンプルとして、
実データを見ていきたいと思います。

解析するMIDIファイルの中身

今回のサンプルMIDIファイルは以下のような内容のものです。
トラック数:3
小節数:1
4/4拍子
テンポ:♩=60

トラック1:Conductorトラック
トラック2:8分音符 C4が4回鳴る
トラック3:全音符 C3が1回鳴る

楽譜にするとこんな感じ
キャプチャ.PNG

非常に簡単な作りにしてみました。
これをバイナリエディタで開くとこんな内容になります。

//ヘッダチャンク
4D 54 68 64 00 00 00 06 00 01 00 03 01 E0 

//トラックチャンク1
4D 54 72 6B 00 00 00 2D 00 FF 03 00 00 FF 02 12 43 6F 70 79 72 69 67 68 74 20 28 43 29 20 32 30 31 35 00 FF 51 03 F 42 40 00 FF 58 04 04 02 18 08 00 FF 2F 00

//トラックチャンク2
4D 54 72 6B 00 00 00 35 00 FF 03 00 00 FF 21 01 00 00 90 3C 64 81 70 80 3C 00 81 70 90 3C 64 81 70 80 3C 00 81 70 90 3C 64 81 70 80 3C 00 81 70 90 3C 64 81 70 80 3C 00 A0 68 FF 2F 00 

//トラックチャンク3
4D 54 72 6B 00 00 00 16 00 FF 03 00 00 FF 21 01 00 00 91 30 64 8F 00 81 30 00 78 FF 2F 00

前回説明したとおり、トラックチャンクの開始4バイトが、
チャンクタイプ(4D 54 72 6B)になっており、
最後はトラックチャンクの終わりを示すイベント(FF 2F 00)になっていることがわかります。

ではトラックチャンク1から詳しく見ていきます

トラック1

Dominoではコンダクタートラックという、テンポ等を管理するだけのトラックがあります。
(MIDIについて、実は私、あまり詳しくありません。なので一般的にどうなのか、知りません)


4D 54 72 6B  //チャンクタイプ
00 00 00 2D //この後のサイズ(バイト) 2Dなので45バイト
00 //デルタタイム
FF 03 00 //イベント タイプ03 = トラック名称。
00 //デルタタイム
//イベント(タイプ02は著作権を示すテキスト (Copyright (C) 2015) と書いてあります。
FF 02 12 43 6F 70 79 72 69 67 68 74 20 28 43 29 20 32 30 31 35 
00 //デルタタイム
FF 51 03 0F 42 40 //イベント タイプ51 テンポを表す
00 //デルタタイム
FF 58 04 04 02 18 08 
00  //デルタタイム
FF 2F 00 //イベント タイプ2F トラックチャンクの終わり

このトラックには、MIDIイベント(音)は登場していませんが、メタイベント(曲の情報)が入っていますね。
(このFFから始まるイベントは、メタイベントと呼ぶのでしたね。)

メタイベントでは、イベントタイプの後の1バイトが、このイベントのデータ数(バイト)を示しています。

例えば、イベントタイプ「51」はテンポを示しています。
「51」の後には「03」とあるので、この後ろの3バイトでテンポを示していることがわかります。テンポを示す3バイトは、 0x04240=1000000となっています。
これは4分音符あたりの長さをマイクロ秒で示しています。
この曲は♩=60で設定したので、4分音符の長さは1秒=1000ミリ秒=1000000マイクロ秒 となります。

最後のFF 2F 00は、トラックの終わりを示しています。

トラック2

ちょっと長いですが・・・

4D 54 72 6B  //チャンクタイプ
00 00 00 35 //この後のデータ数(バイト) 0x35 = 53バイト
00 //デルタタイム
FF 03 00 //イベント タイプ03 = トラック名称。
00 //デルタタイム
FF 21 01 00 //イベント タイプ21
00 //デルタタイム
90 3C 64 //MIDIイベント ノートオン C4をベロシティ0x64で鳴らす
81 70 //デルタタイム
80 3C 00 //MIDIイベント ノートオフ C4を止める
81 70 //デルタタイム・・・以降同じ繰り返し
90 3C 64 
81 70 
80 3C 00 
81 70 
90 3C 64 
81 70 
80 3C 00 
81 70 90 
3C 64 
81 70 
80 3C 00 
A0 68
FF 2F 00 //イベント タイプ2F トラックチャンクの終わり

音を鳴らす指示が出てきました。
90 3C 64
「9」はノートオン(音を出せ!!)を表し「0」は、MIDIチャンネル1を示します
これだけだと、永遠に鳴らることになってしまいますので、以下のように音を止める指示が、必ず出てきます。
80 3C 00
「8」はノートオフ(音を止めろ!!)を表し、「0」は、MIDIチャンネル1を示します
00はベロシティです。止めるんだから当たり前のような気がするのですが、何か用途があるのでしょうか?この辺りに詳しい人がいたら教えてください

さらに、デルタタイムが出てきました。
デルタタイム 81 70 は可変長数値表現です。2進数で表すと
10000001 01110000となり、これが表す数値はそれぞれの下位7ビットを並べれば算出できます。つまり
11110000= 240
となります。
10進数で240 これは前の音からの時間を示します。
この240を、ヘッダチャンクに指示された時間単位(0xE0 = 480)で割り算し、四分音符の長さ(1秒)を掛けると
240 / 480 * 1 = 0.5
0.5秒という時間を取得することができました。
あとは同じ0.5秒間隔で鳴らす音、止める音が交互に指示されているのがわかりますね。

トラック3

4D 54 72 6B //チャンクタイプ
00 00 00 16 //この後のデータ数(バイト) 0x16 = 22バイト
00 //デルタタイム
FF 03 00 //イベント タイプ03 = トラック名称。
00 //デルタタイム
FF 21 01 00 //イベント タイプ21
00 //デルタタイム
91 30 64 //MIDIイベント ノートオン C3をベロシティ0x64で鳴らす
8F 00   //デルタタイム 8F00は可変長数値表現で1920 = 480 x 4  = 4分音符4つ分
81 30 00 //MIDIイベント ノートオフ C3を止める
78 //デルタタイム
FF 2F 00

この曲のトラック3では、全音符が一つなるだけです。
全音符の長さを示すデルタタイム(1920)後に、ノートオフが発生していることがわかります。
ちなみに、トラックチャンクの終わり(FF 2F 00)の前に、微妙なデルタタイムが指示されています。なんでこんな数値になってるのかよくわかりません。シーケンサが適当に作るのでしょうか?(詳しい人いたら教えてください)

以上、だいぶ長くなりましたが、実データからの解説でした。
ここまでわかれば、JavaScriptだろうが何だろうが、解析するのはそんなに難しいことではないかと思います。

私が考えたスクリプトはJavaScriptでMIDIファイルを解析してみる 4
でどうぞ

23
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
22