システムエクスクルーシブメッセージ

システムエクスクルーシブメッセージは、MIDI デバイスを制御するための可変長のメッセージです。このメッセージはMIDIデバイスを開発しているメーカーが独自に定めることができ、基本的に標準化はされていないため、MIDIデバイスが認識でるシステムエクスクルーシブメッセージは、その説明書などを読むしかありません。しかし、ユニバーサルシステムエクスクルーシブメッセージと呼ばれる、メーカーの異なるMIDIデバイスでも共通して使えるメッセージも存在します。

システムエクスクルーシブメッセージの先頭バイトは必ず0xF0で始まり、末尾は0xF7で終了します。よって0xF0から0xF7までの間が、可変長なシステムエクスクルーシブメッセージのデータとなります。0xF0の直後には、MIDIデバイスのメーカーIDを指定します。メーカーIDは社団法人音楽電子事業協会によって発行・管理されている値で、ローランドの 0x41 番やヤマハの 0x43 番などが有名です。詳細は、このページに掲載されています。

MIDIデバイスは、着信したシステムエクスクルーシブメッセージのメーカーIDを調べ、メーカー番号が異なっている場合は無視できます。ただし、ユニバーサルシステムエクスクルーシブメッセージの場合はメーカーに関係なく共通なので、このメッセージのための特別なIDとして0x7D~0x7Fまでが割り当てられています。0x7Dは研究用など非営利目的のID、0x7Eはノンリアルタイムと呼ばれる種類のメッセージ、0x7Fはリアルタイムと呼ばれるメッセージのためのIDです。

メーカーID以降は、メーカー独自に定めた音源制御用のデータが続きます。本稿では特定のMIDIデバイスに依存したメッセージの解説は避けますが、ユニバーサルシステムエクスクルーシブメッセージで定められているマスターボリュームの変更を行うシステムエクスクルーシブメッセージを作成してみたいと思います。このメッセージは、常に以下のようなデータ配列になります。

F0, 7F, 7F, 04, 01, 00, 音量, F7

音量には0~127までの範囲でマスターボリュームの音量を表す値を指定します。0は完全な消音を表し127が最大音量となります。もちろん、MIDIデバイスがユニバーサルシステムエクスクルーシブメッセージに対応していなければ意味はありません。Microsoft GS Wavetable SW Synthの場合、メッセージを認識することはできますが、再生中の音に対しては効果がなく、マスターボシュームの変更後のノートオンで反映されます。

これまで、チャネルメッセージは全てShortMessageクラスのオブジェクトで表現しましたが、システムエクスクルーシブメッセージを送信するにはjavax.sound.midi.SysexMessageクラスを用います。

javax.sound.midi.SysexMessage クラス

public class SysexMessage extends MidiMessage

SysexMessageクラスは、可変長のシステムエクスクルーシブメッセージを表します。公開されているこのクスのコンストラクタは、パラメータを受け取りません。

SysexMessage() クラスのコンストラクタ

public SysexMessage()

生成したSysexMessageオブジェクトにシステムエクスクルーシブメッセージのデータを設定するにはsetMessage()メソッドを使います。

SysexMessage()クラス setMessage() メソッド

public void setMessage(byte[] data, int length)
            throws InvalidMidiDataException

このクラスのsetMessage()メソッドは、任意のサイズの配列を設定できます。このメソッドのdataパラメータに指定するバイト配列には、ステータスバイトを表す値0xF0を含めます。ステータスバイトが不正な場合は例外が発生するので注意してください。lengthにはdataに指定したバイト配列の有効なメッセージの長さを指定します。このオブジェクトに設定するバイト配列が全てのデータを格納している場合、バイト配列の末尾はシステムエクスクルーシブメッセージの終端を表す0xF7にします。

もし、すべてのデータがSysexMessageオブジェクトに含められない場合、複数のSysexMessageに分割して送信する仕組みも提供されています。この場合、SysexMessageオブジェクトのステータスバイトに0xF7を指定し、その後に追加のデータを指定します。追加送信する SysexMessageオブジェクトのステータスバイト0xF7は、MIDIデバイスには送信されません。

サンプル06では、2つのチャンネルを使ってバイオリンとアルトサックスの音を繰り返し文の中で定期的に再生させています。繰り返し処理の中では、異なるチャンネルに同じベロシティでノートオンを送信しています。ベロシティ自体に変更はありませんが、ノートオンを送信する直前に、システム全体のマスターボリュームを調整するシステムエクスクルーシブメッセージを送信し、全体の音量を下げているため、チャンネルに関係なく全体の音量が下がり続けます。

サンプル 06(システム全体のマスターボリュームを調整するシステムエクスクルーシブメッセージを送信)

import java.io.*;
import javax.sound.midi.*;

class Test {
    public static void main(String[] args) throws Exception {
        Receiver receiver = MidiSystem.getReceiver();
        ShortMessage chMsg = new ShortMessage();
        SysexMessage sysMsg = new SysexMessage();

        chMsg.setMessage(ShortMessage.PROGRAM_CHANGE, 41, 0);
        receiver.send(chMsg, -1);
        chMsg.setMessage(ShortMessage.PROGRAM_CHANGE | 1, 66, 0);
        receiver.send(chMsg, -1);

        for(byte i = 127 ; i >= 0 ;i -= 10) {
            byte[] data = new byte[] { (byte)0xF0, 0x7F, 0x7F, 4, 1, 0, i, (byte)0xF7 };
            sysMsg.setMessage(data, data.length);
            receiver.send(sysMsg, -1);

            chMsg.setMessage(ShortMessage.NOTE_ON, 60, 127);
            receiver.send(chMsg, -1);
            chMsg.setMessage(ShortMessage.NOTE_ON | 1, 67, 127);
            receiver.send(chMsg, -1);

            Thread.sleep(800);
        }

        System.out.println("Enter キーを押してプログラムを終了します>");
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        reader.readLine();
    }
}