TickTimerを用いて演奏中の曲の再生時刻を所得する。
MidiInputModuleはTickTimerを指定することでキーが送信された時点でのTickTimeを得ることが出来る。ここでは、SMFを再生し、その再生時刻を返すSMFPlayerを用いる。
SMFPlayerは指定したSMFファイルを再生するクラスで、TickTimerを実装している。
// SMFPlayer SMFPlayer smf = new SMFPlayer(); smf.readSMF("kaeru.mid");
readSMFには再生するSMFのファイル名を指定する。
MidiInputModuleはTickTimerを指定する事で送信オブジェクト(MidiEventWithTickTime)にTickTimeを付加する。
// SPモジュール MidiInputModule mi = new MidiInputModule(vk); mi.setTickTimer(smf);
前回作ったPrintModuleの、表示するメッセージをノートナンバーからTickTimeに変更する。
public void execute(Object[] src, TimeSeriesCompatible[] dest) throws InterruptedException { MidiEventWithTicktime e = (MidiEventWithTicktime)src[0]; if((e.getMessage().getStatus() & 0xf0) == ShortMessage.NOTE_ON) System.out.println(e.music_position); dest[0].add(e); }
表示前の条件分岐でNoteOnメッセージかどうかを判定している。これを実行するとSMFの再生が始まり、キーを押すたびにSMFの再生中の時刻が表示される。
smf.play(); sp.start();
import javax.sound.midi.MidiSystem; import jp.crestmuse.cmx.amusaj.sp.MidiInputModule; import jp.crestmuse.cmx.amusaj.sp.MidiOutputModule; import jp.crestmuse.cmx.amusaj.sp.SPExecutor; import jp.crestmuse.cmx.sound.SMFPlayer; import jp.crestmuse.cmx.sound.VirtualKeyboard; public class CmxTutorial3 { public static void main(String[] args) { try { // 仮想キーボード VirtualKeyboard vk = new VirtualKeyboard(); vk.setVisible(true); // SMFPlayer SMFPlayer smf = new SMFPlayer(); smf.readSMF("kaeru.mid"); // SPモジュール MidiInputModule mi = new MidiInputModule(vk); mi.setTickTimer(smf); PrintModule2 pm = new PrintModule2(); MidiOutputModule mo = new MidiOutputModule(MidiSystem.getReceiver()); // SPExecutor SPExecutor sp = new SPExecutor(null, 1); // SPExecutorにモジュールを登録する sp.addSPModule(mi); sp.addSPModule(pm); sp.addSPModule(mo); // モジュールを繋ぐ sp.connect(mi, 0, pm, 0); sp.connect(pm, 0, mo, 0); smf.play(); sp.start(); // 終了 System.in.read(); sp.stop(); smf.close(); } catch (Exception e) { e.printStackTrace(); } System.exit(0); } }
import javax.sound.midi.ShortMessage; import jp.crestmuse.cmx.amusaj.filewrappers.TimeSeriesCompatible; import jp.crestmuse.cmx.amusaj.sp.MidiEventWithTicktime; import jp.crestmuse.cmx.amusaj.sp.SPModule; public class PrintModule2 extends SPModule { public void execute(Object[] src, TimeSeriesCompatible[] dest) throws InterruptedException { MidiEventWithTicktime e = (MidiEventWithTicktime)src[0]; if((e.getMessage().getStatus() & 0xf0) == ShortMessage.NOTE_ON) System.out.println(e.music_position); dest[0].add(e); } public Class[] getInputClasses() { return new Class[]{MidiEventWithTicktime.class}; } public Class[] getOutputClasses() { return new Class[]{MidiEventWithTicktime.class}; } }