/// <summary> /// Forces naturals to be displayed when there are two synchronous chordSymbols in thisStaffMoment, /// and they share diatonic pitches having different accidentals. /// </summary> private void ForceNaturals(NoteObjectMoment thisStaffMoment) { List <ChordSymbol> momentChordSymbols = new List <ChordSymbol>(2); foreach (ChordSymbol chordSymbol in thisStaffMoment.ChordSymbols) { momentChordSymbols.Add(chordSymbol); } if (momentChordSymbols.Count == 2) { foreach (Head head1 in momentChordSymbols[0].HeadsTopDown) { foreach (Head head2 in momentChordSymbols[1].HeadsTopDown) { if (head1.Pitch == head2.Pitch) { if (head1.Alteration != 0 && head2.DisplayAccidental != DisplayAccidental.force) { head2.DisplayAccidental = DisplayAccidental.force; } if (head2.Alteration != 0 && head1.DisplayAccidental != DisplayAccidental.force) { head1.DisplayAccidental = DisplayAccidental.force; } } } } } }
/// <summary> /// Forces naturals to be displayed when the most recent staff moment containing chords shares /// diatonic pitches with thisStaffMoment, and those pitches have different accidentals. /// </summary> private void ForceNaturals(NoteObjectMoment previousStaffMoment, NoteObjectMoment thisStaffMoment) { foreach (ChordSymbol chordSymbol in thisStaffMoment.ChordSymbols) { foreach (Head head in chordSymbol.HeadsTopDown) { if (head.Alteration == 0) { bool found = false; head.DisplayAccidental = DisplayAccidental.suppress; // naturals are suppressed by default foreach (ChordSymbol previousChordSymbol in previousStaffMoment.ChordSymbols) { foreach (Head previousHead in previousChordSymbol.HeadsTopDown) { if ((head.Pitch == previousHead.Pitch) && previousHead.Alteration != 0) { head.DisplayAccidental = DisplayAccidental.force; found = true; break; } } if (found) { break; } } } } } }
/// <summary> /// Returns the (positive) horizontal distance by which this anchorage symbol overlaps /// (any characters in) the previous noteObjectMoment (which contains symbols from both voices /// in a 2-voice staff). The result can be 0. If there is no overlap, the result is float.Minval. /// </summary> /// <param name="previousAS"></param> public virtual float OverlapWidth(NoteObjectMoment previousNOM) { float overlap = float.MinValue; float localOverlap = float.MinValue; foreach (AnchorageSymbol previousAS in previousNOM.AnchorageSymbols) { localOverlap = this.Metrics.OverlapWidth(previousAS); overlap = overlap > localOverlap ? overlap : localOverlap; } return(overlap); }
/// <summary> /// Returns the (positive) horizontal distance by which this noteObject overlaps /// (any characters in) the previous noteObjectMoment (which contains symbols from both voices /// in a 2-voice staff). The result can be 0. If there is no overlap, the result is float.Minval. /// </summary> /// <param name="previousAS"></param> public virtual float OverlapWidth(NoteObjectMoment previousNOM) { float overlap = float.MinValue; float localOverlap = float.MinValue; foreach(NoteObject noteObject in previousNOM.NoteObjects) { if(this.Metrics != null) { localOverlap = this.Metrics.OverlapWidth(noteObject.Metrics); overlap = overlap > localOverlap ? overlap : localOverlap; } } return overlap; }
/// <summary> /// Sets the visibility of naturals in all the chords on this multi-bar staff. /// Force naturals to be displayed if this staff contains simultaneous chords which share the same /// diatonic pitches, and one of them is not a sharp or flat. /// Naturals are also forced if any of the note heights in the chordSymbol is natural and the same /// height as a sharp or flat in the most recent (synchronous) chords on this _staff_. /// Returns the final MomentSymbol (which only contains ChordSymbols) on this staff, so that the first /// MomentsSymbol in the corresponding staff on the next system can be adjusted too. /// If the chordSymbol has no heads (as in Study2b2), nothing happens. /// </summary> public NoteObjectMoment FinalizeAccidentals(NoteObjectMoment previousStaffMoment) { foreach (NoteObjectMoment thisStaffMoment in this.ChordSymbolMoments) { if (previousStaffMoment != null) { ForceNaturals(previousStaffMoment, thisStaffMoment); } previousStaffMoment = thisStaffMoment; ForceNaturals(thisStaffMoment); } return(previousStaffMoment); }
/// <summary> /// Returns the (positive) horizontal distance by which this noteObject overlaps /// (any characters in) the previous noteObjectMoment (which contains symbols from both voices /// in a 2-voice staff). The result can be 0. If there is no overlap, the result is double.Minval. /// </summary> /// <param name="previousAS"></param> public virtual double OverlapWidth(NoteObjectMoment previousNOM) { double overlap = double.MinValue; double localOverlap = double.MinValue; foreach (NoteObject noteObject in previousNOM.NoteObjects) { if (this.Metrics != null) { localOverlap = this.Metrics.OverlapWidth(noteObject.Metrics); overlap = overlap > localOverlap ? overlap : localOverlap; } } return(overlap); }
/// <summary> /// Returns the maximum (positive) horizontal distance by which this anchorage symbol overlaps /// (any characters in) the previous noteObjectMoment (which contains symbols from both voices /// in a 2-voice staff). /// This function is used by rests and barlines.It is overridden by chords. /// </summary> /// <param name="previousAS"></param> public override double OverlapWidth(NoteObjectMoment previousNOM) { double overlap = double.MinValue; double localOverlap = 0; foreach (Anchor previousAS in previousNOM.Anchors) { //if(this is Study2b2ChordSymbol) // localOverlap = Metrics.OverlapWidth(previousAS); //else localOverlap = ChordMetrics.OverlapWidth(previousAS); overlap = overlap > localOverlap ? overlap : localOverlap; } return(overlap); }
/// <summary> /// Returns the maximum (positive) horizontal distance by which this anchorage symbol overlaps /// (any characters in) the previous noteObjectMoment (which contains symbols from both voices /// in a 2-voice staff). /// This function is used by rests and barlines.It is overridden by chords. /// </summary> /// <param name="previousAS"></param> public override float OverlapWidth(NoteObjectMoment previousNOM) { float overlap = float.MinValue; float localOverlap = 0F; foreach (AnchorageSymbol previousAS in previousNOM.AnchorageSymbols) { //if(this is Study2b2ChordSymbol) // localOverlap = Metrics.OverlapWidth(previousAS); //else localOverlap = ChordMetrics.OverlapWidth(previousAS); overlap = overlap > localOverlap ? overlap : localOverlap; } return(overlap); }
private void FinalizeAccidentals() { for (int staffIndex = 0; staffIndex < Systems[0].Staves.Count; staffIndex++) { if (!(Systems[0].Staves[staffIndex] is InvisibleOutputStaff)) { NoteObjectMoment previousStaffMoment = null; foreach (SvgSystem system in Systems) { Staff staff = system.Staves[staffIndex]; { previousStaffMoment = staff.FinalizeAccidentals(previousStaffMoment); } } } } }
/// <summary> /// Returns a list of MomentSymbols containing objects of the type given in the Type argument. /// Type can be DurationSymbol or any class which inherits from DurationSymbol. /// All DurationSymbol msPositions must be set before calling this function. /// The MomentSymbols are in order of msPosition. /// The contained symbols are in order of voice (top-bottom of this system). /// </summary> /// <typeparam name="Type">DurationSymbol, ChordSymbol, RestSymbol</typeparam> private List <NoteObjectMoment> MomentSymbols <Type>() { Dictionary <int, NoteObjectMoment> dict = new Dictionary <int, NoteObjectMoment>(); foreach (Voice voice in this.Voices) { foreach (NoteObject noteObject in voice.NoteObjects) { if (noteObject is DurationSymbol symbol && symbol is Type) { M.Assert(symbol.AbsMsPosition >= 0, "Symbol.MsPosition must be set before calling this funcion!"); if (!dict.ContainsKey(symbol.AbsMsPosition)) { NoteObjectMoment nom = new NoteObjectMoment(symbol.AbsMsPosition); nom.Add(symbol); dict.Add(symbol.AbsMsPosition, nom); } else { dict[symbol.AbsMsPosition].Add(symbol); } } } } List <NoteObjectMoment> momentSymbols = new List <NoteObjectMoment>(); while (dict.Count > 0) { int smallestKey = int.MaxValue; M.Assert(dict.Count > 0); foreach (int key in dict.Keys) { smallestKey = key < smallestKey ? key : smallestKey; } momentSymbols.Add(dict[smallestKey]); dict.Remove(smallestKey); } return(momentSymbols); }
/// <summary> /// Returns the maximum (positive) horizontal distance by which this anchorage symbol overlaps /// (any characters in) the previous noteObjectMoment (which contains symbols from both voices /// in a 2-voice staff). /// This function is used by rests and barlines.It is overridden by chords. /// </summary> /// <param name="previousAS"></param> public override float OverlapWidth(NoteObjectMoment previousNOM) { float overlap = float.MinValue; float localOverlap = 0F; foreach(AnchorageSymbol previousAS in previousNOM.AnchorageSymbols) { //if(this is Study2b2ChordSymbol) // localOverlap = Metrics.OverlapWidth(previousAS); //else localOverlap = ChordMetrics.OverlapWidth(previousAS); overlap = overlap > localOverlap ? overlap : localOverlap; } return overlap; }
/// <summary> /// The MomentSymbols are in order of msPosition. /// The contained symbols are in order of voice (top-bottom of this system). /// Barlines and ClefSigns have been added to the NoteObjectMomentSymbol containing the following /// DurationSymbol. /// When this function returns, moments are in order of msPosition, /// and aligned internally at AlignmentX = 0; /// </summary> /// <typeparam name="Type">DurationSymbol, ChordSymbol, RestSymbol</typeparam> private List<NoteObjectMoment> MomentSymbols(float gap) { SortedDictionary<int, NoteObjectMoment> dict = new SortedDictionary<int, NoteObjectMoment>(); Barline barline = null; ClefSymbol clef = null; foreach(Staff staff in Staves) { foreach(Voice voice in staff.Voices) { int key = -1; #region foreach noteObject foreach(NoteObject noteObject in voice.NoteObjects) { DurationSymbol durationSymbol = noteObject as DurationSymbol; if(durationSymbol == null) { if(noteObject is ClefSymbol) clef = noteObject as ClefSymbol; if(noteObject is Barline) barline = noteObject as Barline; } else { key = durationSymbol.AbsMsPosition; if(!dict.ContainsKey(key)) { dict.Add(key, new NoteObjectMoment(durationSymbol.AbsMsPosition)); } if(clef != null) { dict[key].Add(clef); clef = null; } if(barline != null) { dict[key].Add(barline); barline = null; } dict[key].Add(durationSymbol); } } #endregion if(clef != null) // final clef { if(dict.ContainsKey(this.AbsEndMsPosition)) dict[this.AbsEndMsPosition].Add(clef); else { NoteObjectMoment nom = new NoteObjectMoment(this.AbsEndMsPosition); nom.Add(clef); dict.Add(this.AbsEndMsPosition, nom); } } if(barline != null) // final barline { if(dict.ContainsKey(this.AbsEndMsPosition)) dict[this.AbsEndMsPosition].Add(barline); else { NoteObjectMoment nom = new NoteObjectMoment(this.AbsEndMsPosition); nom.Add(barline); dict.Add(this.AbsEndMsPosition, nom); } } } } List<NoteObjectMoment> momentSymbols = new List<NoteObjectMoment>(); Debug.Assert(dict.Count > 0); foreach(int key in dict.Keys) momentSymbols.Add(dict[key]); foreach(NoteObjectMoment momentSymbol in momentSymbols) { momentSymbol.AlignBarlineAndClefGlyphs(gap); } #region debug // moments are currently in order of msPosition. float prevMsPos = -1; foreach(NoteObjectMoment moment in momentSymbols) { Debug.Assert(moment.AbsMsPosition > prevMsPos); prevMsPos = moment.AbsMsPosition; } #endregion return momentSymbols; }
private List<NoteObjectMoment> GetVoiceMoments(Voice voice, List<NoteObjectMoment> systemMoments) { List<NoteObjectMoment> voiceMoments = new List<NoteObjectMoment>(); NoteObjectMoment voiceNOM = null; foreach(NoteObjectMoment systemNOM in systemMoments) { voiceNOM = null; foreach(NoteObject noteObject in systemNOM.NoteObjects) { if(noteObject.Voice == voice) { if(voiceNOM == null) { // noteObject in voice 1 voiceNOM = new NoteObjectMoment(systemNOM.AbsMsPosition); voiceNOM.Add(noteObject); voiceNOM.AlignmentX = systemNOM.AlignmentX; } else // noteObject in voice 2 { voiceNOM.Add(noteObject); } } } if(voiceNOM != null) voiceMoments.Add(voiceNOM); } return voiceMoments; }
private List<NoteObjectMoment> GetStaffMoments(Staff staff, List<NoteObjectMoment> systemMoments) { List<NoteObjectMoment> staffMoments = new List<NoteObjectMoment>(); NoteObjectMoment staffNOM = null; foreach(NoteObjectMoment systemNOM in systemMoments) { staffNOM = null; foreach(NoteObject noteObject in systemNOM.NoteObjects) { if(noteObject.Voice.Staff == staff) { if(staffNOM == null) { // noteObject in voice 1 staffNOM = new NoteObjectMoment(systemNOM.AbsMsPosition); staffNOM.Add(noteObject); staffNOM.AlignmentX = systemNOM.AlignmentX; } else // noteObject in voice 2 { staffNOM.Add(noteObject); } } } if(staffNOM != null) staffMoments.Add(staffNOM); } return staffMoments; }
/// <summary> /// Returns the (positive) horizontal distance by which this anchorage symbol overlaps /// (any characters in) the previous noteObjectMoment (which contains symbols from both voices /// in a 2-voice staff). The result can be 0. If there is no overlap, the result is float.Minval. /// </summary> /// <param name="previousAS"></param> public virtual float OverlapWidth(NoteObjectMoment previousNOM) { float overlap = float.MinValue; float localOverlap = float.MinValue; foreach(AnchorageSymbol previousAS in previousNOM.AnchorageSymbols) { localOverlap = this.Metrics.OverlapWidth(previousAS); overlap = overlap > localOverlap ? overlap : localOverlap; } return overlap; }