package com.xenoage.zong.musiclayout.spacer.beam.slant; import com.xenoage.zong.core.music.clef.ClefType; import com.xenoage.zong.musiclayout.notation.BeamNotation; import com.xenoage.zong.musiclayout.spacer.beam.Slant; import lombok.val; import static com.xenoage.utils.collections.ArrayUtils.getFirst; import static com.xenoage.utils.collections.ArrayUtils.getLast; import static com.xenoage.utils.kernel.Range.range; import static com.xenoage.zong.musiclayout.spacer.beam.Slant.horizontalSlant; import static com.xenoage.zong.musiclayout.spacer.beam.slant.SingleStaffBeamSlanter.singleStaffBeamSlanter; /** * Computes the {@link Slant} of a beam that spans over two adjacent staves. * * The beam line is drawn between the staves, so that this class expects all stems * of the upper staff to point down, while the stems of the lower staff must point up. * * For the slant, we use a simple subset of the rules of the single staff beam, * pretending the beam chords to be placed on a single staff instead of two ones. * * @author Andreas Wenger */ public class TwoStavesBeamSlanter { public static final TwoStavesBeamSlanter twoStavesBeamSlanter = new TwoStavesBeamSlanter(); public Slant compute(BeamNotation beam) { //compute LPs, all within a single staff. imagine a beam on two staves (g- and f-clef). //the first note d1 on the upper staff and the second note c1 on the lower staff. //the c1 has a much higher LP due to the f-clef, but in the musical sense, it is a lower note, //so we expect the beam to fall. we find the musical direction by positioning all notes on a //single staff (here, by imagining a g-clef staff). int[] singleStaffLps = new int[beam.chords.size()]; val clef = ClefType.clefTreble; for (int i : range(singleStaffLps)) { val pitch = beam.chords.get(i).getStemSideNotePitch(); singleStaffLps[i] = clef.getLp(pitch); } return compute(singleStaffLps); } /** * This method contains a subset of the rules defined in {@link SingleStaffBeamSlanter}. */ public Slant compute(int... singleStaffLps) { int leftLp = getFirst(singleStaffLps); int rightLp = getLast(singleStaffLps); //Ross, p. 115, row 1: use horizontal beam, if first and last note is on the same LP if (leftLp == rightLp) return horizontalSlant; //otherwise normal slanting return singleStaffBeamSlanter.computeNormal(leftLp, rightLp); } }