Search in sources :

Example 11 with VoiceElement

use of com.xenoage.zong.core.music.VoiceElement 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));
}
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 12 with VoiceElement

use of com.xenoage.zong.core.music.VoiceElement in project Zong by Xenoage.

the class VoicesBeatOffsetterTest method createVoiceSpacings.

/**
 * Create {@link VoiceSpacing}s for the first measure column
 * of the given {@link Score}.
 */
private LinkedList<VoiceSpacing> createVoiceSpacings(Score score) {
    LinkedList<VoiceSpacing> ret = new LinkedList<>();
    for (int iStaff : range(0, score.getStavesCount() - 1)) {
        Measure measure = score.getMeasure(atMeasure(iStaff, 0));
        for (Voice voice : measure.getVoices()) {
            Fraction beat = Companion.fr(0);
            ArrayList<ElementSpacing> se = alist();
            float offset = 0;
            for (VoiceElement e : voice.getElements()) {
                // compute width
                float width = 0;
                if (e.getDuration().equals(Companion.get_0()))
                    width = width_grace;
                else if (e.getDuration().equals(dur_1_8))
                    width = width_1_8;
                else if (e.getDuration().equals(dur_1_6))
                    width = width_1_6;
                else if (e.getDuration().equals(dur_1_4))
                    width = width_1_4;
                else if (e.getDuration().equals(dur_3_8))
                    width = width_3_8;
                else if (e.getDuration().equals(dur_1_2))
                    width = width_1_2;
                else if (e.getDuration().equals(dur_1_1))
                    width = width_1_1;
                // create spacing element with offset
                se.add(new ChordSpacing(new ChordNotation((Chord) e), beat, offset));
                beat = beat.add(e.getDuration());
                offset += width;
            }
            se.add(new BorderSpacing(beat, offset));
            ret.add(new VoiceSpacing(voice, score.getFormat().getInterlineSpace(), se));
        }
    }
    return ret;
}
Also used : ChordNotation(com.xenoage.zong.musiclayout.notation.ChordNotation) Fraction(com.xenoage.utils.math.Fraction) LinkedList(java.util.LinkedList) VoiceElement(com.xenoage.zong.core.music.VoiceElement) Measure(com.xenoage.zong.core.music.Measure) Voice(com.xenoage.zong.core.music.Voice)

Example 13 with VoiceElement

use of com.xenoage.zong.core.music.VoiceElement in project Zong by Xenoage.

the class SingleVoiceSpacerTest method testGrace1.

/**
 * Computes a voice spacing with grace notes,
 * where the element before the grace notes has enough empty rear space
 * to take all the grace notes.
 * <pre>
 * Single elements: [-r1------------][g1][g2][--r4--]
 * Combined:        --r1----~g1~g2~~~r4---
 * </pre> (~: area used by two elements)
 */
@Test
public void testGrace1() {
    // 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, 13), 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, 300f, Companion.fr(4, 4), 5, notations, layoutSettings);
    // check spacing
    ElementSpacing[] ses = vs.elements.toArray(new ElementSpacing[0]);
    ;
    float s = layoutSettings.offsetMeasureStart;
    assertEquals(5, ses.length);
    assertEquals(s + 2, ses[0].xIs, DELTA_FLOAT);
    assertEquals(s + 9, ses[1].xIs, DELTA_FLOAT);
    assertEquals(s + 12, ses[2].xIs, DELTA_FLOAT);
    assertEquals(s + 17, ses[3].xIs, DELTA_FLOAT);
    assertEquals(s + 22, 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);
}
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)

Example 14 with VoiceElement

use of com.xenoage.zong.core.music.VoiceElement 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, 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);
}
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)

Example 15 with VoiceElement

use of com.xenoage.zong.core.music.VoiceElement in project Zong by Xenoage.

the class Test21f method test.

@Test
public void test() {
    Score score = getScore();
    // 1/4 with 3 notes at beat 0
    List<VoiceElement> e = score.getVoice(mp0).getElements();
    Chord chord = (Chord) e.get(0);
    assertEquals(3, chord.getNotes().size());
    assertEquals(Companion.fr(1, 4), chord.getDuration());
    // followed by 2 rests, 1/4 and 2/4
    assertEquals(Companion.fr(1, 4), ((Rest) e.get(1)).getDuration());
    assertEquals(Companion.fr(2, 4), ((Rest) e.get(2)).getDuration());
    // segno at beat 1/4 in column (moved to the end of the measure, since we accept no mid-measure segnos)
    Direction segno = (Segno) score.getColumnHeader(0).getNavigationOrigin();
    assertNotNull(segno);
    // dynamics p at beat 1/4 in measure
    Dynamic dynamics = (Dynamic) score.getMeasure(mp0).getDirections().get(Companion.fr(1, 4));
    assertNotNull(dynamics);
    assertEquals(DynamicValue.p, dynamics.getValue());
}
Also used : Score(com.xenoage.zong.core.Score) Dynamic(com.xenoage.zong.core.music.direction.Dynamic) VoiceElement(com.xenoage.zong.core.music.VoiceElement) Segno(com.xenoage.zong.core.music.direction.Segno) Chord(com.xenoage.zong.core.music.chord.Chord) Direction(com.xenoage.zong.core.music.direction.Direction) Test(org.junit.Test)

Aggregations

VoiceElement (com.xenoage.zong.core.music.VoiceElement)17 Voice (com.xenoage.zong.core.music.Voice)12 Test (org.junit.Test)11 Chord (com.xenoage.zong.core.music.chord.Chord)8 ElementSpacing (com.xenoage.zong.musiclayout.spacing.ElementSpacing)6 VoiceSpacing (com.xenoage.zong.musiclayout.spacing.VoiceSpacing)6 ChordNotation (com.xenoage.zong.musiclayout.notation.ChordNotation)5 RestNotation (com.xenoage.zong.musiclayout.notation.RestNotation)5 ElementWidth (com.xenoage.zong.musiclayout.spacing.ElementWidth)5 Measure (com.xenoage.zong.core.music.Measure)4 Staff (com.xenoage.zong.core.music.Staff)4 VoiceTest (com.xenoage.zong.core.music.VoiceTest)4 Notations (com.xenoage.zong.musiclayout.notation.Notations)4 LayoutSettingsTest (com.xenoage.zong.musiclayout.settings.LayoutSettingsTest)4 Fraction (com.xenoage.utils.math.Fraction)3 Pitch (com.xenoage.zong.core.music.Pitch)2 SlurWaypoint (com.xenoage.zong.core.music.slur.SlurWaypoint)2 ToDo (musicxmltestsuite.tests.utils.ToDo)2 Score (com.xenoage.zong.core.Score)1 MusicElement (com.xenoage.zong.core.music.MusicElement)1