/*
* Copyright (C) 2014-2015 たんらる
*/
package fourthline.mabiicco.midi;
import java.util.ArrayList;
import java.util.List;
import fourthline.mmlTools.MMLNoteEvent;
import fourthline.mmlTools.MMLTempoEvent;
import fourthline.mmlTools.core.MMLTicks;
/**
* 複数のMMLNoteEventリストから, MIDIトラック用リストに変換する.
* マビノギ内の演奏とは若干ちがうけど!(気にしない
* TODO: 再生方式の完全な変更が必要.
*/
public class MMLMidiTrack {
private List<MMLTempoEvent> tempoList;
private ArrayList<MMLNoteEvent> noteEventList;
public MMLMidiTrack(List<MMLTempoEvent> tempoList) {
if (tempoList != null) {
this.tempoList = tempoList;
} else {
this.tempoList = new ArrayList<>();
}
noteEventList = new ArrayList<>();
}
public List<MMLNoteEvent> getNoteEventList() {
return noteEventList;
}
public void add(List<MMLNoteEvent> list) {
for (MMLNoteEvent noteEvent : list) {
addItem(noteEvent.clone());
}
}
private void addItem(MMLNoteEvent addEvent) {
int targetTick = addEvent.getTickOffset();
int targetIndex = 0;
for (MMLNoteEvent noteEvent : noteEventList) {
if (noteEvent.getTickOffset() > targetTick) {
break;
}
targetIndex++;
if ( (noteEvent.getTickOffset() == targetTick) && (noteEvent.getNote() == addEvent.getNote())) {
break;
}
}
// 前の音との重複修正
if ( targetIndex > 0 ) {
MMLNoteEvent prevEvent = noteEventList.get( targetIndex - 1 );
if (addEvent.getNote() == prevEvent.getNote()) {
if ( prevEvent.getTickOffset() == targetTick ) {
// 開始位置が同じときには, 後発音で更新する.
// 前の音とテンポ指定がある場合は元あったノートのまま.
// 後発音が V0 の場合は l64音に更新する.
if (!MMLTempoEvent.searchEqualsTick(tempoList, targetTick)) {
if (addEvent.getVelocity() == 0) {
prevEvent.setTick(MMLTicks.minimumTick());
}
return;
} else {
if (prevEvent.getVelocity() == 0) {
addEvent.setTick(MMLTicks.minimumTick());
}
targetIndex--;
noteEventList.remove(targetIndex);
}
} else {
trimOverlapNote(prevEvent, addEvent);
}
}
}
// 後ろの音との重複修正
if ( targetIndex < noteEventList.size() ) {
MMLNoteEvent nextEvent = noteEventList.get( targetIndex );
trimOverlapNote(addEvent, nextEvent);
}
noteEventList.add(targetIndex, addEvent);
}
private void trimOverlapNote(MMLNoteEvent note1, MMLNoteEvent note2) {
if (note1.getTickOffset() >= note2.getTickOffset()) {
new AssertionError();
}
if (note1.getNote() == note2.getNote()) {
int tickOverlap = note1.getEndTick() - note2.getTickOffset();
if (tickOverlap > 0) {
note1.setTick( note1.getTick() - tickOverlap );
}
}
}
}