独自のSPモジュールを実装する手順を解説する。
SPフレームワークは処理に使用するモジュールを独自に作成して拡張する事が出来る。
ここでは、流れたきたデータを標準出力に表示するモジュールを作る。
独自のSPモジュールを作成するにはまず、SPModuleクラスを継承する
import java.util.List; import jp.crestmuse.cmx.amusaj.filewrappers.TimeSeriesCompatible; import jp.crestmuse.cmx.amusaj.sp.MidiEventWithTicktime; import jp.crestmuse.cmx.amusaj.sp.SPModule; import jp.crestmuse.cmx.misc.QueueReader; public class PrintModule extends SPModule {
SPModuleは二つの型パラメータを要求し、それぞれSPElementインターフェースを実装した入出力されるデータのクラスを指定する。ここではMidiInputModuleとMidiOutputModuleで使用しているMIDIEventWithTickTimeを指定する。(型パラメータは使用しない仕様に変更されました.)
SPModuleクラスを継承したクラスは3つのメソッドを実装する。getInputChannelsとgetOutputChannelsはそれぞれ入出力のチャンネル数を返す。(型パラメータを廃止した代わりに,入出力チャンネルでのやりとりで仕様されるクラス名をここで指定することになりました.)
public Class[] getInputClasses() { return new Class[]{MidiEventWithTicktime.class}; } public Class[] getOutputClasses() { return new Class[]{MidiEventWithTicktime.class}; }
executeメソッドをオーバーライドする事でモジュールの処理を拡張する。
public void execute(Object[] src, TimeSeriesCompatible[] dest) throws InterruptedException { MidiEventWithTicktime e = (MidiEventWithTicktime)src[0]; System.out.println(e.getMessage().getMessage()[1]); dest[0].add(e); }
executeメソッドは入力されるオブジェクト(QueueReader)と出力されるオブジェクト(TimeSeriesCompatible)を引数として受け取り、それぞれチャンネルごとにListで保持している。(第1引数srcにはQueueReaderからtakeした値が渡される仕様に変更されました.また,Listから配列に変更されました.)
ここではどちらもチャンネル数が1なので先頭の要素を所得し、takeで取り出したオブジェクトを標準出力に表示した後addで出力オブジェクトに追加している。
前回と同様の手順でSPExecutorに組み込む。
... // SPモジュール MidiInputModule mi = new MidiInputModule(vk); PrintModule pm = new PrintModule(); 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); ...
キーボードを押すとそのノートナンバーが出力され、音が鳴る。
import jp.crestmuse.cmx.amusaj.filewrappers.TimeSeriesCompatible; import jp.crestmuse.cmx.amusaj.sp.MidiEventWithTicktime; import jp.crestmuse.cmx.amusaj.sp.SPModule; public class PrintModule extends SPModule { public void execute(Object[] src, TimeSeriesCompatible[] dest) throws InterruptedException { MidiEventWithTicktime e = (MidiEventWithTicktime)src[0]; System.out.println(e.getMessage().getMessage()[1]); dest[0].add(e); } public Class[] getInputClasses() { return new Class[]{MidiEventWithTicktime.class}; } public Class[] getOutputClasses() { return new Class[]{MidiEventWithTicktime.class}; } }
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.VirtualKeyboard; public class CmxTutorial2 { public static void main(String[] args) { try { // 仮想キーボード VirtualKeyboard vk = new VirtualKeyboard(); vk.setVisible(true); // SPモジュール MidiInputModule mi = new MidiInputModule(vk); PrintModule pm = new PrintModule(); 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); sp.start(); // 終了 System.in.read(); sp.stop(); } catch (Exception e) { e.printStackTrace(); } System.exit(0); } }