CMXチュートリアル

SPモジュールの拡張

独自のSPモジュールを実装する手順を解説する。

  1. SPModuleを継承したクラスを作る
  2. チャンネル数を設定する
  3. モジュールの振る舞いを実装する
  4. SPExecutorに組み込む

SPフレームワークは処理に使用するモジュールを独自に作成して拡張する事が出来る。

ここでは、流れたきたデータを標準出力に表示するモジュールを作る。

SPModuleを継承したクラスを作る

独自の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に組み込む

前回と同様の手順で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);

      ...

キーボードを押すとそのノートナンバーが出力され、音が鳴る。

PrintModule.java
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};
  }
}

CmxTutorial2.java
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);
  }
}