private void PaintTupletHelper(float cx, float cy, ICanvas canvas, TupletHelper h) { var res = Resources; var oldAlign = canvas.TextAlign; canvas.TextAlign = TextAlign.Center; // check if we need to paint simple footer if (h.Beats.Count == 1 || !h.IsFull) { for (int i = 0, j = h.Beats.Count; i < j; i++) { var beat = h.Beats[i]; var beamingHelper = Helpers.BeamHelperLookup[h.VoiceIndex][beat.Index]; if (beamingHelper == null) continue; var direction = beamingHelper.Direction; var tupletX = beamingHelper.GetBeatLineX(beat) + Scale; var tupletY = cy + Y + CalculateBeamY(beamingHelper, tupletX); var offset = direction == BeamDirection.Up ? res.EffectFont.Size * 1.8f : -3 * Scale; canvas.Font = res.EffectFont; canvas.FillText(h.Tuplet.ToString(), cx + X + tupletX, tupletY - offset); } } else { var firstBeat = h.Beats[0]; var lastBeat = h.Beats[h.Beats.Count - 1]; var firstBeamingHelper = Helpers.BeamHelperLookup[h.VoiceIndex][firstBeat.Index]; var lastBeamingHelper = Helpers.BeamHelperLookup[h.VoiceIndex][lastBeat.Index]; if (firstBeamingHelper != null && lastBeamingHelper != null) { var direction = firstBeamingHelper.Direction; // // Calculate the overall area of the tuplet bracket var startX = firstBeamingHelper.GetBeatLineX(firstBeat) + Scale; var endX = lastBeamingHelper.GetBeatLineX(lastBeat) + Scale; // // Calculate how many space the text will need canvas.Font = res.EffectFont; var s = h.Tuplet.ToString(); var sw = canvas.MeasureText(s); var sp = 3 * Scale; // // Calculate the offsets where to break the bracket var middleX = (startX + endX) / 2; var offset1X = middleX - sw / 2 - sp; var offset2X = middleX + sw / 2 + sp; // // calculate the y positions for our bracket var startY = CalculateBeamY(firstBeamingHelper, startX); var offset1Y = CalculateBeamY(firstBeamingHelper, offset1X); var middleY = CalculateBeamY(firstBeamingHelper, middleX); var offset2Y = CalculateBeamY(lastBeamingHelper, offset2X); var endY = CalculateBeamY(lastBeamingHelper, endX); var offset = 10 * Scale; var size = 5 * Scale; if (direction == BeamDirection.Down) { offset *= -1; size *= -1; } // // draw the bracket canvas.BeginPath(); canvas.MoveTo(cx + X + startX, (int)(cy + Y + startY - offset)); canvas.LineTo(cx + X + startX, (int)(cy + Y + startY - offset - size)); canvas.LineTo(cx + X + offset1X, (int)(cy + Y + offset1Y - offset - size)); canvas.Stroke(); canvas.BeginPath(); canvas.MoveTo(cx + X + offset2X, (int)(cy + Y + offset2Y - offset - size)); canvas.LineTo(cx + X + endX, (int)(cy + Y + endY - offset - size)); canvas.LineTo(cx + X + endX, (int)(cy + Y + endY - offset)); canvas.Stroke(); // // Draw the string canvas.FillText(s, cx + X + middleX, cy + Y + middleY - offset - size - res.EffectFont.Size); } } canvas.TextAlign = oldAlign; }
public BarHelpers(Bar bar) { BeamHelpers = new FastList <FastList <BeamingHelper> >(); BeamHelperLookup = new FastList <FastDictionary <int, BeamingHelper> >(); TupletHelpers = new FastList <FastList <TupletHelper> >(); BeamingHelper currentBeamHelper = null; TupletHelper currentTupletHelper = null; if (bar != null) { for (int i = 0, j = bar.Voices.Count; i < j; i++) { var v = bar.Voices[i]; BeamHelpers.Add(new FastList <BeamingHelper>()); BeamHelperLookup.Add(new FastDictionary <int, BeamingHelper>()); TupletHelpers.Add(new FastList <TupletHelper>()); for (int k = 0, l = v.Beats.Count; k < l; k++) { var b = v.Beats[k]; var forceNewTupletHelper = false; // if a new beaming helper was started, we close our tuplet grouping as well if (!b.IsRest) { // try to fit beam to current beamhelper if (currentBeamHelper == null || !currentBeamHelper.CheckBeat(b)) { if (currentBeamHelper != null) { currentBeamHelper.Finish(); forceNewTupletHelper = currentBeamHelper.Beats.Count > 1; } else { forceNewTupletHelper = true; } // if not possible, create the next beaming helper currentBeamHelper = new BeamingHelper(bar.Staff); currentBeamHelper.CheckBeat(b); BeamHelpers[v.Index].Add(currentBeamHelper); } } if (b.HasTuplet) { // try to fit tuplet to current tuplethelper // TODO: register tuplet overflow var previousBeat = b.PreviousBeat; // don't group if the previous beat isn't in the same voice if (previousBeat != null && previousBeat.Voice != b.Voice) { previousBeat = null; } // if a new beaming helper was started, we close our tuplet grouping as well if (forceNewTupletHelper && currentTupletHelper != null) { currentTupletHelper.Finish(); } if (previousBeat == null || currentTupletHelper == null || !currentTupletHelper.Check(b)) { currentTupletHelper = new TupletHelper(v.Index); currentTupletHelper.Check(b); TupletHelpers[v.Index].Add(currentTupletHelper); } } BeamHelperLookup[v.Index][b.Index] = currentBeamHelper; } if (currentBeamHelper != null) { currentBeamHelper.Finish(); } if (currentTupletHelper != null) { currentTupletHelper.Finish(); } currentBeamHelper = null; currentTupletHelper = null; } } }
public BarHelpers(Bar bar) { BeamHelpers = new FastList<FastList<BeamingHelper>>(); BeamHelperLookup = new FastList<FastDictionary<int, BeamingHelper>>(); TupletHelpers = new FastList<FastList<TupletHelper>>(); BeamingHelper currentBeamHelper = null; TupletHelper currentTupletHelper = null; for (int i = 0, j = bar.Voices.Count; i < j; i++) { var v = bar.Voices[i]; BeamHelpers.Add(new FastList<BeamingHelper>()); BeamHelperLookup.Add(new FastDictionary<int, BeamingHelper>()); TupletHelpers.Add(new FastList<TupletHelper>()); for (int k = 0, l = v.Beats.Count; k < l; k++) { var b = v.Beats[k]; var newBeamingHelper = false; if (!b.IsRest) { // try to fit beam to current beamhelper if (currentBeamHelper == null || !currentBeamHelper.CheckBeat(b)) { // if not possible, create the next beaming helper currentBeamHelper = new BeamingHelper(bar.Track); currentBeamHelper.CheckBeat(b); BeamHelpers[v.Index].Add(currentBeamHelper); newBeamingHelper = true; } } if (b.HasTuplet) { // try to fit tuplet to current tuplethelper // TODO: register tuplet overflow var previousBeat = b.PreviousBeat; // don't group if the previous beat isn't in the same voice if (previousBeat != null && previousBeat.Voice != b.Voice) previousBeat = null; // if a new beaming helper was started, we close our tuplet grouping as well if (newBeamingHelper && currentTupletHelper != null) { currentTupletHelper.Finish(); } if (previousBeat == null || currentTupletHelper == null || !currentTupletHelper.Check(b)) { currentTupletHelper = new TupletHelper(v.Index); currentTupletHelper.Check(b); TupletHelpers[v.Index].Add(currentTupletHelper); } } BeamHelperLookup[v.Index][b.Index] = currentBeamHelper; } currentBeamHelper = null; currentTupletHelper = null; } }