package com.xenoage.zong.io.musicxml.in.readers; import static com.xenoage.utils.NullUtils.notNull; import static com.xenoage.utils.math.Fraction._1; import static com.xenoage.utils.math.Fraction.fr; import static com.xenoage.zong.core.music.format.SP.sp; import com.xenoage.utils.annotations.MaybeNull; import com.xenoage.utils.math.Fraction; import com.xenoage.utils.math.VSide; import com.xenoage.zong.core.music.format.BezierPoint; import com.xenoage.zong.core.music.format.SP; import com.xenoage.zong.core.text.Alignment; import com.xenoage.zong.musicxml.types.MxlBezier; import com.xenoage.zong.musicxml.types.attributes.MxlPosition; import com.xenoage.zong.musicxml.types.enums.MxlLeftCenterRight; import com.xenoage.zong.musicxml.types.enums.MxlPlacement; /** * Reads some other MusicXML elements. * * @author Andreas Wenger */ public final class OtherReader { @MaybeNull public static Alignment readAlignment(MxlLeftCenterRight mxlLeftCenterRight) { switch (mxlLeftCenterRight) { case Left: return Alignment.Left; case Center: return Alignment.Center; case Right: return Alignment.Right; default: return null; } } @MaybeNull public static BezierPoint readBezierPoint(MxlPosition mxlPosition, MxlBezier mxlBezier, float tenthsMm, int staffLinesCount, float noteLP, Fraction chordDuration) { Float px = mxlPosition.getDefaultX(); Float py = mxlPosition.getDefaultY(); Float cx = (mxlBezier != null ? mxlBezier.getBezierX() : null); Float cy = (mxlBezier != null ? mxlBezier.getBezierY() : null); SP point = null; SP control = null; float halfNoteWidth = getNoteheadWidth(chordDuration) / 2; if (px != null && py != null) { float fpx = notNull(px, 0).floatValue(); float fpy = notNull(py, 0).floatValue(); //default-x is relative to left side of note. thus, substract the half width //of a note (TODO: note type. e.g., whole note is wider) point = sp((fpx / 10 - halfNoteWidth) * tenthsMm, (staffLinesCount - 1) * 2 + fpy / 10 * 2 - noteLP); } if (cx != null && cy != null) { float fcx = notNull(cx, 0).floatValue(); float fcy = notNull(cy, 0).floatValue(); control = sp((fcx / 10 - halfNoteWidth) * tenthsMm, fcy / 10 * 2); } if (point != null || control != null) return new BezierPoint(point, control); else return null; } /** * Returns the duration as a {@link Fraction} from the given duration in divisions. */ public static Fraction readDuration(int duration, int divisionsPerQuarter) { Fraction ret = fr(duration, 4 * divisionsPerQuarter); return ret; } @MaybeNull public static VSide readVSide(MxlPlacement mxlPlacement) { if (mxlPlacement == MxlPlacement.Above) return VSide.Top; else if (mxlPlacement == MxlPlacement.Below) return VSide.Bottom; else return null; } //TIDY: see ChordWidths, but is defined in layout project private static float getNoteheadWidth(Fraction chordDuration) { if (chordDuration.compareTo(_1) < 0) return 1.2f; //quarter or half notehead else return 2f; //whole note } }