演奏表現を表すクラスMusicRepresentationの使い方を解説する。
MusicRepresentationは複数の演奏レイヤー(メロディーやコード等)を保持し、それぞれに計算オブジェクトを登録することができる。登録した計算オブジェクトは、レイヤーが更新されるとその情報を元に別のレイヤーの値を更新する。
ここでは、メロディーを表すmelodyレイヤーとコード進行を表すchordレイヤーを持ち、メロディーの値が更新されるとコードの値を更新するMusicRepresentationを作製する。
Calculatorインターフェースを実装したクラスは計算オブジェクトとしてMusicRepresentationに登録することができる。
public class ChordCalculator implements Calculator { private int[] chordMapping = { 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6 };
ここでは、ノートナンバーからコードの種類への変換を表すchordMappingを定義しておく。
Calculatorオブジェクトが登録されたレイヤーが更新されるとupdateメソッドが呼び出される。
public void update(MusicRepresentation musRep, MusicElement me, int index) { int division = musRep.getDivision(); int measureLen = musRep.getMeasureNum(); // 最後の小節なら処理しない if (index > division * (measureLen - 1)) return; // ノートナンバー int noteNum = me.getHighestProbIndex(); // 次の小節の開始インデックス int nextMeasureIndex = index / division + division; // 次の小節のコードを決める MusicElement nextChord = musRep.getMusicElement("chord", nextMeasureIndex); nextChord.setEvidence(chordMapping[noteNum % 12]); // 必要な場合更新する // musRep.update("chord", nextMeasureIndex); }
引数には更新されたMusicElementとそのインデックスが入る。ここでは、渡されたメロディーのMusicElementからノートナンバーを所得し、対応するコードの種類に変換して次の小節のコードを指定している。
import jp.crestmuse.cmx.inference.MusicRepresentation; import jp.crestmuse.cmx.inference.MusicRepresentation.MusicElement; public class CMXTutorial5 { public static void main(String[] args) { // MusicRepresentationの初期化 MusicRepresentation musRep = new MusicRepresentation(8, 8);
コンストラクタの引数にはそれぞれ小節数と小節あたりの分解能を指定する。
MusicRepresentationを使うにはまず使用するレイヤーを登録する。
// レイヤーを登録する musRep.addMusicLayer("melody", 12); musRep.addMusicLayer("chord", new String[]{ "C", "Dm", "Em", "F", "G", "Am", "Bm(b5)" }, 8);
引数はそれぞれレイヤー名、結合長、ノートかコードかを表し、第二第三引数は指定しなければデフォルトの値が適用される。結合長とは、レイヤーがMusicRepresentationを区切る量を表し、例えば分解能が8で結合長が8だと一小節を一つの区切りとして扱う。
// Calculatorを登録する musRep.addCalculator("melody", new ChordCalculator(musRep));
引数にレイヤーの名前とCalculatorオブジェクトを指定する。
// melodyレイヤーを一つ決定する musRep.getMusicElement("melody", 0).setEvidence(62); musRep.update("melody", 0);
メロディーレイヤーの最初の値を決定する。
MusicRepresentation.updateを呼び出すと指定したレイヤーに登録されたCalculatorオブジェクトが計算処理を行う。
// chordが更新されたかどうか確認する MusicElement nextChord = musRep.getMusicElement("chord", 8); int highestIndex = nextChord.getHighestProbIndex(); System.out.println(nextChord.getLabel(highestIndex));
ここでは、登録したChordCalculatorが新しいコードの値を設定している。
import jp.crestmuse.cmx.inference.MusicRepresentation; import jp.crestmuse.cmx.inference.MusicRepresentation.MusicElement; public class CMXTutorial5 { public static void main(String[] args) { // MusicRepresentationの初期化 MusicRepresentation musRep = new MusicRepresentation(8, 8); // レイヤーを登録する musRep.addMusicLayer("melody", 12); musRep.addMusicLayer("chord", new String[]{ "C", "Dm", "Em", "F", "G", "Am", "Bm(b5)" }, 8); // Calculatorを登録する musRep.addCalculator("melody", new ChordCalculator()); // melodyレイヤーを一つ決定する musRep.getMusicElement("melody", 0).setEvidence(62); musRep.update("melody", 0); // chordが更新されたかどうか確認する MusicElement nextChord = musRep.getMusicElement("chord", 8); int highestIndex = nextChord.getHighestProbIndex(); System.out.println(nextChord.getLabel(highestIndex)); } }
import jp.crestmuse.cmx.inference.Calculator; import jp.crestmuse.cmx.inference.MusicRepresentation; import jp.crestmuse.cmx.inference.MusicRepresentation.MusicElement; public class ChordCalculator implements Calculator { private int[] chordMapping = { 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6 }; public void update(MusicRepresentation musRep, MusicElement me, int index) { int division = musRep.getDivision(); int measureLen = musRep.getMeasureNum(); // 最後の小節なら処理しない if (index > division * (measureLen - 1)) return; // ノートナンバー int noteNum = me.getHighestProbIndex(); // 次の小節の開始インデックス int nextMeasureIndex = index / division + division; // 次の小節のコードを決める MusicElement nextChord = musRep.getMusicElement("chord", nextMeasureIndex); nextChord.setEvidence(chordMapping[noteNum % 12]); // 必要な場合更新する // musRep.update("chord", nextMeasureIndex); } }