/// <summary> /// Render the staff for music /// </summary> /// <param name="colorString">The color the staff should be</param> /// <param name="width">Width of the staff to render</param> /// <param name="fontSize">The size of font currently being used</param> /// <returns></returns> private static Panel RenderStaff(String colorString, double width, double fontSize) { Grid grid = WPFRendering.CreateAutoSizingGrid(); //get the height of the staff for the font and use that to draw the lines. double height = WPFRendering.GetFontHeight(fontSize, Constants.MusicFonts.DEFAULT); double lineWidth = CalculateLineWidth(fontSize); int numLines = 5; //todo: different numbers of lines height -= numLines * lineWidth; double spacing = height / numLines; for (int i = 1; i <= numLines; i++) { System.Windows.Shapes.Line staffLine = new System.Windows.Shapes.Line() { X1 = 0, X2 = width + WPFRendering.GetFontFraction(Constants.Staff.STAFF_PADDING, fontSize), //todo: proper padding after line Y1 = i * spacing, Y2 = i * spacing, StrokeThickness = lineWidth, Stroke = new SolidColorBrush((Color)ColorConverter.ConvertFromString(colorString)) }; WPFRendering.RecalculateSize(staffLine); grid.Children.Add(staffLine); } grid.VerticalAlignment = VerticalAlignment.Top; WPFRendering.RecalculateSize(grid); return(grid); }
/// <summary> /// Render the time signature to a Grid /// </summary> /// <param name="time">The time signature to render</param> /// <param name="fontSize">The size of the font currently being used</param> /// <returns>Time signature on a grid</returns> public static FrameworkElement RenderTimeSignature(Time time, double fontSize) { double halfFont = fontSize / 2; //todo: make proper time signature label //todo: measure font size stuff properly Panel grid = WPFRendering.CreateAutoSizingGrid(); Label beatsLabel = WPFRendering.GetMusicalLabel(time.Beats, halfFont); grid.Children.Add(beatsLabel); Label beatType = WPFRendering.GetMusicalLabel(time.BeatType, halfFont); beatType.Margin = new Thickness(0, WPFRendering.GetFontHeight(fontSize / 3, Constants.MusicFonts.DEFAULT), 0, 0); grid.Children.Add(beatType); //todo: interchangable and other type of time signature, see definition of Time to hunt it down grid.VerticalAlignment = VerticalAlignment.Top; WPFRendering.RecalculateSize(grid); return(grid); }
private static System.Windows.Shapes.Line CreateNoteStem(double yOffset, Note note, FrameworkElement noteHead, double fontSize) { if (String.IsNullOrEmpty(note.stem.color)) { note.stem.color = Constants.Colors.DEFAULT_NOTE_COLOR; } double stemHeight = WPFRendering.GetFontHeight(fontSize, Constants.MusicFonts.DEFAULT) * 2.5 / 5; double y1 = 0; double y2 = 0; if (note.stem.Value == stemvalue.up) { y1 = yOffset + noteHead.ActualHeight / 2; y2 = yOffset + noteHead.ActualHeight / 2 - stemHeight; } else if (note.stem.Value == stemvalue.down) { y1 = yOffset + noteHead.ActualHeight / 2; y2 = yOffset + noteHead.ActualHeight / 2 + stemHeight; } else if (note.stem.Value == stemvalue.@double) { //TODO: figure this out } return(new System.Windows.Shapes.Line() { X1 = noteHead.ActualWidth - WPFRendering.GetFontFraction(Constants.Note.STEM_X_OFFSET, fontSize), X2 = noteHead.ActualWidth - WPFRendering.GetFontFraction(Constants.Note.STEM_X_OFFSET, fontSize), Y1 = y1, Y2 = y2, StrokeThickness = CalculateLineWidth(fontSize), Stroke = new SolidColorBrush((Color)ColorConverter.ConvertFromString(note.stem.color)) }); }
//todo: put note rendering into its own class /// <summary> /// Parse the contents of a note and prepare the basic label /// </summary> /// <param name="note">The note to parse and create a label for</param> /// <param name="fontSize">The size of the font being used</param> /// <param name="clefSign">The sign of the clef for this note. Default is G</param> /// <returns>A label with the note in it</returns> public static Panel RenderNoteOrRest(Note note, double fontSize, ClefSign clefSign = ClefSign.G) { double yOffset = WPFRendering.GetFontFraction(-2, fontSize); //offset cause not exactly in right spot //todo: Render appropriate connectors //todo: render barline //todo: tuplets, triplets, beams //todo: likely remove this whole function because will need to draw own notes due to stem when beaming String noteChar = Constants.Note.Characters.WHOLE_NOTE; Panel grid = WPFRendering.CreateAutoSizingGrid(); //todo: if it has a rest, then parse as rest, otherwise parse as note bool isRest = note.Items.SingleOrDefault(i => i.GetType() == typeof(Rest)) != null; if (!isRest) { FrameworkElement noteHead = RenderNoteHead(note, fontSize); noteHead.Margin = new Thickness(noteHead.Margin.Left, noteHead.Margin.Top + yOffset, noteHead.Margin.Right, noteHead.Margin.Bottom); grid.Children.Add(noteHead); //todo: stems when beamed... This will likely require stems to be drawn after the note heads of the beaming // however, beaming is not supposed to go over measures so this will save some of the problems that this could have //get pitch object Pitch pitch = (Pitch)note.Items.SingleOrDefault(t => t.GetType() == typeof(Pitch)); if (pitch != null) { //todo: make into function //move grid up or down appropriately Pitch clefDefaultPitch = GetDefaultPitch(clefSign); int stepDifference = clefDefaultPitch.step - pitch.step + (int.Parse(Constants.Note.TrebelDefaults.PITCH.octave) - int.Parse(pitch.octave)) * 8; if (pitch.step == Step.A || pitch.step == Step.B) { stepDifference -= 7; } // todo: octave var difference = (int.Parse(pitch.octave) - int.Parse(clefDefaultPitch.octave)); if (difference != 0) { difference *= 7; stepDifference += (difference < 0) ? difference : -difference; } const double stepDistance = 5.5; double topOffset = WPFRendering.GetFontFraction(39, fontSize); double marginTop = noteHead.Margin.Top + (stepDifference * WPFRendering.GetFontFraction(stepDistance, fontSize)) + topOffset; // create and add note stem System.Windows.Shapes.Line noteStem = new System.Windows.Shapes.Line(); if (note.stem.Value != stemvalue.none) { noteStem = CreateNoteStem(yOffset, note, noteHead, fontSize); } grid.Children.Add(noteStem); // add the note head noteHead.Margin = new Thickness(noteHead.Margin.Left, marginTop, noteHead.Margin.Right, noteHead.Margin.Bottom); noteStem.Margin = new Thickness(noteStem.Margin.Left, marginTop, noteStem.Margin.Right, noteStem.Margin.Bottom); //debug: remove Console.Out.WriteLine("default: " + Constants.Note.TrebelDefaults.PITCH.step + " " + pitch.step + pitch.octave + " " + stepDifference); } // render ledger line if necessary if (LineThroughNoteHead(pitch, clefSign)) { FrameworkElement ledgerLine = RenderLedgerLine(noteHead, fontSize); grid.Children.Add(ledgerLine); } //todo: accidentals //todo: clef change on note //todo: other notes? //todo: make into function //todo: if is above half of the staff, rotate so everything points down // rotate head /* * RotateTransform rt = new RotateTransform(180); * rt.CenterX = noteHead.ActualWidth / 2; * rt.CenterY = 10 * 3 / 4; //todo: use note height calculation from render notehead * grid.RenderTransform = rt; */ } else { FrameworkElement restElement = RenderRest(note, fontSize); restElement.Margin = new Thickness(0, -WPFRendering.GetFontHeight(fontSize, Constants.MusicFonts.DEFAULT) / 4, 0, 0); grid.Children.Add(restElement); } //grid.VerticalAlignment = VerticalAlignment.Top; WPFRendering.RecalculateSize(grid); return(grid); }