SMF (Standard MIDI Files) の構造
Jan. 4th, 2023: コンテンツ公開の場をgithubに移しました。
今後はそちらをご覧いただけますよう、よろしくお願いいたします。
更新履歴
v1.07: Jan. 6th, 2020;
このページから参照していた「Standard MIDI Files 0.06 March 1, 1988 の翻訳」が @niftyさんのサービス終了で参照できなくなったことを機に、 参照文書をAMEIさん発行の正式な翻訳文書に変更。
ただ、筆者はむしろ「~0.06~の翻訳」の方に大変お世話になったため、 感謝の意味を込めて参考文献として当該資料をそのまま掲載。
(当該資料は転載自由となっており、その意味でも感謝)
これに伴い以下の記載を、新規引用元の文面に即した形に更新。
時間単位の説明
可変長形式で表現できる最大時間の説明
SysExイベントだけでなくメタイベントでもランニングステータスが使えない理由の説明 (新規追加。理由は単に「仕様書でそう定めているから」)
その他、
SMFの元表記が"Standard MIDI Files"と"Standard MIDI Format"とブレていたので、 大本の表記(Standard MIDI Files)に統一。
分かりにくい記載を一部修正。(内容そのものは以前と同じ。)
v1.06: Oct. 25th, 2010;
ランニングステータスの説明中、「ミ」のノート番号をまだ間違えていたのを修正。 (石田さんthanks!!)
全般的に文章を見直し、分かりにくい表現を修正。
v1.05: Oct. 17th, 2010;
ランニングステータスの説明中、「ミ」のノート番号を間違えていたのを修正。 (石田さんthanks!!)
v1.04: Mar. 7th, 2008;
コントロールチェンジの構成バイト数の例外について補足追加。 (OMNI OFF/MONO(MODE 4)の場合のみ、4byteになる) (kAzzさんthanks!!)
v1.03: Feb. 14th, 2005;
ピッチベンドの最大値に対応する値を修正。 (0x7FFF → 0x7F7F) (須田さんthanks!!)
v1.02: Sep. 13th, 2001;
Recommended Practice (RP-019) SMF Device Name and Program Name Meta Events の内容を反映。
こんなのがずいぶん前からあったんですね。 これを使うとポート番号を意識せずに32ch使えますよ、ってな話。
(実際にはあんまし使われてないと思いますが・・)
v1.01: May 6th, 2001;
最後のサンプルのバイト数記述が間違っていたのを修正。(Sadaさんthanks!!)
その他ちょっと整形等したら30kになってしまった・・・。
初版: Nov. 28th, 2000;
簡潔かつ必要十分なSMF解説って見たことがなかったので作ってみた。 でもまだ25kもある・・・。
目次
SMFとは
MIDIを使った演奏情報を一定の形式(フォーマット)のファイルにまとめたものを (ここでは)「MIDIデータファイル」と呼んでいるが、 そのMIDIデータファイルの、世界でもっとも一般的な形式がSMF(Standard MIDI Files)である。 ファイルの拡張子は ~.MID であることが多いが、 ~.SMF であることもある。
SMFは基本的に 「この時間(タイミング)に、この音を強さ**でオンにする」 といったレベルの情報の集まりでしかなく、 「ここを2回繰り返す」とかいった「ちょっと高級な情報」は扱えない。 よって、SMFは曲データを作成しているときの保存フォーマットとして用いられることは少なく、 専ら曲データ完成後の配布用フォーマットとして用いられている。 実際、一般的なシーケンサソフトでは、 独自フォーマットとSMFのどちらでもデータを保存することができ、 前者は通常のデータ保存に、後者は(シーケンサソフト外にデータを渡す)エクスポート的な機能として用いているはず。
以下の表記について、その他
数値は、10進か16進かは特に区別せずルーズに記述している :-)。 ただし、 16進には prefixとして "0x"をつけていることがある。 (例: 0xFFなど。C言語での表記と同じ)
SMFにおいては、数値データはほぼすべてbig endianの即値で表される。 例えば 0x12345678 という4バイトの数値は、 0x12 0x34 0x56 0x78という順で格納される。
(唯一の例外はMIDIイベントの0xEnで、 これだけはlittle endianで格納される)
基本的に「(プログラム側で)理解できないコードは、無視する」 ことができるようなデータ構造になっているため、 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と呼ばれる。
フォーマット0
1本のトラックに全チャンネルの情報を押し込める形式。 トラックが1つしかないため、対応プレーヤの制作が容易。 またプレーヤ・シーケンサ間の互換性も保ち易くなるため、 市販のSMFデータは大抵がこの形式。
フォーマット1
同期演奏される複数のトラックで構成される。 大抵はシーケンサのいちトラックに対して SMFデータのいちトラックが対応するようになる。 つまり、一般的に「トラック」 と呼ばれるものが順番にバイナリ化されて concatenate (結合) されたフォーマットと考えればよい。 そのため、 トラック構成を保存しつつSMF化したい場合はこの形式が用いられる。 通常はこのフォーマット1を用いればよいと思う。
フォーマット2
複数トラックで構成される。パターン情報を保存し、 パターンを切り替えつつ演奏させるなんて場合に用いる。 フォーマット1がトラックを垂直に並べ、 それぞれを同期させて演奏させるフォーマットであるとするなら、 フォーマット2はパターン情報を水平に並べ、 順番に演奏させるようなものといえるだろう。
ただし筆者はフォーマット2に対応したシーケンサソフトを知らない。 通常フォーマット0か1だけを扱っていても特に問題となることはない (・・・と、思う)。
時間単位について (デルタタイムの意味の指定)
正数である場合 (MSB(第15bit目)が0の場合; こちらが一般的)
デルタタイムを、小節・拍等を基準として表現する。 この場合、このフィールドには4分音符あたりの分解能が入る。 例えば、全音符の分解能が1920だったなら、 ここに入るデータは 1920÷4 = 480 = 0x01E0 となる。
負数である場合 (MSB(第15bit目)が1の場合)
デルタタイムを、実時間のタイムコードで表現する。上位1バイトに「SMPTEフォーマットの負数」が、下位1バイトに「フレームあたりの分解能」が入る。
(以下は MIDI 1.0 規格書の4-4ページの内容を若干修正のうえ抜粋)
ビット15が1の場合、ファイル中のデルタ・タイムは、SMPTEやMIDIタイムコードと一致する方法で、秒の分数に相当する。 14から8までのビットは、4つの標準的なSMPTEとMIDIタイムコードのフォーマットに相応して、 -24, -25, -29, あるいは-30の4つの値のうちの一つ (-29は30ドロップ・フレームに相当) を含み、秒ごとのフレーム数を表す。 これらのマイナスの値は、2の補数形式でストアされる。 第2バイト(プラスでストアされる)は、フレーム内の分解能である。 典型的な値は4(MIDIタイムコード分解能), 8, 10, 80(ビット分解能), あるいは100であろう。 この方式は、タイムコード・ベースの正確な分解能を可能にするが、 25フレーム/秒でフレームごとの分解能を40に指定することによって、トラックをミリセカンド・ベースにすることも可能にする。 ファイル中のイベントが30フレーム・タイムコードのビット分解能でストアされている場合、 ここで指定する値は0xE250である。
トラックデータについて
実データ (本当はMTrkイベントと呼ぶ) においては、[デルタタイム] + [イベント] の組がトラック末尾まで続く。
そして、[イベント]には、以下の3種類がある。
[MIDIイベント] (ノートオンとか、ピッチベンドとか)
[SysExイベント] (いわゆるエクスクルーシブメッセージ)
[メタイベント] (テンポ指定とか、曲タイトルとか)
以下、それぞれの構成要素について記す。
デルタタイムとは
次に続くイベントまでの時間を表す時間情報のこと。 ヘッダーブロックで時間単位の項目を正数で指定した場合 (=デルタタイムを小節・拍等を基準として表現する場合)、 デルタタイムは(直前のイベントから)次に続くイベントまでの時間差を表す。 例えば全音符の分解能が480だった場合、デルタタイム120というのは 「四分音符分の時間(の後)」を意味する。同様に、 もしトラックの最初のイベントがトラックの先頭に発生する際のデルタタイムや、 2つのイベントが同時に発生するような場合(の2つ目のイベント)につくデルタタイムは、 0となる。
上記の実データの説明でも分かるように、 前のイベントと次のイベントの時間間隔を定義するために、 デルタタイムは常に必要である。
ちなみにヘッダーブロックで規定するように、 デルタタイムは拍子(に基づく時間情報)を意味するだけではなく、 SMPTEタイムと共にトラックをレコーディングする場合の"秒"の分数 (分解能) を意味することもあるが、後者の表現を用いることは稀であり、 無視して良いと思う。 (映画なんかでSEを挟む場合、こちらの表現を用いることがある、らしい)
可変長形式について
デルタタイムは、以下のような可変長形式で表される。
1byte(8bit)の内、数値に7bit、 次のバイトもデータバイトが続くかどうかのフラグに1bit用いる。 フラグにはMSB(第7bit)を用いる。
最大4バイト。つまり、実際に表現できる数値の最大値は228-1。 これだけあれば、通常の音楽に用いる時間表現には十分。 (デルタタイム 0FFFFFFF というのは、500BPM(拍/分)という速いテンポにおいて、 2 x 106個の96分音符は3日間分にあたり、デルタ・タイムとしては十分な長さである。)
以下具体例。左が数値(16進)で、右が可変長形式での表現(16進)。
00000000 → 00
00000040 → 40
0000007F → 7F
00000080 → 81 00
00002000 → C0 00
00003FFF → FF 7F
00004000 → 81 80 00
00100000 → C0 80 00
001FFFFF → FF FF 7F
00200000 → 81 80 80 00
08000000 → C0 80 80 00
0FFFFFFF → FF FF FF 7F
MIDIイベントとは
いわゆる演奏データのこと。 MIDIのチャンネルメッセージそのままと考えて差し支えない。
以下、具体例。
8n kk vv (3byte) または 9n kk 00
ノートオフ。チャンネル番号nで鳴っているノート番号kkの音を消音する。
9n kk vv (3byte; vvは0以外)
ノートオン。チャンネルnでノート番号kkの音をベロシティvvで発音する。 vvが0の場合は、ノートオフと同じ意味となる。
An kk vv (3byte)
ポリフォニックキープレッシャー。 チャンネルnで発音中のノート番号kkの音に対し、ベロシティvvの プレッシャー情報を与える。 (今押さえている鍵盤を、新たにベロシティvvで押さえ直す)
Bn cc vv (3byte) (特定条件下で、4byteになる時があるので注意。詳細後述)
コントロールチェンジ。 チャンネルnで、コントローラナンバーccに、値vvを送る。
Cn pp (2byte)
プログラムチェンジ。 チャンネルnで、プログラム(音色)をppに変更する。
Dn vv (2byte)
チャンネルプレッシャー。 チャンネルnに対し、プレッシャー情報vvを送信する。 (ポリフォニックキープレッシャーの、チャンネル内全音版)
En mm ll (3byte)
ピッチベンド。チャンネルnに対し、ピッチベンド値llmmを送信する。このイベントのデータに限り、さりげなくlittle endianなので注意。
ピッチベンド値llmmは、他のMIDイベントの2byte目以降と同様に、
llとmmはどちらも7bitの値を採る
正数のみ記載可能である
ため、例えばピッチベンドが-8192,0,8191に対応する値llmmはそれぞれ 0x0000, 0x4000, 0x7F7F となる。(ピッチベンド値に 8192のゲタを履かせた形になる)
これらチャンネルメッセージは、 厳密にはチャンネルモードメッセージとチャンネルボイスメッセージに分かれる。
チャンネルモードメッセージ
コントロールチェンジ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を用いた方が、 ノートオフの意味合いをより明示できるだろう。
SysExイベントとは
主にMIDIシステムエクスクルーシブメッセージを指定するのに用いられる。 SysExイベントには、F0で始まるものとF7で始まるものの2種類がある。
F0で始まる場合、
送信されるデータにはF0が含まれる (つまり、w, y, z が送信される)
データ長にはF0の分を含めない (つまり、y + z 分の長さが収まる)
データの最後は必ずF7で終了する
一般的には、エクスクルーシブメッセージを転送するのに用いる
例: F0 05 aa bb cc dd F7 (これで、F0 aa bb cc dd F7 が転送される)
F7で始まる場合、
送信されるデータにはF7が含まれない (y のみ送信される)
データ長にはF7の分を含めない (y の長さが収まる)
一般的には、任意のデータを転送するのに用いる
例: F7 04 aa bb cc dd (これで、aa bb cc dd が転送される)
いずれの場合も、データ長は可変長形式で格納される。 (従って、SysExイベントにはランニングステータスは適用できない。 データ長のMSB(第7bit)が可変長形式適用で1になっていると、 ランニングステータスとの区別が付かない)
F7で始まるSysExイベントは、リアルタイムバイトやソングポインター、 MIDIタイムコード、システムリセットなど、 通常の方法では送れないデータを直接送るための裏技として用いられるが、 シーケンサを変えた場合にこのデータがどう処理されるかは分からない等互換性維持の面で問題があるため、 通常はF0で始まるエクスクルーシブメッセージ送信のみを用いるのが無難である。
(実際、余程のことがない限りF0のみを使用していても問題とはならないはず)
メタイベントとは
メタイベントは、シーケンサやSMFに便利な、演奏データに含まれない情報 (テンポ、曲タイトル等)を納めるのに用いるイベント。 基本的に、ステータスバイトFFで始まり、 次にイベントタイプを表すバイトが続き、 さらに可変長形式で格納されたデータ長が続き、 最後にデータ自体が続く (SysExイベントのF7の場合と似ている)。
もしデータがなければデータ長は0となる。 SysExイベントと同様に、 ランニングステータスの適用はできない。 (データ構造上は適用できそうなものだが、仕様書で明確に適用不可と明記されている)
すべてのプログラムがすべてのメタイベントをサポートしなければならないということではない。
現在定義されているメタイベントは、具体的には以下のものがある。
FF 00 02 ssss : シーケンス番号
フォーマット2で、パターンを識別するために用いる。 通常フォーマット0,1では用いない。
FF 01 len text : テキスト
任意の長さ・内容のテキストを記述することができる。 ただし、 著作権表示、 シーケンス名/トラック名、 楽器名、 歌詞、 マーカー、 キューポイント、 プログラム名、 デバイス名 といった用途には、 専用のメタイベントタイプ(0x02~0x09)が別途用意されているのでそちらを用いるべき。
(余談: メタイベントタイプの 0x01~0x0Fは、 この手のテキストイベントのために予約されている)
例えば、トラックのいちばん初めに、意図する音源名やオーケストレイション、 その他ユーザがそこに置きたいと思う情報を書いておくと良い。
なお互換性のことを考えると、このイベント中のテキストは、 印刷可能なASCII文字を使用することが推奨されている。 (まあイマドキそんなことを気にする必要もないとは思いますが・・ 以下、 いちいち書きませんがテキスト関連のメタイベントすべてに同じことが当てはまります)
FF 02 len text : 著作権表示
曲に関する著作権表示を記述する。 この表示には (C)の文字、 著作物発行年と、著作権所有者名とが含まれなければならない。
このイベントは第1トラック (Conductor Track)の最初のイベントとして、 デルタタイム0で置かれなければならない。 また、ひとつのMIDIファイルに幾つかの楽曲がある時には、 すべての著作権表示をこのイベントに置いて、 かつそれがファイルの先頭に来るようにしなければならない。
FF 03 len text : シーケンス名(曲タイトル)・トラック名
以下の場合には、シーケンス名(つまり、曲のタイトル)となる。
フォーマット0のトラックに存在するとき
フォーマット1のファイルの、 第1トラック (Conductor Track)に存在するとき。
その他の場合には、トラック名となる。
FF 04 len text : 楽器名
そのトラックで用いられる楽器の種類を記述する。
FF 05 len text : 歌詞
歌詞。
一般的には、(歌詞の)各音節が別々の歌詞イベントとして記述され、 そのイベントが始まるタイミングでシーケンサ等が歌詞を表示することになる。
FF 06 len text : マーカー
リハーサル記号やセクション名のような、 シーケンスのその時点の名称を記述する。 ("Introduction" とか "A", "B" など)
このメタイベントを使用する場合、置き場所としては 通常フォーマット0のトラック、 もしくはフォーマット1のファイルの第1トラック (Conductor Track)となる。
(余談: 日本ファルコム社のYs2 EternalのMIDI曲では、 このメタイベントを 無限ループ用のマーカーとして用いているようです)
FF 07 len text : キューポイント
曲データ中、このメタイベントの挿入されている位置で、 その曲以外の進行を記述するのに用いる。 (曲中の進行の記述には、マーカーを用いる)
例えば「車が走り出す」「画面がフェードアウトする」など。
FF 08 len text : プログラム名 (音色名)
直後に続く「プログラムチェンジ」と 「バンクチェンジ」で表している音色名を記載する。 (非GM音源だと結構使いでがあるでしょ?)
このメタイベントはトラック中のどこにおいても構わないが、 プログラムチェンジやバンクセレクトと共に用いるべきである。
FF 09 len text : デバイス名 (音源名)
このメタイベントがあるトラックが、 どのデバイスに配置されるのかということをテキストで表すものだが、 大抵は音源の名前を入れることになるだろう。
(区別できれば結局どんなテキストでも構わないわけですが)
このメタイベントは、1トラックにつき1回だけ、 最初に音源にデータが送られる前に記述されるべき。
(データが送られた後で音源が決まるんじゃ、意味ないですしね)
ちなみにこのメタイベントは、 あくまで16ch以上のデータを想定して考案されたものなので、 「音源名」に拘らず「ポート番号」や、 もっと極端な話「FM」「WAVE」とか、そういったのもアリ。
FF 20 01 cc : MIDIチャンネルプリフィックス
FF 21 01 pp : 出力ポート指定 (現在のSMFでは未定義)
このメタイベントは現在のSMF Version 1.0では定義されていないが、 32ch対応のMIDI音源の台頭に伴い、 いわゆるデファクトスタンダードとして普及しているようだ。
利用法として、現状以下の3パターンが確認されているが、 どのパターンで作成されているかはデータだけでは識別不能。
pp=0~3が、それぞれポート1~4に対応している場合
pp=0がミュート、1~4がそれぞれポート1~4に対応している場合
pp=0がポート1、pp=1がポート2、pp=2がポート1&2両方、 pp=3がミュート
日本国内(のフリーソフトの類)では基本的に 1. のパターンを想定しておけば問題ないと思われる。
このイベントの効力は次に同イベントが出現するまで続く。 当然ながら初期状態(無指定時)ではポート1が選択されている。
(余談: SMF ver1.0 specに完全に沿った形で32chなデータを表現する (つまり、このメタイベントを用いない)場合、以下の方法が考えられる。
フォーマット2を使う
出力ポート毎に、個別のSMF(ファイル)を出力する
テキストイベント等 メタイベント FF 09 (デバイス名) で、トラック毎に 出力ポート 出力デバイス名 を明記しておく
ただし、1.~3.はいずれも演奏には当然「対応プレーヤ」が必要となる・・・
FF 2F 00 : トラック終端
そのトラックの終端を表す。
これがあることによって トラックの正しい終結点が明確になり、 トラックが正確な長さを持つようになる。 このイベントは仕様上省略不可となっているので注意。
(余談: 逆に、メタイベントに関しては、 このメタイベントと次に出てくるテンポのメタイベントさえ実装すれば、 極端な話それ以外(のメタイベント)は実装上無視しても、 演奏自体は正しいものとなる)
(蛇足: FF 2* 系は、基本的に「トラック全体に関わる設定項目」 を想定しているように思われます)
FF 51 03 tttttt : テンポ設定 (単位は μsec / MIDI 四分音符)
このイベントでテンポ変更を指示する。
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に追われる羽目となってしまいました(^^;)
FF 54 05 hr mn se fr ff : SMPTE オフセット
トラックデータの先頭にこのメタイベントをおくことで、 トラックデータの演奏開始時刻を指定することができる。 時間は、MIDIタイムコードと全く同様に、 SMPTEフォーマットでエンコードされなければならない。
FF 58 04 nn dd cc bb : 拍子記号
拍子記号は、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の場合。 (余程のことがない限り変更する必要はないと思いますが)
FF 59 02 sf mi : 調号
調号を指定する。
sfには、♯や♭の数が入る。正数なら♯の数、負数なら♭の数を表す。 ハ長調(つまり♯も♭もない)の場合は0。 (このあたりの詳細は、楽典などで確認のこと。)
miは長調か短調かを表すフラグで、0なら長調、1なら短調。
FF 7F len data : シーケンサー特定メタイベント
特定のシーケンサーのための特別な要求のためこのイベントタイプを用いる。 データバイトの最初の1バイトはメーカーIDである。 その後、独自フォーマットによるデータが続く。 このようなものであるため、 SMFデータの互換性を考えるならこの機能を使うことはないだろう。
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ページ以降に、より細かい実際のサンプルあり。
筆者がたどったはまり道
ランニングステータスは、 MIDIイベントのみに有効
後者の方は(FFの直後に来るのが00~7Fなので)ランニングステータスを適用できそうなものだが、 仕様書に適用不可と明記されている。 以下は MIDI 1.0 規格書の4-7ページより抜粋。
SysEx イベントとメタ・イベントは、その時点で有効になっているすべてのランニング・ステータスを無効にする。 ランニング・ステータスは、これらのメッセージには適用されないので、使用してはいけない。
SysExイベント(F0, F7)のデータ長は、 可変長形式で格納する
ただ、大抵この手のデータは127バイト以下なので、 ただの1バイトデータだと思いこんでいても何とかなってしまうことが多い。
曲中の テンポ情報(FF 51 03)は、 Conductor Track(最初のMTrk)にすべてまとめる
これをやっておかないと一部シーケンサ (MacのPerformer; バージョンは分からず)なんかで誤動作することがあるらしい。 以下は MIDI 1.0 規格書の4-5ページより抜粋。
フォーマット0のファイルでは、テンポはトラック中のいたるところにばらまかれており、 テンポ・マップ・リーダーは、その間にあるイベントを無視しなければならない。 フォーマット1では、テンポ・マップは第1トラックにストアされなければならない。
参考文献
Standard MIDI Files 0.06 March 1, 1988 の翻訳 (M&A NETの方々)
SMFリファレンス・ブック (リットーミュージック)
MIDI検定3級公式ガイドブック (AMEI/JSPA)
MIDI検定2級公式ガイドブック (AMEI/JSPA)
Recommended Practice (RP-019) SMF Device Name and Program Name Meta Events (MMA / AMEI)
E-mail: