/// <summary>
        /// Draws of performs additional logic at slur end
        /// </summary>
        /// <param name="renderer">Score renderer</param>
        /// <param name="slur">Slur</param>
        /// <param name="element">Element with a slur</param>
        /// <param name="notePositionY">Y position of element with a slur</param>
        /// <param name="slurStartInfo">Information about slur start point</param>
        /// <param name="slurPlacement">Information about slur placement</param>
        protected override void ProcessSlurEnd(ScoreRendererBase renderer, Slur slur, Note element, double notePositionY, SlurInfo slurStartInfo, VerticalPlacement slurPlacement)
        {
            Point endPoint;
            var   noteheadWidth = element.GetNoteheadWidthPx(renderer);

            if (slurStartInfo.StartPlacement == VerticalPlacement.Above)
            {
                var  xShiftConcerningStemDirectionEnd = noteheadWidth / 2;
                bool hasFlagOrBeam = element.BaseDuration.Denominator > 4;
                endPoint = new Point(scoreService.CursorPositionX + xShiftConcerningStemDirectionEnd,
                                     (element.StemDirection == VerticalDirection.Up ? element.StemEndLocation.Y + (hasFlagOrBeam ? -2 : 0) : notePositionY - 7));
            }
            else if (slurStartInfo.StartPlacement == VerticalPlacement.Below)
            {
                var xShiftConcerningStemDirectionEnd = noteheadWidth / 2;
                endPoint = new Point(scoreService.CursorPositionX + xShiftConcerningStemDirectionEnd, notePositionY + 5);
            }
            else
            {
                throw new Exception("Unsupported placement type.");
            }

            var slurHeight = DetermineSlurHeight(element, slur, slurStartInfo, endPoint);

            for (int i = 0; i < 3; i++) //Draw a few curves one by one to simulate a curve with variable thickness. It will be replaced by a path in future releases.
            {
                var controlPoints = GetBezierControlPoints(slurStartInfo.StartPoint, endPoint, slurStartInfo.StartPlacement, slurHeight + i);
                renderer.DrawBezier(slurStartInfo.StartPoint, controlPoints.Item1, controlPoints.Item2, endPoint, element);
            }

            //DrawSlurFrame(renderer, startPoint, controlPoints.Item1, controlPoints.Item2, endPoint, element);
        }
예제 #2
0
        /// <summary>
        /// Draws a slur
        /// </summary>
        /// <param name="renderer"></param>
        /// <param name="slur"></param>
        /// <param name="element"></param>
        /// <param name="notePositionY"></param>
        public void Draw(ScoreRendererBase renderer, Slur slur, Note element, double notePositionY)
        {
            VerticalPlacement slurPlacement;

            if (slur.Placement.HasValue)
            {
                slurPlacement = slur.Placement.Value;
            }
            else
            {
                slurPlacement = element.StemDirection == VerticalDirection.Up ? VerticalPlacement.Below : VerticalPlacement.Above;
            }

            if (slur.Type == NoteSlurType.Start)
            {
                ProcessSlurStart(renderer, slur, element, notePositionY, GetSlurInfoForWriting(slur.Number), slurPlacement);
            }
            if (slur.Type == NoteSlurType.Stop)
            {
                var slurInfo = GetSlurInfoForReading(slur.Number);
                if (slurInfo == null)
                {
                    return;                     //There is no slur with that number. MusicXml file might be malformed (like in DWOK tom 1, s. 315, nr 24.xml)
                }
                ProcessSlurEnd(renderer, slur, element, notePositionY, slurInfo, slurPlacement);
                measurementService.Slurs.Remove(slur.Number);
            }
        }
        /// <summary>
        /// Calculates slur height trying to avoid collisions with stems
        /// </summary>
        /// <param name="note"></param>
        /// <param name="endPoint"></param>
        /// <returns></returns>
        private double DetermineSlurHeight(Note note, Slur slur, SlurInfo slurStartInfo, Point endPoint)
        {
            var notesUnderSlur = note.Staff.EnumerateUntilConditionMet <Note>(note, n => n.Slurs.FirstOrDefault(s => s.Number == slur.Number)?.Type == NoteSlurType.Start, true).ToArray();

            if (notesUnderSlur.Length < 3)
            {
                return(10);
            }

            var notesUnderSlurExclusive = notesUnderSlur.Take(notesUnderSlur.Length - 1).Skip(1);
            var mostExtremePoint        = GetMostExtremePoint(notesUnderSlurExclusive, slurStartInfo.StartPlacement);

            var angle = UsefulMath.BeamAngle(slurStartInfo.StartPoint.X, slurStartInfo.StartPoint.Y, endPoint.X, endPoint.Y);
            var slurYPositionInMostExtremePoint = slurStartInfo.StartPoint.TranslateHorizontallyAndMaintainAngle(angle, mostExtremePoint.X - slurStartInfo.StartPoint.X).Y;
            var mostExtremeYPosition            = mostExtremePoint.Y;

            if (slurStartInfo.StartPlacement == VerticalPlacement.Above && mostExtremeYPosition < slurYPositionInMostExtremePoint)
            {
                return(Math.Abs(mostExtremeYPosition - slurYPositionInMostExtremePoint) + 10);
            }
            if (slurStartInfo.StartPlacement == VerticalPlacement.Below && mostExtremeYPosition > slurYPositionInMostExtremePoint)
            {
                return(Math.Abs(slurYPositionInMostExtremePoint - mostExtremeYPosition) + 10);
            }

            return(10);
        }
예제 #4
0
        public static Slur CreateSlur(string type)
        {
            //create a slur
            Slur slur = new Slur();

            slur.setType(StartStopContinue.fromValue(type));
            slur.setNumber(new Integer(1));
            return(slur);
        }
        /// <summary>
        /// Draws of performs additional logic at slur end
        /// </summary>
        /// <param name="renderer">Score renderer</param>
        /// <param name="slur">Slur</param>
        /// <param name="element">Element with a slur</param>
        /// <param name="notePositionY">Y position of element with a slur</param>
        /// <param name="slurStartInfo">Information about slur start point</param>
        /// <param name="slurPlacement">Information about slur placement</param>
        protected override void ProcessSlurEnd(ScoreRendererBase renderer, Slur slur, Note element, double notePositionY, SlurInfo slurStartInfo, VerticalPlacement slurPlacement)
        {
            var absoluteControlPoint = RelativeToAbsolute(renderer, renderer.TenthsToPixels(slur.BezierStartOrEndPoint), notePositionY);
            var absoluteEndPoint     = RelativeToAbsolute(renderer, renderer.TenthsToPixels(slur.BezierControlPoint), notePositionY);

            renderer.DrawBezier(slurStartInfo.StartPoint.X, slurStartInfo.StartPoint.Y,
                                slurStartInfo.BezierStartControlPoint.X, slurStartInfo.BezierStartControlPoint.Y,
                                absoluteControlPoint.X, absoluteControlPoint.Y,
                                absoluteEndPoint.X, absoluteEndPoint.Y, element);
        }
        /// <summary>
        /// Draws or performs additional logic at slur start
        /// </summary>
        /// <param name="renderer">Score renderer</param>
        /// <param name="slur">Slur</param>
        /// <param name="element">Element with a slur</param>
        /// <param name="notePositionY"></param>
        /// <param name="slurStartInfo">Information about slur start point</param>
        /// <param name="slurPlacement">Information about slur placement</param>
        protected override void ProcessSlurStart(ScoreRendererBase renderer, Slur slur, Note element, double notePositionY, SlurInfo slurStartInfo, VerticalPlacement slurPlacement)
        {
            slurStartInfo.StartPlacement          = slurPlacement;
            slurStartInfo.StartPointStemDirection = element.StemDirection;
            var polihymniaFix = renderer.LinespacesToPixels(element.GetNoteheadWidthLs(renderer) * 0.5);

            if (slurPlacement == VerticalPlacement.Above)
            {
                bool hasFlagOrBeam = element.BaseDuration.Denominator > 4;  //If note has a flag or beam start the slur above the note. If not, start a bit to the right and down.
                var  xShiftConcerningStemDirectionStart = slurStartInfo.StartPointStemDirection == VerticalDirection.Up ? (hasFlagOrBeam ? 5 : 10) : 1;
                slurStartInfo.StartPoint = new Point(scoreService.CursorPositionX + xShiftConcerningStemDirectionStart + polihymniaFix, element.StemDirection == VerticalDirection.Down ? notePositionY - 7 : element.StemEndLocation.Y + (hasFlagOrBeam ? -3 : 8));
            }
            else
            {
                slurStartInfo.StartPoint = new Point(scoreService.CursorPositionX + 3 + polihymniaFix, notePositionY + 5);
            }
        }
예제 #7
0
        public DougResponse AddSlur(Command command)
        {
            var existingSlur = _slurRepository.GetSlurByText(command.Text);

            if (existingSlur != null)
            {
                return(new DougResponse(DougMessages.SlurAlreadyExists));
            }

            var slur = new Slur(command.Text, command.UserId);

            _slurRepository.AddSlur(slur);

            _userRepository.AddCredits(command.UserId, AddSlurCredit);

            return(new DougResponse(string.Format(DougMessages.GainedCredit, AddSlurCredit)));
        }
예제 #8
0
        public static string slurToABC(Slur slur)
        {
            string resslur = "";

            switch (slur.Type)
            {
            case "start":
                resslur = "(";
                break;

            case "stop":
                resslur = ")";
                break;
            }

            return(resslur);
        }
예제 #9
0
        private void SetBeam(List <Symbol> symbolList)
        {
            switch (_beam)
            {
            case "begin":
            {
                _slur = new Slur();
                _slur.GetList().Add((Note)_symbol);
                ((Note)_symbol).SetSlur(true);
                ((Note)_symbol).SetNext(true);
            }
            break;

            case "continue":
            {
                _slur.GetList().Add((Note)_symbol);
                ((Note)_symbol).SetLastNote((Note)symbolList[symbolList.Count - 1]);
                ((Note)_symbol).SetSlur(true);
//                    ((Note) _symbol).SetLast(true);
                ((Note)_symbol).SetNext(true);
            }
            break;

            case "end":
            {
                Note lastNote = (Note)symbolList[symbolList.Count - 1];
                _slur.GetList().Add((Note)_symbol);
                ((Note)_symbol).SetLastNote(lastNote);
                ((Note)_symbol).SetSlur(true);
                ((Note)_symbol).SetLast(true);

                if (_slur != null)
                {
                    _slur.Operate();
                }
            }
            break;

            default: break;
            }

            ((Note)_symbol).SetBeam(_beam);
            _beam = "";
        }
예제 #10
0
        private async Task SendSlurToChannel(Command command, Slur slur)
        {
            var users = _userRepository.GetUsers();

            var rnd        = new Random();
            var randomUser = users.ElementAt(rnd.Next(users.Count)).Id;

            var message = BuildSlurMessage(slur.Text, randomUser, command.GetTargetUserId());

            message = _itemEventDispatcher.OnFlaming(command, message);

            var timestamp = await _slack.BroadcastMessage(message, command.ChannelId);

            _slurRepository.LogRecentSlur(slur.Id, timestamp);

            await _slack.AddReaction(DougMessages.UpVote, timestamp, command.ChannelId);

            await _slack.AddReaction(DougMessages.Downvote, timestamp, command.ChannelId);
        }
예제 #11
0
 public void AddSlur(Slur slur)
 {
     _db.Slurs.Add(slur);
 }
예제 #12
0
        private Note GetNote(XmlNode noteNode)
        {
            var note = new Note();

            var typeNode = noteNode.SelectSingleNode("type");

            if (typeNode != null)
            {
                note.Type = typeNode.InnerText;
            }

            var voiceNode = noteNode.SelectSingleNode("voice");

            if (voiceNode != null)
            {
                note.Voice = Convert.ToInt32(voiceNode.InnerText);
            }

            var durationNode = noteNode.SelectSingleNode("duration");

            if (durationNode != null)
            {
                note.Duration = Convert.ToInt32(durationNode.InnerText);
            }

            var accidental = noteNode.SelectSingleNode("accidental");

            if (accidental != null)
            {
                note.Accidental = accidental.InnerText;
            }

            note.Lyric = GetLyric(noteNode);

            note.Pitch = GetPitch(noteNode);

            var staffNode = noteNode.SelectSingleNode("staff");

            if (staffNode != null)
            {
                note.Staff = Convert.ToInt32(staffNode.InnerText);
            }

            var chordNode = noteNode.SelectSingleNode("chord");

            if (chordNode != null)
            {
                note.IsChordTone = true;
            }

            var restNode = noteNode.SelectSingleNode("rest");

            if (restNode != null)
            {
                note.IsRest = true;
            }

            var dotNode = noteNode.SelectNodes("dot");

            note.DotNumber = dotNode.Count;

            var slurNode = noteNode.SelectSingleNode("notations").SelectSingleNode("slur");

            if (slurNode != null)
            {
                Slur slur = new Slur();
                slur.Type      = slurNode.Attributes["type"].ToString();
                slur.Number    = Convert.ToInt32(slurNode.Attributes["number"]);
                slur.Placement = slurNode.Attributes["placement"].ToString();
            }

            return(note);
        }
예제 #13
0
        private void BuildScoreConvertSameSlurredNotesToTies_RecursiveFixSlurs(Score score, int partIndex, int staffIndex, int elementGroupIndex, int elementIndex, INotation currentElementSlurStartNotation)
        {
            var part         = score.Parts[partIndex];
            var staff        = part.Staves[staffIndex];
            var elementGroup = staff.Elements[elementGroupIndex];
            var element      = elementGroup[elementIndex];

            var isEndOfElementGroup = elementGroupIndex >= staff.Elements.Length;

            if (isEndOfElementGroup)
            {
                return;
            }

            var nextElementGroup = staff.Elements[elementGroupIndex + 1];
            var nextElementGroupNoteOfSamePitch = nextElementGroup.FirstOrDefault(nextElement => nextElement.Pitch == element.Pitch);

            if (nextElementGroupNoteOfSamePitch == null)
            {
                return;
            }

            /* If the next element group at the same pitch has an ending slur, convert this to a start/stop tie. */
            {
                var nextElementGroupNoteStopSlur = nextElementGroupNoteOfSamePitch.Notations.FirstOrDefault(nextElementNotation => nextElementNotation != null && nextElementNotation is Slur && (nextElementNotation as Slur).Type == StartStopContinue.Stop);

                if (nextElementGroupNoteStopSlur == null)
                {
                    /* No issue with two notes of the same pitch being slurred */
                    return;
                }
                else
                {
                    /* For current element. replace the slur start notation with a tie start notation */
                    {
                        var newNotations = element.Notations.ToList();
                        newNotations = (List <INotation>)newNotations.Where(x => x != currentElementSlurStartNotation);

                        newNotations.Add(new Tie()
                        {
                            Type   = StartStopContinue.Start,
                            Number = (currentElementSlurStartNotation as Slur).Number,
                        });
                        element.Notations = newNotations.ToArray();
                    }

                    /* For next element. replace the slur stop notation with a tie stop notation */
                    {
                        var newNotations = nextElementGroupNoteOfSamePitch.Notations.ToList();
                        newNotations = (List <INotation>)newNotations.Where(x => x != nextElementGroupNoteStopSlur);

                        newNotations.Add(new Tie()
                        {
                            Type   = StartStopContinue.Stop,
                            Number = (currentElementSlurStartNotation as Slur).Number,
                        });
                        nextElementGroupNoteOfSamePitch.Notations = newNotations.ToArray();
                    }
                }
            }

            /* If the next element group at the same pitch has a continuation slur, recursively evaluate this */
            {
                var nextElementGroupNoteContinueSlur = nextElementGroupNoteOfSamePitch.Notations.FirstOrDefault(nextElementNotation => nextElementNotation != null && nextElementNotation is Slur && (nextElementNotation as Slur).Type == StartStopContinue.Stop);

                if (nextElementGroupNoteContinueSlur == null)
                {
                    /* No issue with two notes of the same pitch being slurred */
                    return;
                }
                else
                {
                    /* For current element. replace the slur start notation with a tie start notation */
                    {
                        var newNotations = element.Notations.ToList();
                        newNotations = (List <INotation>)newNotations.Where(x => x != currentElementSlurStartNotation);

                        newNotations.Add(new Tie()
                        {
                            Type   = StartStopContinue.Start,
                            Number = (currentElementSlurStartNotation as Slur).Number,
                        });
                        element.Notations = newNotations.ToArray();
                    }

                    /* For next element. replace the slur stop notation with a tie continue notation */
                    {
                        var newNotations = nextElementGroupNoteOfSamePitch.Notations.ToList();
                        newNotations = (List <INotation>)newNotations.Where(x => x != nextElementGroupNoteContinueSlur);

                        newNotations.Add(new Tie()
                        {
                            Type   = StartStopContinue.Stop,
                            Number = (currentElementSlurStartNotation as Slur).Number,
                        });

                        var newStartNotation = new Slur()
                        {
                            Type   = StartStopContinue.Start,
                            Number = (currentElementSlurStartNotation as Slur).Number,
                        };
                        newNotations.Add(newStartNotation);
                        nextElementGroupNoteOfSamePitch.Notations = newNotations.ToArray();

                        BuildScoreConvertSameSlurredNotesToTies_RecursiveFixSlurs(score, partIndex, staffIndex, elementGroupIndex + 1, elementIndex, newStartNotation);
                    }
                }
            }
        }
예제 #14
0
 /// <summary>
 /// Draws of performs additional logic at slur end
 /// </summary>
 /// <param name="renderer">Score renderer</param>
 /// <param name="slur">Slur</param>
 /// <param name="element">Element with a slur</param>
 /// <param name="notePositionY">Y position of element with a slur</param>
 /// <param name="slurStartInfo">Information about slur start point</param>
 /// <param name="slurPlacement">Information about slur placement</param>
 protected abstract void ProcessSlurEnd(ScoreRendererBase renderer, Slur slur, Note element, double notePositionY, SlurInfo slurStartInfo, VerticalPlacement slurPlacement);
예제 #15
0
 /// <summary>
 /// Returns true if this strategy type is relevant for drawing a specific slur
 /// </summary>
 /// <param name="element">Element with a slur</param>
 /// <param name="slur">Slur</param>
 /// <returns>True if this strategy is relevant for rendering a specific slur</returns>
 public abstract bool IsRelevant(Note element, Slur slur);
 /// <summary>
 /// Returns true if this strategy type is relevant for drawing a specific slur
 /// </summary>
 /// <param name="element">Element with a slur</param>
 /// <param name="slur">Slur</param>
 /// <returns>True if this strategy is relevant for rendering a specific slur</returns>
 public override bool IsRelevant(Note element, Slur slur)
 {
     return(slur.IsDefinedAsBezierCurve);
 }
예제 #17
0
        //Read the note
        public static NoteProperties ReadNote(int notenumber, ScorePartwise.Part.Measure measure)
        {
            if (getnoteindex(notenumber, measure) != -1)
            {
                Note           note     = (Note)measure.getNoteOrBackupOrForward().get(getnoteindex(notenumber, measure));
                NoteProperties noteprop = new NoteProperties();

                noteprop.chord = note.getChord() == new Empty() ? true : false;

                if (note.getRest() != null)
                {
                    //MessageBox.Show("Rest Read!");

                    noteprop.rest = true;
                    try
                    {
                        noteprop.NoteType = note.getType().getValue();
                    }
                    catch (System.Exception)
                    {
                        noteprop.NoteType = "";
                    }
                }
                else if (note.getPitch() is Pitch)
                {
                    noteprop.NoteType    = note.getType().getValue();   // get the notetype only if it is not a rest
                    noteprop.PitchStep   = note.getPitch().getStep().value();
                    noteprop.Pitchoctave = note.getPitch().getOctave();
                    if (note.getPitch().getAlter() != null)
                    {
                        noteprop.PitchAlter = note.getPitch().getAlter().floatValue();
                    }
                }

                noteprop.duration = note.getDuration().intValue();

                if (note.getTie().size() != 0)
                {
                    Tie tie = (Tie)note.getTie().get(0);
                    noteprop.TieType = tie.getType().toString();
                }



                noteprop.dot = note.getDot().size() == 0? false:true;

                noteprop.AccidentalType = note.getAccidental() == null? "":note.getAccidental().getValue().value();



                if (note.getTimeModification() != null)
                {
                    noteprop.TimeModactualnotes = note.getTimeModification().getActualNotes().intValue().ToString();
                    noteprop.TimeModnormalnotes = note.getTimeModification().getNormalNotes().intValue().ToString();
                    noteprop.TimeModnormaltype  = note.getTimeModification().getNormalType() == null ? "" : note.getTimeModification().getNormalType();
                }

                ///////////////////////////////////COMPLETE ME
                Beam beam;
                for (int i = 0; i < note.getBeam().size(); i++)
                {
                    beam = (Beam)note.getBeam().get(i);
                    noteprop.beamvalue.Add(beam.getValue().value());
                    noteprop.beamnumber.Add(beam.getNumber());
                }

                if (note.getNotations().size() != 0)
                {
                    Notations notations = (Notations)note.getNotations().get(0);
                    for (int i = 0; i < notations.getTiedOrSlurOrTuplet().size(); i++)
                    {
                        if (notations.getTiedOrSlurOrTuplet().get(i) is Tied)
                        {
                            Tied tied = (Tied)notations.getTiedOrSlurOrTuplet().get(i);
                            //if(tied.getNumber().intValue()==1)
                            noteprop.TiedType = tied.getType().value();
                        }

                        if (notations.getTiedOrSlurOrTuplet().get(i) is Slur)
                        {
                            Slur slur = (Slur)notations.getTiedOrSlurOrTuplet().get(i);
                            if (slur.getNumber() == 1)
                            {
                                noteprop.SlurType = slur.getType().value();
                            }
                        }

                        if (notations.getTiedOrSlurOrTuplet().get(i) is Tuplet)
                        {
                            Tuplet tuplet = (Tuplet)notations.getTiedOrSlurOrTuplet().get(i);
                            noteprop.TupletType = tuplet.getType().value();
                            //noteprop.TupletNumber = tuplet.getNumber().intValue();
                        }
                        if (notations.getTiedOrSlurOrTuplet().get(i) is Dynamics)
                        {
                            Dynamics dynamics            = (Dynamics)notations.getTiedOrSlurOrTuplet().get(i);
                            javax.xml.bind.JAXBElement x = (javax.xml.bind.JAXBElement)dynamics.getPOrPpOrPpp().get(0);
                            noteprop.dynamic = x.getName().ToString();
                        }
                    }
                }

                if (note.getLyric().size() != 0)
                {
                    Lyric lyric = (Lyric)note.getLyric().get(0);
                    for (int i = 0; i < lyric.getElisionAndSyllabicAndText().size(); i++)
                    {
                        if (lyric.getElisionAndSyllabicAndText().get(i) is Syllabic)
                        {
                            Syllabic syllabic = (Syllabic)lyric.getElisionAndSyllabicAndText().get(i);
                            noteprop.LyricSyllabic = syllabic.value();
                        }

                        if (lyric.getElisionAndSyllabicAndText().get(i) is TextElementData)
                        {
                            TextElementData text = (TextElementData)lyric.getElisionAndSyllabicAndText().get(i);
                            noteprop.LyricText = text.getValue();
                        }
                    }
                    noteprop.LyricEndline = lyric.getEndLine() == null?false:true;
                }
                return(noteprop);
            }
            return(null);
        }
예제 #18
0
        public override void ParseElement(MusicXmlParserState state, Staff staff, XElement element)
        {
            var builder = new NoteOrRestBuilder(state);

            element.IfAttribute("default-x").HasValue <double>().Then(m => builder.DefaultX = m);
            element.IfAttribute("measure").HasValue("yes").Then(m => builder.FullMeasure    = true);
            element.IfAttribute("print-object").HasValue(new Dictionary <string, bool> {
                { "yes", true }, { "no", false }
            }).Then(m => builder.IsVisible = m);
            element.IfAttribute("size").HasValue(new Dictionary <string, NoteOrRestSize>
            {
                { "cue", NoteOrRestSize.Cue },
                { "full", NoteOrRestSize.Full },
                { "large", NoteOrRestSize.Large },
            }).Then(s => builder.Size = s);
            element.IfElement("staff").HasValue <int>().Then(m => builder.Staff = staff.Part.Staves.ElementAt(m - 1));
            element.IfElement("type").HasValue(new Dictionary <string, RhythmicDuration> {
                { "breve", RhythmicDuration.DoubleWhole },
                { "whole", RhythmicDuration.Whole },
                { "half", RhythmicDuration.Half },
                { "quarter", RhythmicDuration.Quarter },
                { "eighth", RhythmicDuration.Eighth },
                { "16th", RhythmicDuration.Sixteenth },
                { "32nd", RhythmicDuration.D32nd },
                { "64th", RhythmicDuration.D64th },
                { "128th", RhythmicDuration.D128th }
            }).Then(m => builder.BaseDuration = m);
            var typeElement = element.GetElement("type");

            if (typeElement != null)
            {
                typeElement.IfAttribute("size").HasValue(new Dictionary <string, NoteOrRestSize>
                {
                    { "cue", NoteOrRestSize.Cue },
                    { "full", NoteOrRestSize.Full },
                    { "large", NoteOrRestSize.Large },
                }).Then(s => builder.Size = s);   //"size" attribute apparently can be added to element "type" too
            }

            element.IfElement("voice").HasValue <int>().Then(m => builder.Voice = m);
            var graceElement = element.GetElement("grace");

            if (graceElement != null)
            {
                graceElement.IfAttribute("slash").HasValue("yes")
                .Then(v => builder.GraceNoteType      = GraceNoteType.Slashed)
                .Otherwise(v => builder.GraceNoteType = GraceNoteType.Simple);
            }
            element.IfElement("chord").Exists().Then(() => builder.IsChordElement             = true);
            element.IfElement("accidental").HasValue("natural").Then(() => builder.HasNatural = true);
            element.IfElement("rest").Exists().Then(() => builder.IsRest = true);
            element.ForEachDescendant("dot", f => f.Exists().Then(() => builder.NumberOfDots++));

            var pitchElement = element.IfElement("pitch").Exists().ThenReturnResult();

            pitchElement.IfElement("step").HasAnyValue().Then(v => builder.Step        = v);
            pitchElement.IfElement("octave").HasValue <int>().Then(v => builder.Octave = v);
            pitchElement.IfElement("alter").HasValue <int>().Then(v => builder.Alter   = v);

            var unpitchedElement = element.IfElement("unpitched").Exists().Then(x => builder.IsUnpitched = true).AndReturnResult();

            unpitchedElement.IfElement("display-step").HasAnyValue().Then(v => builder.Step        = v);
            unpitchedElement.IfElement("display-octave").HasValue <int>().Then(v => builder.Octave = v);
            unpitchedElement.IfElement("display-alter").HasValue <int>().Then(v => builder.Alter   = v);

            var tieElements = element.Elements().Where(e => e.Name == "tie");

            foreach (var tieElement in tieElements)
            {
                tieElement.IfAttribute("type").HasValue("start").Then(v =>
                {
                    if (builder.TieType == NoteTieType.Stop)
                    {
                        builder.TieType = NoteTieType.StopAndStartAnother;
                    }
                    else
                    {
                        builder.TieType = NoteTieType.Start;
                    }
                }).Otherwise(r => builder.TieType = NoteTieType.Stop);
            }

            element.IfElement("stem").HasValue("down")
            .Then(() => builder.StemDirection     = VerticalDirection.Down)
            .Otherwise(r => builder.StemDirection = VerticalDirection.Up);
            element.GetElement("stem").IfAttribute("default-y").HasValue <float>().Then(v =>
            {
                builder.StemDefaultY          = v;
                builder.CustomStemEndPosition = true;
            });

            element.ForEachDescendant("beam", h => h.HasValue(new Dictionary <string, NoteBeamType> {
                { "begin", NoteBeamType.Start },
                { "end", NoteBeamType.End },
                { "continue", NoteBeamType.Continue },
                { "forward hook", NoteBeamType.ForwardHook },
                { "backward hook", NoteBeamType.BackwardHook }
            }).Then(v => builder.BeamList.Add(v))
                                      .Otherwise(r => { if (r.ToLowerInvariant() != "single")
                                                        {
                                                            throw new ScoreException(builder, $"Unsupported beam type \"{r}\".");
                                                        }
                                                 }));

            var notationsNode = element.GetElement("notations");
            var tupletNode    = notationsNode.GetElement("tuplet");

            tupletNode.IfAttribute("type").HasValue(new Dictionary <string, TupletType> {
                { "start", TupletType.Start },
                { "stop", TupletType.Stop },
            }).Then(v => builder.Tuplet = v);
            tupletNode.IfAttribute("placement").HasValue(new Dictionary <string, VerticalPlacement> {
                { "above", VerticalPlacement.Above },
                { "below", VerticalPlacement.Below },
            }).Then(v => builder.TupletPlacement = v);

            notationsNode.IfElement("fermata").Exists().Then(() => builder.HasFermataSign = true);
            notationsNode.IfElement("sound").Exists().Then(e => e.IfAttribute("dynamics").HasValue <int>().Then(v => state.CurrentDynamics = v));

            notationsNode.IfHasElement("dynamics").Then(d =>
            {
                var dir = new Direction();
                d.IfAttribute("default-y").HasValue <int>().Then(v =>
                {
                    dir.DefaultYPosition = v;
                    dir.Placement        = DirectionPlacementType.Custom;
                });
                d.IfAttribute("placement").HasValue(new Dictionary <string, DirectionPlacementType>
                {
                    { "above", DirectionPlacementType.Above },
                    { "below", DirectionPlacementType.Below }
                }).Then(v =>
                {
                    if (dir.Placement != DirectionPlacementType.Custom)
                    {
                        dir.Placement = v;
                    }
                });
                foreach (XElement dynamicsType in d.Elements())
                {
                    dir.Text = dynamicsType.Name.LocalName;
                }
                staff.Elements.Add(dir);
            });

            notationsNode.IfHasElement("articulations").Then(d =>
            {
                d.IfElement("staccato").HasAnyValue().Then(() => builder.Articulation = ArticulationType.Staccato);
                d.IfElement("accent").HasAnyValue().Then(() => builder.Articulation   = ArticulationType.Accent);
                d.IfAttribute("placement").HasValue(new Dictionary <string, VerticalPlacement> {
                    { "above", VerticalPlacement.Above },
                    { "below", VerticalPlacement.Below },
                }).Then(v => builder.ArticulationPlacement = v);
            });

            var ornamentsNode = notationsNode.GetElement("ornaments");

            ornamentsNode.GetElement("trill-mark").IfAttribute("placement").HasValue(new Dictionary <string, NoteTrillMark> {
                { "above", NoteTrillMark.Above },
                { "below", NoteTrillMark.Below }
            }).Then(v => builder.TrillMark = v);
            ornamentsNode.IfElement("tremolo").HasValue <int>().Then(v => builder.TremoloLevel = v);

            var invMordentNode = ornamentsNode
                                 .IfElement("inverted-mordent")
                                 .Exists()
                                 .Then(e => builder.Mordent = new Mordent()
            {
                IsInverted = true
            })
                                 .AndReturnResult();

            invMordentNode.IfAttribute("placement").HasValue(new Dictionary <string, VerticalPlacement> {
                { "above", VerticalPlacement.Above },
                { "below", VerticalPlacement.Below }
            }).Then(v => builder.Mordent.Placement = v);
            invMordentNode.IfAttribute("default-x").HasValue <double>().Then(v => builder.Mordent.DefaultXPosition = v);
            invMordentNode.IfAttribute("default-y").HasValue <double>().Then(v => builder.Mordent.DefaultYPosition = v);

            foreach (var slurNode in notationsNode?.Elements().Where(e => e.Name == "slur") ?? new XElement[] { })
            {
                var slur = new Slur();
                builder.Slurs.Add(slur);
                slurNode.IfAttribute("number").HasValue <int>().Then(v => slur.Number = v);
                slurNode.IfAttribute("type").HasValue(new Dictionary <string, NoteSlurType> {
                    { "start", NoteSlurType.Start },
                    { "stop", NoteSlurType.Stop }
                }).Then(v => slur.Type = v);
                slurNode.IfAttribute("placement").HasValue(new Dictionary <string, VerticalPlacement> {
                    { "above", VerticalPlacement.Above },
                    { "below", VerticalPlacement.Below }
                }).Then(v => slur.Placement = v);
                slurNode.IfAttribute("default-x").HasValue <double>().Then(v => slur.DefaultXPosition = v);
                slurNode.IfAttribute("default-y").HasValue <double>().Then(v => slur.DefaultYPosition = v);
                slurNode.IfAttribute("bezier-x").HasValue <double>().Then(v => slur.BezierX           = v);
                slurNode.IfAttribute("bezier-y").HasValue <double>().Then(v => slur.BezierY           = v);
            }

            foreach (var lNode in element.Elements().Where(n => n.Name == "lyric"))
            {
                //There can be more than one lyrics in one <lyrics> tag. Add lyrics to list once syllable type and text is set.
                //Then reset these tags so the next <syllabic> tag starts another lyric.
                Lyrics          lyricsInstance    = new Lyrics();
                Lyrics.Syllable syllable          = new Lyrics.Syllable();
                bool            isSylabicSet      = false;
                bool            isTextSet         = false;
                var             defaultYattribute = lNode.Attributes().FirstOrDefault(a => a.Name == "default-y");
                if (defaultYattribute != null)
                {
                    lyricsInstance.DefaultYPosition = UsefulMath.TryParse(defaultYattribute.Value);
                }

                foreach (XElement lyricAttribute in lNode.Elements())
                {
                    if (lyricAttribute.Name == "syllabic")
                    {
                        if (lyricAttribute.Value == "begin")
                        {
                            syllable.Type = SyllableType.Begin;
                        }
                        else if (lyricAttribute.Value == "middle")
                        {
                            syllable.Type = SyllableType.Middle;
                        }
                        else if (lyricAttribute.Value == "end")
                        {
                            syllable.Type = SyllableType.End;
                        }
                        else if (lyricAttribute.Value == "single")
                        {
                            syllable.Type = SyllableType.Single;
                        }
                        isSylabicSet = true;
                    }
                    else if (lyricAttribute.Name == "text")
                    {
                        syllable.Text = lyricAttribute.Value;
                        isTextSet     = true;
                    }
                    else if (lyricAttribute.Name == "elision")
                    {
                        syllable.ElisionMark = lyricAttribute.Value;
                    }

                    if (isSylabicSet && isTextSet)
                    {
                        lyricsInstance.Syllables.Add(syllable);
                        syllable     = new Lyrics.Syllable();
                        isSylabicSet = false;
                        isTextSet    = false;
                    }
                }

                builder.Lyrics.Add(lyricsInstance);
            }

            if (builder.BeamList.Count == 0)
            {
                builder.BeamList.Add(NoteBeamType.Single);
            }

            var noteOrRest = builder.Build();

            var correctStaff = noteOrRest.Staff ?? staff;

            correctStaff.Elements.Add(noteOrRest);
        }