前回の演奏部分のコードは4小節を演奏するだけのものであるのにコード量がまだ多いです。チェロ組曲第一番の前奏曲は同じようなフレーズがずっと続いているためこのフレーズの表現方法の部分だけクラスにまとめたいと思います。
フレーズ編集クラスの概要
シーケンスを編集するにあたり曲の構造と関係なくフレーズ表現の部分だけ管理できるクラスをデザインします。およそ以下のようなことをしたいと思います。
- 曲中のどこでも何度でも利用できる
- 内部でシーケンスを保持している
- テンポの緩急や音の長さや強さは内部で実装されている
- 利用時には小節と拍と使う音名をノート番号で指定する
実装方法の検討
クラス名はPhraseEditorとします。上記の4のとおりフレーズの演奏は以下のメソッドを呼び出すものとします。曲の指定の小節と拍の位置にフレーズを演奏させるためのメソッドです。フレーズに使うノート番号もここで指定するようにします。
public void playPhrase(int measure, double beat, int... notes)
PhraseEditorはインスタンスごとにフレーズの演奏方法が変わるので抽象クラスとします。フレーズを演奏処理は継承クラスで抽象メソッドを実装しそこで行うようにします。
protected abstract void playPhrase(int[] notes);
抽象メソッドで小節と拍の情報が引数で指定されないのはフレーズ演奏時にはこれを意識させないためです。
フィールドは以下のようにします。前回作ったシーケンスエディターを保持するようにします。また基準となる小節と拍の位置も保持するようにします。
private final SequenceEditor se; private int baseMeasure; private double baseBeat;
フィールドが決まればコンストラクタも作れます。基準の小節と拍はともにデフォルト値として0にしておきます。
public PhraseEditor(SequenceEditor se){ this.se = se; baseMeasure = 0; baseBeat = 0; }
publicメソッドのplayPhraseから抽象メソッドのplayPhraseを呼ぶには以下のようにします。呼び出されるごとに基準の小節と拍の位置を更新してから抽象メソッドを呼ぶようにします。
public void playPhrase(int measure, double beat, int... notes){ baseMeasure = measure; baseBeat = beat; playPhrase(notes); }
次に抽象メソッドplayPhraseの実装時に使えるメソッドを用意します。テンポの変更やノートの演奏は相対的な位置で指定できるようにします。今回は二つだけですが必要に応じて今後追加していきます。
protected void setTempo(int measure, double beat, double tempo){ se.setTempo(baseMeasure + measure, baseBeat + beat, tempo); } protected void play(int measure, double beat, int track, int note, int velocity, double duration){ se.getTrackEditor(track).play(baseMeasure + measure, baseBeat + beat, note, velocity, duration); }
これで準備ができました。次回は実際にこのクラスを継承して前奏曲の実装を変更します。
ソース
今回作ったソースです。
/* * mocha-java.com * */ package mocha.sound.midi; /** * * @author minaberger */ public abstract class PhraseEditor { private final SequenceEditor se; private int baseMeasure; private double baseBeat; public PhraseEditor(SequenceEditor se) { this.se = se; baseMeasure = 0; baseBeat = 0; } public void playPhrase(int measure, double beat, int... notes) { baseMeasure = measure; baseBeat = beat; playPhrase(notes); } protected abstract void playPhrase(int[] notes); protected void setTempo(int measure, double beat, double tempo) { se.setTempo(baseMeasure + measure, baseBeat + beat, tempo); } protected void play(int measure, double beat, int track, int note, int velocity, double duration) { se.getTrackEditor(track).play(baseMeasure + measure, baseBeat + beat, note, velocity, duration); } }