MIDIには音の長さを表すパラメータが存在しないため、ノートオンを送信するとプログラムが終了するまで再生され続けます。ピアノのような打鍵楽器であれば自然に消音しますが、弦楽器や管楽器であれば音が鳴り続けることになります。ノートオンは、ピアノの鍵盤を押したということを意味するメッセージなので、音源はノートオンによって鍵盤が叩かれたと認識します。当然、鍵盤から指を離さない限り音が持続することになります。

サンプル03は、ノートナンバー60の音Cから半音ずつ上げてオクターブ上のCまで200ミリ秒の間隔でノートオンを送信するプログラムです。直前に送信したメッセージによって再生された音が残っている状態で次の半音上の音が再生されるため、不協和音となって聞こえるでしょう。

サンプル03(再生された音が残っている状態で次の半音上の音を再生)

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

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

        for(int i = 60 ; i <= 72 ; i++) {
            message.setMessage(ShortMessage.NOTE_ON, i, 127);
            receiver.send(message, -1);
            Thread.sleep(200);
        }

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

ノートオフで消音

音を消すには鍵盤から指を放したという意味を持つノートオフを使います。ノートオフは、ステータスバイト0x80から始まるチャンネルメッセージで、構造はノートオンと同じです。第1データバイトには消音するノートナンバーを、第2データバイトには消音の強さを表すベロシティを指定します。ただし、第2データバイトは性質的に使われることはありません。ノートオフのステータスバイトはShortMessageクラスのNOTE_OFFフィールドでも宣言されています。

ShortMessage クラス `NOTE_OFF` フィールド

public static final int NOTE_OFF

ノートオフが音源に送られると、音源は指定されたチャンネルの再生中のノートナンバーの音を消します。ノートオンで再生している音を消すときにこのメッセージを送信してください。

サンプル04は、ノートオンを送信した後200ミリ秒プログラムを停止させ、次の音を再生する前にノートオフで直前にノートオンで再生した音を消しています。そのため、サンプル03のような不協和音にはなりません。ノートオフの他に、ノートオンをベロシティ0で送信しても同じ効果が得られます。

サンプル04(新しい音を再生する前に、ノートオフで消音)

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

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

        for(int i = 60 ; i <= 72 ; i++) {
            message.setMessage(ShortMessage.NOTE_ON, i, 127);
            receiver.send(message, -1);
            Thread.sleep(200);
            message.setMessage(ShortMessage.NOTE_OFF, i, 127);
            receiver.send(message, -1);
        }

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