23
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

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

JavaScriptでMIDIファイルを解析してみる 1の続きです。

ここでは実際の音の高さ、強さ、演奏するタイミングといったいわば、SMFの本丸部分の構造について説明します。

トラックチャンクの構造

前回はヘッダチャンクについて解説しました。
ヘッダチャンク以降のデータをまとめてトラックチャンクと呼びます。
構造は以下のようになっています。
トラックチャンクは、トラックの数だけ存在します。

1.チャンクタイプ(4byte)

ヘッダのチャンクタイプ同様、値が決まっています。4D 54 72 6Bです。

2.データ長(4byte)

この後に続くデータの長さです。4バイトだから、4ギガくらいのファイルは扱えるのでしょうか?

3.データ本体

要はここを解析したいわけですね。

データ本体の構造

本体のデータはデルタタイムイベントの繰り返しです

デルタタイム

デルタタイムとは直前のイベントからの時間を表す可変長のデータです。

データサイズはどこにも保持していません。
ではどうやってデルタタイムのデータ長を知ることができるのでしょうか?
それにはデルタタイムのデータ構造を知る必要があります。

デルタタイムは7ビットで表現し、最上位の1ビットは次のバイトデータがあるかどうか
を判定するためのフラグに使います。
わかりやすく2進数で説明すると

01111111(0x7F)は、最上位ビットが0なので、次のデータはありません。
0x80を表現するには最上位ビットに1をたてて、次のバイトを使います。

10000001 00000000

こうなります。
よって各バイトを16進数表記にして0x80以上の場合は、次のバイトにもデルタタイムの情報があり、0x79以下ならそこで終了、と判定できます。
このようなデータ表現を可変長数値表現と呼びます。

では、可変長数値から、実際の数値を求めるにはどうすればよいでしょう?
もっとも簡単な考え方は、
それぞれのバイトの下位7ビットだけ取り出し、結合する
です。
0x80を可変長数値表現で書くと

10000001 00000000

このようになります。この1バイト目、2バイト目の下位7ビットを取り出してつなげると

0000001 0000000
=10000000
=0x80

となります。

イベント

イベントとは、どの音をどの強さで演奏するか、演奏をやめるか、テンポの指示、トラックの終わり、などさまざまな情報を持つことができます。
イベントには3種類あり、どのイベントかを識別するためのステータスバイトと呼ばれる情報が、イベントの1バイト目に保持されます。ステータスバイトは(0x80~FF)の値で表されます。
つまり、イベントの最上位ビットは必ず1にならなければなりません。

1.MIDIイベント(3バイト)

音を出したり、止めたりする指示を行うイベントです。

代表的なイベント



 
 
 
イベント名 効果 1バイト目 2バイト目 3バイト目
ノートオフ音を止める。 8n(nにはチャンネル数が入る) 音の高さ0~127(7F)で表される。再低音(0)はC-1,最高音はG9になる ベロシティ。音の強さ0~127(7F)で表される。ノートオフの場合、0になる
ノートオン音を鳴らす。 9n(nにはチャンネル数が入る) 音の高さ0~127(7F)で表される。再低音(0)はC-1,最高音はG9になる ベロシティ。音の強さ0~127(7F)で表される。
コントロールチェンジ A0~EF 0~127(7F) 0~127(7F)

ノートオンの例 チャンネル1のC4をベロシティ90で鳴らす場合のデータ
91 3C 5A
コントロールチェンジはよくわかりません。
ここに書いてある

2.SysExイベント(可変長)

システムエクスクルーシブメッセージを表すイベント
ステータスバイトはF0 or F7
可変長のデータを取ることができます。

3.メタイベント

メタイベントにはトラックの情報が入っていると考えておけばよいでしょう。
メタイベントはステータスバイトが必ずFFになります。
2バイト目にイベントタイプ
3バイト目にデータ長
4バイト以降にデータ
が入ります

下記に代表的なメタイベントを示します。
※lenは後に続くデータのバイト数を表現した、1バイトの16進数です。











データ 機能
FF 01 len Text コメントなどのテキスト
FF 02 len text 著作権などのテキスト
FF 03 len text シーケンス名・トラック名
FF 04 len text 楽器名
FF 05 len text 歌詞
FF 51 03 tempo テンポ。
4分音符の長さをマイクロ秒単位で表現。
FF 58 04 nn dd cc bb 拍子
nn=分子 4分の2拍子なら2
dd=分親 2のdd乗の値が分母となる。dd=2なら、2^2=4、dd=3なら、2^3=8 といった具合。
cc= メトロノームの音価。♩=60 の♩のことです。4分音符なら0x18 です。
しかし、テンポは上記で書いたとおり、4分音符の長さで表現するので、ここは0x18固定になる気がします。たぶん。
bb=四分音符あたりの三十二分音符の数
FF 59 02 sf ml キー(調)を表す
sf=正・・シャープの数 負・・フラットの数
ml=0・・・長調 1・・・短調
FF 2F 00 トラックチャンクの終わりを示す

まとめると

1.データ領域はトラックチャンクの集まり
2.トラックチャンクはトラックの数だけ存在。
3.トラックチャンクは、4D 54 72 6B(チャンクタイプ)で始まり、FF 2F 00(メタイベント) で終わる
4.トラックチャンクのデータ量はチャンクタイプの次4バイトに保持されている
5.トラックチャンクのデータはデルタタイムイベントの繰り返しである。
 デルタタイムは前の音からの時間を表す。最初は0になる。

こんな感じです。
実際にデータを見てみないとしっくりこないと思います。
SMFをバイナリエディタで開いてみるとわかると思います。

実際の解析データの説明については、JavaScriptでMIDIファイルを解析してみる 3でどうぞ。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
23
Help us understand the problem. What are the problem?