/// <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); } }
////// 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); } }