use of com.xenoage.zong.musiclayout.notation.beam.Fragments in project Zong by Xenoage.
the class BeamFragmenter method compute.
/**
* Computes the line fragments for all lines of the given beam,
* starting with the 16th, then 32nd, ... line.
*/
public List<Fragments> compute(Beam beam) {
int linesCount = beam.getMaxLinesCount();
List<Fragments> ret = alist(linesCount - 1);
Fragments lastFragments = null;
for (int line : range(1, linesCount - 1)) ret.add(lastFragments = compute(beam, line, lastFragments));
return ret;
}
use of com.xenoage.zong.musiclayout.notation.beam.Fragments in project Zong by Xenoage.
the class BeamStamper method stamp.
/**
* Computes the stampings for the given beam and returns them.
* @param beam the beam to stamp
* @param staff the staff stamping of the first chord of the beam
*/
public List<BeamStamping> stamp(BeamSpacing beam, StaffStamping staff) {
int beamSize = beam.chords.size();
val leftEndSp = beam.getLeftSp();
val rightEndSp = beam.getRightSp();
val primaryStemDir = beam.getStemDirection(0);
// number of beam lines
int linesCount = beam.notation.getLinesCount();
// first guess of the size (is correct for simple beams)
List<BeamStamping> ret = alist(linesCount);
// first line (8th line) is always continuous
val beam8th = new BeamStamping(beam, staff, leftEndSp, rightEndSp, primaryStemDir);
ret.add(beam8th);
// this is stored in the notation
for (int i : range(beam.notation.linesFragments)) {
int line = i + 1;
float lineLp = -1 * primaryStemDir.getSign() * (lineHeightIs + beam.notation.gapIs) * 2 * line;
val beamLinePoints = new LinearInterpolationPoints(leftEndSp.lp + lineLp, rightEndSp.lp + lineLp, leftEndSp.xMm, rightEndSp.xMm);
// create the line stampings
float startXMm = 0;
Fragments fragments = beam.notation.linesFragments.get(i);
for (int iChord : range(fragments)) {
Fragment fragment = fragments.get(iChord);
float stemXMm = beam.getStemEndSp(iChord).xMm;
if (fragment == Start) {
// begin a new beam line
startXMm = stemXMm;
} else if (fragment == Stop) {
// end the beam line and stem it
float stopXMm = stemXMm;
SP leftSp = sp(startXMm, INSTANCE.interpolateLinear(beamLinePoints, startXMm));
SP rightSp = sp(stopXMm, INSTANCE.interpolateLinear(beamLinePoints, stopXMm));
val stamping = new BeamStamping(beam, staff, leftSp, rightSp, primaryStemDir);
ret.add(stamping);
} else if (fragment == HookLeft || fragment == HookRight) {
// left or right hook
float lengthMm = hookLengthIs * staff.is;
float x1Mm = (fragment == HookLeft ? stemXMm - lengthMm : stemXMm);
float x2Mm = (fragment == HookLeft ? stemXMm : stemXMm + lengthMm);
SP leftSp = sp(x1Mm, INSTANCE.interpolateLinear(beamLinePoints, x1Mm));
SP rightSp = sp(x2Mm, INSTANCE.interpolateLinear(beamLinePoints, x2Mm));
val stamping = new BeamStamping(beam, staff, leftSp, rightSp, primaryStemDir);
ret.add(stamping);
}
}
}
return ret;
}
use of com.xenoage.zong.musiclayout.notation.beam.Fragments in project Zong by Xenoage.
the class BeamFragmenterTest method computeTest.
@Test
public void computeTest() {
ChlapikBeamFragments source = new ChlapikBeamFragments();
Beam b;
// example of row 1, column 1
b = source.exampleRow1Col1();
try {
// not working for 8th lines
testee.compute(b, 0, null);
fail();
} catch (IllegalArgumentException ex) {
// ok
}
Fragments wp = testee.compute(b, 2, null);
// 32th
assertEqualsList(wp, None, None, None);
// 16th
assertEqualsList(testee.compute(b, 1, wp), HookRight, None, HookLeft);
// example of row 1, column 2
b = source.exampleRow1Col2();
// 16th
assertEqualsList(testee.compute(b, 1, null), HookRight, None, HookLeft);
// example of row 1, column 3
b = source.exampleRow1Col3();
// 16th
assertEqualsList(testee.compute(b, 1, null), HookRight, None, None, HookLeft);
// example of row 1, column 4
b = source.exampleRow1Col4();
// 16th
assertEqualsList(testee.compute(b, 1, null), HookRight, None, None, HookLeft);
// example of row 2, column 1
b = source.exampleRow2Col1();
// 16th
assertEqualsList(testee.compute(b, 1, null), None, HookLeft);
// example of row 2, column 2
b = source.exampleRow2Col2();
// 16th
assertEqualsList(testee.compute(b, 1, null), None, HookLeft);
// example of row 2, column 3
b = source.exampleRow2Col3();
wp = testee.compute(b, 2, null);
// 32th
assertEqualsList(wp, None, HookLeft, None, HookLeft);
// 16th
assertEqualsList(testee.compute(b, 1, wp), Start, None, None, Stop);
// example of row 2, column 4
b = source.exampleRow2Col4();
wp = testee.compute(b, 2, null);
// 32th
assertEqualsList(wp, None, HookLeft, None, HookLeft);
// 16th
assertEqualsList(testee.compute(b, 1, wp), Start, None, None, Stop);
// example of row 3, column 2
b = source.exampleRow3Col2();
// 16th
assertEqualsList(testee.compute(b, 1, null), HookRight, None, HookLeft, None);
// example of row 3, column 4
b = source.exampleRow3Col4();
// 16th
assertEqualsList(testee.compute(b, 1, null), None, HookRight, None);
// example of row 3, column 6
b = source.exampleRow3Col6();
wp = testee.compute(b, 2, null);
// 32th
assertEqualsList(wp, None, HookLeft, None, HookLeft);
// 16th
assertEqualsList(testee.compute(b, 1, wp), None, HookLeft, Start, Stop);
}
use of com.xenoage.zong.musiclayout.notation.beam.Fragments in project Zong by Xenoage.
the class BeamFragmenter method compute.
/**
* Computes the fragments for the given line (1: 16th line, 2: 32th line, ...).
* Use an algorithm based on the rules in Chlapik, page 45, rule 6.
*
* Begin with the highest line (e.g. 32th before 16th), and use the result of line n
* as a parameter to compute line n-1 (for the first computation, use null).
* This is needed to support Chlapik, page 45, rule 6, example of row 3, column 6.
* Without that, the 16th line would go from the second note to the fourth one.
*/
Fragments compute(Beam beam, int line, Fragments higherLine) {
if (line < 1)
throw new IllegalArgumentException("This method only works for 16th lines or higher");
// in this algorithm, we go from note to note, looking for "groups".
// groups are consecutive chords/stems with the same number of flags (or
// a higher number inbetween) and not divided by a subdivision break.
// initialize return array with none-waypoints
Fragments ret = new Fragments(beam.size());
int lastFlagsCount = -1;
// start chord of the last group, or -1 if no group is open
int startChord = -1;
// stop chord of the last group, or -1 if group is open
int stopChord = -1;
for (int iChord : range(beam.size() + 1)) {
if (iChord < beam.getWaypoints().size()) {
// another chord within the beam
Chord chord = beam.getChord(iChord);
int flagsCount = INSTANCE.getFlagsCount(chord.getDuration());
// enough flags for the given line? (e.g. a 8th beam has no 16th line)
if (flagsCount >= line + 1) {
// yes, we need a line of the given line for this stem
if (startChord == -1) {
if (higherLine == null || higherLine.get(iChord) != HookLeft) {
// start new group
startChord = iChord;
lastFlagsCount = flagsCount;
} else {
// example mentioned in the method documentation (Chlapik, page 45, row 3, col 6)
// we place a hook. this is not explicitly mentioned in the text, but seems to
// be right when looking at the example.
startChord = iChord;
stopChord = iChord;
}
} else if (lastFlagsCount > -1 && (// less flags than previous stem
flagsCount < flagsCount || beam.isEndOfSubdivision(iChord))) {
// forced subdivision break
// end the group here
stopChord = iChord - 1;
}
} else {
// no, we need no line of the given line for this stem
// so, close the last group
stopChord = iChord - 1;
}
} else {
// no more chord in the beam, so we have to close
stopChord = iChord - 1;
}
// if a group was closed, create it
if (startChord > -1 && stopChord > -1) {
// type of line is dependent on number of chords in the group
int chordsCount = stopChord - startChord + 1;
if (chordsCount > 1) {
// simple case: more than one chord. create a normal line
// between those stems
ret.set(startChord, Start);
ret.set(stopChord, Stop);
} else {
// more difficult case: exactly one chord.
if (startChord == 0) {
// first chord in beam has always hook to the right
ret.set(startChord, HookRight);
} else if (startChord == beam.getWaypoints().size() - 1) {
// last chord in beam has always hook to the left
ret.set(startChord, HookLeft);
} else {
// middle chords have left hook, if the preceding chord
// has a longer or equal duration than the following chord,
// otherwise they have a right hook
Fraction left = beam.getChord(startChord - 1).getDuration();
Fraction right = beam.getChord(startChord + 1).getDuration();
if (left.compareTo(right) >= 0)
ret.set(startChord, HookLeft);
else
ret.set(startChord, HookRight);
}
}
// reset group data
startChord = -1;
stopChord = -1;
lastFlagsCount = -1;
}
}
return ret;
}
use of com.xenoage.zong.musiclayout.notation.beam.Fragments in project Zong by Xenoage.
the class BeamNotator method compute.
@MaybeNull
public BeamNotation compute(Beam beam, Notations notations) {
// compute fragments
List<Fragments> fragments = beamFragmenter.compute(beam);
// get minimum stem length and gap
BeamRules beamRules = BeamRules.getRules(beam);
float gapIs = beamRules.getGapIs();
// collect chords
List<ChordNotation> chords = notations.getBeamChords(beam);
// create notation
BeamNotation beamNotation = new BeamNotation(beam, beam.getMP(), fragments, gapIs, chords);
return beamNotation;
}
Aggregations