MIDIを再生する

はじめに


市販ゲームでBGMにMIDIを使うというのは、最近ほとんど無いような気がしますが、個人で作るゲームでは十分使えると思います。MIDI再生にはDirectMusicを使うと簡単にBGMとして使えるのですが、どうもファイルによっては音色がきちんと設定されないようなのです。使い方の問題かもしれませんが…

ということで、低レベルAPIを使って自作することを最終目標として、まずは基本的なところからMIDIを学んでいこうと思います。

なお、MIDI再生に関してはAPIの使い方というよりもMIDIそのものの仕様を理解しておく必要があります。
参考リンク:
Direct Art Studio 「詳説MIDI規格」の中に詳しい説明があります。


初期化と後処理


初期化も後処理も決められた関数を呼ぶだけです。

初期化:

HMIDIOUT hMidi;
UINT uResult;

/* MIDI出力デバイスを開く */
uResult = midiOutOpen (&hMidi, MIDIMAPPER, NULL, 0, CALLBACK_NULL);
if (uResult != MMSYSERR_NOERROR) {
    /* エラー処理 */
}

後処理:

/* 音を止めてからMIDI出力デバイスを閉じる */
midiOutReset (hMidi);
midiOutClose (hMidi);

後処理は、まず音を止めてからデバイスを閉じています。midiOutLongMsgを使って送信された出力バッファが残っている場合はmidiOutCloseが失敗するらしいのですが、とりあえず無視しています。


音色を設定する


次は音色の設定です。16チャンネルあるうち、リズム専用の10以外のチャンネルにそれぞれ音色(楽器)を設定することができます。音色や音を出すにはmidiOutShortMsgを使ってMIDIデバイスにメッセージを通知すればOKです。

引数としてメッセージを指定するのですが、いろんなところで紹介されている便利マクロがあるので書いておきます。

MIDIMSG(msg,channel,data1,data2) (DWORD)((msg<<4) | channel | (data1<<8) | (data2<<16))

メッセージID(4ビット)、チャンネル番号(4ビット)、データ1(1バイト)、データ2(1バイト)の順番で指定すれば、引数に必要なDWORD値を出してくれます。最初の1バイトは未使用のようなので、メッセージ部分は3バイトということになります。

例として、チャンネル2にピアノ(音色番号0)を指定するには次のようになります。

midiOutShortMsg (hMidi, MIDIMSG (0xC, 1, 0, 0));


「0xC」が音色設定のメッセージID、「1」がチャンネル番号、「0」が音色番号、最後の「0」はダミーです。