/// <summary> /// If a small ClefSymbol has no following chord in the voice, it is moved before the final barline. /// </summary> private void MoveRestClefChangesToEndOfVoice(Voice voice) { bool restFound = false; ClefSymbol smallClef = null; int smallClefIndex = -1; for (int i = voice.NoteObjects.Count - 1; i >= 0; --i) { if (voice.NoteObjects[i] is OutputChordSymbol) { break; } if (voice.NoteObjects[i] is RestSymbol) { restFound = true; } ClefSymbol clef = voice.NoteObjects[i] as ClefSymbol; if (clef != null && clef.FontHeight == _pageFormat.CautionaryNoteheadsFontHeight) { smallClef = clef; smallClefIndex = i; break; } } if (restFound && (smallClef != null)) { voice.NoteObjects.RemoveAt(smallClefIndex); Debug.Assert(voice.NoteObjects[voice.NoteObjects.Count - 1] is Barline); voice.NoteObjects.Insert(voice.NoteObjects.Count - 1, smallClef); } }
/// <summary> /// Aligns barline glyphs in this moment, moving an immediately preceding clef, but /// without moving the following duration symbol (which is aligned at this.AlignmentX). /// </summary> public void AlignBarlineGlyphs() { float minBarlineOriginX = float.MaxValue; foreach (NoteObject noteObject in _noteObjects) { Barline b = noteObject as Barline; if (b != null && b.Metrics != null && b.Metrics.OriginX < minBarlineOriginX) { minBarlineOriginX = b.Metrics.OriginX; } } for (int index = 0; index < _noteObjects.Count; index++) { Barline barline = _noteObjects[index] as Barline; if (barline != null && barline.Metrics != null) { Debug.Assert(AlignmentX == 0F); if (index > 0) { ClefSymbol clef = _noteObjects[index - 1] as ClefSymbol; if (clef != null) { clef.Metrics.Move(minBarlineOriginX - barline.Metrics.OriginX, 0); } } barline.Metrics.Move(minBarlineOriginX - barline.Metrics.OriginX, 0); } } }
public VerticalDir DefaultStemDirection(ClefSymbol clef) { Debug.Assert(this.HeadsTopDown.Count > 0); float gap = 32F; // dummy value List <float> topDownHeadOriginYs = new List <float>(); int lastMidiPitch = int.MaxValue; foreach (Head head in this.HeadsTopDown) { Debug.Assert(head.MidiPitch < lastMidiPitch); topDownHeadOriginYs.Add(head.GetOriginY(clef, gap)); } float heightOfMiddleStaffLine = (this.Voice.Staff.NumberOfStafflines / 2) * gap; float halfHeight = 0F; if (topDownHeadOriginYs.Count == 1) { halfHeight = topDownHeadOriginYs[0]; } else { halfHeight = (topDownHeadOriginYs[topDownHeadOriginYs.Count - 1] + topDownHeadOriginYs[0]) / 2; } if (halfHeight <= heightOfMiddleStaffLine) { return(VerticalDir.down); } else { return(VerticalDir.up); } }
private VerticalDir GetDirectionFromExtremes(ClefSymbol currentClef, List <ChordSymbol> chordsBeamedTogether) { float headMinTop = float.MaxValue; float headMaxBottom = float.MinValue; float gap = chordsBeamedTogether[0].Voice.Staff.Gap; int numberOfStafflines = chordsBeamedTogether[0].Voice.Staff.NumberOfStafflines; foreach (ChordSymbol chord in chordsBeamedTogether) { foreach (Head head in chord.HeadsTopDown) { float headY = head.GetOriginY(currentClef, gap); headMinTop = headMinTop < headY ? headMinTop : headY; headMaxBottom = headMaxBottom > headY ? headMaxBottom : headY; } } headMaxBottom -= (gap * (numberOfStafflines - 1)); headMinTop *= -1; if (headMaxBottom > headMinTop) { return(VerticalDir.up); } else { return(VerticalDir.down); } }
private float GetDefaultStemTipY(ClefSymbol currentClef, List <ChordSymbol> chordsBeamedTogether) { float headMinTop = float.MaxValue; float headMaxBottom = float.MinValue; float gap = chordsBeamedTogether[0].Voice.Staff.Gap; int numberOfStafflines = chordsBeamedTogether[0].Voice.Staff.NumberOfStafflines; VerticalDir direction = chordsBeamedTogether[0].Stem.Direction; foreach (ChordSymbol chord in chordsBeamedTogether) { foreach (Head head in chord.HeadsTopDown) { float headY = head.GetOriginY(currentClef, gap); headMinTop = headMinTop < headY ? headMinTop : headY; headMaxBottom = headMaxBottom > headY ? headMaxBottom : headY; } } if (direction == VerticalDir.up) { return(headMinTop - (gap * numberOfStafflines)); } else { return(headMaxBottom + (gap * numberOfStafflines)); } }
private List <ClefSymbol> GetClefs(Voice voice) { List <ClefSymbol> clefs = new List <ClefSymbol>(); foreach (NoteObject noteObject in voice.NoteObjects) { ClefSymbol clef = noteObject as ClefSymbol; if (clef != null) { clefs.Add(clef); } } return(clefs); }
private string FindClefTypeAtEndOfStaff1(Voice staff1voice0) { ClefSymbol mainStaff1Clef = staff1voice0.NoteObjects[0] as ClefSymbol; Debug.Assert(mainStaff1Clef != null); string clefTypeAtEndOfStaff1 = mainStaff1Clef.ClefType; foreach (NoteObject noteObject in staff1voice0.NoteObjects) { ClefChangeSymbol ccs = noteObject as ClefChangeSymbol; if (ccs != null) { clefTypeAtEndOfStaff1 = ccs.ClefType; } } return(clefTypeAtEndOfStaff1); }
/// <summary> /// Copies Systems[systemIndex]'s content to the end of the previous system (taking account of clefs), /// then removes Systems[systemIndex] from the Systems list. /// </summary> /// <param name="barlineIndex"></param> private void JoinToPreviousSystem(int systemIndex) { Debug.Assert(Systems.Count > 1 && Systems.Count > systemIndex); SvgSystem system1 = Systems[systemIndex - 1]; SvgSystem system2 = Systems[systemIndex]; Debug.Assert(system1.Staves.Count == system2.Staves.Count); for (int staffIndex = 0; staffIndex < system2.Staves.Count; staffIndex++) { bool visibleStaff = !(system1.Staves[staffIndex] is InvisibleOutputStaff); string clefTypeAtEndOfStaff1 = null; if (visibleStaff) { // If a staff has two voices, both contain the same clefTypes (some clefs may be invisible). clefTypeAtEndOfStaff1 = FindClefTypeAtEndOfStaff1(system1.Staves[staffIndex].Voices[0]); } for (int voiceIndex = 0; voiceIndex < system2.Staves[staffIndex].Voices.Count; voiceIndex++) { Voice voice1 = system1.Staves[staffIndex].Voices[voiceIndex]; Voice voice2 = system2.Staves[staffIndex].Voices[voiceIndex]; if (visibleStaff) { ClefSymbol voice2FirstClef = voice2.NoteObjects[0] as ClefSymbol; Debug.Assert(voice2FirstClef != null && clefTypeAtEndOfStaff1 == voice2FirstClef.ClefType); voice2.NoteObjects.Remove(voice2FirstClef); } try { voice1.AppendNoteObjects(voice2.NoteObjects); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } Systems.Remove(system2); system2 = null; }
public BeamBlock(ClefSymbol clef, List<ChordSymbol> chordsBeamedTogether, VerticalDir voiceStemDirection, float beamThickness, float strokeThickness) : base(null, 0, 0) { Chords = new List<ChordSymbol>(chordsBeamedTogether); SetBeamedGroupStemDirection(clef, chordsBeamedTogether, voiceStemDirection); foreach(ChordSymbol chord in chordsBeamedTogether) chord.BeamBlock = this; // prevents an isolated flag from being created _gap = Chords[0].Voice.Staff.Gap; _beamSeparation = _gap; _beamThickness = beamThickness; _strokeThickness = strokeThickness; _stemDirection = Chords[0].Stem.Direction; /****************************************************************************** * Important to set stem tips to this value before justifying horizontally. * Allows collisions between the objects outside the tips (e.g. dynamics or ornaments) * to be detected correctly. */ _defaultStemTipY = GetDefaultStemTipY(clef, chordsBeamedTogether); }
public BeamBlock(ClefSymbol clef, List <ChordSymbol> chordsBeamedTogether, VerticalDir voiceStemDirection, float beamThickness, float strokeThickness) : base(null, 0, 0) { Chords = new List <ChordSymbol>(chordsBeamedTogether); SetBeamedGroupStemDirection(clef, chordsBeamedTogether, voiceStemDirection); foreach (ChordSymbol chord in chordsBeamedTogether) { chord.BeamBlock = this; // prevents an isolated flag from being created } _gap = Chords[0].Voice.Staff.Gap; _beamSeparation = _gap; _beamThickness = beamThickness; _strokeThickness = strokeThickness; _stemDirection = Chords[0].Stem.Direction; /****************************************************************************** * Important to set stem tips to this value before justifying horizontally. * Allows collisions between the objects outside the tips (e.g. dynamics or ornaments) * to be detected correctly. */ _defaultStemTipY = GetDefaultStemTipY(clef, chordsBeamedTogether); }
/// <summary> /// This algorithm follows Gardner Read when the stemDirection is "none" (i.e. not forced): /// If there were no beam, and the majority of the stems would go up, then all the stems in the beam go up. /// ji: if there are the same number of default up and default down stems, then the direction is decided by /// the most extreme notehead in the beam group. If both extremes are the same (e.g. 1 ledgeline up and down) /// then the stems are all down. /// </summary> /// <param name="currentClef"></param> /// <param name="chordsBeamedTogether"></param> private void SetBeamedGroupStemDirection(ClefSymbol currentClef, List <ChordSymbol> chordsBeamedTogether, VerticalDir voiceStemDirection) { Debug.Assert(chordsBeamedTogether.Count > 1); VerticalDir groupStemDirection = voiceStemDirection; if (voiceStemDirection == VerticalDir.none) { // here, there is only one voice in the staff, so the direction depends on the height of the noteheads. int upStems = 0; int downStems = 0; foreach (ChordSymbol chord in chordsBeamedTogether) { VerticalDir direction = chord.DefaultStemDirection(currentClef); if (direction == VerticalDir.up) { upStems++; } else { downStems++; } } if (upStems == downStems) { groupStemDirection = GetDirectionFromExtremes(currentClef, chordsBeamedTogether); } else if (upStems > downStems) { groupStemDirection = VerticalDir.up; } else { groupStemDirection = VerticalDir.down; } } foreach (ChordSymbol chord in chordsBeamedTogether) { chord.Stem.Direction = groupStemDirection; } }
/// <summary> /// Adds all the staff's metrics, except for the top or bottom staffline. /// </summary> /// <param name="staff"></param> protected void AddStaffMetrics(Staff staff) { foreach (Voice voice in staff.Voices) { foreach (NoteObject noteObject in voice.NoteObjects) { OutputChordSymbol chordSymbol = noteObject as OutputChordSymbol; ClefSymbol clef = noteObject as ClefSymbol; if (chordSymbol != null) { chordSymbol.ChordMetrics.AddToEdge(this); } else if (clef != null && clef.ClefType != "n") { Add(clef.Metrics); } else { Add(noteObject.Metrics); } Barline barline = noteObject as Barline; if (barline != null) { BarlineMetrics barlineMetrics = barline.Metrics as BarlineMetrics; if (barlineMetrics.BarnumberMetrics != null) { Add(barlineMetrics.BarnumberMetrics); } if (barlineMetrics.StaffNameMetrics != null) { Add(barlineMetrics.StaffNameMetrics); } } } } }
public override Metrics NoteObjectMetrics(Graphics graphics, NoteObject noteObject, VerticalDir voiceStemDirection, float gap, float strokeWidth) { Metrics returnMetrics = null; ClefSymbol clef = noteObject as ClefSymbol; Barline barline = noteObject as Barline; CautionaryChordSymbol cautionaryChordSymbol = noteObject as CautionaryChordSymbol; ChordSymbol chord = noteObject as ChordSymbol; RestSymbol rest = noteObject as RestSymbol; if (barline != null) { returnMetrics = new BarlineMetrics(graphics, barline, gap); } else if (clef != null) { if (clef.ClefType != "n") { returnMetrics = new ClefMetrics(clef, gap); } } else if (cautionaryChordSymbol != null) { returnMetrics = new ChordMetrics(graphics, cautionaryChordSymbol, voiceStemDirection, gap, strokeWidth); } else if (chord != null) { returnMetrics = new ChordMetrics(graphics, chord, voiceStemDirection, gap, strokeWidth); } else if (rest != null) { // All rests are originally created on the centre line. // They are moved vertically later, if they are on a 2-Voice staff. returnMetrics = new RestMetrics(graphics, rest, gap, noteObject.Voice.Staff.NumberOfStafflines, strokeWidth); } return(returnMetrics); }
/// <summary> /// Returns the head's y-coordinates wrt the chord. /// The chord's y-origin is the top line of the staff. /// (Y-Alignment of a notehead on the top line of the staff is 0.) /// Uses the following protected variables (in Metrics) which have been set by GetStaffParameters() /// protected float _gapVBPX = 0F; /// protected int _nStafflines = 0; /// protected ClefSymbol _clef = null; /// </summary> /// <param name="headIndex"></param> /// <param name="?"></param> /// <param name="?"></param> public float GetOriginY(ClefSymbol clef, float gap) { string[] alphabet = { "C", "D", "E", "F", "G", "A", "B" }; float shiftFactor = 0F; switch (this.Pitch[0]) { case 'A': shiftFactor = 2.5F; break; case 'B': shiftFactor = 2F; break; case 'C': shiftFactor = 5; break; case 'D': shiftFactor = 4.5F; break; case 'E': shiftFactor = 4F; break; case 'F': shiftFactor = 3.5F; break; case 'G': shiftFactor = 3F; break; } // shiftFactor is currently for the octave above middle C (octave = 5) on a normal treble clef // F6 is at shiftFactor 0 (the top line of the staff). int octave = 0; try { string octaveString = this.Pitch.Substring(1); if (octaveString == ":") { octave = 10; } else { octave = int.Parse(octaveString); } } catch { Debug.Assert(false, "Error in octave string"); } float octaveShift = octave - 5F; shiftFactor -= (octaveShift * 3.5F); // 3.5 spaces is one octave // shiftFactor is currently correct for all octaves on a normal treble clef switch (clef.ClefType) { case "t": break; case "t1": // trebleClef8 shiftFactor += 3.5F; // shift down one octave break; case "t2": // trebleClef2x8 shiftFactor += 7F; // shift down two octaves break; case "t3": // trebleClef3x8 shiftFactor += 10.5F; // shift down three octaves break; case "b": shiftFactor -= 6F; // shift up six spaces break; case "b1": // bassClef8 shiftFactor -= 9.5F; // shift up six spaces + 1 octave break; case "b2": // bassClef2x8 shiftFactor -= 13F; // shift up six spaces + 2 octaves break; case "b3": // bassClef3x8 shiftFactor -= 16.5F; // shift up six spaces + 3 octaves break; default: break; } float headY = shiftFactor * gap; return(headY); }
public ClefMetrics(ClefSymbol clef, float gap) : base() { float trebleTop = -4.35F * gap; float trebleRight = 3.1F * gap; float highTrebleTop = -5.9F * gap; float trebleBottom = 2.7F * gap; #region treble clefs switch (clef.ClefType) { case "t": _objectType = "trebleClef"; _top = trebleTop; _right = trebleRight; _bottom = trebleBottom; break; case "t1": // trebleClef8 _objectType = "trebleClef8"; _top = highTrebleTop; _right = trebleRight; _bottom = trebleBottom; break; case "t2": // trebleClef2x8 _objectType = "trebleClef2x8"; _top = highTrebleTop; _right = trebleRight; _bottom = trebleBottom; break; case "t3": // trebleClef3x8 _objectType = "trebleClef3x8"; _top = highTrebleTop; _right = trebleRight; _bottom = trebleBottom; break; default: // can be a bass clef ( see below) break; } if (_right > 0F) { Move(0F, 3 * gap); } #endregion treble clefs if (!(_right > 0F)) { float bassTop = -gap; float bassRight = trebleRight; float bassBottom = gap * 3F; float lowBassBottom = gap * 4.5F; #region bass clefs switch (clef.ClefType) { case "b": _objectType = "bassClef"; _top = bassTop; _right = bassRight; _bottom = bassBottom; break; case "b1": // bassClef8 _objectType = "bassClef8"; _top = bassTop; _right = bassRight; _bottom = lowBassBottom; break; case "b2": // bassClef2x8 _objectType = "bassClef2x8"; _top = bassTop; _right = bassRight; _bottom = lowBassBottom; break; case "b3": // bassClef3x8 _objectType = "bassClef3x8"; _top = bassTop; _right = bassRight; _bottom = lowBassBottom; break; default: Debug.Assert(false, "Unknown clef type."); break; } if (_right > 0F) { Move(0, gap); } } #endregion FontHeight = clef.FontHeight; }
/// <summary> /// This algorithm follows Gardner Read when the stemDirection is "none" (i.e. not forced): /// If there were no beam, and the majority of the stems would go up, then all the stems in the beam go up. /// ji: if there are the same number of default up and default down stems, then the direction is decided by /// the most extreme notehead in the beam group. If both extremes are the same (e.g. 1 ledgeline up and down) /// then the stems are all down. /// </summary> /// <param name="currentClef"></param> /// <param name="chordsBeamedTogether"></param> private void SetBeamedGroupStemDirection(ClefSymbol currentClef, List<ChordSymbol> chordsBeamedTogether, VerticalDir voiceStemDirection) { Debug.Assert(chordsBeamedTogether.Count > 1); VerticalDir groupStemDirection = voiceStemDirection; if(voiceStemDirection == VerticalDir.none) { // here, there is only one voice in the staff, so the direction depends on the height of the noteheads. int upStems = 0; int downStems = 0; foreach(ChordSymbol chord in chordsBeamedTogether) { VerticalDir direction = chord.DefaultStemDirection(currentClef); if(direction == VerticalDir.up) upStems++; else downStems++; } if(upStems == downStems) groupStemDirection = GetDirectionFromExtremes(currentClef, chordsBeamedTogether); else if(upStems > downStems) groupStemDirection = VerticalDir.up; else groupStemDirection = VerticalDir.down; } foreach(ChordSymbol chord in chordsBeamedTogether) { chord.Stem.Direction = groupStemDirection; } }
private VerticalDir GetDirectionFromExtremes(ClefSymbol currentClef, List<ChordSymbol> chordsBeamedTogether) { float headMinTop = float.MaxValue; float headMaxBottom = float.MinValue; float gap = chordsBeamedTogether[0].Voice.Staff.Gap; int numberOfStafflines = chordsBeamedTogether[0].Voice.Staff.NumberOfStafflines; foreach(ChordSymbol chord in chordsBeamedTogether) { foreach(Head head in chord.HeadsTopDown) { float headY = head.GetOriginY(currentClef, gap); headMinTop = headMinTop < headY ? headMinTop : headY; headMaxBottom = headMaxBottom > headY ? headMaxBottom : headY; } } headMaxBottom -= (gap * (numberOfStafflines - 1)); headMinTop *= -1; if(headMaxBottom > headMinTop) return VerticalDir.up; else return VerticalDir.down; }
private float GetDefaultStemTipY(ClefSymbol currentClef, List<ChordSymbol> chordsBeamedTogether) { float headMinTop = float.MaxValue; float headMaxBottom = float.MinValue; float gap = chordsBeamedTogether[0].Voice.Staff.Gap; int numberOfStafflines = chordsBeamedTogether[0].Voice.Staff.NumberOfStafflines; VerticalDir direction = chordsBeamedTogether[0].Stem.Direction; foreach(ChordSymbol chord in chordsBeamedTogether) { foreach(Head head in chord.HeadsTopDown) { float headY = head.GetOriginY(currentClef, gap); headMinTop = headMinTop < headY ? headMinTop : headY; headMaxBottom = headMaxBottom > headY ? headMaxBottom : headY; } } if(direction == VerticalDir.up) return headMinTop - (gap * numberOfStafflines); else return headMaxBottom + (gap * numberOfStafflines); }
/// <summary> /// Sets Chord.Stem.Direction for each chord. /// Chords are beamed together, duration classes permitting, unless a rest or clef intervenes. /// If a barline intervenes, and beamsCrossBarlines is true, the chords are beamed together. /// If a barline intervenes, and beamsCrossBarlines is false, the beam is broken. /// </summary> public void SetChordStemDirectionsAndCreateBeamBlocks(PageFormat pageFormat) { List <ChordSymbol> chordsBeamedTogether = new List <ChordSymbol>(); ClefSymbol currentClef = null; bool breakGroup = false; ChordSymbol lastChord = null; foreach (ChordSymbol cs in ChordSymbols) { lastChord = cs; } foreach (NoteObject noteObject in NoteObjects) { CautionaryChordSymbol cautionaryChord = noteObject as CautionaryChordSymbol; ChordSymbol chord = noteObject as ChordSymbol; RestSymbol rest = noteObject as RestSymbol; ClefSymbol clef = noteObject as ClefSymbol; Barline barline = noteObject as Barline; if (cautionaryChord != null) { continue; } if (chord != null) { if (chord.DurationClass == DurationClass.cautionary || chord.DurationClass == DurationClass.breve || chord.DurationClass == DurationClass.semibreve || chord.DurationClass == DurationClass.minim || chord.DurationClass == DurationClass.crotchet) { if (currentClef != null) { if (this.StemDirection == VerticalDir.none) { chord.Stem.Direction = chord.DefaultStemDirection(currentClef); } else { chord.Stem.Direction = this.StemDirection; } } breakGroup = true; } else { chordsBeamedTogether.Add(chord); if (chord.Stem.BeamContinues) // this is true by default { breakGroup = false; } else { breakGroup = true; } } } if (chordsBeamedTogether.Count > 0) { if (rest != null) { if (rest.LocalCautionaryChordDef == null) { breakGroup = true; } } if (clef != null) { breakGroup = true; } if (barline != null && !pageFormat.BeamsCrossBarlines) { breakGroup = true; } if (chord == lastChord) { breakGroup = true; } } if (chordsBeamedTogether.Count > 0 && breakGroup) { if (currentClef != null) { if (chordsBeamedTogether.Count == 1) { if (this.StemDirection == VerticalDir.none) { chordsBeamedTogether[0].Stem.Direction = chordsBeamedTogether[0].DefaultStemDirection(currentClef); } else { chordsBeamedTogether[0].Stem.Direction = this.StemDirection; } } else if (chordsBeamedTogether.Count > 1) { float beamThickness = pageFormat.BeamThickness; float beamStrokeThickness = pageFormat.StafflineStemStrokeWidth; if (this is InputVoice) { beamThickness *= pageFormat.InputStavesSizeFactor; beamStrokeThickness *= pageFormat.InputStavesSizeFactor; } chordsBeamedTogether[0].BeamBlock = new BeamBlock(currentClef, chordsBeamedTogether, this.StemDirection, beamThickness, beamStrokeThickness); } } chordsBeamedTogether.Clear(); } if (clef != null) { currentClef = clef; } } }
public ClefMetrics(ClefSymbol clef, float gap) : base() { float trebleTop = -4.35F * gap; float trebleRight = 3.1F * gap; float highTrebleTop = -5.9F * gap; float trebleBottom = 2.7F * gap; #region treble clefs switch(clef.ClefType) { case "t": _objectType = "trebleClef"; _top = trebleTop; _right = trebleRight; _bottom = trebleBottom; break; case "t1": // trebleClef8 _objectType = "trebleClef8"; _top = highTrebleTop; _right = trebleRight; _bottom = trebleBottom; break; case "t2": // trebleClef2x8 _objectType = "trebleClef2x8"; _top = highTrebleTop; _right = trebleRight; _bottom = trebleBottom; break; case "t3": // trebleClef3x8 _objectType = "trebleClef3x8"; _top = highTrebleTop; _right = trebleRight; _bottom = trebleBottom; break; default: // can be a bass clef ( see below) break; } if(_right > 0F) { Move(0F, 3 * gap); } #endregion treble clefs if(!(_right > 0F)) { float bassTop = -gap; float bassRight = trebleRight; float bassBottom = gap * 3F; float lowBassBottom = gap * 4.5F; #region bass clefs switch(clef.ClefType) { case "b": _objectType = "bassClef"; _top = bassTop; _right = bassRight; _bottom = bassBottom; break; case "b1": // bassClef8 _objectType = "bassClef8"; _top = bassTop; _right = bassRight; _bottom = lowBassBottom; break; case "b2": // bassClef2x8 _objectType = "bassClef2x8"; _top = bassTop; _right = bassRight; _bottom = lowBassBottom; break; case "b3": // bassClef3x8 _objectType = "bassClef3x8"; _top = bassTop; _right = bassRight; _bottom = lowBassBottom; break; default: Debug.Assert(false, "Unknown clef type."); break; } if(_right > 0F) { Move(0, gap); } } #endregion FontHeight = clef.FontHeight; }
private void GetStaffParameters(NoteObject rootObject) { // If a staff has two voices, both should contain the same clefs. // The clefs are, however, different objects in the two voices: // clef.IsVisible may be true in one voice and false in the other one. Voice voice = rootObject.Voice; _staffOriginY = voice.Staff.Metrics.StafflinesTop; _nStafflines = voice.Staff.NumberOfStafflines; foreach(NoteObject noteObject in voice.NoteObjects) { ClefSymbol cs = noteObject as ClefSymbol; if(cs != null) _clef = cs; if(noteObject == rootObject) break; } }
/// <summary> /// Returns the head's y-coordinates wrt the chord. /// The chord's y-origin is the top line of the staff. /// (Y-Alignment of a notehead on the top line of the staff is 0.) /// Uses the following protected variables (in Metrics) which have been set by GetStaffParameters() /// protected float _gapVBPX = 0F; /// protected int _nStafflines = 0; /// protected ClefSymbol _clef = null; /// </summary> /// <param name="headIndex"></param> /// <param name="?"></param> /// <param name="?"></param> public float GetOriginY(ClefSymbol clef, float gap) { string[] alphabet = { "C", "D", "E", "F", "G", "A", "B" }; float shiftFactor = 0F; switch(this.Pitch[0]) { case 'A': shiftFactor = 2.5F; break; case 'B': shiftFactor = 2F; break; case 'C': shiftFactor = 5; break; case 'D': shiftFactor = 4.5F; break; case 'E': shiftFactor = 4F; break; case 'F': shiftFactor = 3.5F; break; case 'G': shiftFactor = 3F; break; } // shiftFactor is currently for the octave above middle C (octave = 5) on a normal treble clef // F6 is at shiftFactor 0 (the top line of the staff). int octave = 0; try { string octaveString = this.Pitch.Substring(1); if(octaveString == ":") octave = 10; else octave = int.Parse(octaveString); } catch { Debug.Assert(false, "Error in octave string"); } float octaveShift = octave - 5F; shiftFactor -= (octaveShift * 3.5F); // 3.5 spaces is one octave // shiftFactor is currently correct for all octaves on a normal treble clef switch(clef.ClefType) { case "t": break; case "t1": // trebleClef8 shiftFactor += 3.5F; // shift down one octave break; case "t2": // trebleClef2x8 shiftFactor += 7F; // shift down two octaves break; case "t3": // trebleClef3x8 shiftFactor += 10.5F; // shift down three octaves break; case "b": shiftFactor -= 6F; // shift up six spaces break; case "b1": // bassClef8 shiftFactor -= 9.5F; // shift up six spaces + 1 octave break; case "b2": // bassClef2x8 shiftFactor -= 13F; // shift up six spaces + 2 octaves break; case "b3": // bassClef3x8 shiftFactor -= 16.5F; // shift up six spaces + 3 octaves break; default: break; } float headY = shiftFactor * gap; return headY; }
private void AddExtendersAtTheBeginningsofStaves(List <Staff> staves, float rightMarginPos, float gap, float extenderStrokeWidth, float hairlinePadding) { foreach (Staff staff in staves) { if (!(staff is InvisibleOutputStaff)) { foreach (Voice voice in staff.Voices) { List <NoteObject> noteObjects = voice.NoteObjects; ClefSymbol firstClef = null; CautionaryChordSymbol cautionaryChordSymbol = null; ChordSymbol firstChord = null; RestSymbol firstRest = null; for (int index = 0; index < noteObjects.Count; ++index) { if (firstClef == null) { firstClef = noteObjects[index] as ClefSymbol; } if (cautionaryChordSymbol == null) { cautionaryChordSymbol = noteObjects[index] as CautionaryChordSymbol; } if (firstChord == null) { firstChord = noteObjects[index] as ChordSymbol; } if (firstRest == null) { firstRest = noteObjects[index] as RestSymbol; } if (firstClef != null && (cautionaryChordSymbol != null || firstChord != null || firstRest != null)) { break; } } if (firstClef != null && cautionaryChordSymbol != null) { // create brackets List <CautionaryBracketMetrics> cbMetrics = cautionaryChordSymbol.ChordMetrics.CautionaryBracketsMetrics; Debug.Assert(cbMetrics.Count == 2); Metrics clefMetrics = firstClef.Metrics; // extender left of cautionary List <float> ys = cautionaryChordSymbol.ChordMetrics.HeadsOriginYs; List <float> x1s = GetEqualFloats(clefMetrics.Right - (hairlinePadding * 2), ys.Count); List <float> x2s = GetEqualFloats(cbMetrics[0].Left, ys.Count); for (int i = 0; i < x2s.Count; ++i) { if ((x2s[i] - x1s[i]) < gap) { x1s[i] = x2s[i] - gap; } } cautionaryChordSymbol.ChordMetrics.NoteheadExtendersMetricsBefore = CreateExtenders(x1s, x2s, ys, extenderStrokeWidth, gap, true); // extender right of cautionary x1s = GetEqualFloats(cbMetrics[1].Right, ys.Count); x2s = GetCautionaryRightExtenderX2s(cautionaryChordSymbol, voice.NoteObjects, x1s, ys, hairlinePadding); cautionaryChordSymbol.ChordMetrics.NoteheadExtendersMetrics = CreateExtenders(x1s, x2s, ys, extenderStrokeWidth, gap, true); } } } } }
public VerticalDir DefaultStemDirection(ClefSymbol clef) { Debug.Assert(this.HeadsTopDown.Count > 0); float gap = 32F; // dummy value List<float> topDownHeadOriginYs = new List<float>(); int lastMidiPitch = int.MaxValue; foreach(Head head in this.HeadsTopDown) { Debug.Assert(head.MidiPitch < lastMidiPitch); topDownHeadOriginYs.Add(head.GetOriginY(clef, gap)); } float heightOfMiddleStaffLine = (this.Voice.Staff.NumberOfStafflines / 2) * gap; float halfHeight = 0F; if(topDownHeadOriginYs.Count == 1) halfHeight = topDownHeadOriginYs[0]; else halfHeight = (topDownHeadOriginYs[topDownHeadOriginYs.Count - 1] + topDownHeadOriginYs[0]) / 2; if(halfHeight <= heightOfMiddleStaffLine) return VerticalDir.down; else return VerticalDir.up; }