package com.xenoage.zong.musiclayout.notator;
import com.xenoage.utils.annotations.MaybeNull;
import com.xenoage.utils.collections.CollectionUtils;
import com.xenoage.zong.core.Score;
import com.xenoage.zong.core.music.*;
import com.xenoage.zong.core.music.beam.Beam;
import com.xenoage.zong.core.position.MPElement;
import com.xenoage.zong.core.util.BeamIterator;
import com.xenoage.zong.core.util.ColumnElementIterator;
import com.xenoage.zong.core.util.MeasureElementIterator;
import com.xenoage.zong.core.util.VoiceElementIterator;
import com.xenoage.zong.musiclayout.layouter.Context;
import com.xenoage.zong.musiclayout.notation.Notation;
import com.xenoage.zong.musiclayout.notation.Notations;
import java.util.Map;
import static com.xenoage.utils.collections.CollectionUtils.map;
import static com.xenoage.utils.kernel.Range.range;
import static com.xenoage.zong.musiclayout.notator.ChordNotator.chordNotator;
import static com.xenoage.zong.musiclayout.notator.ClefNotator.clefNotator;
import static com.xenoage.zong.musiclayout.notator.RestNotator.restNotator;
import static com.xenoage.zong.musiclayout.notator.TimeNotator.timeNotator;
import static com.xenoage.zong.musiclayout.notator.TraditionalKeyNotator.traditionalKeyNotator;
import static com.xenoage.zong.musiclayout.notator.beam.BeamNotator.beamNotator;
/**
* Creates layout information about the isolated layout of {@link MusicElement}s,
* so called {@link Notation}s.
*
* For example, the positioning for musical elements like chords,
* rests, clefs and so on is computed, but without respect to other
* neighboring elements.
*
* @author Andreas Wenger
*/
public final class Notator {
public static final Notator notator = new Notator();
private static final Map<MusicElementType, ElementNotator> notators = map();
static {
notators.put(MusicElementType.Beam, beamNotator);
notators.put(MusicElementType.Chord, chordNotator);
notators.put(MusicElementType.Clef, clefNotator);
notators.put(MusicElementType.Rest, restNotator);
notators.put(MusicElementType.Time, timeNotator);
notators.put(MusicElementType.TraditionalKey, traditionalKeyNotator);
}
/**
* Computes the {@link Notation}s of all elements and returns them.
*/
public Notations computeAll(Context context) {
context.saveMp();
Score score = context.score;
Notations notations = new Notations();
//iterate over all column elements, measure elements and voice elements
ColumnElementIterator itC = new ColumnElementIterator(score);
for (ColumnElement e : itC) {
//column elements: one notation for each staff
for (int iStaff : range(context.score.getStavesCount())) {
context.mp = itC.getMp().withStaff(iStaff);
notations.add(compute(e, context, notations), iStaff);
}
}
MeasureElementIterator itM = new MeasureElementIterator(score);
for (MeasureElement e : itM) {
context.mp = itM.getMp();
notations.add(compute(e, context, notations));
}
VoiceElementIterator itV = new VoiceElementIterator(score);
for (VoiceElement e : itV) {
context.mp = itV.getMp();
notations.add(compute(e, context, notations));
}
BeamIterator itB = new BeamIterator(score);
for (Beam e : itB) {
context.mp = itB.getMp();
notations.add(compute(e, context, notations));
}
context.restoreMp();
return notations;
}
/**
* Computes the {@link Notation} of the given element.
*/
@MaybeNull private Notation compute(MPElement element, Context context, Notations notations) {
ElementNotator notator = notators.get(element.getMusicElementType());
if (notator == null) //element needs no notation
return null;
Notation notation = notator.compute(element, context, notations);
return notation;
}
}