トップページ > SMF フォーマット解説

お読みになる前に


この文章は1997年に書いたものです。 ところどころ不遜な表現、読みづらい箇所があるかと思いますが、若気のいたり(?)ということで、お許しください。


はじめに


SMF(Standard MIDI File)のフォーマットを詳しく書いたものを探している人が多いようで、 ここではSMFフォーマットの中身を簡単に説明します。 まだ、わかりにくい説明だと思いますので徐々に充実させていければと思っています。 ご意見・ご感想などがあればメールをください。

ただし、16進数の知識はあらかじめ持っているものとします。 16進数は "10H" というように "H"を末尾につけます。2進数は11111111Bというように、 最後に "B" をつけます。まあ、2進数なんてみればわかりますよね


SMFのフォーマット


SMFには、Format 0/1/2 の3つのフォーマットがあります。
Format 0 はすべてのチャンネルのデータを1トラックに全て収めたものです。
Format 1 はマルチトラック対応のフォーマット。 楽譜でいえば、楽器のパート毎にきれいに分けられて、記述されいるのが Format 1 で、楽器の分け隔てなく、全てのパートを同じ五線譜にごっちゃになって書かれているものが、 Format 0です。ふーむ、こんな例えでいいのかな。
Format 2ってのはシーケンスパターンをそのまま保存する・・・といったような、 私もよくわかっていない仕様なんですが、対応機種が少ないので、ここでは無視します。

FORMAT 0 のイメージ図
トラック1
1:0:0001チャンネルのドを鳴らせ
1:0:0002チャンネルのミを鳴らせ
1:0:00010チャンネルのソを鳴らせ
FORMAT 1のイメージ図
トラック1
1:0:0001チャンネルのドを鳴らせ
トラック2
1:0:0002チャンネルのミを鳴らせ
トラック3
1:0:00010チャンネルのソを鳴らせ


SMFの構造


SMFの構造は、意外と簡単です。 SMFは大きく分けると1つのヘッダのブロック(ヘッダ・チャンクと申します) と複数のトラックのブロック(トラック・チャンクと申します)に分けることができます。 ヘッダチャンクは、その曲の基本的情報が詰まっています。詳細は後で述べましょう。 トラックチャンクってのは、名前の通り、1トラックごとの情報がつまっています。

SMFにはFORMAT 0/1/2 と3つのフォーマットがありますが、 FORMAT 0 は・・・そう、トラックチャンクは1つしかございません。(Format 0 はすべてのチャンネルのデータを1トラックに全て収めたものですから) FORMAT 1/2 は使用しているトラックの数だけトラックチャンクがございます。

ヘッダチャンク

では、早速SMFファイルのデータ構造を見てみましょう。 読者の皆さんは、いくつかのSMFファイルとバイナリエディタを用意して、実際にSMFの中身を見てみるといいですね。

さて、SMFファイルはヘッダチャンクから始まります。ヘッダチャンクの構造を下に示します。 下の数字(16進数)は一例ですので、データによって変わります。

チャンクタイプ(4byte) データ長(4byte) フォーマット(2byte) トラック数(2byte) 時間単位(2byte)
4D546864 00000006 00000001 01E0

■チャンクタイプ(4byte)
チャンクタイプはこれから始まるチャンクのタイプを記号で表したもの。 マジックナンバーってやつですね。 ヘッダチャンクは"MThd"となっている。これを数値化してやれば、 4DH, 54H, 68H, 64Hとなる。ので、どんなSMFファイルも先頭の4バイトは、 上のように決まっているはず。

■データ長(4byte)
チャンクタイプの次にデータ長が4バイトをしめます。 データ長っていうのは、これから先、このチャンクが何バイト続くかを示したものです。 4バイトであらわすことができるが、ヘッダチャンクは必ず [00H, 00H, 00H, 06H] (このチャンクは6バイトですって意味ですね)となります。 だって、この後に続くのは、フォーマット(2byte) + トラック数(2byte) + 時間単位(2byte) で、合計6バイトと決まっているんだもん。 じゃあ、なんで4バイトもあるのさって私に聞かないでくださいね。 多分、将来の拡張用だったり、トラックチャンクに合わせたりしてるんでしょうね。

■フォーマット(2byte)
SMFフォーマットの0か1か2を2バイト利用して、 あらわします。フォーマット0なら、[00H, 00H]、フォーマット1なら、[00H, 01H]となります。

■トラック数(2byte)
データの全トラック数をあらわします。フォーマット0なら、 無条件で、[00H, 01H]となるのがおわかりでしょうか? (フォーマット0は1トラックオンリーですよね)

■時間単位
要するに分解能ってやつです。 じゃあ、時間単位なんて書かずに分解能って書いちゃえばいいじゃんって思うのですが、 だって虎の巻にそう書いてあるんだもん。(笑)
って冗談はさておき、 みなさんはふだん音楽を作る時に、 「何小節の何拍目」といった感じで、タイミングを調整しますね。 音楽を作る時に「演奏開始時から2分43秒000のタイミングで・・・」 なんてタイミングの取り方をしている人はまずいないと思います。

SMFフォーマットでは、 この2種類(「何小節何拍」と「何分何秒何フレーム」)の指定ができます。 どちらを指定するかは、2バイトのうちの上位バイト(図の左側ですね) の最上位ビット(第7ビット)によって決定されます。 0なら前者が採用され、1なら後者が採用されます。 上位ビットが80H以上ならば、後者ということになりますね。 (10000000Bを16進数に変換すると80Hだから) ま、大抵のデータが前者を使っていますので、気にする必要はないですね。 上の例では[01H, E0H]となっていますので、素直に[01E0H]と解釈しましょう。 (わざわざひっくりかえしたりしない) 01E0Hを10進数に直すと480。要するにこの例では「分解能480のデータ」であることを示しています。

トラックチャンク

さあ、早くも最終章です。(笑)
このトラックチャンクが重要なんですよね。右のスクロールバーの下がり具合でその重要さが分かります。

それでは、下に例を示します。
チャンクタイプ(4byte)データ長(4byte)データ本体(左のデータ長で示された長さ)
4D54726B 00005B6A ........

■チャンクタイプ(4byte)
トラックチャンクのマジックナンバーは「MTrk」[4DH, 54H, 72H, 6BH]です。 トラックチャンクは必ずこの4バイトから始まります。

■データ長(4byte)
ヘッダチャンク同様、この後に続くデータの長さを4バイトであらわします。 上の例では[00H, 00H, 5BH, 6AH]を素直に00005B6AHバイトと解釈して、23562バイト(多分) となります。

■データ本体
さ、いよいよ本番です。けっこう最初は ?? な感じですが、 慣れてくるとバイナリエディタに並んだ16進数をポカンと見てるだけで、 どんなデータか想像出来るようになります。(ほんとか?)

データ本体は無数のイベントが集まって出来ています。 「1チャンネルのC4を鳴らせ」・・・で、これは立派な1イベントです。 SMFファイルは、[タイミング]と[イベント]が組になっています。 わかりやすくいうと「いつ」「何をするのか?」がセットになったものが、 何百何千と続いているということです。この「いつ」の部分を「デルタ・タイム」 と呼びます。

デルタタイムの表現方法

デルタタイムは可変長の数値で表現します。 可変長というのはその名前の通り「長さを変えることができるデータ」です。 これまでに出てきた数値表現はみんな「固定長の数値表現」でした。「各チャンクのデータ長は4バイトであらわす」 という具合に2バイトとか4バイトって決まっていました。 しかし、いつもいつも4バイトも必要になるわけでもなく。 例えば、ヘッダチャンクのようにデータ長が6バイトで済んでしまうのなら、 なにもデータ長の部分で[00H, 00H, 00H, 06H]って4バイトも使わなくても、 [06H]の1バイトだけで終わらせることができますね。

デルタタイムに「固定長数値表現」を当てはめると、 データが冗長になってしまい大変です。"0"をあらわすのに[00H, 00H, 00H, 00H] なんて4バイトも使う余裕はありません。 なぜならデルタタイムは1イベントに1回出現するからです。 1音なるごとに1回出現(設定)するのです。1曲あたり何万というイベントがあります。 その度に4バイトも使ってたら、大変なデータ量になりますよね。 逆に1バイトで済ませてしまうと、精度の高い(どころか普通の)音楽は表現できません。

そこで考え出された(?)のが、「可変長数値表現」です。 可変長数値表現は1バイトのうち、 最上位ビットを除く7ビットを数値を表現するのに利用します。 最上位ビットは次のバイトもデータバイトであるか? をあらわすためのフラグに利用されます。

それでは下に表でまとめます。これを見れば一発で理解できるかも?

表現したい数
(10進数)
16進数 可変長数値表現
(16進数)
可変長数値表現
(2進数)
0 00H 00H 0000 0000B
127 7FH 7FH 0111 1111B
128 80H 81H 00H 1000 0001 0000 0000B

む〜。わかんない?わかんないですよね。これじゃあ。

えー、先ほど申しましたように、「各バイトの最上位ビットはフラグに利用する」 ということから、7ビットで表現できる数値までは1バイトで表現できることになります。 2進数でいえば、00000000Bから01111111Bまでですよね。 16進数になおせば、00Hから7FHまで。
じゃあ、80Hはどうあらわすかというと、もう1バイト余分に使います。 そこで上の表を128の列を見てください。 128を普通に16進数表現すれば、80H。2進数は10000000Hとなりますが、 可変長数値表現の場合、最上位ビットが使えないので、上位バイトの最下位ビットに繰り上げをします。 また上位バイトの方では次のバイトもデータバイトである事を示すために、 最上位ビットに1を立てます。逆に最上位ビットがが0ならば、 データバイトはこのバイトで終わりという意味になります。 128を可変長数値表現に直した場合の下位ビットがそれにあたりますね。

可変長数値表現わかりましたか? 説明するのも難しいですね〜。ふぅ。

デルタタイムに話を戻します。 1つのイベントを表現する場合、まずデルタタイムを設定します。 デルタタイムは「直前のイベントからの時間」をあらわします。 デルタタイムはヘッダチャンクで設定した「時間単位」の設定に左右されます。 もし「時間単位」が [00H 60H](96)に設定されていれば、 デルタタイム30H(48)は八分音符をあらわします。 デルタタイムが00H(0)であれば、 直前のイベントと同時にそのイベントが実行されるという意味になります。 和音を表現する時はこれにあたりますね。

イベント

デルタタイムを設定したら、次はイベントです。 イベントは必ずデルタタイムとセットになっていて、 [デルタタイム(いつ?)][イベント(何をする?)][デルタタイム][イベント]と 交互に繰り返されて、データ本体を構成します。

イベントは次の3つに分けることが出来ます。

  • MIDIイベント
  • SysExイベント
  • メタイベント

    それでは、この3つを順番に説明します。

    ■MIDIイベント
    MIDIイベントは単純にMIDIチャンネルメッセージをあらわしたもの。 ぶっちゃけた話、演奏データのことです。 音源のマニュアルの後ろの方に詳細が載っているのですが、 ここでも簡単に説明します。

    MIDIイベントは、ステータスバイトとデータバイトを利用して表現します。 例えば「C5の音を鳴らせ」という命令であれば、 「鳴らせ」というのがステータスバイト、「C5の音を」というのがデータバイトになります。 ステータスバイトは最上位ビットが 1 (80H-FFH)になっています。 データバイトはその逆で 0 (00-7FH)になっています。 ボリューム等の設定の多くが制限値を127(7FH)にしているのはこういうことからなのです。

    それでは代表的なチャンネルメッセージを紹介します。
    メッセージの名称データ効能
    ノート・オフ 8nH kkH vvH
    (n=対象チャンネルナンバー
    kk=ノートナンバー
    vv=ベロシティー
    音を止める。ベロシティーは鍵盤から手を離す時の速さを表す。
    ノート・オン 9nH kkH vvH
    (n=対象チャンネルナンバー
    kk=ノートナンバー
    vv=ベロシティー
    音を鳴らす。ベロシティーは鍵盤を弾く際の速さを表す(音の強さってことです)
    コントロールチェンジ BnH ccH vvH
    (n=対象チャンネルナンバー
    cc=コントロールナンバー
    vv=データ
    各種コントローラの設定ができる。

    MIDIイベントは上記のように3バイトのデータが組み合わさっています。 例えば「8チャンネルのC4(60=3CH)をベロシティ90で鳴らせ」 というメッセージは[98H 3CH 5AH]という具合です。 ランニングステータス ただし、同じチャンネルメッセージが連続して続く場合は、ステータスバイトを省略できる ランニング・ステータス・ルールが適用できます。 例えば、同一チャンネルのノートオンが連続している場合はステータスバイトの 9nHが省略できるというわけです。 このようなルールがあるので、[8nH kkH vvH]とするノートオフを、 [9nH kkH 00H](ベロシティ0のノートオン)として、 第一バイトを省略して、データ量を削減するシンケーサもあります。

    ■SysExイベント
    システムエクスクルーシブメッセージを表すイベントです。 SysExイベントは以下のような2種類のフォーマットが存在します。

    F0データ長(可変長)エクスクルーシブメッセージF7

    F7データ長(可変長)エクスクルーシブメッセージ

    SysExイベントにはF0ステータスとF7ステータスの2種類がありますが、 実際にはF0ステータスを使うのが好ましいとされてます。 エクスクルーシブメッセージの詳細は音源等のマニュアルの後ろに掲載されているはずですので、 そちらをご覧ください。

    SysExイベントがMIDIイベントと異なるのは、 ステータスバイトの後に可変長のデータ長が格納される点です。

    ■メタイベント

    メタイベントは、拍子やテンポ、著作者情報や歌詞等の情報を格納します。 すべてのメッセージが重要ではなく、歌詞等は無視するシンケーサが多いですね。 逆にテンポやトラックエンドの情報はシンケーサにとってかかせない情報になります。

    メタイベントではステータスバイトにFFHが利用されます。 フォーマットは以下の通り

    FFHイベントタイプ(1byte)データ長(可変長)データ

    イベントタイプは次のようなものがあります。代表的なものを挙げます。

    データ機能効能
    FFH 00H 02HSequence Numberシーケンス番号。FORMAT 0/1では利用されない
    FFH 01H len textTextコメントなどのテキスト
    FFH 02H len textCopyright Notice著作権表示
    FFH 03H len textSequence/Track Nameシーケンス名・トラック名
    FFH 04H len textInstrument Name楽器名
    FFH 05H len textLylic歌詞
    FFH 2FH 00HEnd of Trackトラックチャンクの終わりを示す
    FFH 51H 03H tempo(3byte)Set Tempoテンポ。
    4分音符の長さをマイクロ秒単位で表現。
    FFH 58H 04H nn dd cc bbTime Signature 拍子
    nn=分子
    dd=分子(2の負のべき乗で表す)
    cc=メトロノーム間隔(四分音符間隔なら18H)
    bb=四分音符あたりの三十二分音符の数
    FFH 59H 02H sf mlKey Signature キー(調)を表す
    sf=正・・シャープの数 負・・フラットの数
    ml=0・・・長調 1・・・短調

    3つのイベントの種類を紹介しましたがいずれも、 イベントの前にデルタタイムを設定することを忘れないようにしましょう。

    【参考文献】もっと詳しく知りたい方は・・・

    SMFリファレンスブック

    新井 純 著 リットーミュージック \2,800

    ご感想などをお送りください


    このウェブサイトが、少しでもあなたのお役にたてたなら幸いです。 ぜひとも、ご意見・ご感想などをお気軽にお寄せください。 どんなことでも結構です。あなたの一言が大きな励みとなります。 よろしくお願いします。

    お名前・性別は、未記入でも結構です。
    お名前
    メールアドレス
    性別
    ご意見・ご感想

    送信後は、現在のページが再表示されます。 ボタンは一回だけ押してください。

  • Taichi MARUYAMA