さてさて、クロスプラットフォームな開発言語であるJavaでMIDIの音声をパソコンのスピーカーから
出力させるプログラミングに挑戦してみました。

まずは一番簡単なものから行きましょう。

今回はUSBのMIDIキーボードのなどのUSBデバイスは使用せずに、プログラミング言語だけで、
OS側の音声出力からドレミファソラシドを出すということをやってみました。

以下の部分が、ドレミファソラシドを担う部分です。

音声データの作成

引数は以下となっております。
(Receiver receiver, int channel, int note, int velocity, int ms)

レシーバはおまじない、チャンネル 0 、鍵盤のキーのアサイン情報が72〜84となります。
ベロシティ、時間(ミリセカンドms)となります。1000msで1秒です。


	Synthesizer synthesizer = MidiSystem.getSynthesizer();
	synthesizer.open();
	playNote(synthesizer.getReceiver(), 0, 72, 127, 100);  // ド
	playNote(synthesizer.getReceiver(), 0, 74, 127, 100);  // レ
	playNote(synthesizer.getReceiver(), 0, 76, 127, 100);  // ミ
	playNote(synthesizer.getReceiver(), 0, 77, 127, 100);  // ファ
	playNote(synthesizer.getReceiver(), 0, 79, 127, 100);  // ソ
	playNote(synthesizer.getReceiver(), 0, 81, 127, 300);  // ラ
	playNote(synthesizer.getReceiver(), 0, 83, 127, 500);  // シ
	playNote(synthesizer.getReceiver(), 0, 84, 127, 800);  // ド
	synthesizer.close();
    }

音声データの出力

以下がPlayNoteの関数で上の音声パラメータを元に音声に変換してを出力します。

上記のPlayNoteから4つの引数(channel、note、velocity、ms)を受領して音声を再生します。


    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);
   }

ソースコード全体は以下

あちこち前回の使い回しのコードも含まれています。


//
import javax.sound.midi.*;
import java.util.*;
//
class MidiKeyBoardChk{
//* Midi Detect
    private final static boolean EMULATE_NO_MIDI_IN = false;
    private static MidiDevice.Info[] createInputMidiDeviceInfo()
            throws MidiUnavailableException {
        ArrayList list = new ArrayList();

        MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
        for (int i = 0; i < infos.length; i++) {
            // throws MidiUnavailableException
            MidiDevice device = MidiSystem.getMidiDevice(infos[i]);
            if (device.getMaxTransmitters() != 0
                    && !(device instanceof Synthesizer)
                    && !(device instanceof Sequencer)
                    && !EMULATE_NO_MIDI_IN)
                list.add(infos[i]);
        }
        return (MidiDevice.Info[]) list.toArray(new MidiDevice.Info[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);
   }
//
    public static void main(String[] args) throws MidiUnavailableException, InvalidMidiDataException, InterruptedException{
//* Main
	String osname = System.getProperty("os.name");
	String osver = System.getProperty("os.version");
	String osarch = System.getProperty("os.arch");
	System.out.println(">>> " + osname + " " + osver +"("+ osarch +") <<<");
//
        MidiDevice.Info[] info=MidiSystem.getMidiDeviceInfo();
        for(int i = 0 ; i < info.length; i++){
                System.out.println(
		"[" + i +"] "+ 
		info[i].getVendor() + " <" + 
		info[i].getDescription()+"("+
		info[i].getName() + ")>"
		);
        }
//
	Synthesizer synthesizer = MidiSystem.getSynthesizer();
	synthesizer.open();
	playNote(synthesizer.getReceiver(), 0, 72, 127, 100); 
	playNote(synthesizer.getReceiver(), 0, 74, 127, 100);
	playNote(synthesizer.getReceiver(), 0, 76, 127, 100);
	playNote(synthesizer.getReceiver(), 0, 77, 127, 100);
	playNote(synthesizer.getReceiver(), 0, 79, 127, 100);
	playNote(synthesizer.getReceiver(), 0, 81, 127, 300);
	playNote(synthesizer.getReceiver(), 0, 83, 127, 500);
	playNote(synthesizer.getReceiver(), 0, 84, 127, 800);
	synthesizer.close();
    }
}

上記を保存して、実行するとドレミファソラシドの音声が出力されます。

「MidiKeyBoardChk.java」とファイル名で保存し、以下で実行となります。

$ java MidiKeyBoardChk.java

今回も以下の警告が出ますが、無視で大丈夫です。

ノート:MidiKeyBoardChk.javaの操作は、未チェックまたは安全ではありません。 
ノート:詳細は、-Xlint:uncheckedオプションを指定して再コンパイルしてください。