Ejemplo n.º 1
0
        /// <summary>
        /// Adds the note to the staff in the correct location
        /// </summary>
        /// <param name="nr">The note to add</param>
        private void addNoteOrRestToStaff(NoteOrRest nr)
        {
            // Get the currently selected note, rest, or staff fragment
            var elem = Viewer.SelectedElement;

            if (elem == null)
            {
                //MessageBox.Show("You must select a staff to write to or a note to insert after.");
                //return;
                elem = model.Data.FirstStaff.Elements[0];
            }

            //If user selects the staff itself, append to last note. Else insert after selected note.
            //int staffIndex = model.Data.Staves.IndexOf(elem.Staff); // Get current staff **PROBABLY NOT NEEDED**
            if (elem.GetType().IsSubclassOf(typeof(NoteOrRest)))
            {   // Not staff fragment, so insert note after selected element
                int index = elem.Staff.Elements.IndexOf(elem);
                elem.Staff.Elements.Insert(index + 1, nr);
                elem.Measure.Elements.Insert(elem.Measure.Elements.IndexOf(elem) + 1, nr);
                model.fitMeasure(elem.Measure, model.TimeSig);
            }
            else
            {
                elem.Staff.Elements.Add(nr);  // Staff fragment, so add note to end of staff
                model.fitMeasure(nr.Measure, model.TimeSig);
            }

            // Trigger an update in the viewmodel
            model.updateView();
        }
Ejemplo n.º 2
0
        public static void TupletMark(IMeasurementService measurementService, IScoreService scoreService, ScoreRendererBase renderer, NoteOrRest element, int beamLoop)
        {
            if (measurementService.TupletState == null)
            {
                throw new Exception("DrawTupletMark was called but no tuplet is currently open in staff.");
            }
            Staff staff = scoreService.CurrentStaff;

            NoteOrRest           firstElementInTuplet = staff.Peek <NoteOrRest>(element, PeekType.BeginningOfTuplet);
            int                  index = staff.Elements.IndexOf(firstElementInTuplet);
            List <MusicalSymbol> elementsUnderTuplet = staff.Elements.GetRange(index, staff.Elements.IndexOf(element) - index);
            var                  elementsUnderTupletForAverageStemLength = elementsUnderTuplet.OfType <Note>().Where(n => MusicalSymbol.DirectionToPlacement(n.StemDirection) == measurementService.TupletState.TupletPlacement).ToList();
            double               averageStemLength = elementsUnderTupletForAverageStemLength.Count == 0 ? 0 : elementsUnderTupletForAverageStemLength.Average(n => n.ActualStemLength);

            averageStemLength += 10;                //Add space
            int    placementMod = measurementService.TupletState.TupletPlacement == VerticalPlacement.Above ? -1 : 1;
            double tupletBracketStartXPosition = firstElementInTuplet.TextBlockLocation.X + 6;
            double tupletBracketStartYPosition = firstElementInTuplet.TextBlockLocation.Y + 25 + averageStemLength * placementMod;
            double tupletBracketEndXPosition   = element.TextBlockLocation.X + 12;
            double tupletBracketEndYPosition   = element.TextBlockLocation.Y + 25 + averageStemLength * placementMod;

            if (measurementService.TupletState.AreSingleBeamsPresentUnderTuplet)                //Draw tuplet bracket
            {
                renderer.DrawLine(new Point(tupletBracketStartXPosition, tupletBracketStartYPosition),
                                  new Point(tupletBracketEndXPosition, tupletBracketEndYPosition), element);
                renderer.DrawLine(new Point(tupletBracketStartXPosition, tupletBracketStartYPosition),
                                  new Point(tupletBracketStartXPosition, firstElementInTuplet.TextBlockLocation.Y + 25 + (averageStemLength - 4) * placementMod), element);
                renderer.DrawLine(new Point(tupletBracketEndXPosition, tupletBracketEndYPosition),
                                  new Point(tupletBracketEndXPosition, element.TextBlockLocation.Y + 25 + (averageStemLength - 4) * placementMod), element);
            }

            double numberOfNotesYTranslation = 0;

            if (measurementService.TupletState.TupletPlacement == VerticalPlacement.Above)
            {
                numberOfNotesYTranslation -= 18;                                                                                        //If text should appear above the tuplet, move a bit to up
            }
            //If bracket is not drawn, move up or down to fill space
            if (!measurementService.TupletState.AreSingleBeamsPresentUnderTuplet)
            {
                numberOfNotesYTranslation += 10 * (measurementService.TupletState.TupletPlacement == VerticalPlacement.Above ? 1 : -1);
            }

            var allElementsUnderTuplet = elementsUnderTuplet.OfType <NoteOrRest>().ToList();

            allElementsUnderTuplet.Add(element);
            var tupletNumber = CalculateTupletNumber(allElementsUnderTuplet);

            renderer.DrawString(Convert.ToString(tupletNumber), MusicFontStyles.LyricsFont,
                                new Point(tupletBracketStartXPosition + (tupletBracketEndXPosition - tupletBracketStartXPosition) / 2 - 6,
                                          tupletBracketStartYPosition + (tupletBracketEndYPosition - tupletBracketStartYPosition) / 2 + numberOfNotesYTranslation), element);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Draws tuplet mark
        /// </summary>
        /// <param name="measurementService"></param>
        /// <param name="scoreService"></param>
        /// <param name="renderer"></param>
        /// <param name="element"></param>
        public static void TupletMark(IMeasurementService measurementService, IScoreService scoreService, ScoreRendererBase renderer, NoteOrRest element)
        {
            if (measurementService.TupletState == null)
            {
                throw new Exception("DrawTupletMark was called but no tuplet is currently open in staff.");
            }

            var   tupletBracketPen = renderer.CreatePenFromDefaults(element, "tupletBracketThickness", s => s.DefaultTupletBracketThickness);
            Staff staff            = scoreService.CurrentStaff;

            NoteOrRest           firstElementInTuplet = staff.Peek <NoteOrRest>(element, PeekType.BeginningOfTuplet);
            int                  index = staff.Elements.IndexOf(firstElementInTuplet);
            List <MusicalSymbol> elementsUnderTuplet = staff.Elements.GetRange(index, staff.Elements.IndexOf(element) - index + 1);

            var noteGroupBounds = elementsUnderTuplet.OfType <Note>().GetBounds(renderer);

            if (IsDebugMode)
            {
                DrawNoteGroupOutline(renderer, noteGroupBounds, element);
            }

            var boundsOnOneSide = measurementService.TupletState.TupletPlacement == VerticalPlacement.Above ?
                                  new Tuple <Point, Point>(noteGroupBounds.NW, noteGroupBounds.NE) :
                                  new Tuple <Point, Point>(noteGroupBounds.SW, noteGroupBounds.SE);

            int placementMod      = measurementService.TupletState.TupletPlacement == VerticalPlacement.Above ? -1 : 1;
            var bracketDefinition = new TupletBracketDefinition(
                boundsOnOneSide.Item1.X,
                boundsOnOneSide.Item1.Y + renderer.LinespacesToPixels(2) * placementMod,
                boundsOnOneSide.Item2.X,
                boundsOnOneSide.Item2.Y + renderer.LinespacesToPixels(2) * placementMod);

            if (measurementService.TupletState.AreSingleBeamsPresentUnderTuplet)    //Draw tuplet bracket
            {
                renderer.DrawLine(bracketDefinition.StartPoint, bracketDefinition.Point25, tupletBracketPen, element);
                renderer.DrawLine(bracketDefinition.Point75, bracketDefinition.EndPoint, tupletBracketPen, element);
                renderer.DrawLine(bracketDefinition.StartPoint, bracketDefinition.StartPoint.Translate(0, renderer.LinespacesToPixels(-1) * placementMod), tupletBracketPen, element);
                renderer.DrawLine(bracketDefinition.EndPoint, bracketDefinition.EndPoint.Translate(0, renderer.LinespacesToPixels(-1) * placementMod), tupletBracketPen, element);
            }

            var tupletNumber = CalculateTupletNumber(elementsUnderTuplet.OfType <NoteOrRest>());

            var textToWrite  = renderer.Settings.MusicFontProfile.MusicFont.BuildTupletNumber(tupletNumber);
            var fontStyle    = renderer.IsSMuFLFont ? MusicFontStyles.MusicFont : MusicFontStyles.LyricsFont;
            var textSize     = renderer.CanMeasureString ? renderer.MeasureString(fontStyle, textToWrite) : new Size();
            var textPosition = renderer.CanMeasureString ?
                               bracketDefinition.MidPoint.Translate(textSize.Width / -2, textSize.Height / 2) :
                               bracketDefinition.MidPoint.Translate(-3.7, 4.7);

            renderer.DrawString(textToWrite, fontStyle, textPosition, element);
        }
Ejemplo n.º 4
0
        private NoteOrRest GetCurrentNoteOrRestAndDetermineTupletState(Staff staff)
        {
            NoteOrRest noteOrRest = CurrentElement as NoteOrRest;

            if (noteOrRest != null && noteOrRest.Voice < 2)
            {
                if (noteOrRest.Tuplet == TupletType.Start)
                {
                    NoteOrRest tupletStart = staff.Peek <NoteOrRest>(noteOrRest, PeekType.BeginningOfTuplet);
                    NoteOrRest tupletEnd   = staff.Peek <NoteOrRest>(noteOrRest, PeekType.EndOfTuplet);
                    if (tupletStart != null && tupletEnd != null)
                    {
                        TupletState = new Tuplet();
                        TupletState.NumberOfNotesUnderTuplet = staff.Elements.GetRange(staff.Elements.IndexOf(tupletStart), staff.Elements.IndexOf(tupletEnd) -
                                                                                       staff.Elements.IndexOf(tupletStart)).OfType <NoteOrRest>().Where(nr => !(nr is Note) || (nr is Note && !((Note)nr).IsUpperMemberOfChord)).Count() + 1;
                    }
                }
            }
            return(noteOrRest);
        }
        internal static string GetDurationName(NoteOrRest symbol)
        {
            switch (symbol.BaseDuration.Denominator)
            {
            case 1:
                return("whole");

            case 2:
                return("half");

            case 4:
                return("quarter");

            case 8:
                return("eighth");

            case 16:
                return("16th");

            case 32:
                return("32nd");

            case 64:
                return("64th");

            case 128:
                return("128th");

            case 256:
                return("256th");

            case 512:
                return("512th");

            default:
                throw new ScoreException(symbol, $"Invalid rhythmic duration denominator {symbol.BaseDuration.Denominator}.");
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Adds the note to the staff in the correct location
        /// </summary>
        /// <param name="nr">The note to add</param>
        private void addNoteOrRestToStaff(NoteOrRest nr)
        {
            // New for LStaff
            var        elem  = Viewer.SelectedElement;
            LStaff     staff = getLStaff(elem);
            NoteOrRest noteToPlay;

            if (isValidTarget(elem))
            {
                LMeasure measure = staff.getMeasure(elem);
                staff.AddAfter(elem, nr);
                if (measure.Contains(nr))
                {
                    Viewer.SelectedElement = nr;
                }
                else if (measure.Node.Next != null && measure.Node.Next.Value.Count > 0)
                {
                    Viewer.SelectedElement = measure.Node.Next.Value.First.Value;
                }
                noteToPlay = (NoteOrRest)Viewer.SelectedElement;
            }
            else
            {
                staff.Add(nr);
                noteToPlay = (NoteOrRest)staff.Last.Value.Last(e => e.GetType().IsSubclassOf(typeof(NoteOrRest)));
            }

            // Play the note
            if (noteToPlay.GetType() == typeof(Note))
            {
                model.PlayNote((Note)noteToPlay);
            }

            // Update the view model to make the Play command available
            model.updateView();
        }
Ejemplo n.º 7
0
        private void FetchNextElement(object state)
        {
            try
            {
                if (ShouldRestart)
                {
                    CurrentElement = null;
                    Enumerator     = null;
                    ShouldRestart  = false;
                }

                TimerState timerState = state as TimerState;
                if (timerState == null)
                {
                    return;
                }
                if (timerState.CancellationToken)
                {
                    return;
                }
                if (timerState.Score == null)
                {
                    return;
                }
                Staff staff = timerState.Score.Staves.FirstOrDefault();
                if (staff == null)
                {
                    return;
                }

                if (Enumerator == null)
                {
                    Enumerator = staff.Elements.GetEnumerator();
                }
                if (!Enumerator.MoveNext())
                {
                    Stop();
                    return;
                }
                CurrentElement = Enumerator.Current;

                NoteOrRest noteOrRest = GetCurrentNoteOrRestAndDetermineTupletState(staff);
                if (ProcessGraceNotesAndChordElements(staff))
                {
                    FetchNextElement(timerState);
                    return;
                }

                //
                // Determine duration == next note start time
                //
                IHasDuration durationElement = CurrentElement as IHasDuration;
                if (durationElement != null)
                {
                    double dueTime = MusicalSymbol.DurationToTime(durationElement, Tempo).TotalMilliseconds;
                    if (TupletState != null)
                    {
                        dueTime = dueTime / TupletState.NumberOfNotesUnderTuplet * ((double)durationElement.BaseDuration.Denominator / (double)Tempo.BeatUnit.Denominator);
                    }
                    Debug.WriteLine("{0} with {1} dots will be played in {2} ms", durationElement.BaseDuration, durationElement.NumberOfDots, dueTime);
                    Timer.Change((int)dueTime, Timeout.Infinite);
                }
                else
                {
                    FetchNextElement(timerState);                  //If element does not have a duration, play next immediately
                }
                if (noteOrRest != null && noteOrRest.Tuplet == TupletType.Stop)
                {
                    TupletState = null;
                }

                PlayElement(CurrentElement);
            }
            catch (Exception ex)
            {
                PlaybackExceptions.Add(ex);
                Stop();
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Adds a barline to the current measure if needed, and breaks the last note of the measure if it
        /// exceeds the allowed beats/measure, inserting the remainder into the next measure. Then recursively calls
        /// itself on subsequent measures until it hits a measure that does not overflow.
        /// </summary>
        /// <param name="m"></param>
        /// <param name="ts"></param>
        internal void fitMeasure(Measure m, TimeSignature ts) // Still need to add support for deletion
        {
            bool  nextMeasureChanged = false;
            Staff staff        = m.Staff;
            int   measureIndex = staff.Measures.IndexOf(m);


            foreach (MusicalSymbol item in m.Elements)
            {
                // If new time signature, update
                if (item.GetType() == typeof(TimeSignature))
                {
                    ts = (TimeSignature)item;
                }

                // Make sure that any cleffs and signatures are at the beginning of the measure, before notes and rests
                if (item.GetType() == typeof(TimeSignature) || item.GetType() == typeof(Key) || item.GetType() == typeof(Clef))
                {
                    NoteOrRest firstBeat = getFirstBeat(m);
                    if (m.Elements.IndexOf(firstBeat) < m.Elements.IndexOf(item))
                    {
                        swapPositions(staff, item, firstBeat);
                    }
                }
            }

            // While the current measure is not full and is not the end of the song, steal the first beat from the next measure
            // ****VERIFY THIS CODE ONCE NOTE DELETION IS IN PLACE****
            while (getDurations(m).Sum() < ts.WholeNoteCapacity &&
                   m.Number < staff.Measures.Count &&
                   getFirstBeat(getNextMeasure(m)) != null)
            {
                Measure    next = getNextMeasure(m);
                NoteOrRest nr   = getFirstBeat(next);
                next.Elements.Remove(nr);
                m.Elements.Add(nr);     // This note might be longer than we have room for, but the next loop will take care of it
                nextMeasureChanged = true;
            }

            // While the current measure has too many beats, push the extra into the next measure
            while (getDurations(m).Sum() > ts.WholeNoteCapacity)
            {
                double     overage           = getOverage(m, ts);                                                              // How much the content of the current measure exceeds its alloted time
                NoteOrRest lastNoteOrRest    = (NoteOrRest)m.Elements.Last(e => e.GetType().IsSubclassOf(typeof(NoteOrRest))); // Last note or rest in measure
                double     lastDurationValue = lastNoteOrRest.Duration.ToDouble();                                             // Value of last note or rest in measure
                int        lastItemIndex     = staff.Elements.IndexOf(lastNoteOrRest);                                         // Index of last note or rest in the measure
                NoteOrRest itemToMove        = null;                                                                           // The last note or portion thereof that doesn't fit in the current measure

                // If the overage is because the last note is too big, break it into two notes
                if (lastDurationValue > overage)
                {
                    NoteOrRest itemInPlace;     // Shortened version of lastNoteOrRest that fits in currrent measure
                    if (lastNoteOrRest.GetType() == typeof(Note))
                    {
                        itemInPlace = new Note(((Note)lastNoteOrRest).Pitch, toRhythmicDuration(lastDurationValue - overage));
                        itemToMove  = new Note(((Note)lastNoteOrRest).Pitch, toRhythmicDuration(overage)); // Remaining note value
                    }
                    else
                    {
                        itemInPlace = new Rest(toRhythmicDuration(lastDurationValue - overage));
                        itemToMove  = new Rest(toRhythmicDuration(overage));
                    }
                    // Have to remove lastNoteOrRest from both the staff and the measure
                    staff.Elements.Remove(lastNoteOrRest);
                    m.Elements.Remove(lastNoteOrRest);
                    // Replace with shortened version, automatically populates to measure when adding
                    staff.Elements.Insert(lastItemIndex, itemInPlace);
                }
                else
                {
                    itemToMove = lastNoteOrRest;
                    staff.Elements.Remove(lastNoteOrRest);
                    m.Elements.Remove(lastNoteOrRest);
                    lastItemIndex--;
                }

                // Refresh the updated measure in the staff.measures collection
                Barline bar = moveOrAddBarlineAfter(staff.Elements[lastItemIndex]);

                // Add itemToMove after the barline
                staff.Elements.Insert(lastItemIndex + 2, itemToMove);

                // Add it to the measure as well if it's not already there
                Measure nextMeasure = getNextMeasure(m);
                if (!nextMeasure.Elements.Contains(itemToMove))
                {
                    nextMeasure.Elements.Insert(0, itemToMove);
                }

                // set the flag to check the next measure
                nextMeasureChanged = true;
            }

            // If there are changes to the next measure, fix it.
            if (nextMeasureChanged)
            {
                fitMeasure(getNextMeasure(m), ts);
            }
        }
Ejemplo n.º 9
0
        ////// IN PROGRESS ////////
        /// <summary>
        /// Adds a barline to the current measure if needed, and breaks the last note of the measure if it
        /// exceeds the allowed beats/measure, inserting the remainder into the next measure, then recursively calls
        /// itself on subsequent measures until it hits a measure that does not overflow.
        /// </summary>
        /// <param name="m"></param>
        /// <param name="ts"></param>
        internal void fitMeasure(Measure m, TimeSignature ts) // Still need to add support for deletion
        {
            bool nextMeasureChanged = false;

            foreach (MusicalSymbol item in m.Elements)
            {
                // If new time signature, update
                if (item.GetType() == typeof(TimeSignature))
                {
                    ts = (TimeSignature)item;
                }

                // Make sure that any cleffs and signatures are at the beginning of the measure, before notes and rests
                if (item.GetType() == typeof(TimeSignature) || item.GetType() == typeof(Key) || item.GetType() == typeof(Clef))
                {
                    NoteOrRest firstBeat = getFirstBeat(m);
                    if (m.Elements.IndexOf(firstBeat) < m.Elements.IndexOf(item))
                    {
                        swapPositions(m.Staff, item, firstBeat);
                    }
                }
            }

            // While the current measure is not full and is not the end of the song, steal the first beat from the next measure
            while (getDurations(m).Sum() < ts.WholeNoteCapacity &&
                   m.Number < m.Staff.Measures.Count &&
                   getFirstBeat(getNextMeasure(m)) != null)
            {
                Measure    next = getNextMeasure(m);
                NoteOrRest nr   = getFirstBeat(next);
                next.Elements.Remove(nr);
                m.Elements.Add(nr);     // This note might be longer than we have room for, but the next loop will take care of it
                nextMeasureChanged = true;
            }

            Staff staff        = m.Staff;
            int   measureIndex = staff.Measures.IndexOf(m);

            // While the current measure has too many beats, push the extra into the next measure
            while (getDurations(m).Sum() > ts.WholeNoteCapacity)
            {
                //double[] d = getDurations(m);
                double     overage           = getOverage(m, ts);// d.Sum() - ts.WholeNoteCapacity;
                NoteOrRest lastNoteOrRest    = (NoteOrRest)m.Elements.Last(e => e.GetType().IsSubclassOf(typeof(NoteOrRest)));
                double     lastDurationValue = lastNoteOrRest.Duration.ToDouble();
                int        lastItemIndex     = staff.Elements.IndexOf(lastNoteOrRest);
                NoteOrRest itemToMove        = null;

                // If the overage is because the last note is too big, break it into two notes
                if (lastDurationValue > overage)
                {
                    // Shorten the duration of the culprit to fit the measure
                    //lastNoteOrRest.Duration = toRhythmicDuration(lastDurationValue - overage);

                    // Instead of shortening in place, try replacing so the viewer notices the change
                    NoteOrRest itemInPlace;

                    // Propagate the change to the staff -- Never mind. It propagates fine here.
                    //m.Staff.Elements[m.Staff.Elements.IndexOf(lastNoteOrRest)] = null;
                    //m.Staff.Elements[m.Staff.Elements.IndexOf(lastNoteOrRest)] = lastNoteOrRest;


                    // Add a copy of the culprit note or rest at the remaining duration
                    if (lastNoteOrRest.GetType() == typeof(Note))
                    {
                        itemInPlace = new Note(((Note)lastNoteOrRest).Pitch, toRhythmicDuration(lastDurationValue - overage));
                        itemToMove  = new Note(((Note)lastNoteOrRest).Pitch, toRhythmicDuration(overage));
                    }
                    else
                    {
                        itemInPlace = new Rest(toRhythmicDuration(lastDurationValue - overage));
                        itemToMove  = new Rest(toRhythmicDuration(overage));
                    }
                    m.Staff.Elements.Remove(lastNoteOrRest);
                    m.Elements.Remove(lastNoteOrRest);
                    m.Staff.Elements.Insert(lastItemIndex, itemInPlace);
                }
                else
                {
                    itemToMove = lastNoteOrRest;
                    m.Staff.Elements.Remove(lastNoteOrRest);
                    m.Elements.Remove(lastNoteOrRest);
                    lastItemIndex--;
                }

                // Grab the next barline and put it after the last note of the adjusted measure
                //Barline bar = moveOrAddBarlineAfter(staff.Elements[lastItemIndex -1 ]);   // This is adding it to the staff elements, which have not been refreshed

                // Refresh the updated measure in the staff.measures collection

                if (m.Elements[m.Elements.Count - 1].GetType() != typeof(Barline))
                {
                    m.Staff.Elements.Insert(lastItemIndex + 1, new Barline());                                                                // may have to use "add"
                }
                //*** May need to remove m from staff.measures and insert updated version***

                // Add the new note/rest or new partial note/rest to the new measure
                // getNextMeasure(m).Elements.Insert(0, itemToMove);
                m.Staff.Elements.Insert(lastItemIndex + 2, itemToMove);

                // m.Staff.Elements.Insert(lastItemIndex + 1, lastElem);
                //staff.Elements.Insert(lastItemIndex + 2, itemToMove);
                updateView();
                //getNextMeasure(m).Elements.Insert(0, itemToMove);
                nextMeasureChanged = true;

                // Refresh measures against the current staff
                //m = null;
                //m = staff.Measures.ElementAt(measureIndex);
                //nextMeasure = null;
                //nextMeasure = staff.Measures.ElementAt(measureIndex + 1);
            }

            // If there are changes to the next measure, fix it.
            if (nextMeasureChanged) //fitMeasure(staff.Measures[staff.Measures.IndexOf(m) + 1], ts);
            {
                fitMeasure(getNextMeasure(m), ts);
            }
        }
Ejemplo n.º 10
0
 private static void DrawNoteGroupOutline(ScoreRendererBase renderer, Quadrangle noteGroupBounds, NoteOrRest element)
 {
     renderer.DrawLine(noteGroupBounds.NW, noteGroupBounds.NE, new Pen(Color.Red), element);
     renderer.DrawLine(noteGroupBounds.NE, noteGroupBounds.SE, new Pen(Color.Red), element);
     renderer.DrawLine(noteGroupBounds.SE, noteGroupBounds.SW, new Pen(Color.Red), element);
     renderer.DrawLine(noteGroupBounds.SW, noteGroupBounds.NW, new Pen(Color.Red), element);
 }