package com.xenoage.zong.musiclayout.stamper;
import static com.xenoage.utils.kernel.Range.range;
import static com.xenoage.zong.core.music.format.SP.sp;
import static com.xenoage.zong.musiclayout.notation.chord.NoteSuspension.None;
import static com.xenoage.zong.musiclayout.notation.chord.NoteSuspension.Right;
import com.xenoage.zong.musiclayout.notation.ChordNotation;
import com.xenoage.zong.musiclayout.notation.chord.NoteDisplacement;
import com.xenoage.zong.musiclayout.notation.chord.NoteSuspension;
import com.xenoage.zong.musiclayout.notation.chord.NotesNotation;
import com.xenoage.zong.musiclayout.stampings.LegerLineStamping;
import com.xenoage.zong.musiclayout.stampings.StaffStamping;
/**
* Creates {@link LegerLineStamping}s from a {@link ChordNotation}.
*
* @author Andreas Wenger
*/
public class LegerLinesStamper {
public static final LegerLinesStamper legerLinesStamper = new LegerLinesStamper();
public static final LegerLineStamping[] empty = new LegerLineStamping[0];
public LegerLineStamping[] stamp(ChordNotation chordNotation, float chordXMm, StaffStamping staffStamping) {
NotesNotation notes = chordNotation.notes;
int bottomCount = getBottomCount(notes.getBottomNote().lp);
int topCount = getTopCount(notes.getTopNote().lp, staffStamping.linesCount);
if (bottomCount > 0 || topCount > 0) {
//horizontal position and width (may differ above and below staff, dependent on suspended notes)
NoteSuspension bottomSuspension = getBottomSuspension(notes.notes);
float xTopMm = getXMm(chordXMm, notes.noteheadWidthIs, bottomSuspension, staffStamping.is);
float widthBottomIs = getWidthIs(bottomSuspension != None);
NoteSuspension topSuspension = getTopSuspension(notes.notes, staffStamping.linesCount);
float xBottomMm = getXMm(chordXMm, notes.noteheadWidthIs, topSuspension, staffStamping.is);
float widthTopIs = getWidthIs(bottomSuspension != None);
//vertical positions
int[] bottomLps = getBottomLps(bottomCount);
int[] topLps = getTopLps(topCount, staffStamping.linesCount);
//create stampings
LegerLineStamping[] ret = new LegerLineStamping[bottomCount + topCount];
for (int i : range(bottomCount))
ret[i] = new LegerLineStamping(sp(xBottomMm, bottomLps[i]), widthBottomIs, staffStamping);
for (int i : range(topCount))
ret[bottomCount + i] = new LegerLineStamping(sp(xTopMm, topLps[i]), widthTopIs, staffStamping);
return ret;
}
else {
return empty;
}
}
float getXMm(float chordXMm, float noteheadWidthIs, NoteSuspension suspension, float staffIs) {
float leftNoteXMm = chordXMm;
//center x on middle of chord notes
if (suspension == None)
leftNoteXMm += noteheadWidthIs * staffIs / 2;
else if (suspension == Right)
leftNoteXMm += noteheadWidthIs * staffIs;
return leftNoteXMm;
}
NoteSuspension getBottomSuspension(NoteDisplacement... notes) {
//find a suspended note which needs a leger line on the bottom side
for (NoteDisplacement note : notes)
if (note.suspension != None && note.lp <= -2)
return note.suspension;
return None;
}
NoteSuspension getTopSuspension(NoteDisplacement[] notes, int staffLinesCount) {
//find a suspended note which needs a leger line on the top side
for (NoteDisplacement note : notes)
if (note.suspension != None && note.lp >= staffLinesCount * 2)
return note.suspension;
return None;
}
float getWidthIs(boolean suspended) {
return suspended ? LegerLineStamping.lengthSuspendedIs : LegerLineStamping.lengthNormalIs;
}
int getTopCount(int topNoteLp, int staffLinesCount) {
int staffTopLp = staffLinesCount * 2 - 2;
if (topNoteLp > staffTopLp + 1)
return (topNoteLp - staffTopLp) / 2;
else
return 0;
}
int getBottomCount(int bottomNoteLp) {
if (bottomNoteLp < -1)
return bottomNoteLp / -2;
else
return 0;
}
int[] getBottomLps(int legerLinesBottomCount) {
int[] ret = new int[legerLinesBottomCount];
//in ascending order
for (int i : range(legerLinesBottomCount)) {
int lp = -2 - (legerLinesBottomCount - i - 1) * 2;
ret[i] = lp;
}
return ret;
}
int[] getTopLps(int legerLinesTopCount, int staffLinesCount) {
int[] ret = new int[legerLinesTopCount];
//in ascending order
for (int i : range(legerLinesTopCount)) {
int lp = (staffLinesCount + i) * 2;
ret[i] = lp;
}
return ret;
}
}