Programming Field

MIDIファイル構文(Syntax)

このページでは、MIDIファイル(Standard MIDI Format ファイル)の構文・構成について記述しています。

※ 現在工事中です。

目次

  1. まえがき・注意点
  2. 可変長数値表現
  3. MIDIファイルのヘッダー
  4. MIDIトラック
  5. 複数のMIDIトラック(Format 1以降)
  6. MIDIメタイベント

まえがき・注意点

MIDIファイルの構造体(struct または Type)のなかでは、数値はすべて「ビッグエンディアン」と呼ばれる方法で処理されます。これは、それぞれの数値データをバイトに分けたときに読み取られる数値の順番がWindowsなどと逆であり、例えば従来16進数でDWORD(Long)値「0x12345678」(&H12345678)となるものが「0x78563412」となったり、WORD(Integer)値「0x0012」が「0x1200」となったりします。

※ コード例に使用されるメンバや変数の名称は適当です。

また、MIDIトラックの説明の項から先では、以下のようにバイトデータの並びを表現することがあります。

FF 03 03 41 42 43

この例では、6バイトのデータ(配列)で先頭から「0xFF (&HFF)」「0x03」「0x03」「0x41」「0x42」「0x43」という値になっていることを表します。

[VB] MIDIファイルを読み込むには、ファイルをバイナリモードで開き、GetステートメントやInputB関数のようにバイナリをサポートするものを利用する必要があります。

[VB.NET] 以降で記述されている構造体に(ファイルから)データを読み込む場合、Microsoft.VisualBasic.FileSystem.FileGetメソッドなどを使うことができますが、.NET固有のクラスやメソッドを使って構造体に直接読み込む方法は存在しません。代わりにSystem.IO.BinaryReaderクラスなどを使い、バイト単位でデータを読み込んでください。

可変長数値表現

可変長数値表現はMIDIファイル内で利用される数値の表し方で、MIDIファイルにおいては0から268435455(0x0FFFFFFF)までの数値を、その数値に見合った1バイトから4バイトまでのバイト列で表現します。通常の(符号なし)32ビット値(0~4294967295)は必ず4バイトで表現されますが、この表現方法を使うと小さい数値(127まで)は1バイトで表現できるため、全体のファイルサイズを小さくすることができます。

MIDIファイルにおける可変長数値表現は以下のルールを採用しています。

0から127(0x7F)まで
1バイトで表現し、値をそのままバイトデータとして使用します。(「00」~「7F」)
128(0x80)から16383(0x3FFF)まで
2バイトで表現し、「81 00」から「FF 7F」までのデータを使用します。128=「81 00」、129=「81 01」、…、255=「81 7F」、256=「82 00」、…と続きます。
16384(0x4000)から2097151(0x1FFFFF)まで
3バイトで表現し、「81 80 00」から「FF FF 7F」までのデータを使用します。16384=「81 80 00」、16385=「81 80 01」、…、16511=「81 80 7F」、16512=「81 81 00」、…と続きます。
2097152(0x200000)から268435455(0xFFFFFFF)まで
4バイトで表現し、「81 80 80 00」から「FF FF FF 7F」までのデータを使用します。

※ この表現方法を使えば5バイト以上のデータも作ることは可能ですが、MIDIファイルではそれ以上の値は利用されず、記述すると異常な動作をする可能性があります。

MIDIファイルのヘッダー

MIDIファイルのヘッダーは14バイトのデータで構成されます。その定義は以下の通りです。

[C/C++][VB][VB.NET]
typedef struct {
    char signature[4];
    DWORD dwHeaderSize;
    WORD wFormat;
    WORD wNumTracks;
    WORD wDivision;
} MTHD_CHUNK;
Type MTHD_CHUNK
    signature(0 To 3) As Byte
    dwHeaderSize As Long
    wFormat As Integer
    wNumTracks As Integer
    wDivision As Integer
End Type
Structure MTHD_CHUNK
    signature(0 To 3) As Byte
    dwHeaderSize As Integer
    wFormat As Short
    wNumTracks As Short
    wDivision As Short
End Structure
メンバ名 説明
signature MIDIファイルを示す4文字の識別記号で、「MThd」となります。
[VB, VB.NET] この配列の 0 から順に一文字ずつ Asc("M"), Asc("T"), Asc("h"), Asc("d") と代入してください。(~ As String * 4 ではうまくいかない可能性が。)
dwHeaderSize 識別記号とこのサイズ部分を除いたヘッダーのサイズを表す数値で、この場合は6になります。
wFormat MIDIファイルのフォーマット形式(バージョン)を表す数値で、今は多くで1(Format 1)が利用されています。(0(Format 0)2(Format 2)もあります。その他の数値は無効です。)
wNumTracks MIDIファイルの中にトラックがいくつあるかを表します。このトラックには、テンポ命令などのみで音符が書かれていない「テンポ トラック」も含まれます。
wDivision 演奏時間に使われる「デルタ時間」について、1デルタ時間が何ミリ秒かを表す数値です。

MIDIトラック

MIDIトラックは以下のヘッダーから始まるもので、実際の曲データが入る位置になります。

トラックのヘッダー定義は以下のとおりです。

[C/C++][VB][VB.NET]
typedef struct {
    char signature[4];
    DWORD dwDataSize;
} MTRK_CHUNK;
Type MTRK_CHUNK
    signature(0 To 3) As Byte
    dwDataSize As Long
End Type
Structure MTRK_CHUNK
    signature(0 To 3) As Byte
    dwDataSize As Integer
End Structure
メンバ名 説明
signature MIDI ファイルを示す4文字の識別記号で、「MTrk」となります。
[VB, VB.NET] この配列の 0 から順に一文字ずつ Asc("M"), Asc("T"), Asc("r"), Asc("k") と代入してください。(~ As String * 4 ではうまくいかない可能性が。)
dwDataSize 識別記号とこのサイズ部分(合計するとヘッダーのサイズ)を除いたデータのサイズを表す数値で、この値は曲データの量によります。ただし、最も短くても「4」になります。

ヘッダーのあとには、決まった形式でさまざまなデータが続きます。

(ヘッダー直後)<delta-time><data><delta-time><data>
...
(最後の位置)<delta-time> FF 2F 00
delta-time
データとデータの間に置く、演奏を休む時間(デルタ時間)です。0を指定すると休まないことを示します。0以外の値を指定する場合、可変長数値表現を使って指定します。
data
命令や音符などの1つのデータです。和音など、複数のデータを指定する場合も、必ず間にデルタ時間を置かなければなりません。
FF 2F 00
トラックの末尾であることを示す命令(16進数、上の表記は順に1バイト目から FF、2F、00 という意味)です。
※ヘッダーにおけるトラックのサイズが「最も短くても4」なのは、デルタ時間とこのデータが最低限必要であり、その合計サイズが4となるためです。

複数のMIDIトラック(Format 1以降)

MIDIファイルには複数のトラックを含めることができ、ファイル再生時はすべてのトラックのデータを同時に演奏します。

各トラックには様々なデータを含めることができ、トラックの順序や位置によって含めることのできるデータに制限はありません。具体的には、2番目のトラックにMIDIチャンネル4や5の演奏情報を含めることもできます。

ただし多くのアプリケーションにおいて、各トラックは以下の規則に従ってデータを記述しており、この規則に従っていないデータが存在する場合正しく読み込み・演奏ができない場合があります。

  1. 1番目のトラック(ファイル内で最初に現れるトラック)はメタイベントSysExメッセージのみを含む
  2. 2番目以降のトラックでもメタイベントを含むことができるが、「タイトル」情報がそのトラックの名前を表すなど、元の意味と異なるか意味を為さないメタイベントも存在する
  3. 1つのトラック内では原則1つのMIDIチャンネルに対するメッセージしか記述しない

MIDIメタイベント

MIDIトラックの中には「メタイベント」と呼ばれる、楽曲の情報や楽曲全体の演奏に影響するデータを含めることができます。

メタイベントは、共通して以下の形式を採ります。

FF <event> <length> ...

ここで、<event>には1バイトのイベント番号(0~127)、<length>にはこの後に続くデータの長さを可変長数値表現で表したデータが入ります。

以下は、メタイベントで利用することができるイベントの種類です。なお、イベントごとに<event>の番号が定められており、イベントによっては<length>が決まっている場合があるため、以下の定義では「FF」を含めたバイト列を記述しています。

シーケンス番号 (00)

FF 00 02 ss ss
FF 00 00

トラックのシーケンス番号を指定します。番号を指定する場合は1つ目の構文を利用し、16ビット(2バイト)の数値を ss ss として2バイトで記述します。2つ目の構文を利用するとトラックの位置を番号として利用します(ファイルデータ上で1番目のトラックなら0、2番目のトラックなら1、…となります)。

テキスト (01)

FF 01 <length> <text-data>

任意のテキスト情報を記述します。長さは可変長であり、<length>可変長数値表現で表されたテキストの長さ(NULL文字を除く)を指定します。また、<text-data>にはASCII文字コードで表されたテキストを指定します(日本語を使う場合はShift JISがよく用いられますが、実際には文字コードに関する規則はありません)。このテキスト情報はいわゆる「コメント」であり、作曲者や楽器名などいろいろな内容が記述されることがあります。なお、名前歌詞など特定の意味を持つテキストイベントも存在するため、記述したい内容がそれらに当てはまる場合はそちらのイベントを優先してください。

FF 02 <length> <text-data>

ファイルの著作権情報を記述します。指定方法はテキストと同じです。

シーケンス名/トラック名 (03)

FF 03 <length> <text-data>

ファイルのシーケンス名やタイトル、または各トラックの名前を指定します。指定方法はテキストと同じです。通常、最初のトラックに存在する場合は曲のタイトルを、それ以外のトラックに存在する場合はトラックの名前を示しています。

(以下工事中…)

SysExメッセージ

(工事中…)