SMF (Standard MIDI Files) の構造

Jan. 4th, 2023: コンテンツ公開の場をgithubに移しました。

今後はそちらをご覧いただけますよう、よろしくお願いいたします。




更新履歴

目次

SMFとは

MIDIを使った演奏情報を一定の形式(フォーマット)のファイルにまとめたものを (ここでは)「MIDIデータファイル」と呼んでいるが、 そのMIDIデータファイルの、世界でもっとも一般的な形式がSMF(Standard MIDI Files)である。 ファイルの拡張子は ~.MID であることが多いが、 ~.SMF であることもある。

SMFは基本的に 「この時間(タイミング)に、この音を強さ**でオンにする」 といったレベルの情報の集まりでしかなく、 「ここを2回繰り返す」とかいった「ちょっと高級な情報」は扱えない。 よって、SMFは曲データを作成しているときの保存フォーマットとして用いられることは少なく、 専ら曲データ完成後の配布用フォーマットとして用いられている。 実際、一般的なシーケンサソフトでは、 独自フォーマットとSMFのどちらでもデータを保存することができ、 前者は通常のデータ保存に、後者は(シーケンサソフト外にデータを渡す)エクスポート的な機能として用いているはず。

以下の表記について、その他

SMFのおおざっぱな構造

ものすごく大雑把に書くと、以下のものを順番に単純に結合(concatenate)したもの、 ということになる。

以下サンプル。テンポ120で、四分音符でドレ、全音符でミを鳴らすSMF。 ヘッダとトラックデータその1(Conductor Track)、トラックデータその2を色分けしている。

000000 4D 54 68 64 00 00 00 06 00 01 00 02 00 30 4D 54  / MThd.........0MT 

000010 72 6B 00 00 00 0B 00 FF 51 03 07 A1 20 00 FF 2F  / rk......Q....../ 

000020 00 4D 54 72 6B 00 00 00 18 00 90 3C 7F 30 3C 00  / .MTrk.....・0<.. 

000030 00 3E 7F 30 3E 00 00 40 7F 81 49 40 00 00 FF 2F  / .>.0>..@..0@.../ 

000040 00                                               / .

また、フォーマット1の場合、「トラックデータその1」 (Conductor Track)には演奏以外のデータ (テンポ等の各種メタイベントSysExイベント) を格納し、実際の演奏データは「トラックその2」以降に格納するのが一般的。

以下、ヘッダ以下の具体的なデータ構造を記す。

ヘッダについて

ヘッダにおける、実データの大きさについて

ヘッダに含まれる実データの大きさを4byteのbig endianで格納する。 ヘッダでの実データの大きさは、 フォーマットに2byte、トラック数に2byte、時間単位で2byteなので、合計6byte。 結局、ここには (現状では) 常に 00 00 00 06 が格納されることになる。

フォーマットについて

現在、0, 1, 2の3種類が定義されている。それぞれフォーマット0, フォーマット1, フォーマット2と呼ばれる。

時間単位について (デルタタイムの意味の指定)

トラックデータについて

実データ (本当はMTrkイベントと呼ぶ) においては、[デルタタイム] + [イベント] の組がトラック末尾まで続く。

そして、[イベント]には、以下の3種類がある。

以下、それぞれの構成要素について記す。

デルタタイムとは

次に続くイベントまでの時間を表す時間情報のこと。 ヘッダーブロックで時間単位の項目を正数で指定した場合 (=デルタタイムを小節・拍等を基準として表現する場合)、 デルタタイムは(直前のイベントから)次に続くイベントまでの時間差を表す。 例えば全音符の分解能が480だった場合、デルタタイム120というのは 「四分音符分の時間(の後)」を意味する。同様に、 もしトラックの最初のイベントがトラックの先頭に発生する際のデルタタイムや、 2つのイベントが同時に発生するような場合(の2つ目のイベント)につくデルタタイムは、 0となる。

上記の実データの説明でも分かるように、 前のイベントと次のイベントの時間間隔を定義するために、 デルタタイムは常に必要である。

ちなみにヘッダーブロックで規定するように、 デルタタイムは拍子(に基づく時間情報)を意味するだけではなく、 SMPTEタイムと共にトラックをレコーディングする場合の"秒"の分数 (分解能) を意味することもあるが、後者の表現を用いることは稀であり、 無視して良いと思う。 (映画なんかでSEを挟む場合、こちらの表現を用いることがある、らしい)

可変長形式について

デルタタイムは、以下のような可変長形式で表される。

MIDIイベントとは

いわゆる演奏データのこと。 MIDIのチャンネルメッセージそのままと考えて差し支えない。

以下、具体例。

これらチャンネルメッセージは、 厳密にはチャンネルモードメッセージとチャンネルボイスメッセージに分かれる。

チャンネルモードメッセージの中で、 「MIDIモードをモード4にする」操作を行うときにのみ、 コントロールチェンジ(0xBn)の構成バイトが4byteになるので注意。 それ以外のコントロールチェンジはすべて3byte構成になる。

例: MIDIモードをモード4(OMNI OFF / MONO)にする B1 7C 00 (MIDIチャンネル2を、まずOMNI OFFにする) B1 7E 00 04 (MONO; 4byte目に使用するチャンネル数(ここでは4つ)を記載する)  例: MIDIモードをモード2(OMNI ON / MONO)にする B1 7D 00 (MIDIチャンネル2を、まずOMNI ONにする) B1 7E 00 (そして、MONO ONにする) 

ランニングステータスについて

前のMIDIチャンネルメッセージのステータスバイトと同じステータスバイトが連続する場合、 2回目以降のステータスバイトを省略することができる。 これをランニングステータス(ルール)と呼ぶ。 ステータスバイトとは、 MIDIのチャンネルメッセージで書いたところの、 0x8nとか0x9nとか0xAnとか。

例えば、以下の実データ例において、 太字で表した部分はランニングステータスルールにより省略可能である。

(なお一番左のデータはデルタタイムである。念のため)

00 90 3C 7F : ノート番号3C(ド)をベロシティ7Fで発音

60 90 3C 00 : ノート番号3C(ド)を消音

00 90 3E 7F : ノート番号3E(レ)をベロシティ7Fで発音

60 90 3E 00 : ノート番号3E(レ)を消音

00 90 3C 7F : ノート番号3C(ド)をベロシティ7Fで発音

00 90 40 7F : ノート番号40(ミ)をベロシティ7Fで発音

00 90 43 7F : ノート番号43(ソ)をベロシティ7Fで発音

60 90 3C 00 : ノート番号3C(ド)を消音

00 90 40 00 : ノート番号40(ミ)を消音

00 90 43 00 : ノート番号43(ソ)を消音

00 C0 00 : 音色をピアノに変更

ランニングステータスが適用されているかどうかは、 ステータスバイトに相当する部分のMSB(第7bit)で判定できる。 (0なら適用、1なら未適用)

ノートオフを表現する場合、8nと9nによる2つの表現方法があるが、 当然9nを用いた方がランニングステータスを適用しやすくなる、 すなわち、SMFのデータを小さくすることができる。

一方で、ランニングステータスを用いると、 曲の途中から再生するようときに、省略されたステータスをプレーヤが復元できない、 といったこともあり得るので、SMFデータ作成者は、 ランニングステータスを用いない方法でもデータを作成できるようにしておくべき。 またこの場合、先ほどとは逆にノートオフには8nを用いた方が、 ノートオフの意味合いをより明示できるだろう。

SysExイベントとは

主にMIDIシステムエクスクルーシブメッセージを指定するのに用いられる。 SysExイベントには、F0で始まるものとF7で始まるものの2種類がある。

いずれの場合も、データ長は可変長形式で格納される。 (従って、SysExイベントにはランニングステータスは適用できない。 データ長のMSB(第7bit)が可変長形式適用で1になっていると、 ランニングステータスとの区別が付かない)

F7で始まるSysExイベントは、リアルタイムバイトやソングポインター、 MIDIタイムコード、システムリセットなど、 通常の方法では送れないデータを直接送るための裏技として用いられるが、 シーケンサを変えた場合にこのデータがどう処理されるかは分からない等互換性維持の面で問題があるため、 通常はF0で始まるエクスクルーシブメッセージ送信のみを用いるのが無難である。

(実際、余程のことがない限りF0のみを使用していても問題とはならないはず)

メタイベントとは

メタイベントは、シーケンサやSMFに便利な、演奏データに含まれない情報 (テンポ、曲タイトル等)を納めるのに用いるイベント。 基本的に、ステータスバイトFFで始まり、 次にイベントタイプを表すバイトが続き、 さらに可変長形式で格納されたデータ長が続き、 最後にデータ自体が続く (SysExイベントのF7の場合と似ている)。

もしデータがなければデータ長は0となる。 SysExイベントと同様に、 ランニングステータスの適用はできない。 (データ構造上は適用できそうなものだが、仕様書で明確に適用不可と明記されている)

すべてのプログラムがすべてのメタイベントをサポートしなければならないということではない。

現在定義されているメタイベントは、具体的には以下のものがある。

SMFの実際

テンポ120で、四分音符でドレ、全音符でミを鳴らすSMF。

ランニングステータスが多用されていることに注意。 また、ランニングステータスの効果を高めるために、 ノートオフとして 9n kk 00 (ベロシティゼロでノートオン) を使用している。


000000 4D 54 68 64 00 00 00 06 00 01 00 02 00 30 4D 54  / MThd.........0MT 

000010 72 6B 00 00 00 0B 00 FF 51 03 07 A1 20 00 FF 2F  / rk......Q....../ 

000020 00 4D 54 72 6B 00 00 00 18 00 90 3C 7F 30 3C 00  / .MTrk.....・0<.. 

000030 00 3E 7F 30 3E 00 00 40 7F 81 49 40 00 00 FF 2F  / .>.0>..@..0@.../ 

000040 00

                                               / .

ヘッダ

4D 54 68 64    "MThd" 

00 00 00 06    ブロック長(6) 

00 01フォーマット(1) 

00 02     トラック数(2) 

00 30四分音符の分解能(0x30=48)  


トラック1のデータ (Conductor Track)

4D 54 72 6B    "MTrk" 

00 00 00 0B    ブロック長(0x0B=11) 

00 FF 51 03 07 A1 20テンポ(120)

00 FF 2F 00トラックエンド  


トラック2のデータ (演奏トラックその1)

4D 54 72 6B    "MTrk" 00 00 00 18    ブロック長(0x18=24) 

00    90 3C 7F    ベロシティ127でノート3Cをノートオン 

30       3C 00    48tick後、ノート3Cをノートオフ 

00       3E 7F    直後に、ベロシティ127でノート3Eをノートオン 

30       3E 00    48tick後、ノート3Eをノートオフ 

00       40 7F    直後に、ベロシティ127でノート40をノートオン 

81 40    40 00    192tick後、ノート40をノートオフ 

00    FF 2F 00トラックエンド


MIDI 1.0 規格書の4-12ページ以降に、より細かい実際のサンプルあり。


筆者がたどったはまり道

参考文献

E-mail: