Esempio n. 1
0
        //TODO: Need to use "last attribute" somehow for measures without attributes set
        /// <summary>
        /// Render the attributes of a measure
        /// </summary>
        /// <param name="attributes">The attributes object to render</param>
        /// <param name="c">The canvas to render onto</param>
        /// <param name="staff">The staff being rendered for</param>
        /// <returns>A canvas with the attributes of a measure rendered onto it</returns>
        private static Panel RenderAttributes(Attributes attributes, int staff, double fontSize)
        {
            Panel  grid = WPFRendering.CreateAutoSizingGrid();
            double left = 0;

            //todo: render multiple clefs because of multi-line parts
            FrameworkElement element = RenderClef(attributes.clef[0], fontSize);

            element.Margin = new Thickness(fontSize * 2 / 3, 0, 0, 0);
            grid.Children.Add(element);
            left += fontSize * 2 / 3;

            //todo: render key signature
            element        = RenderKeySignature(fontSize);
            element.Margin = new Thickness(left, 0, 0, 0);
            grid.Children.Add(element);
            left += element.ActualWidth;

            //todo: render time signature
            element        = RenderTimeSignature(attributes.time[staff], fontSize);
            element.Margin = new Thickness(left, WPFRendering.GetFontFraction(9, fontSize), 0, 0);
            grid.Children.Add(element);
            left += element.ActualWidth;

            grid.VerticalAlignment = VerticalAlignment.Top;
            WPFRendering.RecalculateSize(grid);
            return(grid);
        }
Esempio n. 2
0
        /// <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);
        }
Esempio n. 3
0
        /// <summary>
        /// Wrapper for rendering a page. This is here so that information not held within the
        /// definition of MusicXML can be passed in.
        /// </summary>
        /// <returns>Canvas with a page rendered on it</returns>
        public Grid RenderPage(WPFPage wpfPage)
        {
            Grid grid = WPFRendering.CreateAutoSizingGrid();

            //todo: render score info (large on page 1, small on pages after) (optionally selectable)
            //todo: render each line
            //todo: render page number
            return(grid);
        }
Esempio n. 4
0
        /// <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);
        }
Esempio n. 5
0
        /// <summary>
        /// Render a line of music
        /// </summary>
        /// <returns>A Grid containing a line of the musical score</returns>
        public Grid RenderLine()
        {
            Grid grid = WPFRendering.CreateAutoSizingGrid();
            //todo: render staff
            int measuresPerLine = Math.Min(CalculateMeasuresPerLine(), AllMeasures.Count);

            FrameworkElement prev = null;

            for (int i = 0; i < measuresPerLine; i++)
            {
                var measure = AllMeasures[i].MeasureFrameworkElement;
                if (prev != null)
                {
                    measure.Margin = new Thickness(prev.Margin.Left + prev.ActualWidth, prev.Margin.Top, 0, 0);
                }

                grid.Children.Add(measure);
                prev = measure;
                //todo: should be a f(n) of line number and measure OR use a line class to hold
            }
            return(grid);
        }
Esempio n. 6
0
        /// <summary>
        /// Render a measure onto a canvas
        /// </summary>
        /// <param name="measure">The measure to render</param>
        /// <param name="staff">The staff being rendered for</param>
        /// <returns>A Framework Element with the measure rendered onto it</returns>
        public static Panel RenderMeasure(ScorePartwisePartMeasure measure, int staff, double fontSize) //todo: not return canvas
        {
            //todo: stack/queue for tie
            //todo: stack/queue for slur
            //todo: stack/queue for beam

            //todo: maybe approach this by doing all staves in render measure?

            double left = 0; //todo: padding/margin
            double top  = 0; //todo: padding/margin

            ICollection <object> itemList = measure.Items;
            FrameworkElement     element  = null;
            Panel grid = WPFRendering.CreateAutoSizingGrid();

            grid.Margin = new Thickness(50, 50, 0, 0); //todo: proper margin

            //todo: render each item
            for (int i = 0; i < itemList.Count; i++)
            {
                object obj  = itemList.ElementAt(i);
                Type   type = obj.GetType();


                if (type == typeof(Attributes))
                {
                    Attributes attributes = (Attributes)obj;
                    element = RenderAttributes(attributes, staff, fontSize);
                }
                else if (type == typeof(Note))
                {
                    //todo: may need to use attributes from previous measure to figure out where to render
                    Note note = (Note)obj;
                    element = RenderNoteOrRest(note, fontSize);
                }
                else if (type == typeof(Barline))
                {
                    Barline barline = (Barline)obj;
                    element = RenderBarline(barline, fontSize);
                }
                else if (type == typeof(Print))
                {
                    //todo: complete this section
                    element = new Label();
                }
                else if (type == typeof(Direction))
                {
                    //todo: complete this section
                    element = new Label();
                }

                if (element != null)
                {
                    element.Margin = new Thickness(left, top, 0, 0);
                    grid.Children.Add(element);
                    left += element.ActualWidth + 0; //todo: margin
                }
                else
                {
                    throw new NullMeasureElementException("Null element: " + obj.GetType() + "\n");
                }
            }

            //todo: render multiple staves for multi-part instruments etc
            //      This should be as simple as rendering a second staff then putting the note onto that staff as required
            //      Then joining those two staves via a wrapper container

            element = RenderStaff(Constants.Colors.DEFAULT_NOTE_COLOR, left, fontSize);
            grid.Children.Add(element);

            WPFRendering.RecalculateSize(grid);
            return(grid);
        }
Esempio n. 7
0
        //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);
        }
Esempio n. 8
0
        /// <summary>
        /// Render a note.
        /// </summary>
        /// <param name="note">Information for the note to render</param>
        /// <returns>A note rendered on a Fraemwork Element</returns>
        private static FrameworkElement RenderNoteHead(Note note, double fontSize)
        {
            //todo: chords
            //todo: different shapes of note heads
            Panel            noteHeadGrid   = WPFRendering.CreateAutoSizingGrid();
            FrameworkElement noteHead       = new Label();
            FrameworkElement noteHeadInside = new Label();

            if (string.IsNullOrEmpty(note.color))
            {
                note.color = Constants.Colors.DEFAULT_NOTE_COLOR;
            }
            Brush noteBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(note.color));

            RotateTransform hollowRT = new RotateTransform();

            bool   rotateHead     = false;
            bool   hollow         = false;
            double noteHeadHeight = WPFRendering.GetFontFraction(12, fontSize);
            double noteHeadWidth  = noteHeadHeight * 1.5;

            switch (note.type.Value)
            {
            //todo: size note heads using width expected for font
            case NoteTypeValue.whole:
                // make outside
                // todo: made this into a function
                noteHead = new Ellipse()
                {
                    Fill = noteBrush, Height = noteHeadHeight, Width = noteHeadWidth
                };
                hollow = true;
                // make hole
                noteHeadInside = new Ellipse()
                {
                    Fill = new SolidColorBrush(Colors.White), Height = noteHeadHeight * 0.6, Width = noteHeadWidth / 2
                };
                hollowRT.Angle = Constants.Note.HeadRotations.WHOLE_NOTE_HOLLOW;     //todo: make this rotation a constant, note same as head rotation
                break;

            case NoteTypeValue.half:
                // make outside
                noteHead = new Ellipse()
                {
                    Fill = noteBrush, Height = noteHeadHeight, Width = noteHeadWidth
                };
                rotateHead = true;
                hollow     = true;
                // make hole
                noteHeadInside = new Ellipse()
                {
                    Fill = new SolidColorBrush(Colors.White), Height = noteHeadHeight * 0.7, Width = noteHeadWidth * .8
                };
                hollowRT.Angle = Constants.Note.HeadRotations.HALF_NOTE_HOLLOW;     //todo: make this rotation a constant, note same as head rotation
                break;

            case NoteTypeValue.quarter:
                noteHead = new Ellipse()
                {
                    Fill = noteBrush, Height = noteHeadHeight, Width = noteHeadWidth
                };
                rotateHead = true;
                break;

            case NoteTypeValue.eighth:
                noteHead = new Ellipse()
                {
                    Fill = noteBrush, Height = noteHeadHeight, Width = noteHeadWidth
                };
                rotateHead = true;
                break;

            case NoteTypeValue.Item16th:
                noteHead = new Ellipse()
                {
                    Fill = noteBrush, Height = noteHeadHeight, Width = noteHeadWidth
                };
                rotateHead = true;
                break;

            case NoteTypeValue.Item32nd:
                noteHead = new Ellipse()
                {
                    Fill = noteBrush, Height = noteHeadHeight, Width = noteHeadWidth
                };
                rotateHead = true;
                break;

            case NoteTypeValue.Item64th:
                noteHead = new Ellipse()
                {
                    Fill = noteBrush, Height = noteHeadHeight, Width = noteHeadWidth
                };
                rotateHead = true;
                break;

            case NoteTypeValue.Item128th:
                noteHead = new Ellipse()
                {
                    Fill = noteBrush, Height = noteHeadHeight, Width = noteHeadWidth
                };
                rotateHead = true;
                break;

            case NoteTypeValue.Item256th:
                rotateHead = true;
                break;

            case NoteTypeValue.Item512th:
                rotateHead = true;
                break;
            }

            // perform head rotation and add to the notehead grid
            if (rotateHead)
            {
                RotateNoteHead(noteHead);
            }
            noteHeadGrid.Children.Add(noteHead);

            // if it is hallow, add the hallow center
            if (hollow)
            {
                noteHeadInside.LayoutTransform = hollowRT;
                noteHeadGrid.Children.Add(noteHeadInside);
            }

            WPFRendering.RecalculateSize(noteHead);
            WPFRendering.RecalculateSize(noteHeadGrid);
            //todo: Render modifiers

            return(noteHeadGrid);
        }
Esempio n. 9
0
 public Panel RenderMeasure(ScorePartwisePartMeasure measure, List <int> staves)
 {
     // todo: only render certain staves of a line of music
     return(WPFRendering.CreateAutoSizingGrid());
 }