Search in sources :

Example 1 with VSide

use of com.xenoage.utils.math.VSide in project Zong by Xenoage.

the class ArticulationsNotator method compute.

/**
 * Computes the notations of the articulations of the given chord.
 * If there are no articulations, {@link ArticulationsNotation#empty} is returned.
 */
public ArticulationsNotation compute(Chord chord, StemDirection stemDirection, NotesNotation notesAlignment, int linesCount) {
    // depending on the stem direction, place the articulation on the other side.
    // if there is no stem direction, always place at the top
    VSide side = (stemDirection == StemDirection.Up ? VSide.Bottom : VSide.Top);
    // dependent on the side of the articulation, take the top or bottom note
    NoteDisplacement outerNote = (side == VSide.Top ? notesAlignment.getTopNote() : notesAlignment.getBottomNote());
    // compute alignment of articulations
    return compute(chord.getArticulations(), outerNote, side, linesCount);
}
Also used : NoteDisplacement(com.xenoage.zong.musiclayout.notation.chord.NoteDisplacement) VSide(com.xenoage.utils.math.VSide)

Example 2 with VSide

use of com.xenoage.utils.math.VSide in project Zong by Xenoage.

the class SlurReader method readToContext.

public static void readToContext(Chord chord, int noteIndex, int staffIndexInPart, Context context, MxlSlurOrTied mxlSlur) {
    Pitch pitch = chord.getNotes().get(noteIndex).getPitch();
    float noteLP = context.getMusicContext(staffIndexInPart).getLp(pitch);
    // type
    SlurType type = (mxlSlur.getElementType() == MxlElementType.Slur ? SlurType.Slur : SlurType.Tie);
    // number (tied does usually not use a number, but is distinguished by pitch)
    Integer number = mxlSlur.getNumber();
    BezierPoint bezierPoint = readBezierPoint(mxlSlur.getPosition(), mxlSlur.getBezier(), context.getTenthMm(), context.getStaffLinesCount(staffIndexInPart), noteLP, chord.getDuration());
    VSide side = readVSide(mxlSlur.getPlacement());
    // waypoint
    SlurWaypoint wp = new SlurWaypoint(chord, noteIndex, bezierPoint);
    if (type == SlurType.Tie && number == null) {
        // unnumbered tied
        OpenUnnumberedTieds openTieds = context.getOpenElements().getOpenUnnumberedTies();
        if (mxlSlur.getType() == MxlStartStopContinue.Start) {
            openTieds.startTied(wp, side);
        } else if (mxlSlur.getType() == MxlStartStopContinue.Stop) {
            OpenSlur openTied = openTieds.stopTied(wp, side, context);
            if (openTied != null)
                context.createSlur(openTied);
        }
    } else {
        // numbered
        WaypointPosition wpPos;
        if (mxlSlur.getType() == MxlStartStopContinue.Start)
            wpPos = WaypointPosition.Start;
        else if (mxlSlur.getType() == MxlStartStopContinue.Stop)
            wpPos = WaypointPosition.Stop;
        else
            wpPos = WaypointPosition.Continue;
        context.registerSlur(type, wpPos, number, wp, side);
    }
}
Also used : BezierPoint(com.xenoage.zong.core.music.format.BezierPoint) OtherReader.readBezierPoint(com.xenoage.zong.io.musicxml.in.readers.OtherReader.readBezierPoint) WaypointPosition(com.xenoage.zong.core.music.WaypointPosition) OpenSlur(com.xenoage.zong.io.musicxml.in.util.OpenSlur) Pitch(com.xenoage.zong.core.music.Pitch) SlurType(com.xenoage.zong.core.music.slur.SlurType) OtherReader.readVSide(com.xenoage.zong.io.musicxml.in.readers.OtherReader.readVSide) VSide(com.xenoage.utils.math.VSide) SlurWaypoint(com.xenoage.zong.core.music.slur.SlurWaypoint) OpenUnnumberedTieds(com.xenoage.zong.io.musicxml.in.util.OpenUnnumberedTieds)

Example 3 with VSide

use of com.xenoage.utils.math.VSide in project Zong by Xenoage.

the class StemReader method read.

/**
 * Reads and returns the stem of the given chord.
 * If not available, {@link Stem#defaultStem} is returned.
 * @param context   the global context
 * @param chord     the chord, whose notes are already collected
 * @param staff     the staff index of the current chord
 */
public Stem read(Context context, Chord chord, int staff) {
    if (mxlStem == null)
        return Companion.getDefaultStem();
    // direction
    StemDirection direction = readStemDirection();
    // length
    Float length = null;
    MxlPosition yPos = mxlStem.getPosition();
    if (yPos.getDefaultY() != null) {
        // convert position in tenths relative to topmost staff line into
        // a length in interline spaces measured from the outermost chord note on stem side
        float stemEndLinePosition = convertDefaultYToLP(context, yPos.getDefaultY(), staff);
        VSide side = (direction == StemDirection.Up ? VSide.Top : VSide.Bottom);
        length = Math.abs(stemEndLinePosition - getOuterNoteLp(context, chord, side, staff)) / 2;
    }
    // create stem
    return new Stem(direction, length);
}
Also used : MxlPosition(com.xenoage.zong.musicxml.types.attributes.MxlPosition) StemDirection(com.xenoage.zong.core.music.chord.StemDirection) VSide(com.xenoage.utils.math.VSide) Stem.defaultStem(com.xenoage.zong.core.music.chord.Stem.defaultStem) MxlStem(com.xenoage.zong.musicxml.types.MxlStem) Stem(com.xenoage.zong.core.music.chord.Stem)

Example 4 with VSide

use of com.xenoage.utils.math.VSide in project Zong by Xenoage.

the class QuadraticCurvesTools method computeOverConvexHull.

/**
 * Computes a list of possible quadratic curves over the given {@link ConvexHull},
 * that start at the first point of the hull and end at the last point of the hull,
 * but may also start and end further away according to the given parameters. The curve
 * will not cross the area of the convex hull.
 * @param convexHull  the convex hull
 * @param leftArea    the tolerance of the distance of the start point
 *                    (between 0 and this value). always positive or 0.
 * @param rightArea   the tolerance of the distance of the end point
 *                    (between 0 and this value). always positive or 0.
 * @return  a list of possible quadratic curves
 */
public static List<QuadraticCurve> computeOverConvexHull(ConvexHull convexHull, float leftArea, float rightArea) {
    LinkedList<QuadraticCurve> ret = new LinkedList<>();
    ArrayList<Point2f> points = convexHull.getPoints();
    VSide side = convexHull.getSide();
    int sideDir = side.getDir();
    int n = points.size();
    // compute the possible start and endpoints
    Point2f[] startPoints = new Point2f[] { points.get(0), points.get(0).add(0, sideDir * leftArea) };
    Point2f[] endPoints = new Point2f[] { points.get(n - 1), points.get(n - 1).add(0, sideDir * rightArea) };
    // the quadratic expression {a, b, c} for ax² + bx + c = 0
    // equations:
    // - (2): must start at startPoints[0] or startPoints[1] (between is never optimal!)
    // - (2): must end at endPoints[0] or endPoints[1] (between is never optimal!)
    // inequations:
    // - (0): a must be <=/>= 0 (parabola is open on the bottom/top side, dependent
    // on the side of the convex hull) - not used in SLE, checked later
    // - (m): curve must be above/below each of the m = n-2 middle points (dependent on the side)
    int m = n - 2;
    Point2f[] eq = new Point2f[2 + 2 + m];
    eq[0] = startPoints[0];
    eq[1] = startPoints[1];
    eq[2] = endPoints[0];
    eq[3] = endPoints[1];
    for (int i = 0; i < m; i++) {
        eq[4 + i] = points.get(1 + i);
    }
    // strategy, based on the simplex algorithm for linear optimization:
    // for each possible combination of 3 equations (optimum is always at the corner of the simplex,
    // so we can use the inequations like equations), solve the SLE, test, if the curve is
    // valid for all inequations, and if so, compute the area between the curve and the convex hull.
    // take the curve which has the smallest area.
    // there are ((m+4) choose 3) possible SLEs, but we have to ignore those where eq[0] AND eq[1]
    // are used and those where eq[2] AND eq[3] are used.
    int[][] subsets = getAllCombinationsOf3(m + 4);
    for (int[] eqIndices : subsets) {
        // not useable: {0,1,?}, {2,3,?} and {?,2,3}
        if (eqIndices[0] == 0 && eqIndices[1] == 1 || eqIndices[0] == 2 && eqIndices[1] == 3 || eqIndices[1] == 2 && eqIndices[2] == 3) {
        // ignore
        } else {
            // usable. solve SLE
            double[][] A = new double[3][3];
            double[] b = new double[3];
            for (int iy = 0; iy < 3; iy++) {
                Point2f p = eq[eqIndices[iy]];
                A[iy][0] = p.x * p.x;
                A[iy][1] = p.x;
                A[iy][2] = 1;
                b[iy] = p.y;
            }
            double[] params = Gauss.solve(A, b);
            // parameters ok for all equations?
            boolean ok = true;
            ok &= sideDir * getY(startPoints[0].x, params) >= sideDir * startPoints[0].y;
            ok &= sideDir * getY(startPoints[1].x, params) <= sideDir * startPoints[1].y;
            ok &= sideDir * getY(endPoints[0].x, params) >= sideDir * endPoints[0].y;
            ok &= sideDir * getY(endPoints[1].x, params) <= sideDir * endPoints[1].y;
            // parabole is open on the bottom/top side
            ok &= sideDir * params[0] <= 0;
            for (int im = 0; ok && im < m; im++) {
                ok &= sideDir * getY(points.get(1 + im).x, params) >= sideDir * points.get(1 + im).y;
            }
            if (ok) {
                // remember this equation
                ret.add(new QuadraticCurve((float) params[0], (float) params[1], (float) params[2]));
            }
        }
    }
    if (ret.size() == 0) {
        // no curve found. use direct line between first and last point.
        double[][] A = new double[][] { { points.get(0).x, 1 }, { points.get(n - 1).x, 1 } };
        double[] b = new double[] { points.get(0).y, points.get(n - 1).y };
        double[] params = Gauss.solve(A, b);
        ret.add(new QuadraticCurve(0f, (float) params[0], (float) params[1]));
    }
    // return result
    return ret;
}
Also used : LinkedList(java.util.LinkedList) VSide(com.xenoage.utils.math.VSide) QuadraticCurve(com.xenoage.utils.math.QuadraticCurve) Point2f(com.xenoage.utils.math.geom.Point2f)

Example 5 with VSide

use of com.xenoage.utils.math.VSide 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;
}
Also used : lombok.val(lombok.val) WaypointPosition(com.xenoage.zong.core.music.WaypointPosition) SlurWaypoint(com.xenoage.zong.core.music.slur.SlurWaypoint) SlurWaypoint(com.xenoage.zong.core.music.slur.SlurWaypoint) VSide(com.xenoage.utils.math.VSide) Beam(com.xenoage.zong.core.music.beam.Beam) Tuplet(com.xenoage.zong.core.music.tuplet.Tuplet) Slur(com.xenoage.zong.core.music.slur.Slur) Lyric(com.xenoage.zong.core.music.lyric.Lyric) SyllableType(com.xenoage.zong.core.music.lyric.SyllableType) Chord(com.xenoage.zong.core.music.chord.Chord) ChordStampings(com.xenoage.zong.musiclayout.layouter.scoreframelayout.util.ChordStampings) SP(com.xenoage.zong.core.music.format.SP)

Aggregations

VSide (com.xenoage.utils.math.VSide)6 SlurWaypoint (com.xenoage.zong.core.music.slur.SlurWaypoint)3 WaypointPosition (com.xenoage.zong.core.music.WaypointPosition)2 BezierPoint (com.xenoage.zong.core.music.format.BezierPoint)2 SP (com.xenoage.zong.core.music.format.SP)2 Slur (com.xenoage.zong.core.music.slur.Slur)2 QuadraticCurve (com.xenoage.utils.math.QuadraticCurve)1 Point2f (com.xenoage.utils.math.geom.Point2f)1 Pitch (com.xenoage.zong.core.music.Pitch)1 Beam (com.xenoage.zong.core.music.beam.Beam)1 Chord (com.xenoage.zong.core.music.chord.Chord)1 Stem (com.xenoage.zong.core.music.chord.Stem)1 Stem.defaultStem (com.xenoage.zong.core.music.chord.Stem.defaultStem)1 StemDirection (com.xenoage.zong.core.music.chord.StemDirection)1 Lyric (com.xenoage.zong.core.music.lyric.Lyric)1 SyllableType (com.xenoage.zong.core.music.lyric.SyllableType)1 SlurType (com.xenoage.zong.core.music.slur.SlurType)1 Tuplet (com.xenoage.zong.core.music.tuplet.Tuplet)1 OtherReader.readBezierPoint (com.xenoage.zong.io.musicxml.in.readers.OtherReader.readBezierPoint)1 OtherReader.readVSide (com.xenoage.zong.io.musicxml.in.readers.OtherReader.readVSide)1