CMXチュートリアル

TickTimerの使い方

TickTimerを用いて演奏中の曲の再生時刻を所得する。

  1. SMFPlayerを用意する
  2. MidiInputModuleにTickTimerを指定する
  3. 新しい表示用モジュールを作る

MidiInputModuleはTickTimerを指定することでキーが送信された時点でのTickTimeを得ることが出来る。ここでは、SMFを再生し、その再生時刻を返すSMFPlayerを用いる。

SMFPlayerを用意する

SMFPlayerは指定したSMFファイルを再生するクラスで、TickTimerを実装している。

      // SMFPlayer
      SMFPlayer smf = new SMFPlayer();
      smf.readSMF("kaeru.mid");

readSMFには再生するSMFのファイル名を指定する。

kaeru.mid

MidiInputModuleにTickTimerを指定する

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();
CmxTutorial3.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.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);
  }
}

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