use of com.xenoage.zong.musiclayout.spacing.ElementSpacing 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._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 : 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));
}
use of com.xenoage.zong.musiclayout.spacing.ElementSpacing in project Zong by Xenoage.
the class MeasureElementsSpacerTest method testNeedAdditionalSpace.
/**
* If there is not enough space left for the measure elements,
* the voice spacings have to be moved to create enough space.
* To understand the following sketch, have a look at the comments
* in {@link MeasureElementsSpacer}.
* <pre>
* enough space:
* beat: 0 2 4 6 8
* offset: 3 5 7 9 13 17 21
* . . . . . . . . . .
* clef: *[clef]* (on beat 4)
* voice 1: o 2
* voice 2: 1 o
* </pre>
* Between VE1 and VE2, there are 6 spaces.
* Assuming a padding width of 1 and a clef width of 6,
* the clef can be moved two spaces to the left, but this is not
* enough. All elements at or after beat 3 have to be moved 2 spaces
* to the right.
*/
@Test
public void testNeedAdditionalSpace() {
Rest[] ve = ve();
List<VoiceSpacing> vs = alist(new VoiceSpacing(null, 1, alist(spacing(ve[0], fr(1, 2), 4), spacing(ve[1], fr(4), 11))), new VoiceSpacing(null, 1, alist(spacing(ve[2], fr(1), 5), spacing(ve[3], fr(13, 2), 16))));
Clef innerClef = new Clef(ClefType.clefTreble);
BeatEList<Clef> innerClefs = beatEList();
innerClefs.add(beatE(innerClef, fr(4)));
List<ElementSpacing> mes = testee.compute(innerClefs, beatEList(), null, false, vs, 0, notations(ve, innerClef), ls);
// voice spacings
assertEquals(2, vs.size());
assertEqualsSpacings(ilist(spacing(ve[0], fr(1, 2), 4), spacing(ve[1], fr(4), 13)), vs.get(0).elements);
assertEqualsSpacings(ilist(spacing(ve[2], fr(1), 5), spacing(ve[3], fr(13, 2), 18)), vs.get(1).elements);
// clef must be at offset 13 - padding - clefwidth/2
ElementSpacing[] se = mes.toArray(new ElementSpacing[0]);
assertEquals(1, se.length);
assertEquals(fr(4), se[0].beat);
assertEquals(13 - paddingWidth - clefWidth / 2, se[0].xIs, Delta.DELTA_FLOAT);
}
use of com.xenoage.zong.musiclayout.spacing.ElementSpacing in project Zong by Xenoage.
the class AlignedVoicesSpacerTest method computeTest2.
@Test
public void computeTest2() {
float is = 3;
// voice spacing:
// beats: 0.2
// offsets: | |
// | ⌎- 2
// ⌎--- 0
VoiceSpacing voiceSpacing = new VoiceSpacing(voice(), is, alist(spacing(beat(0), 0f), spacing(beat(2), 2f)));
// given beat offsets:
// beats: 0.2
// offsets: | |
// | ⌎- 2
// ⌎--- 0
List<BeatOffset> beatOffsets = alist(new BeatOffset(beat(0), 0f), new BeatOffset(beat(2), 2f));
// shared beats: 0, 2.
//
// resulting spacing:
// beats: 0.2
// offsets: | |
// | ⌎- 2
// ⌎--- 0
testee.compute(voiceSpacing, beatOffsets);
List<ElementSpacing> finalSpacing = voiceSpacing.elements;
assertEquals(2, finalSpacing.size());
assertEquals(beat(0), finalSpacing.get(0).beat);
assertEquals(0f / is, finalSpacing.get(0).xIs, df);
assertEquals(beat(2), finalSpacing.get(1).beat);
assertEquals(2f / is, finalSpacing.get(1).xIs, df);
}
use of com.xenoage.zong.musiclayout.spacing.ElementSpacing in project Zong by Xenoage.
the class AlignedVoicesSpacerTest method computeTest3.
@Test
public void computeTest3() {
float is = 4;
// voice spacing:
// beats: 0.2
// offsets: | |
// | ⌎- 2
// ⌎--- 0
VoiceSpacing voiceSpacing = new VoiceSpacing(voice(), is, alist(spacing(beat(0), 0f), spacing(beat(2), 2f)));
// given beat offsets:
// beats: 0.2
// offsets: | |
// | ⌎- 6
// ⌎--- 2
List<BeatOffset> beatOffsets = alist(new BeatOffset(beat(0), 2f), new BeatOffset(beat(2), 6f));
// shared beats: 0, 2.
//
// resulting spacing:
// beats: 0.2
// offsets: | |
// | ⌎- 6
// ⌎--- 2
testee.compute(voiceSpacing, beatOffsets);
List<ElementSpacing> finalSpacing = voiceSpacing.elements;
assertEquals(2, finalSpacing.size());
assertEquals(beat(0), finalSpacing.get(0).beat);
assertEquals(2f / is, finalSpacing.get(0).xIs, df);
assertEquals(beat(2), finalSpacing.get(1).beat);
assertEquals(6f / is, finalSpacing.get(1).xIs, df);
}
use of com.xenoage.zong.musiclayout.spacing.ElementSpacing in project Zong by Xenoage.
the class SingleVoiceSpacerTest method testGrace3.
/**
* Computes a voice spacing with grace notes,
* where the element before the grace notes has not enough empty rear space
* to take even a single 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 testGrace3() {
// 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, 3), 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, 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(fr(0, 8), ses[0].beat);
assertEquals(fr(2, 8), ses[1].beat);
assertEquals(fr(2, 8), ses[2].beat);
assertEquals(fr(2, 8), ses[3].beat);
assertEquals(fr(6, 8), ses[4].beat);
}
Aggregations