use of com.xenoage.zong.core.music.format.SP 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.core.music.format.SP in project Zong by Xenoage.
the class DirectionStamper method createDynamics.
/**
* Creates a {@link StaffTextStamping} for the given {@link Dynamic}s
* below the given {@link Chord} and its {@link ChordStampings}.
*/
public StaffTextStamping createDynamics(Dynamic dynamics, Chord chord, ChordStampings chordStampings, SymbolPool symbolPool) {
StaffStamping staff = chordStampings.staff;
// positioning
// below (default): 3 IS below the base line, or 2 IS below the lowest note
// above: 2 IS above the top line, or 1 IS above the highest note
float defaultLPBelow = -3f * 2;
float defaultLPAbove = (staff.linesCount - 1) * 2 + 2 * 2;
if (chordStampings.noteheads.length > 0) {
defaultLPBelow = Math.min(defaultLPBelow, chordStampings.getFirstNotehead().position.lp - 2 * 2);
defaultLPAbove = Math.max(defaultLPAbove, chordStampings.getLastNotehead().position.lp + 1 * 2);
}
SP sp = computePosition(dynamics, staff, defaultLPBelow, defaultLPAbove, defaultLPBelow);
// create text
CList<FormattedTextElement> elements = clist();
for (CommonSymbol s : CommonSymbol.getDynamics(dynamics.getValue())) {
Symbol symbol = symbolPool.getSymbol(s);
elements.add(new FormattedTextSymbol(symbol, staff.is * FONT_SIZE_IN_IS, FormattedTextStyle.Companion.getDefaultColor()));
}
elements.close();
FormattedTextParagraph paragraph = new FormattedTextParagraph(elements, Alignment.Center);
FormattedText text = Companion.fText(paragraph);
// create stamping
return new StaffTextStamping(text, sp, staff, dynamics);
}
use of com.xenoage.zong.core.music.format.SP in project Zong by Xenoage.
the class DirectionStamper method createPedal.
/**
* Creates a {@link StaffSymbolStamping} for the given {@link Pedal}.
*/
public StaffSymbolStamping createPedal(Pedal pedal, StamperContext context) {
val staff = context.getCurrentStaffStamping();
// positioning
// below (default): 4 IS below the base line
// above: 3 IS above the top line
float defaultLPBelow = -4f * 2;
float defaultLPAbove = (staff.linesCount - 1) * 2 + 3 * 2;
SP sp = computePosition(pedal, staff, defaultLPBelow, defaultLPAbove, defaultLPBelow);
// create stamping
Symbol symbol = context.getSymbol(CommonSymbol.getPedal(pedal.getType()));
return new StaffSymbolStamping(null, staff, symbol, null, sp, 1, false);
}
use of com.xenoage.zong.core.music.format.SP in project Zong by Xenoage.
the class SlurStamper method createStartForFirstSystem.
/**
* Creates a {@link SlurStamping} for a curved line that
* starts at this system but spans at least one other system.
*/
SlurStamping createStartForFirstSystem(StaffStamping staff, SP defaultSp, Slur slur) {
SlurWaypoint wp1 = slur.getStart();
// end points of the bezier curve
SP p1 = computeEndPoint(slur, defaultSp, wp1.getBezierPoint());
SP p2 = sp(staff.positionMm.x + staff.lengthMm, p1.lp);
// control points of the bezier curve
BezierPoint b1 = wp1.getBezierPoint();
SP c1 = (// custom formatting
b1 != null && b1.getControl() != null ? // custom formatting
b1.getControl() : // default formatting
computeLeftControlPoint(slur, p1, p2, staff));
// default formatting
SP c2 = computeRightControlPoint(slur, p1, p2, staff);
return new SlurStamping(slur, p1, p2, c1, c2, staff, staff);
}
use of com.xenoage.zong.core.music.format.SP in project Zong by Xenoage.
the class ChordStamper method stampAll.
/**
* Returns all the stampings for the given {@link Chord}, including beams,
* tuplets, slurs and other attachments.
*
* The given {@link OpenSlursCache},
* {@link OpenLyricsCache}, {@link LastLyrics} and {@link OpenTupletsCache} may be modified.
*/
public List<Stamping> stampAll(ChordNotation chord, float xMm, BeamSpacing beam, StaffStampings staffStampings, StamperContext context, FormattedTextStyle defaultLyricStyle, OpenSlursCache openSlursCache, OpenLyricsCache openLyricsCache, LastLyrics lastLyrics, OpenTupletsCache openTupletsCache) {
List<Stamping> ret = alist();
Chord element = chord.getElement();
int staffIndex = context.staffIndex;
int systemIndex = context.systemIndex;
// noteheads, leger lines, dots, accidentals, stem, flags, articulations
ChordStampings chordSt = stampCore(chord, xMm, context);
chordSt.addAllTo(ret);
// beam
if (beam != null) {
// stamp the whole beam (when we find the beginning of the beam)
// TIDY: create/store beam stampings elsewhere?
Beam beamElement = beam.notation.element;
int chordIndex = beamElement.getWaypointIndex(element);
if (chordIndex == 0) {
ret.addAll(beamStamper.stamp(beam, context.getCurrentStaffStamping()));
}
}
// ties and slurs
for (Slur slur : element.getSlurs()) {
SlurWaypoint wp = slur.getWaypoint(element);
WaypointPosition pos = slur.getWaypointPosition(element);
// TODO: choose top/bottom
int noteIndex = notNull(wp.getNoteIndex(), 0);
NoteheadStamping notehead = chordSt.noteheads[noteIndex];
// define the placement: above or below (TODO: better strategy)
VSide side = slurStamper.getSide(slur);
// compute position
val staff = staffStampings.get(systemIndex, notehead.parentStaff.staffIndex);
val slurCache = openSlursCache.getOrCreate(slur);
float distanceIs = slurStamper.getAdditionalDistanceIs(chord, slur.getSide());
SP defaultSp = sp(notehead.position.xMm, notehead.position.lp + side.getDir() * distanceIs * 2);
if (pos == WaypointPosition.Start)
slurCache.setStart(defaultSp, staff, systemIndex);
else
slurCache.setStop(defaultSp, staff, systemIndex);
}
// lyric
List<Lyric> lyrics = element.getLyrics();
if (lyrics.size() > 0) {
float baseLine = -10;
for (Lyric lyric : lyrics) {
if (lyric != null) {
SyllableType lyricType = lyric.getSyllableType();
StaffTextStamping lastLyric = lastLyrics.get(staffIndex, lyric.getVerse());
if (lyricType == SyllableType.Extend) {
// extend
if (// TODO: frame breaks...
lastLyric != null) {
// remember it
openLyricsCache.setUnderscore((Lyric) lastLyric.getElement(), lastLyric, chordSt.noteheads[0], /* TODO*/
staffIndex);
}
} else {
// normal lyric
// create text stamping
StaffTextStamping sts = lyricStamper.createSyllableStamping(lyric, defaultLyricStyle, context.getCurrentStaffStamping(), chordSt.noteheads[0].position.xMm, baseLine);
ret.add(sts);
// when middle or end syllable, add a hypen between the preceding syllable and this syllable
if (// TODO: frame breaks...
lastLyric != null) {
if (lyricType == SyllableType.Middle || lyricType == SyllableType.End) {
StaffTextStamping hyphenStamping = lyricStamper.createHyphenStamping(lastLyric, sts, defaultLyricStyle);
ret.add(hyphenStamping);
}
}
// remember this lyric as the currently last one in the current staff and verse
lastLyrics.set(staffIndex, lyric.getVerse(), sts);
}
}
baseLine += -5;
}
}
// directions
ret.addAll(directionStamper.stampForChord(chordSt, context.layouter.symbols));
// tuplet
Tuplet tuplet = element.getTuplet();
if (tuplet != null) {
openTupletsCache.addChord(element, tuplet, chordSt);
}
return ret;
}
Aggregations