JavaとMIDI:シーケンスの内容を出力する (2)

スポンサーリンク

前回シーケンスの内容を出力するメソッドを作ったのでこれを利用したいと思います。

出力先について

前回のメソッドでは引数にPrintStreamを指定していました。通常一曲のシーケンスは数百数千のメッセージでできているため標準出力に出力すると初めの情報は流れてしまい全て確認するのが難しいことが想定されます。PrintStreamにSystem.outを指定すれば標準出力になりますが以下のように初期化するとファイルに出力することができます。

new PrintStream(File file);

サンプルシーケンス

以前自前で作ったシーケンスを流用します。ただし複数トラックを確認したいのでトラックを3つ作ります。

Sequence sequence = new Sequence(Sequence.PPQ, 480);
Track track;
track = sequence.createTrack();
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 60, 127), 480 * 4));
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 60, 0), 480 * 5));
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 60, 127), 480 * 7));
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 60, 0), 480 * 8));

track = sequence.createTrack();
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 64, 127), 480 * 5));
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 64, 0), 480 * 6));
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 64, 127), 480 * 7));
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 64, 0), 480 * 8));

track = sequence.createTrack();
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 67, 127), 480 * 6));
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 67, 0), 480 * 7));
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 67, 127), 480 * 7));
track.add(new MidiEvent(new ShortMessage(ShortMessage.NOTE_ON, 0, 67, 0), 480 * 8));

シーケンスをMIDIファイルに出力する

シーケンスは簡単にMIDIファイルに出力することができます。拡張子は.midです。二つ目の引数の数字はスタンダードMIDIファイルのフォーマットのことで0はトラックが一つだけの形式、1は複数の形式です。今回はトラックが複数あるので1にします。だいたいの場合1で良いと思います。

また2の形式もあるようですがあまり使われていないようです。

MidiSystem.write(sequence, 1, new File("midi/test.mid"));

シーケンス内容をテキストに出力する

前回作った出力用のメソッドを使って出力して見ます。

SequencePrinter.printSequence(sequence, System.out);

出力した結果です。

division type  : PPQ
resolution     : 480
length in ms   : 4000000
length in tick : 3840
track-0 length in tick :3840
track-0 size           :5
track-0.event-0 tick : 1920
track-0.event-0.short command : NOTE_ON
track-0.event-0.short channel : 0
track-0.event-0.short data    : 60, 127
track-0.event-1 tick : 2400
track-0.event-1.short command : NOTE_ON
track-0.event-1.short channel : 0
track-0.event-1.short data    : 60, 0
track-0.event-2 tick : 3360
track-0.event-2.short command : NOTE_ON
track-0.event-2.short channel : 0
track-0.event-2.short data    : 60, 127
track-0.event-3 tick : 3840
track-0.event-3.short command : NOTE_ON
track-0.event-3.short channel : 0
track-0.event-3.short data    : 60, 0
track-0.event-4 tick : 3840
track-0.event-4.meta type : 47
track-1 length in tick :3840
track-1 size           :5
track-1.event-0 tick : 2400
track-1.event-0.short command : NOTE_ON
track-1.event-0.short channel : 0
track-1.event-0.short data    : 64, 127
track-1.event-1 tick : 2880
track-1.event-1.short command : NOTE_ON
track-1.event-1.short channel : 0
track-1.event-1.short data    : 64, 0
track-1.event-2 tick : 3360
track-1.event-2.short command : NOTE_ON
track-1.event-2.short channel : 0
track-1.event-2.short data    : 64, 127
track-1.event-3 tick : 3840
track-1.event-3.short command : NOTE_ON
track-1.event-3.short channel : 0
track-1.event-3.short data    : 64, 0
track-1.event-4 tick : 3840
track-1.event-4.meta type : 47
track-2 length in tick :3840
track-2 size           :5
track-2.event-0 tick : 2880
track-2.event-0.short command : NOTE_ON
track-2.event-0.short channel : 0
track-2.event-0.short data    : 67, 127
track-2.event-1 tick : 3360
track-2.event-1.short command : NOTE_ON
track-2.event-1.short channel : 0
track-2.event-1.short data    : 67, 0
track-2.event-2 tick : 3360
track-2.event-2.short command : NOTE_ON
track-2.event-2.short channel : 0
track-2.event-2.short data    : 67, 127
track-2.event-3 tick : 3840
track-2.event-3.short command : NOTE_ON
track-2.event-3.short channel : 0
track-2.event-3.short data    : 67, 0
track-2.event-4 tick : 3840
track-2.event-4.meta type : 47

自分では入れていないのですがメタメッセージがそれぞれのトラックの最後に入っています。これはEnd of Track「トラックの終了」を意味するメタメッセージです。スタンダードMIDIファイルの仕様上各トラックの終了位置に必要なためJavaのAPIで自動で追加しているようです。

ソース

最後に出力用のソースを載せておきます。

package mocha.sound.midi;

import java.io.PrintStream;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.Sequence;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.SysexMessage;
import javax.sound.midi.Track;

public class SequencePrinter {

  public static void printSequence(Sequence sequence, PrintStream out) {
    String divisionTypeName;
    if (sequence.getDivisionType() == Sequence.PPQ) {
      divisionTypeName = "PPQ";
    } else if (sequence.getDivisionType() == Sequence.SMPTE_24) {
      divisionTypeName = "SMPTE_24";
    } else if (sequence.getDivisionType() == Sequence.SMPTE_25) {
      divisionTypeName = "SMPTE_25";
    } else if (sequence.getDivisionType() == Sequence.SMPTE_30) {
      divisionTypeName = "SMPTE_30";
    } else if (sequence.getDivisionType() == Sequence.SMPTE_30DROP) {
      divisionTypeName = "SMPTE_30DROP";
    } else {
      divisionTypeName = "unknown";
    }
    out.println("division type  : " + divisionTypeName);
    out.println("resolution     : " + sequence.getResolution());
    out.println("length in ms   : " + sequence.getMicrosecondLength());
    out.println("length in tick : " + sequence.getTickLength());
    int i = 0;
    for (Track track : sequence.getTracks()) {
      printTrack(track, "track-" + i++, out);
    }
  }

  public static void printTrack(Track track, String name, PrintStream out) {
    out.println(name + " length in tick :" + track.ticks());
    out.println(name + " size           :" + track.size());
    for (int i = 0; i < track.size(); i++) {
      printMidiEvent(track.get(i), name + ".event-" + i, out);
    }
  }

  public static void printMidiEvent(MidiEvent event, String name, PrintStream out) {
    out.println(name + " tick : " + event.getTick());
    MidiMessage message = event.getMessage();
    if (message instanceof ShortMessage) {
      printShortMessage((ShortMessage) message, name + ".short", out);
    } else if (message instanceof MetaMessage) {
      printMetaMessage((MetaMessage) message, name + ".meta", out);
    } else if (message instanceof SysexMessage) {
      out.println(name + " sysex message");
    } else {
      out.println(name + " unknown");
    }

  }

  public static void printMetaMessage(MetaMessage message, String name, PrintStream out) {
    out.println(name + " type : " + message.getType());
  }

  public static void printShortMessage(ShortMessage message, String name, PrintStream out) {
    String command;
    switch (message.getCommand()) {
      case ShortMessage.ACTIVE_SENSING:
        command = "ACTIVE_SENSING";
        break;
      case ShortMessage.CHANNEL_PRESSURE:
        command = "CHANNEL_PRESSURE";
        break;
      case ShortMessage.CONTINUE:
        command = "CONTINUE";
        break;
      case ShortMessage.CONTROL_CHANGE:
        command = "CONTROL_CHANGE";
        break;
      case ShortMessage.END_OF_EXCLUSIVE:
        command = "END_OF_EXCLUSIVE";
        break;
      case ShortMessage.MIDI_TIME_CODE:
        command = "MIDI_TIME_CODE";
        break;
      case ShortMessage.NOTE_OFF:
        command = "NOTE_OFF";
        break;
      case ShortMessage.NOTE_ON:
        command = "NOTE_ON";
        break;
      case ShortMessage.PITCH_BEND:
        command = "PITCH_BEND";
        break;
      case ShortMessage.POLY_PRESSURE:
        command = "POLY_PRESSURE";
        break;
      case ShortMessage.PROGRAM_CHANGE:
        command = "PROGRAM_CHANGE";
        break;
      case ShortMessage.SONG_POSITION_POINTER:
        command = "SONG_POSITION_POINTER";
        break;
      case ShortMessage.SONG_SELECT:
        command = "SONG_SELECT";
        break;
      case ShortMessage.START:
        command = "START";
        break;
      case ShortMessage.STOP:
        command = "STOP";
        break;
      case ShortMessage.SYSTEM_RESET:
        command = "SYSTEM_RESET";
        break;
      case ShortMessage.TIMING_CLOCK:
        command = "TIMING_CLOCK";
        break;
      case ShortMessage.TUNE_REQUEST:
        command = "TUNE_REQUEST";
        break;
      default:
        command = "unknown(" + message.getCommand() + ")";
        break;
    }
    out.println(name + " command : " + command);
    out.println(name + " channel : " + message.getChannel());
    out.println(name + " data    : " + message.getData1() + ", " + message.getData2());

  }

}
スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

%d人のブロガーが「いいね」をつけました。