MIDIを使った演奏情報を一定の形式(フォーマット)のファイルにまとめたものを (ここでは)「MIDIデータファイル」と呼んでいるが、 そのMIDIデータファイルの、世界でもっとも一般的な形式がSMF(Standard MIDI Format)である。 ファイルの拡張子は 〜.MID であることが多いが、 〜.SMF であることもある。
SMFは基本的に 「この時間(タイミング)に、この音を強さ**でオンにする」 といったレベルの情報の集まりでしかなく、 「ここを2回繰り返す」とかいった「ちょっと高級な情報」は扱えない。 よって、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」以降に格納するのが一般的。
以下、ヘッダ以下の具体的なデータ構造を記す。
| データ例 | 4D 54 68 64 | 00 00 00 06 | 00 00 | 00 02 | 00 30 |
|---|---|---|---|---|---|
| 説明 | "MThd" | 実データの大きさ (現状、必ず6) | フォーマット(0000/0001/0002) | トラック数 (2byte数値) | 時間単位 (デルタタイムの意味の指定) |
ヘッダに含まれる実データの大きさを4byteのbig endianで格納する。 ヘッダでの実データの大きさは、 フォーマットに2byte、トラック数に2byte、時間単位で2byteなので、合計6byte。 結局、ここには常に 00 00 00 06 が格納されることになる。
現在、0, 1, 2の3種類が定義されている。それぞれフォーマット0, フォーマット1, フォーマット2と呼ばれる。
上位バイトは -24, -25, -29, -30 の4つのうちひとつとなる。 (これは SMPTEや MIDIタイムコードの4種類の秒当りのフレーム数に対応している) 2番目のバイト(正数)はフレーム当りの分解能である。 通常の値は 4 (MIDIタイムコードの分解能), 8, 10, 80(ビット分解能), 100 であろう。 このシステムはタイムコードベースのトラックにはぴったりだが、 さらに、25 frames/sec で分解能を 40 units / frame にすることによって、 ミリセコンド・ベースのトラックにも有効である)
| データ例 | 4D 54 72 6B | ** ** ** ** | ** ** 〜 |
|---|---|---|---|
| 説明 | "MTrk" | 実データのデータ長 | 実データが続く |
実データ (本当はMTrkイベントと呼ぶ) においては、以下のデータの組み合わせがトラック末尾まで続く。
以下、それぞれの構成要素について記す。
次に続くイベントまでの時間を表す時間情報のこと。 ヘッダーブロックで時間単位の項目を正数で指定した場合 (=デルタタイムを小節・拍等を基準として表現する場合)、 デルタタイムは(直前のイベントから)次に続くイベントまでの時間差を表す。 例えば全音符の分解能が480だった場合、デルタタイム120というのは 「四分音符分の時間(の後)」を意味する。同様に、 もしトラックの最初のイベントがトラックの先頭に発生する際のデルタタイムや、 2つのイベントが同時に発生するような場合(の2つ目のイベント)につくデルタタイムは、 0となる。
上記の実データの説明でも分かるように、 前のイベントと次のイベントの時間間隔を定義するために、 デルタタイムは常に必要である。
ちなみにヘッダーブロックで規定するように、 デルタタイムは拍子(に基づく時間情報)を意味するだけではなく、 SMPTEタイムと共にトラックをレコーディングする場合の"秒"の分数 (分解能) を意味することもあるが、後者の表現を用いることは稀であり、 無視して良いと思う。 (映画なんかでSEを挟む場合、こちらの表現を用いることがある、らしい)
デルタタイムは、以下のような可変長形式で表される。
いわゆる演奏データのこと。
MIDIのチャンネルメッセージそのままと考えて差し支えない。
以下、具体例。
これらチャンネルメッセージは、
厳密にはチャンネルモードメッセージとチャンネルボイスメッセージに分かれる。
チャンネルモードメッセージは、
コントロールチェンジ120〜127を使用するメッセージ
(0xBn 0x78 〜 0x7F)
のことで、要は音源制御系のメッセージである。
(All Sounds Off とか、Reset All Controllers など)
一方、チャンネルボイスメッセージは、これ以外のチャンネルメッセージのことで、
要は発音系のメッセージである。
チャンネルモードメッセージの中で、 「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を用いた方が、
ノートオフの意味合いをより明示できるだろう。
主にMIDIシステムエクスクルーシブメッセージを指定するのに用いられる。 SysExイベントには、F0で始まるものとF7で始まるものの2種類がある。
| w | x | y | z | |
| F0なSysEx | F0 | データ長 (= y + z) | 転送データ (= w + y + z) | F7 |
| F7なSysEx | F7 | データ長 (= y) | 転送データ(= y) |
いずれの場合も、データ長は可変長形式で格納される。 (従って、SysExイベントにはランニングステータスは適用できない。 データ長のMSB(第7bit)が可変長形式適用で1になっていると、 ランニングステータスとの区別が付かない)
F7で始まるSysExイベントは、リアルタイムバイトやソングポインター、
MIDIタイムコード、システムリセットなど、
通常の方法では送れないデータを直接送るための裏技として用いられるが、
シーケンサを変えた場合にこのデータがどう処理されるかは分からない等互換性維持の面で問題があるため、
通常はF0で始まるエクスクルーシブメッセージ送信のみを用いるのが無難である。
(実際、余程のことがない限りF0のみを使用していても問題とはならないはず)
メタイベントは、シーケンサやSMFに便利な、演奏データに含まれない情報 (テンポ、曲タイトル等)を納めるのに用いるイベント。 基本的に、ステータスバイトFFで始まり、 次にイベントタイプを表すバイトが続き、 さらに可変長形式で格納されたデータ長が続き、 最後にデータ自体が続く (SysExイベントのF7の場合と似ている)。
もしデータがなければデータ長は0となる。 SysExイベントと同様に、 ランニングステータスの適用はできない。
すべてのプログラムがすべてのメタイベントをサポートしなければならないということではない。
現在定義されているメタイベントは、具体的には以下のものがある。
| ステータス バイト | メタイベント 種類 |
データ長 (可変長形式) | データ | 意味 | 備考 |
|---|---|---|---|---|---|
| FF | 00 | 02 | ssss | シーケンス番号 | |
| FF | 01 | len | text | テキスト | |
| FF | 02 | len | text | 著作権表示 | |
| FF | 03 | len | text | シーケンス名(曲タイトル)・トラック名 | |
| FF | 04 | len | text | 楽器名 | |
| FF | 05 | len | text | 歌詞 | |
| FF | 06 | len | text | マーカー | |
| FF | 07 | len | text | キューポイント | |
| FF | 08 | len | text | プログラム名 (音色名) | RP-019 |
| FF | 09 | len | text | デバイス名 (音源名) | RP-019 |
| FF | 20 | 01 | cc | MIDIチャンネルプリフィックス | v1.0 |
| FF | 21 | 01 | pp | ポート指定 | SMF非標準 |
| FF | 2F | 00 | --- | トラック終端 | |
| FF | 51 | 03 | tttttt | テンポ設定 | |
| FF | 54 | 05 | hr mn se fr ff | SMPTEオフセット | |
| FF | 58 | 04 | nn dd cc bb | 拍子の設定 | |
| FF | 59 | 02 | sf mi | 調の設定 | |
| FF | 7F | len | data | シーケンサ特定メタイベント |
フォーマット2で、パターンを識別するために用いる。 通常フォーマット0,1では用いない。
任意の長さ・内容のテキストを記述することができる。
ただし、
著作権表示、
シーケンス名/トラック名、
楽器名、
歌詞、
マーカー、
キューポイント、
プログラム名、
デバイス名
といった用途には、
専用のメタイベントタイプ(0x02〜0x09)が別途用意されているのでそちらを用いるべき。
(余談: メタイベントタイプの 0x01〜0x0Fは、
この手のテキストイベントのために予約されている)
例えば、トラックのいちばん初めに、意図する音源名やオーケストレイション、 その他ユーザがそこに置きたいと思う情報を書いておくと良い。
なお互換性のことを考えると、このイベント中のテキストは、 印刷可能なASCII文字を使用することが推奨されている。 (まあイマドキそんなことを気にする必要もないとは思いますが・・ 以下、 いちいち書きませんがテキスト関連のメタイベントすべてに同じことが当てはまります)
曲に関する著作権表示を記述する。 この表示には (C)の文字、 著作物発行年と、著作権所有者名とが含まれなければならない。
このイベントは第1トラック (Conductor Track)の最初のイベントとして、 デルタタイム0で置かれなければならない。 また、ひとつのMIDIファイルに幾つかの楽曲がある時には、 すべての著作権表示をこのイベントに置いて、 かつそれがファイルの先頭に来るようにしなければならない。
以下の場合には、シーケンス名(つまり、曲のタイトル)となる。
そのトラックで用いられる楽器の種類を記述する。
歌詞。
一般的には、(歌詞の)各音節が別々の歌詞イベントとして記述され、
そのイベントが始まるタイミングでシーケンサ等が歌詞を表示することになる。
リハーサル記号やセクション名のような、 シーケンスのその時点の名称を記述する。 ("Introduction" とか "A", "B" など)
このメタイベントを使用する場合、置き場所としては 通常フォーマット0のトラック、 もしくはフォーマット1のファイルの第1トラック (Conductor Track)となる。
(余談: 日本ファルコム社のYs2 EternalのMIDI曲では、 このメタイベントを 無限ループ用のマーカーとして用いているようです)
曲データ中、このメタイベントの挿入されている位置で、 その曲以外の進行を記述するのに用いる。 (曲中の進行の記述には、マーカーを用いる)
例えば「車が走り出す」「画面がフェードアウトする」など。
直後に続く「プログラムチェンジ」と 「バンクチェンジ」で表している音色名を記載する。 (非GM音源だと結構使いでがあるでしょ?)
このメタイベントはトラック中のどこにおいても構わないが、 プログラムチェンジやバンクセレクトと共に用いるべきである。
このメタイベントがあるトラックが、
どのデバイスに配置されるのかということをテキストで表すものだが、
大抵は音源の名前を入れることになるだろう。
(区別できれば結局どんなテキストでも構わないわけですが)
このメタイベントは、1トラックにつき1回だけ、
最初に音源にデータが送られる前に記述されるべき。
(データが送られた後で音源が決まるんじゃ、意味ないですしね)
ちなみにこのメタイベントは、 あくまで16ch以上のデータを想定して考案されたものなので、 「音源名」に拘らず「ポート番号」や、 もっと極端な話「FM」「WAVE」とか、そういったのもアリ。
MIDIイベント以外 (つまりSysExイベントかメタイベント)のイベントに対して、 MIDIチャンネルを指定する際に用いる。
例えば、 エクスクルーシブメッセージをMIDIチャンネルに対応させたり、 楽器名をMIDIチャンネルに対応させたり、 フォーマット0を使用時にMIDIチャンネルとトラック名を対応させたりする場合に用いる。
なおこのイベントによる設定は、再度このイベントが現れるか、 任意のMIDIイベントが現れるまで有効。
このメタイベントは現在のSMF Version 1.0では定義されていないが、 32ch対応のMIDI音源の台頭に伴い、 いわゆるデファクトスタンダードとして普及しているようだ。
利用法として、現状以下の3パターンが確認されているが、 どのパターンで作成されているかはデータだけでは識別不能。
日本国内(のフリーソフトの類)では基本的に 1. のパターンを想定しておけば問題ないと思われる。
このイベントの効力は次に同イベントが出現するまで続く。 当然ながら初期状態(無指定時)ではポート1が選択されている。
(余談: SMF ver1.0 specに完全に沿った形で32chなデータを表現する (つまり、このメタイベントを用いない)場合、以下の方法が考えられる。
そのトラックの終端を表す。
これがあることによって トラックの正しい終結点が明確になり、
トラックが正確な長さを持つようになる。
このイベントは仕様上省略不可となっているので注意。
(余談: 逆に、メタイベントに関しては、 このメタイベントと次に出てくるテンポのメタイベントさえ実装すれば、 極端な話それ以外(のメタイベント)は実装上無視しても、 演奏自体は正しいものとなる)
(蛇足: FF 2* 系は、基本的に「トラック全体に関わる設定項目」 を想定しているように思われます)
このイベントでテンポ変更を指示する。
tttttt (3byte) には、四分音符の長さをマイクロ秒 (μsec)
で表したものを格納する。
例えば、BPM=120 (1分あたり四分音符が120個)の場合、
四分音符の長さは 60 x 106 / 120 = 500,000 (μsec)。
これを16進にすると0x07A120。従って、メタイベントは
FF 51 03 07 A1 20
となる。
(余談: 割算した結果が割り切れない場合、大抵のプレーヤは 「有効桁数以下切り捨て」として扱っている → データ作成時も切り捨てていることを想定している、 ようです。 個人的には有効桁数以下0捨1入した方がより正確なテンポ値に近づくと考えますが、 自身のMMLコンパイラでそのように実装した結果プレーヤでの表示が1ずれたりしちゃって、 「何でテンポ値がずれるの?」 というFAQに追われる羽目となってしまいました(^^;)
トラックデータの先頭にこのメタイベントをおくことで、 トラックデータの演奏開始時刻を指定することができる。 時間は、MIDIタイムコードと全く同様に、 SMPTEフォーマットでエンコードされなければならない。
拍子記号は、4つの数字で表現される。 nnとddは、そのまま拍子記号の分子と分母を表す。 ただし分母は2のマイナス乗で表現する。 つまり2=4分音符、3=8分音符、4=16分音符・・・となる。
ccは、メトロノーム1拍あたりのMIDIクロック数を表している。 24MIDIクロックで4分音符を表す(後述)ため、 例えば4分音符ごとにメトロノームを鳴らす場合、 cc=0x18 (=24)となる。
bbは、MIDI4分音符(24MIDIクロック)の中に入る32分音符の数を表す。 大抵bb=8となる。
例:
4/4拍子だと、FF 58 04 04 02 18 08
3/4拍子だと、FF 58 04 03 02 18 08
6/8拍子だと、FF 58 04 06 03 18 08
いずれも、cc=0x18(=24)、bb=8の場合。
(余程のことがない限り変更する必要はないと思いますが)
調号を指定する。
sfには、♯や♭の数が入る。正数なら♯の数、負数なら♭の数を表す。 ハ長調(つまり♯も♭もない)の場合は0。 (このあたりの詳細は、楽典などで確認のこと。)
miは長調か短調かを表すフラグで、0なら長調、1なら短調。
特定のシーケンサーのための特別な要求のためこのイベントタイプを用いる。 データバイトの最初の1バイトはメーカーIDである。 その後、独自フォーマットによるデータが続く。 このようなものであるため、 SMFデータの互換性を考えるならこの機能を使うことはないだろう。
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 トラックエンド
フォーマット0 のファイルでは、テンポはトラック中に分散し、 テンポ・マップ・リーダーは間のイベントを無視しなければならない。 フォーマット1 のファイルでは、テンポ・マップは最初のトラックになければならない (0.04から追加)。