use of com.xenoage.zong.musiclayout.notation.ChordNotation in project Zong by Xenoage.
the class StretchMeasuresTest method createSystemWith1Measure.
/**
* Creates and returns a simple {@link SystemSpacing} with only one
* measure with a clef and two notes, using the given parameters.
* @param leadingWidth width of the leading spacing in mm
* @param offsetBeat0 offset of beat 1/4 in mm
* @param offsetBeat1 offset of beat 3/4 in mm
* @param offsetBeat2 width of the voice spacing in mm
*/
public static SystemSpacing createSystemWith1Measure(float leadingWidth, float offsetBeat0, float offsetBeat1, float offsetBeat2) {
Chord chord1 = chord(Companion.pi(0, 0, 4), Companion.fr(2, 4));
Chord chord2 = chord(Companion.pi(1, 0, 4), Companion.fr(2, 4));
Voice voice = new Voice(alist(chord1, chord2));
List<BeatOffset> beatOffsets = alist(new BeatOffset(Companion.fr(1, 4), offsetBeat0), new BeatOffset(Companion.fr(3, 4), offsetBeat1), new BeatOffset(Companion.fr(5, 4), offsetBeat2));
float is = 1;
List<VoiceSpacing> voiceSpacings = alist(new VoiceSpacing(voice, is, alist(new ChordSpacing(new ChordNotation(chord1), beatOffsets.get(0).getBeat(), beatOffsets.get(0).getOffsetMm()), new ChordSpacing(new ChordNotation(chord2), beatOffsets.get(1).getBeat(), beatOffsets.get(1).getOffsetMm()))));
MeasureSpacing measureSpacing = new MeasureSpacing(atMeasure(0, 0), is, voiceSpacings, empty, LeadingSpacingMock.createGClefSpacing(leadingWidth));
List<MeasureSpacing> measureSpacings = alist(measureSpacing);
ColumnSpacing mcs = new ColumnSpacing(-1, measureSpacings, beatOffsets, alist(new BeatOffset(Companion.fr(0, 4), 0), new BeatOffset(Companion.fr(6, 4), offsetBeat2)));
SystemSpacing system = new SystemSpacing(ilist(mcs), 0, 0, leadingWidth + offsetBeat2, null, 0);
return system;
}
use of com.xenoage.zong.musiclayout.notation.ChordNotation in project Zong by Xenoage.
the class SingleVoiceSpacerTest method testGrace2.
/**
* Computes a voice spacing with grace notes,
* where the element before the grace notes has enough empty rear space
* to take at least one of the grace notes.
* <pre>
* Single elements: [-r1------][g1][g2][--r4--]
* Combined: --r1_~g1~g2~~~r4---
* </pre> (~: area used by two elements, _: minimal distance between elements)
*/
@Test
public void testGrace2() {
// create voice and notations
Voice voice = new Voice(alist((VoiceElement) r1, g1, g2, r4));
Notations notations = new Notations();
notations.add(new RestNotation(r1, new ElementWidth(2, 2, 7), null));
notations.add(new ChordNotation(g1, new ElementWidth(1, 2, 1)));
notations.add(new ChordNotation(g2, new ElementWidth(1, 2, 1)));
notations.add(new RestNotation(r4, new ElementWidth(3, 2, 3), null));
// compute spacing
VoiceSpacing vs = testee.compute(voice, 400f, Companion.fr(4, 4), 5, notations, layoutSettings);
// check spacing
ElementSpacing[] ses = vs.elements.toArray(new ElementSpacing[0]);
;
float s = layoutSettings.offsetMeasureStart;
float d = layoutSettings.spacings.widthDistanceMin;
assertEquals(5, ses.length);
assertEquals(s + 2, ses[0].xIs, DELTA_FLOAT);
assertEquals(s + 5 + d, ses[1].xIs, DELTA_FLOAT);
assertEquals(s + 8 + d, ses[2].xIs, DELTA_FLOAT);
assertEquals(s + 13 + d, ses[3].xIs, DELTA_FLOAT);
assertEquals(s + 18 + d, ses[4].xIs, DELTA_FLOAT);
// check beats
assertEquals(Companion.fr(0, 8), ses[0].beat);
assertEquals(Companion.fr(2, 8), ses[1].beat);
assertEquals(Companion.fr(2, 8), ses[2].beat);
assertEquals(Companion.fr(2, 8), ses[3].beat);
assertEquals(Companion.fr(6, 8), ses[4].beat);
}
use of com.xenoage.zong.musiclayout.notation.ChordNotation in project Zong by Xenoage.
the class ChordNotator method compute.
public ChordNotation compute(Chord chord, Context context, @MaybeNull Notations notations) {
Score score = context.score;
float interlineSpace = score.getInterlineSpace(context.mp);
FontInfo lyricsFont = score.getFormat().getLyricFont();
MusicContext mc = score.getMusicContext(context.mp, BeforeOrAt, Before);
// grace or normal chord?
boolean grace = chord.isGrace();
ChordWidths chordWidths = (grace ? context.settings.graceChordWidths : context.settings.chordWidths);
ChordSpacings spacings = (grace ? context.settings.spacings.graceChordSpacings : context.settings.spacings.normalChordSpacings);
// use or compute stem direction
StemDirection stemDirection = chord.getStem().getDirection();
if (stemDirection == StemDirection.Default) {
// if stem direction was not computed yet, compute it now
if (notations != null)
stemDirection = notations.getChord(chord).stemDirection;
if (stemDirection == StemDirection.Default) {
Map<Chord, StemDirection> computedStems = stemDirector.compute(chord);
stemDirection = computedStems.get(chord);
// also remember the other computed stems
if (notations != null)
for (Chord computedChord : computedStems.keySet()) notations.getChord(computedChord).stemDirection = computedStems.get(computedChord);
}
}
// notes displacement
NotesNotation notes = notesNotator.compute(chord, stemDirection, chordWidths, mc);
float leftSuspendedWidth = (notes.leftSuspended ? notes.noteheadWidthIs : 0);
// accidentals
AccidentalsNotation accs = accidentalsNotator.compute(chord, notes, chordWidths, mc);
// symbol's width: width of the noteheads and dots
float symbolWidth = notes.widthIs - leftSuspendedWidth;
float frontGap = accs.widthIs + leftSuspendedWidth;
// rear gap: empty duration-dependent space behind the chord minus the symbol's width
float rearGap = spacings.getWidth(chord.getDisplayedDuration()) - symbolWidth;
// lyric width
float lyricWidth = 0;
TextMeasurer textMeasurer = platformUtils().getTextMeasurer();
for (Lyric lyric : chord.getLyrics()) {
if (lyric != null && lyric.getText() != null) {
// width of lyric in interline spaces
FormattedText lyricText = styleText(lyric.getText(), new FormattedTextStyle(lyricsFont));
float l = lyricText.getWidth() / interlineSpace;
// for start and end syllable, request "-" more space, for middle syllables "--"
// TODO: unsymmetric - start needs space on the right, end on the left, ...
SyllableType lyricType = lyric.getSyllableType();
if (lyricType == SyllableType.Begin || lyricType == SyllableType.End) {
l += textMeasurer.measure(lyricsFont, "-").getWidth() / interlineSpace;
} else if (lyricType == SyllableType.Middle) {
l += textMeasurer.measure(lyricsFont, "--").getWidth() / interlineSpace;
}
// save width of the widest lyric
lyricWidth = Math.max(lyricWidth, l);
}
}
// compute length of the stem (if any)
float scaling = grace ? context.settings.scalingGrace : 1;
StemNotation stem = stemNotator.compute(chord.getStem(), notes.getLps(), stemDirection, context.mp.getStaff(), Companion.staffLines(mc.getLinesCount()), scaling);
// compute articulations
ArticulationsNotation arts = articulationsNotator.compute(chord, stemDirection, notes, mc.getLinesCount());
return new ChordNotation(chord, chord.getMP(), new ElementWidth(frontGap, symbolWidth, rearGap, lyricWidth), context.mp.getStaff(), notes, stemDirection, stem, accs, arts);
}
use of com.xenoage.zong.musiclayout.notation.ChordNotation in project Zong by Xenoage.
the class VoiceStamper method stampVoice.
public List<Stamping> stampVoice(VoiceSpacing voice, float voiceXMm, StaffStampings staffStampings, boolean stampLeadingRests, StamperContext context, // TODO:
FormattedTextStyle defaultLyricStyle, Map<Beam, BeamSpacing> beams, OpenSlursCache openCurvedLinesCache, OpenLyricsCache openLyricsCache, LastLyrics lastLyrics, OpenTupletsCache openTupletsCache) {
List<Stamping> ret = alist();
// create the voice elements
boolean onlyRestsSoFar = true;
for (ElementSpacing spacingElement : voice.elements) {
MusicElement element = spacingElement.getElement();
if (element != null) /* TODO && (stampRests || !(element instanceof Rest)) */
{
Notation notation = context.getNotation(element);
float xMm = voiceXMm + spacingElement.xIs * voice.interlineSpace;
if (element instanceof Chord) {
// chord
onlyRestsSoFar = false;
Chord chord = (Chord) element;
BeamSpacing beam = beams.get(chord.getBeam());
ret.addAll(chordStamper.stampAll((ChordNotation) spacingElement.getNotation(), xMm, beam, staffStampings, context, defaultLyricStyle, openCurvedLinesCache, openLyricsCache, lastLyrics, openTupletsCache));
} else if (spacingElement instanceof RestSpacing) {
// rest
if (false == onlyRestsSoFar || stampLeadingRests) {
// not a leading rest, or a leading rest which should be stamped
ret.add(elementStamper.createRestStamping((RestSpacing) spacingElement, xMm, context));
}
} else {
throw new IllegalArgumentException("Notation not supported: " + notation);
}
}
}
return ret;
}
use of com.xenoage.zong.musiclayout.notation.ChordNotation in project Zong by Xenoage.
the class SingleVoiceSpacer method compute.
VoiceSpacing compute(Voice voice, float interlineSpace, Fraction measureBeats, int staffLinesCount, Notations notations, LayoutSettings layoutSettings) {
LinkedList<ElementSpacing> ret = llist();
// special case: no elements in the measure.
if (voice.getElements().size() == 0) {
return new VoiceSpacing(voice, interlineSpace, alist((ElementSpacing) new BorderSpacing(Fraction.Companion.get_0(), 0), new BorderSpacing(measureBeats, layoutSettings.spacings.widthMeasureEmpty)));
}
// we compute the spacings in reverse order. this is easier, since grace chords
// use shared space when possible, but are aligned to the right. so we begin
// at position 0, and create the spacings in reverse direction (thus we find negative positions).
// at the end, we shift the voice spacing to the right to be aligned at the left measure border,
// which is position 0.
// last symbol offset:
// real offset where the last element's symbol started
// since we do not know the right border yet, we start at 0
float lastSymbolOffset = 0;
// front gap offset:
// offset where the last element (including front gap) started.
float lastFrontGapOffset = lastSymbolOffset;
// last full element offset:
// lastSymbolOffset of the last full (non-grace) element
float lastFullSymbolOffset = lastSymbolOffset;
// at last beat
Fraction curBeat = voice.getFilledBeats();
ret.addFirst(new BorderSpacing(curBeat, lastFrontGapOffset));
// iterate through the elements in reverse order
for (VoiceElement element : Companion.reverseIt(voice.getElements())) {
// get the notation
Notation notation = notations.get(element);
if (notation == null)
throw new IllegalStateException("No notation for element " + element);
// get the width of the element (front gap, symbol's width, rear gap, lyric's width)
ElementWidth elementWidth = notation.getWidth();
// add spacing for voice element
float symbolOffset;
boolean grace = !element.getDuration().isGreater0();
if (!grace) {
// full element
// share this rear gap and the front gap of the following
// element + the space of following grace elements, when possible
// (but use at least minimal distance)
symbolOffset = Math.min(lastFrontGapOffset - layoutSettings.spacings.widthDistanceMin, lastFullSymbolOffset - elementWidth.rearGap) - elementWidth.symbolWidth;
lastFullSymbolOffset = symbolOffset;
// update beat cursor
curBeat = curBeat.sub(element.getDuration());
} else {
// grace element
// share this rear gap and the front gap of the following element, when possible
symbolOffset = Math.min(lastFrontGapOffset, lastSymbolOffset - elementWidth.rearGap) - elementWidth.symbolWidth;
}
ElementSpacing elementSpacing = null;
if (notation instanceof RestNotation) {
// rest spacing
elementSpacing = restSpacer.compute((RestNotation) notation, curBeat, symbolOffset, staffLinesCount);
} else {
// chord spacing
elementSpacing = new ChordSpacing((ChordNotation) notation, curBeat, symbolOffset);
}
ret.addFirst(elementSpacing);
lastFrontGapOffset = symbolOffset - elementWidth.frontGap;
lastSymbolOffset = symbolOffset;
}
// shift spacings to the right
float shift = (-lastFrontGapOffset) + layoutSettings.offsetMeasureStart;
for (ElementSpacing e : ret) e.xIs += shift;
return new VoiceSpacing(voice, interlineSpace, ilist(ret));
}
Aggregations