Search in sources :

Example 21 with ElementSpacing

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));
}
Also used : ElementWidth(com.xenoage.zong.musiclayout.spacing.ElementWidth) ChordNotation(com.xenoage.zong.musiclayout.notation.ChordNotation) RestNotation(com.xenoage.zong.musiclayout.notation.RestNotation) Fraction(com.xenoage.utils.math.Fraction) Notation(com.xenoage.zong.musiclayout.notation.Notation) RestNotation(com.xenoage.zong.musiclayout.notation.RestNotation) ChordNotation(com.xenoage.zong.musiclayout.notation.ChordNotation) ElementSpacing(com.xenoage.zong.musiclayout.spacing.ElementSpacing) ChordSpacing(com.xenoage.zong.musiclayout.spacing.ChordSpacing) BorderSpacing(com.xenoage.zong.musiclayout.spacing.BorderSpacing) VoiceElement(com.xenoage.zong.core.music.VoiceElement) VoiceSpacing(com.xenoage.zong.musiclayout.spacing.VoiceSpacing)

Example 22 with ElementSpacing

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);
}
Also used : ElementSpacing(com.xenoage.zong.musiclayout.spacing.ElementSpacing) Rest(com.xenoage.zong.core.music.rest.Rest) Clef(com.xenoage.zong.core.music.clef.Clef) VoiceSpacing(com.xenoage.zong.musiclayout.spacing.VoiceSpacing) Test(org.junit.Test)

Example 23 with ElementSpacing

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);
}
Also used : ElementSpacing(com.xenoage.zong.musiclayout.spacing.ElementSpacing) BeatOffset(com.xenoage.zong.musiclayout.spacing.BeatOffset) VoiceSpacing(com.xenoage.zong.musiclayout.spacing.VoiceSpacing) Test(org.junit.Test)

Example 24 with ElementSpacing

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);
}
Also used : ElementSpacing(com.xenoage.zong.musiclayout.spacing.ElementSpacing) BeatOffset(com.xenoage.zong.musiclayout.spacing.BeatOffset) VoiceSpacing(com.xenoage.zong.musiclayout.spacing.VoiceSpacing) Test(org.junit.Test)

Example 25 with ElementSpacing

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);
}
Also used : ElementSpacing(com.xenoage.zong.musiclayout.spacing.ElementSpacing) ElementWidth(com.xenoage.zong.musiclayout.spacing.ElementWidth) ChordNotation(com.xenoage.zong.musiclayout.notation.ChordNotation) VoiceElement(com.xenoage.zong.core.music.VoiceElement) RestNotation(com.xenoage.zong.musiclayout.notation.RestNotation) Notations(com.xenoage.zong.musiclayout.notation.Notations) VoiceSpacing(com.xenoage.zong.musiclayout.spacing.VoiceSpacing) Voice(com.xenoage.zong.core.music.Voice) Test(org.junit.Test) VoiceTest(com.xenoage.zong.core.music.VoiceTest) LayoutSettingsTest(com.xenoage.zong.musiclayout.settings.LayoutSettingsTest)

Aggregations

ElementSpacing (com.xenoage.zong.musiclayout.spacing.ElementSpacing)26 VoiceSpacing (com.xenoage.zong.musiclayout.spacing.VoiceSpacing)17 Test (org.junit.Test)11 BeatOffset (com.xenoage.zong.musiclayout.spacing.BeatOffset)10 ElementWidth (com.xenoage.zong.musiclayout.spacing.ElementWidth)7 Fraction (com.xenoage.utils.math.Fraction)6 VoiceElement (com.xenoage.zong.core.music.VoiceElement)6 Voice (com.xenoage.zong.core.music.Voice)5 Clef (com.xenoage.zong.core.music.clef.Clef)5 ChordNotation (com.xenoage.zong.musiclayout.notation.ChordNotation)5 Notation (com.xenoage.zong.musiclayout.notation.Notation)5 RestNotation (com.xenoage.zong.musiclayout.notation.RestNotation)5 MusicElement (com.xenoage.zong.core.music.MusicElement)4 VoiceTest (com.xenoage.zong.core.music.VoiceTest)4 ClefNotation (com.xenoage.zong.musiclayout.notation.ClefNotation)4 Notations (com.xenoage.zong.musiclayout.notation.Notations)4 LayoutSettingsTest (com.xenoage.zong.musiclayout.settings.LayoutSettingsTest)4 LeadingSpacing (com.xenoage.zong.musiclayout.spacing.LeadingSpacing)4 TraditionalKeyNotation (com.xenoage.zong.musiclayout.notation.TraditionalKeyNotation)3 Stamping (com.xenoage.zong.musiclayout.stampings.Stamping)3