Ejemplo n.º 1
0
        /// <summary>
        /// Writes out an SVG Voice
        /// </summary>
        /// <param name="w"></param>
        public virtual void WriteSVG(SvgWriter w, bool staffIsVisible)
        {
            for (int i = 0; i < NoteObjects.Count; ++i)
            {
                NoteObject noteObject = NoteObjects[i];
                Barline    barline    = noteObject as Barline;
                if (staffIsVisible && barline != null)
                {
                    bool       isLastNoteObject = (i == (NoteObjects.Count - 1));
                    float      top                  = Staff.Metrics.StafflinesTop;
                    float      bottom               = Staff.Metrics.StafflinesBottom;
                    PageFormat pageFormat           = Staff.SVGSystem.Score.PageFormat;
                    float      barlineStrokeWidth   = pageFormat.BarlineStrokeWidth;
                    float      stafflineStrokeWidth = pageFormat.StafflineStemStrokeWidth;
                    barline.WriteSVG(w, top, bottom, barlineStrokeWidth, stafflineStrokeWidth, isLastNoteObject, false);
                }

                ChordSymbol chordSymbol = noteObject as ChordSymbol;
                if (chordSymbol != null)
                {
                    chordSymbol.WriteSVG(w, staffIsVisible);
                }
                else
                {
                    // if this is the first barline, the staff name and (maybe) barnumber will be written.
                    noteObject.WriteSVG(w, staffIsVisible);
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// This function moves the lowerChord to the left or right in order to avoid collisions with
        /// the noteheads of the upper chord.
        /// The positions of noteheads and ledgerlines relative to their own stem is never changed.
        /// The positions of accidentals are adjusted in both chords after the lower chord has moved.
        /// Stem lengths, and the positions of flags and beamBlocks, are adjusted later in FinalizeBeamBlocks().
        ///
        /// The stems are currently at the standard x-positions for stems up and down at the same MsPosition.
        /// Their lengths have been changed if necessary, for crossing parts. So collisions can be checked
        /// reliably in this function.
        /// There are 7 possible horizontal positions for the stem of the lower chord:
        ///     1. the standard position (aligned as when the lower chord is well below the upper chord)
        ///     2. hairline left of upper noteheads
        ///     3. aligned with upper stem
        ///          (top notehead of the bottom chord is half a space below the bottom notehead of the upper chord)
        ///     4. thin hairline right of upper stem
        ///          (top notehead of the bottom chord is at the same height as the bottom notehead of the upper chord)
        ///     5. thick hairline right of upper stem
        ///          (top notehead of the bottom chord is above the bottom notehead of the upper chord)
        ///     If both upper and lower chords have sideways shifted noteheads, and there are no notehead collisions:
        ///         6. thick hairline right of right-side note head on upper stem
        ///     else
        ///         7. a head width left of its original position
        /// The position selected, is the first of these which can be applied without causing any collisions.
        /// The principle is that the total width of all the noteheads should be minimized.
        /// Accidentals are rearranged (top to bottom, to the left of the combined chord) once the
        /// noteheads and ledgerlines have been given their final positions.
        /// </summary>
        private void AdjustLowerChordXPosition(ChordSymbol upperChord, ChordSymbol lowerChord)
        {
            Debug.Assert(upperChord.MsPosition == lowerChord.MsPosition);
            if (!(upperChord is CautionaryChordSymbol))
            {
                Debug.Assert(upperChord.Stem.Direction == VerticalDir.up);
            }
            if (!(lowerChord is CautionaryChordSymbol))
            {
                Debug.Assert(lowerChord.Stem.Direction == VerticalDir.down);
            }

            List <HeadMetrics> upperChordHeadMetrics = upperChord.ChordMetrics.HeadsMetrics; // a clone
            List <HeadMetrics> lowerChordHeadMetrics = lowerChord.ChordMetrics.HeadsMetrics; // a clone
            StemMetrics        lowerChordStemMetrics = lowerChord.ChordMetrics.StemMetrics;  // a clone

            float deltaX = LowerChordDeltaX(upperChordHeadMetrics, lowerChordHeadMetrics, lowerChordStemMetrics);

            if (deltaX != 0)
            {
                lowerChord.ChordMetrics.Move(deltaX, 0F); // move the whole chord, including accidentals
            }
            // adjust the positions of accidentals in both chords
            lowerChord.AdjustAccidentalsX(upperChord);
        }
Ejemplo n.º 3
0
 public Stem(ChordSymbol chordSymbol, Stem stem)
 {
     Chord = chordSymbol;
     if(stem != null)
     {
         Direction = stem.Direction;
     }
 }
Ejemplo n.º 4
0
 public Stem(ChordSymbol chordSymbol, Stem stem)
 {
     Chord = chordSymbol;
     if (stem != null)
     {
         Direction = stem.Direction;
     }
 }
Ejemplo n.º 5
0
        public ChordMetrics(System.Drawing.Graphics graphics, ChordSymbol chord, VerticalDir voiceStemDirection, float gap, float stemStrokeWidthVBPX)
            : base()
        {
            _top = float.MaxValue;
            _right = float.MinValue;
            _bottom = float.MinValue;
            _left = float.MaxValue;
            _drawObjects = chord.DrawObjects;

            _gap = gap;

            // The _objectType is written to the SVG file as a group name, but is otherwise not used.
            if(chord is CautionaryChordSymbol)
                _objectType = "cautionary chord";
            else
                _objectType = "chord";

            GetStaffParameters(chord); // sets _clef to the most recent clef, and _nStafflines.

            // For each component, find its characterID, deltaX and deltaY re the chord's origin.
            // The chord's x-origin is the centre of the outermost notehead.
            // (deltaX of the outermost notehead is 0.)
            // The chord's y-origin is the top line of the staff.
            // (deltaY of a notehead on the top line of the staff is 0.)

            if(chord.BeamBlock != null && chord.BeamBlock.Chords[0] == chord)
                this.BeamBlock = chord.BeamBlock;

            SetHeadsMetrics(chord, stemStrokeWidthVBPX);
            if(chord.Stem.Draw) // false for cautionary chords
                SetStemAndFlags(chord, _headsMetricsTopDown, stemStrokeWidthVBPX);

            // if the chord is part of a beamGroup, the stem tips are all at one height here.

            // These objects are created with originX and originY at 0,0 (the chord's origin).
            CreateLedgerlineAndAccidentalMetrics(chord.FontHeight, chord.HeadsTopDown, _headsMetricsTopDown, stemStrokeWidthVBPX);
            CautionaryChordSymbol cautionaryChordSymbol = chord as CautionaryChordSymbol;
            if(cautionaryChordSymbol != null)
            {
                CreateCautionaryBracketsMetrics(cautionaryChordSymbol);
            }
            else
            {
                bool dynamicIsBelow;
                bool ornamentIsBelow;
                _lyricMetrics = NewLyricMetrics(chord.Voice.StemDirection, graphics, gap);

                GetRelativePositions(chord.Voice.StemDirection, _lyricMetrics, out ornamentIsBelow, out dynamicIsBelow);
                _ornamentMetrics = NewOrnamentMetrics(graphics, gap, ornamentIsBelow);

                _dynamicMetrics = NewDynamicMetrics(gap, dynamicIsBelow);

                MoveAuxilliaries(chord.Stem.Direction, gap);
            }

            SetExternalBoundary();
        }
Ejemplo n.º 6
0
        public bool Draw = true; // set to false for cautionary chords

        #endregion Fields

        #region Constructors

        public Stem(ChordSymbol chordSymbol, bool beamContinues)
        {
            Chord = chordSymbol;
            if(chordSymbol.DurationClass == DurationClass.breve
                || chordSymbol.DurationClass == DurationClass.semibreve
                || chordSymbol.DurationClass == DurationClass.minim
                || chordSymbol.DurationClass == DurationClass.crotchet)
                BeamContinues = false;
            else
                BeamContinues = beamContinues;
        }
Ejemplo n.º 7
0
        public bool Draw = true; // set to false for cautionary chords

        #endregion Fields

        #region Constructors

        public Stem(ChordSymbol chordSymbol)
        {
            Chord = chordSymbol;
            if(chordSymbol.DurationClass == DurationClass.breve
                || chordSymbol.DurationClass == DurationClass.semibreve
                || chordSymbol.DurationClass == DurationClass.minim
                || chordSymbol.DurationClass == DurationClass.crotchet)
                BeamContinues = false;
            else
                BeamContinues = true; // theoretically, I can reset this default value later (when breaking beams programmatically)
        }
Ejemplo n.º 8
0
        public HeadMetrics(ChordSymbol chord, float gapVBPX)
            : base(chord.DurationClass, false, chord.FontHeight)
        {
            Move((Left - Right) / 2F, 0F);             // centre horizontally

            float horizontalPadding = chord.FontHeight * 0.04F;

            _leftStemX  = _left;
            _rightStemX = _right;
            _left      -= horizontalPadding;
            _right     += horizontalPadding;
        }
Ejemplo n.º 9
0
        private void AddExtendersAtTheEndsOfStaves(List <Staff> staves, float rightMarginPos, float gap, float extenderStrokeWidth,
                                                   float hairlinePadding, SvgSystem nextSystem)
        {
            for (int staffIndex = 0; staffIndex < staves.Count; ++staffIndex)
            {
                Staff staff = staves[staffIndex];
                if (!(staff is InvisibleOutputStaff))
                {
                    for (int voiceIndex = 0; voiceIndex < staff.Voices.Count; ++voiceIndex)
                    {
                        Voice                 voice       = staff.Voices[voiceIndex];
                        List <NoteObject>     noteObjects = voice.NoteObjects;
                        ChordSymbol           lastChord   = null;
                        RestSymbol            lastRest    = null;
                        CautionaryChordSymbol cautionary  = null;
                        for (int index = noteObjects.Count - 1; index >= 0; --index)
                        {
                            lastChord  = noteObjects[index] as ChordSymbol;
                            lastRest   = noteObjects[index] as RestSymbol;
                            cautionary = noteObjects[index] as CautionaryChordSymbol;
                            if (cautionary != null)
                            {
                                cautionary.Visible = false;
                                // a CautionaryChordSymbol is a ChordSymbol, but we have not found a real one yet.
                            }
                            else if (lastChord != null || lastRest != null)
                            {
                                break;
                            }
                        }

                        if (lastChord != null && lastChord.MsDurationToNextBarline != null)
                        {
                            List <float> x1s = GetX1sFromChord1(lastChord.ChordMetrics, hairlinePadding);
                            List <float> x2s;
                            List <float> ys = lastChord.ChordMetrics.HeadsOriginYs;
                            if (nextSystem != null && FirstDurationSymbolOnNextSystemIsCautionary(nextSystem.Staves[staffIndex].Voices[voiceIndex]))
                            {
                                x2s = GetEqualFloats(rightMarginPos + gap, x1s.Count);
                            }
                            else
                            {
                                x2s = GetEqualFloats(rightMarginPos, x1s.Count);
                            }
                            lastChord.ChordMetrics.NoteheadExtendersMetrics =
                                CreateExtenders(x1s, x2s, ys, extenderStrokeWidth, gap, true);
                        }
                    }
                }
            }
        }
Ejemplo n.º 10
0
 public Stem(ChordSymbol chordSymbol)
 {
     Chord = chordSymbol;
     if (chordSymbol.DurationClass == DurationClass.breve ||
         chordSymbol.DurationClass == DurationClass.semibreve ||
         chordSymbol.DurationClass == DurationClass.minim ||
         chordSymbol.DurationClass == DurationClass.crotchet)
     {
         BeamContinues = false;
     }
     else
     {
         BeamContinues = true; // theoretically, I can reset this default value later (when breaking beams programmatically)
     }
 }
Ejemplo n.º 11
0
        public HeadMetrics(ChordSymbol chord, Head head, double gapVBPX, CSSObjectClass headClass)
            : base(chord.DurationClass, chord.FontHeight, headClass)
        {
            Move((Left - Right) / 2, 0F);             // centre horizontally

            double horizontalPadding = chord.FontHeight * 0.04;

            _leftStemX  = _left;
            _rightStemX = _right;
            _left      -= horizontalPadding;
            _right     += horizontalPadding;
            if (head != null)
            {
                CSSColorClass = head.ColorClass;
            }
        }
Ejemplo n.º 12
0
        private float BeamEndMsPosition(Beam beam)
        {
            Debug.Assert(this.Beams.Contains(beam));
            float beamEndMsPosition = float.MinValue;

            for (int i = Chords.Count - 1; i >= 0; --i)
            {
                ChordSymbol chord = Chords[i];
                float       stemX = chord.ChordMetrics.StemMetrics.OriginX;
                if (stemX == beam.LeftX || stemX == beam.RightX) // rightX can be a beam stub
                {
                    beamEndMsPosition = chord.MsPosition;
                    break;
                }
            }
            Debug.Assert(beamEndMsPosition != float.MinValue);
            return(beamEndMsPosition);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Construct a new Head with a particular midi pitch number.
        /// </summary>
        /// <param name="chord">The containing ChordSymbol</param>
        /// <param name="midiPitch">The midiPitch. Must be in range [0..127]</param>
        /// <param name="midiVelocity">The midiVelocity. Must be in range [0..127] for output Heads.</param>
        /// <param name="useSharp">true means use #, false means use flat(if there is a choice).</param>
        public Head(ChordSymbol chord, int midiPitch, int midiVelocity, bool useSharp)
        {
            Chord = chord;
            KeyValuePair <string, int> sharpKVP    = new KeyValuePair <string, int>();
            KeyValuePair <string, int> flatKVP     = new KeyValuePair <string, int>();
            KeyValuePair <string, int> previousKVP = new KeyValuePair <string, int>("C0", 0);

            foreach (KeyValuePair <string, int> kvp in M.MidiPitchDict)
            {
                if (kvp.Value >= midiPitch)
                {
                    flatKVP  = kvp;
                    sharpKVP = previousKVP;
                    break;
                }
                previousKVP = kvp;
            }
            if (flatKVP.Value == midiPitch)
            {
                Pitch      = flatKVP.Key;
                Alteration = 0;
            }
            else if (useSharp)
            {
                Pitch      = sharpKVP.Key;
                Alteration = midiPitch - sharpKVP.Value;
            }
            else
            {
                Pitch      = flatKVP.Key;
                Alteration = midiPitch - flatKVP.Value;
            }
            if (Alteration != 0)
            {
                DisplayAccidental = DisplayAccidental.force;
            }

            if (chord != null)
            {
                FontSize = chord.FontHeight;
            }

            MidiVelocity = midiVelocity;
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Construct a new Head with a particular midi pitch number.
        /// </summary>
        /// <param name="chord">The containing ChordSymbol</param>
        /// <param name="midiPitch">The midiPitch. Must be in range [0..127]</param>
        /// <param name="midiVelocity">The midiVelocity. Must be in range [0..127] for output Heads. Is -1 for input Heads</param>
        /// <param name="useSharp">true means use #, false means use flat(if there is a choice).</param>
        public Head(ChordSymbol chord, int midiPitch, int midiVelocity, bool useSharp)
        {
            Chord = chord;
            KeyValuePair<string, int> sharpKVP = new KeyValuePair<string, int>();
            KeyValuePair<string, int> flatKVP = new KeyValuePair<string, int>();
            KeyValuePair<string, int> previousKVP = new KeyValuePair<string, int>("C0", 0);
            foreach(KeyValuePair<string, int> kvp in M.MidiPitchDict)
            {
                if(kvp.Value >= midiPitch)
                {
                    flatKVP = kvp;
                    sharpKVP = previousKVP;
                    break;
                }
                previousKVP = kvp;
            }
            if(flatKVP.Value == midiPitch)
            {
                Pitch = flatKVP.Key;
                Alteration = 0;
            }
            else if(useSharp)
            {
                Pitch = sharpKVP.Key;
                Alteration = midiPitch - sharpKVP.Value;
            }
            else
            {
                Pitch = flatKVP.Key;
                Alteration = midiPitch - flatKVP.Value;
            }
            if(Alteration != 0)
                DisplayAccidental = DisplayAccidental.force;

            if(chord != null)
                FontSize = chord.FontHeight;

            _midiVelocity = midiVelocity;
        }
Ejemplo n.º 15
0
 /// <summary>
 /// Force the display of naturals where the synchronous chords share a diatonic pitch,
 /// and one of them is not natural.
 /// </summary>
 private void ForceNaturals(ChordSymbol synchChord1, ChordSymbol synchChord2)
 {
     Debug.Assert(synchChord1.MsPosition == synchChord2.MsPosition);
     foreach (Head head1 in synchChord1.HeadsTopDown)
     {
         foreach (Head head2 in synchChord2.HeadsTopDown)
         {
             if (head1.Pitch == head2.Pitch)
             {
                 if (head1.Alteration != 0)
                 {
                     head2.DisplayAccidental = DisplayAccidental.force;
                 }
                 if (head2.Alteration != 0)
                 {
                     head1.DisplayAccidental = DisplayAccidental.force;
                 }
                 break;
             }
         }
     }
 }
Ejemplo n.º 16
0
        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);
        }
Ejemplo n.º 17
0
        private List <float> GetCautionaryRightExtenderX2s(CautionaryChordSymbol cautionaryChordSymbol1,
                                                           List <NoteObject> noteObjects, List <float> x1s, List <float> ys, float hairlinePadding)
        {
            List <float> x2s     = new List <float>();
            NoteObject   no2     = GetFollowingChordRestOrBarlineSymbol(noteObjects);
            Barline      barline = no2 as Barline;
            ChordSymbol  chord2  = no2 as ChordSymbol;
            RestSymbol   rest2   = no2 as RestSymbol;

            if (barline != null)
            {
                float x2 = barline.Metrics.OriginX;
                x2s = GetEqualFloats(x2, x1s.Count);
            }
            else if (chord2 != null)
            {
                x2s = GetX2sFromChord2(ys, chord2.ChordMetrics, hairlinePadding);
            }
            else if (rest2 != null)
            {
                float x2 = rest2.Metrics.Left - hairlinePadding;
                x2s = GetEqualFloats(x2, x1s.Count);
            }
            else // no2 == null
            {
                Debug.Assert(no2 == null);
                // This voice has no further chords or rests,
                // so draw extenders to the right margin.
                // extend to the right margin
                PageFormat pageFormat     = cautionaryChordSymbol1.Voice.Staff.SVGSystem.Score.PageFormat;
                float      rightMarginPos = pageFormat.RightMarginPos;
                float      gap            = pageFormat.Gap;
                x2s = GetEqualFloats(rightMarginPos + gap, ys.Count);
            }
            return(x2s);
        }
Ejemplo n.º 18
0
        private HashSet <ChordSymbol> FindChordSymbolsThatStartBeamBlocks()
        {
            HashSet <ChordSymbol> chordSymbolsThatStartBeamBlocks = new HashSet <ChordSymbol>();
            var chordSymbols = new List <ChordSymbol>();

            foreach (ChordSymbol symb in ChordSymbols)
            {
                chordSymbols.Add(symb);
            }
            for (int i = 0; i < chordSymbols.Count; i++)
            {
                ChordSymbol chord = chordSymbols[i];
                if (chord.BeamBlockDef != null)
                {
                    if ((chord.IsBeamStart) ||
                        (i == 0 && (chord.IsBeamRestart || chord.IsBeamEnd)))
                    {
                        chordSymbolsThatStartBeamBlocks.Add(chord);
                    }
                }
            }

            return(chordSymbolsThatStartBeamBlocks);
        }
Ejemplo n.º 19
0
        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);
                        }
                    }
                }
            }
        }
Ejemplo n.º 20
0
        /// <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;
                }
            }
        }
Ejemplo n.º 21
0
 /// <summary>
 /// Sets the stem. Pass flagsBlockMetrics=null for duration classes having no flags.
 /// </summary>
 private StemMetrics NewStemMetrics(List<HeadMetrics> topDownHeadsMetrics, ChordSymbol chord, Metrics flagsBlockMetrics, float strokeWidth)
 {
     return NewStemMetrics(topDownHeadsMetrics, chord.Stem.Direction, chord.FontHeight, flagsBlockMetrics, chord.BeamBlock, strokeWidth);
 }
Ejemplo n.º 22
0
 public Stem(ChordSymbol chordSymbol)
 {
     Chord = chordSymbol;
 }
Ejemplo n.º 23
0
        /// <summary>
        /// This chordSymbol is in the lower of two voices on a staff. The argument is another synchronous chordSymbol
        /// at the same MsPosition on the same staff. Both chordSymbols have ChordMetrics, and the chord in the lower
        /// voice has been moved (either right or left) so that there are no collisions between noteheads.
        /// This function moves the accidentals in both chords horizontally, so that they are all on the left of both
        /// chords but as far to the right as possible without there being any collisions.
        /// Accidentals are positioned in top-bottom and right-left order.
        /// If two noteheads are at the same diatonic height, both accidentals will already exist and have forced display.
        /// Such accidentals are placed in the left-right order of the noteheads
        /// </summary>
        /// <param name="upperChord"></param>
        public void AdjustAccidentalsX(ChordSymbol upperChord)
        {
            float stafflineStemStrokeWidth = Voice.Staff.SVGSystem.Score.PageFormat.StafflineStemStrokeWidth;

            this.ChordMetrics.AdjustAccidentalsForTwoChords(upperChord.ChordMetrics, stafflineStemStrokeWidth);
        }
Ejemplo n.º 24
0
        /// <summary>
        /// This chordSymbol is in the lower of two voices on a staff. The argument is another synchronous chordSymbol
        /// at the same MsPosition on the same staff. Both chordSymbols have ChordMetrics, and the chord in the lower
        /// voice has been moved (either right or left) so that there are no collisions between noteheads.
        /// This function moves the accidentals in both chords horizontally, so that they are all on the left of both
        /// chords but as far to the right as possible without there being any collisions.
        /// Accidentals are positioned in top-bottom and right-left order.
        /// If two noteheads are at the same diatonic height, both accidentals will already exist and have forced display.
        /// Such accidentals are placed in the left-right order of the noteheads
        /// </summary>
        /// <param name="upperChord"></param>
        public void AdjustAccidentalsX(ChordSymbol upperChord)
        {
            float stafflineStemStrokeWidth = Voice.Staff.SVGSystem.Score.PageFormat.StafflineStemStrokeWidth;

            this.ChordMetrics.AdjustAccidentalsForTwoChords(upperChord.ChordMetrics, stafflineStemStrokeWidth);
        }
Ejemplo n.º 25
0
        public HeadMetrics(ChordSymbol chord, float gapVBPX)
            : base(chord.DurationClass, false, chord.FontHeight)
        {
            Move((Left - Right) / 2F, 0F); // centre horizontally

            float horizontalPadding = chord.FontHeight * 0.04F;
            _leftStemX = _left;
            _rightStemX = _right;
            _left -= horizontalPadding;
            _right += horizontalPadding;
        }
Ejemplo n.º 26
0
        public HeadMetrics(ChordSymbol chord, Head head, float gapVBPX)
            : base(chord.DurationClass, false, chord.FontHeight)
        {
            Move((Left - Right) / 2F, 0F); // centre horizontally

            float horizontalPadding = chord.FontHeight * 0.04F;
            _leftStemX = _left;
            _rightStemX = _right;
            _left -= horizontalPadding;
            _right += horizontalPadding;
            if(head != null && head.ColorAttribute != null)
            {
                _colorAttribute = head.ColorAttribute;
            }
        }
Ejemplo n.º 27
0
 private void AdjustStemLengths(ChordSymbol upperChord, ChordSymbol lowerChord)
 {
     upperChord.ChordMetrics.AdjustStemLengthAndFlagBlock(upperChord.DurationClass, upperChord.FontHeight, lowerChord.ChordMetrics.HeadsMetrics);
     lowerChord.ChordMetrics.AdjustStemLengthAndFlagBlock(lowerChord.DurationClass, lowerChord.FontHeight, upperChord.ChordMetrics.HeadsMetrics);
 }
Ejemplo n.º 28
0
        private void AddExtendersInStaves(List <Staff> staves, float extenderStrokeWidth, float gap, float hairlinePadding)
        {
            foreach (Staff staff in staves)
            {
                if (!(staff is InvisibleOutputStaff))
                {
                    foreach (Voice voice in staff.Voices)
                    {
                        List <NoteObject> noteObjects = voice.NoteObjects;
                        int index = 0;
                        while (index < noteObjects.Count - 1)
                        {
                            // noteObjects.Count - 1 because index is immediately incremented when a continuing
                            // chord or rest is found, and it should always be less than noteObjects.Count.
                            ChordSymbol chord1 = noteObjects[index] as ChordSymbol;
                            if (chord1 != null)
                            {
                                List <float> x1s = GetX1sFromChord1(chord1.ChordMetrics, hairlinePadding);
                                List <float> x2s = null;
                                List <float> ys  = null;
                                ++index;
                                if (chord1.MsDurationToNextBarline != null)
                                {
                                    while (index < noteObjects.Count)
                                    {
                                        CautionaryChordSymbol cautionaryChordSymbol = noteObjects[index] as CautionaryChordSymbol;
                                        ChordSymbol           chord2 = noteObjects[index] as ChordSymbol;
                                        RestSymbol            rest2  = noteObjects[index] as RestSymbol;
                                        if (cautionaryChordSymbol != null)
                                        {
                                            cautionaryChordSymbol.Visible = false;
                                        }
                                        else if (chord2 != null)
                                        {
                                            ys  = chord1.ChordMetrics.HeadsOriginYs;
                                            x2s = GetX2sFromChord2(ys, chord2.ChordMetrics, hairlinePadding);
                                            break;
                                        }
                                        else if (rest2 != null)
                                        {
                                            float x2 = rest2.Metrics.Left - hairlinePadding;
                                            ys  = chord1.ChordMetrics.HeadsOriginYs;
                                            x2s = GetEqualFloats(x2, x1s.Count);
                                            break;
                                        }
                                        ++index;
                                    }

                                    if (x2s != null && ys != null)
                                    {
                                        bool hasContinuingBeamBlock =
                                            ((chord1.BeamBlock != null) && (chord1.BeamBlock.Chords[chord1.BeamBlock.Chords.Count - 1] != chord1));
                                        if (hasContinuingBeamBlock)
                                        {
                                            Debug.Assert(true);
                                        }

                                        Barline barline = noteObjects[index - 1] as Barline;
                                        if (barline != null)
                                        {
                                            float x2 = barline.Metrics.OriginX;
                                            x2s = GetEqualFloats(x2, x1s.Count);
                                        }
                                        bool drawExtender = false;
                                        if (chord1.DurationClass > DurationClass.semiquaver)
                                        {
                                            drawExtender = true;
                                        }
                                        if (chord1.DurationClass < DurationClass.crotchet && hasContinuingBeamBlock)
                                        {
                                            drawExtender = false;
                                        }

                                        chord1.ChordMetrics.NoteheadExtendersMetrics =
                                            CreateExtenders(x1s, x2s, ys, extenderStrokeWidth, gap, drawExtender);
                                    }
                                }
                            }
                            else
                            {
                                ++index;
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 29
0
        /// <summary>
        /// chord.Heads are in top-down order.
        /// </summary>
        private void SetHeadsMetrics(ChordSymbol chord, float ledgerlineStemStrokeWidth)
        {
            _headsMetricsTopDown = new List<HeadMetrics>();

            HeadMetrics hMetrics = new HeadMetrics(chord, null, _gap); // the head is horizontally aligned at 0 by default.
            float horizontalShift = hMetrics.RightStemX - hMetrics.LeftStemX - (ledgerlineStemStrokeWidth / 2F); // the distance to shift left or right if heads would collide
            float shiftRange = _gap * 0.75F;

            if(chord.Stem.Direction == VerticalDir.up)
            {
                List<Head> bottomUpHeads = new List<Head>();
                foreach(Head head in chord.HeadsTopDown)
                    bottomUpHeads.Insert(0, head);
                List<HeadMetrics> bottomUpMetrics = new List<HeadMetrics>();

                foreach(Head head in bottomUpHeads)
                {
                    float newHeadOriginY = head.GetOriginY(_clef, _gap); // note that the CHORD's originY is always at the top line of the staff
                    float newHeadAlignX = 0F;
                    foreach(Metrics headMetric in bottomUpMetrics)
                    {
                        float existingHeadAlignX = (headMetric.Left + headMetric.Right) / 2F;
                        if((newHeadOriginY == headMetric.OriginY)
                        || (existingHeadAlignX == 0F
                            && newHeadAlignX < (existingHeadAlignX + horizontalShift)
                            && newHeadOriginY > (headMetric.OriginY - shiftRange)))
                        {
                            newHeadAlignX = existingHeadAlignX + horizontalShift; // shifts more than once for extreme clusters ( e.g. F,F#,G)
                        }
                        else
                            newHeadAlignX = 0;
                    }

                    HeadMetrics headMetrics = new HeadMetrics(chord, head, _gap);
                    headMetrics.Move(newHeadAlignX, newHeadOriginY); // moves head.originY to headY
                    bottomUpMetrics.Add(headMetrics);
                }
                for(int i = bottomUpMetrics.Count - 1; i >= 0; --i)
                {
                    _headsMetricsTopDown.Add(bottomUpMetrics[i]);
                }
            }
            else // stem is down
            {
                foreach(Head head in chord.HeadsTopDown)
                {
                    float newHeadOriginY = head.GetOriginY(_clef, _gap); // note that the CHORD's originY is always at the top line of the staff
                    float newHeadAlignX = 0F;
                    foreach(HeadMetrics headMetric in _headsMetricsTopDown)
                    {
                        float existingHeadAlignX = (headMetric.Left + headMetric.Right) / 2F;
                        if((newHeadOriginY == headMetric.OriginY)
                        || (existingHeadAlignX == 0F
                            && newHeadAlignX < (existingHeadAlignX + horizontalShift)
                            && newHeadOriginY < (headMetric.OriginY + shiftRange)))
                        {
                            newHeadAlignX -= horizontalShift; // can shift left more than once
                        }
                        else
                            newHeadAlignX = 0;
                    }

                    HeadMetrics headMetrics = new HeadMetrics(chord, head, _gap);
                    headMetrics.Move(newHeadAlignX, newHeadOriginY); // moves head.originY to headY
                    _headsMetricsTopDown.Add(headMetrics);
                }
            }

            Debug.Assert(_originX == 0F);
            Debug.Assert(_headsMetricsTopDown.Count == chord.HeadsTopDown.Count);
        }
Ejemplo n.º 30
0
        private void SetStemAndFlags(ChordSymbol chord, List<HeadMetrics> topDownHeadsMetrics, float stemThickness)
        {
            DurationClass durationClass = chord.DurationClass;
            _flagsBlockMetrics = null;
            if(chord.BeamBlock == null
            && (durationClass == DurationClass.quaver
                || durationClass == DurationClass.semiquaver
                || durationClass == DurationClass.threeFlags
                || durationClass == DurationClass.fourFlags
                || durationClass == DurationClass.fiveFlags))
            {
                _flagsBlockMetrics = GetFlagsBlockMetrics(topDownHeadsMetrics,
                                                                durationClass,
                                                                chord.FontHeight,
                                                                chord.Stem.Direction,
                                                                stemThickness);
            }

            if(durationClass == DurationClass.minim
            || durationClass == DurationClass.crotchet
            || durationClass == DurationClass.quaver
            || durationClass == DurationClass.semiquaver
            || durationClass == DurationClass.threeFlags
            || durationClass == DurationClass.fourFlags
            || durationClass == DurationClass.fiveFlags)
            {
                _stemMetrics = NewStemMetrics(topDownHeadsMetrics, chord, _flagsBlockMetrics, stemThickness);
            }
        }
Ejemplo n.º 31
0
 /// <summary>
 /// This chordSymbol is in the lower of two voices on a staff. The argument is another synchronous chordSymbol
 /// at the same MsPosition on the same staff. Both chordSymbols have ChordMetrics, and the chord in the lower
 /// voice has been moved (either right or left) so that there are no collisions between noteheads.
 /// This function moves the accidentals in both chords horizontally, so that they are all on the left of both
 /// chords but as far to the right as possible without there being any collisions.
 /// Accidentals are positioned in top-bottom and right-left order.
 /// If two noteheads are at the same diatonic height, both accidentals will already exist and have forced display.
 /// Such accidentals are placed in the left-right order of the noteheads
 /// </summary>
 /// <param name="upperChord"></param>
 public void AdjustAccidentalsX(ChordSymbol upperChord)
 {
     this.ChordMetrics.AdjustAccidentalsForTwoChords(upperChord.ChordMetrics, M.PageFormat.StafflineStemStrokeWidthVBPX);
 }
Ejemplo n.º 32
0
 /// <summary>
 /// Force the display of naturals where the synchronous chords share a diatonic pitch,
 /// and one of them is not natural.
 /// </summary>
 private void ForceNaturals(ChordSymbol synchChord1, ChordSymbol synchChord2)
 {
     Debug.Assert(synchChord1.AbsMsPosition == synchChord2.AbsMsPosition);
     foreach(Head head1 in synchChord1.HeadsTopDown)
     {
         foreach(Head head2 in synchChord2.HeadsTopDown)
         {
             if(head1.Pitch == head2.Pitch)
             {
                 if(head1.Alteration != 0)
                     head2.DisplayAccidental = DisplayAccidental.force;
                 if(head2.Alteration != 0)
                     head1.DisplayAccidental = DisplayAccidental.force;
                 break;
             }
         }
     }
 }
Ejemplo n.º 33
0
 private List<float> GetCautionaryRightExtenderX2s(ChordSymbol cautionaryChordSymbol1,
     List<NoteObject> noteObjects, List<float> x1s, List<float> ys, float hairlinePadding)
 {
     List<float> x2s = new List<float>();
     NoteObject no2 = GetFollowingChordRestOrBarlineSymbol(noteObjects);
     Barline barline = no2 as Barline;
     ChordSymbol chord2 = no2 as ChordSymbol;
     RestSymbol rest2 = no2 as RestSymbol;
     if(barline != null)
     {
         float x2 = barline.Metrics.OriginX;
         x2s = GetEqualFloats(x2, x1s.Count);
     }
     else if(chord2 != null)
     {
         x2s = GetX2sFromChord2(ys, chord2.ChordMetrics, hairlinePadding);
     }
     else if(rest2 != null)
     {
         float x2 = rest2.Metrics.Left - hairlinePadding;
         x2s = GetEqualFloats(x2, x1s.Count);
     }
     else // no2 == null
     {
         Debug.Assert(no2 == null);
         // This voice has no further chords or rests,
         // so draw extenders to the right margin.
         // extend to the right margin
         PageFormat pageFormat = cautionaryChordSymbol1.Voice.Staff.SVGSystem.Score.PageFormat;
         float rightMarginPos = pageFormat.RightMarginPos;
         float gap = pageFormat.Gap;
         x2s = GetEqualFloats(rightMarginPos + gap, ys.Count);
     }
     return x2s;
 }
Ejemplo n.º 34
0
        private void CreateCautionaryBracketsMetrics(ChordSymbol chord)
        {
            PageFormat pageFormat = chord.Voice.Staff.SVGSystem.Score.PageFormat;
            float gap = pageFormat.Gap;
            float padding = pageFormat.StafflineStemStrokeWidth;
            float strokeWidth = pageFormat.StafflineStemStrokeWidth;
            float top, left, bottom, right;
            GetAccidentalsAndHeadsBox(out top, out right, out bottom, out left, gap, padding);
            float leftBracketLeft = left - (gap / 2F);
            float rightBracketRight = right + (gap / 2F);
            // the left bracket
            CautionaryBracketMetrics leftBracketMetrics = new CautionaryBracketMetrics(true, top, left, bottom, leftBracketLeft, strokeWidth);
            // the right bracket
            CautionaryBracketMetrics rightBracketMetrics = new CautionaryBracketMetrics(false, top, rightBracketRight, bottom, right, strokeWidth);

            _cautionaryBracketsMetrics = new List<CautionaryBracketMetrics>();
            this._cautionaryBracketsMetrics.Add(leftBracketMetrics);
            this._cautionaryBracketsMetrics.Add(rightBracketMetrics);
        }