Sequencerの使い方

JavaMIDIを扱う方法の解説。MacOSX(10.5.8), JDK1.5にて確認。

  1. 主に使用するクラス
  2. Sequencerを使って音を再生するサンプル
  3. SMFファイルからSequencerを生成する
  4. Sequence内の情報を所得

主に使用するクラス

Sequencer 曲の再生を管理するクラス
Sequence 曲を表すクラス
Track トラックを表すクラス
MidiEvent MIDIメッセージとタイミングを表すクラス
MidiMessage MIDIメッセージを表すクラス

Sequencerを使って音を再生するサンプル

import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Track;

public class Hoge {

  public static void main(String[] args) {
    try {
      // デフォルトシーケンサの所得
      Sequencer sequencer = MidiSystem.getSequencer();

      // シーケンサの生成
      // テンポベースのタイミング形式で
      // TicksPerBeatに480を指定
      Sequence sequence = new Sequence(Sequence.PPQ, 480);

      // トラックを生成
      Track track = sequence.createTrack();

      // ノートオンイベントの生成
      ShortMessage noteOn = new ShortMessage();
      noteOn.setMessage(ShortMessage.NOTE_ON, 60, 127);
      MidiEvent e1 = new MidiEvent(noteOn, 480);

      // ノートオフイベントの生成
      ShortMessage noteOff = new ShortMessage();
      noteOff.setMessage(ShortMessage.NOTE_OFF, 60, 0);
      MidiEvent e2 = new MidiEvent(noteOff, 960);

      // イベントをトラックに追加する
      track.add(e1);
      track.add(e2);

      // シーケンスをシーケンサに追加する
      sequencer.setSequence(sequence);

      // 演奏開始
      sequencer.open();
      sequencer.start();

      // 標準入力でブロック
      System.in.read();

      // 終了
      sequencer.stop();
      sequencer.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

SMFファイルからSequencerを生成する

既存のSMFファイルからSequencerを生成するにはMidiSystemのgetSequenceメソッドを使用する。

Sequence sequence = MidiSystem.getSequence(new File("hoge.mid"));

Sequence内の情報を所得

Track, MidiEventに順にアクセスする。

      // シーケンス内のイベントを出力する
      for(Track t : sequence.getTracks()) {
        for(int i=0; i<t.size(); i++) {
          MidiEvent e = t.get(i);
          byte[] m = e.getMessage().getMessage();
          System.out.println(e.getTick() + ", " + m[1] + ", " + m[2]);
        }
      }

このように所得したSequence内の情報は再生中に値を更新しても内容が即座に反映される。例えば先のサンプルで、演奏開始後にタイミングを変更すると

      // 演奏開始
      sequencer.open();
      sequencer.start();
      e1.setTick(1440);
      e2.setTick(1920);

再生が遅れる。