ShortMessageについて少し説明してから実装をします。以下で16進数は頭に0xをつけて表現してあります。
ノートオンに必要な二つのデータ
ShortMessageには二つのデータバイトを指定します。一つ目はノート番号で二つ目はベロシティです。
ノート番号
MIDIのノート番号は以下のようになっています。
- 値の範囲は0-127(0x00-0x8F)
- 一番真ん中のドが60(0x3C)
- オクターブ上になると12を足す
- オクターブ下になると12を引く
ベロシティ
「音の速さ」という意味です。鍵盤を叩くときの強さに相当していてこの値が高いほど大きく音色も明るい音になります。一般にシンセサイザーでは音の大きさだけでなく音色にも関係する概念なので「音量」とは区別して考えます。
ノートオフについて
ノートオフはノートオンと同じようにノート番号が最初のデータバイトに指定する必要がありますがベロシティはあまり重要でありません。ほとんどのシンセサイザーの実装では無視されることが多いからです。またノートオンでベロシティを0にするとノートオフと同じ動作をするためノートオフにはふた通りの実装が存在することになります。
実装
まず一つの音を演奏するメソッドを作ります。Receiverのsendメソッドで演奏情報に送信するときの二つ目の引数-1は「すぐに処理する」意味になります。スレッドにたいして指定のミリ秒処理を待たせその後にノートオフの処理を行います。このとき同じチャンネルの同じノート番号にしないと音が終了しないで鳴りっぱなしになるので注意が必要です。ノートオフの二つ目のデータは使われないので0にしてあります。
public static void playNote(Receiver receiver, int channel, int note, int velocity, int ms) throws InvalidMidiDataException, InterruptedException { ShortMessage sm1 = new ShortMessage(ShortMessage.NOTE_ON, channel, note, velocity); receiver.send(sm1, -1); Thread.sleep(ms); ShortMessage sm2 = new ShortMessage(ShortMessage.NOTE_OFF, channel, note, 0); receiver.send(sm2, -1); }
ノートオフは以下のようにしても同じです。この場合ベロシティが0のノートオンという扱いになります。
ShortMessage sm2 = new ShortMessage(ShortMessage.NOTE_ON, channel, note, 0);
ではこのメソッドを呼び出す処理を書きます。mainメソッドに書きます。
デフォルトのシンセサイザーよ呼び出して回線を開きます。
Synthesizer synthesizer = MidiSystem.getSynthesizer(); synthesizer.open();
チャンネル0の真ん中のドを1000ミリ秒、つまり1秒鳴らすようにします。
playNote(synthesizer.getReceiver(), 0, 60, 127, 1000);
この後シンセサイザーを閉じます。
synthesizer.close();
これを実行するとドの音が1秒なるはずです。ここでは音色や音量の指定をしていません。他の細かい設定は今後他のコマンドを使って行うことになります。
ソース
最後にソースを載せておきます。
/* * mocha-java.com */ package mocha.sound.midi; import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.MidiSystem; import javax.sound.midi.MidiUnavailableException; import javax.sound.midi.Receiver; import javax.sound.midi.ShortMessage; import javax.sound.midi.Synthesizer; /** * * @author minaberger */ public class MidiUtil { public static void playNote(Receiver receiver, int channel, int note, int velocity, int ms) throws InvalidMidiDataException, InterruptedException { ShortMessage sm1 = new ShortMessage(ShortMessage.NOTE_ON, channel, note, velocity); receiver.send(sm1, -1); Thread.sleep(ms); ShortMessage sm2 = new ShortMessage(ShortMessage.NOTE_OFF, channel, note, 0); receiver.send(sm2, -1); } public static void main(String[] args) throws MidiUnavailableException, InvalidMidiDataException, InterruptedException { Synthesizer synthesizer = MidiSystem.getSynthesizer(); synthesizer.open(); playNote(synthesizer.getReceiver(), 0, 60, 127, 1000); synthesizer.close(); } }