예제 #1
0
        BringStemsCloser(ChordSymbol[] chords)
        {
            Stem firstStem = chords[0].Stem;
            Stem lastStem  = chords[1].Stem;

            /* If we're connecting a dotted 8th to a 16th, increase
             * the stem end of the dotted eighth.
             */
            if (firstStem.Duration == NoteDuration.DottedEighth &&
                lastStem.Duration == NoteDuration.Sixteenth)
            {
                if (firstStem.Direction == Stem.Up)
                {
                    firstStem.End = firstStem.End.Add(2);
                }
                else
                {
                    firstStem.End = firstStem.End.Add(-2);
                }
            }

            /* Bring the stem ends closer together */
            int distance = Math.Abs(firstStem.End.Dist(lastStem.End));

            if (firstStem.Direction == Stem.Up)
            {
                if (WhiteNote.Max(firstStem.End, lastStem.End) == firstStem.End)
                {
                    lastStem.End = lastStem.End.Add(distance / 2);
                }
                else
                {
                    firstStem.End = firstStem.End.Add(distance / 2);
                }
            }
            else
            {
                if (WhiteNote.Min(firstStem.End, lastStem.End) == firstStem.End)
                {
                    lastStem.End = lastStem.End.Add(-distance / 2);
                }
                else
                {
                    firstStem.End = firstStem.End.Add(-distance / 2);
                }
            }
        }
예제 #2
0
        void CreateBeam(ChordSymbol[] chords, int spacing)
        {
            Stem firstStem = chords[0].Stem;
            Stem lastStem  = chords[chords.Length - 1].Stem;

            /* Calculate the new stem direction */
            int newdirection = -1;

            foreach (ChordSymbol chord in chords)
            {
                if (chord.HasTwoStems)
                {
                    newdirection = chord.Stem.Direction;
                    break;
                }
            }

            if (newdirection == -1)
            {
                WhiteNote note1;
                WhiteNote note2;
                note1        = (firstStem.Direction == Stem.Up ? firstStem.Top : firstStem.Bottom);
                note2        = (lastStem.Direction == Stem.Up ? lastStem.Top : lastStem.Bottom);
                newdirection = StemDirection(note1, note2, chords[0].Clef);
            }
            foreach (ChordSymbol chord in chords)
            {
                chord.Stem.Direction = newdirection;
            }

            if (chords.Length == 2)
            {
                BringStemsCloser(chords);
            }
            else
            {
                LineUpStemEnds(chords);
            }

            firstStem.SetPair(lastStem, spacing);
            for (int i = 1; i < chords.Length; i++)
            {
                chords[i].Stem.Receiver = true;
            }
        }
예제 #3
0
 /** Create a new stem.  The top note, bottom note, and direction are
  * needed for drawing the vertical line of the stem.  The duration is
  * needed to draw the tail of the stem.  The overlap boolean is true
  * if the notes in the chord overlap.  If the notes overlap, the
  * stem must be drawn on the right side.
  */
 public Stem(WhiteNote bottom, WhiteNote top,
             NoteDuration duration, int direction, bool overlap)
 {
     this.top          = top;
     this.bottom       = bottom;
     this.duration     = duration;
     this.direction    = direction;
     this.notesoverlap = overlap;
     if (direction == Up || notesoverlap)
     {
         side = RightSide;
     }
     else
     {
         side = LeftSide;
     }
     end              = CalculateEnd();
     pair             = null;
     width_to_pair    = 0;
     receiver_in_pair = false;
 }
예제 #4
0
        bool CanCreateBeam(ChordSymbol[] chords, TimeSignature time, bool startQuarter)
        {
            int  numChords = chords.Length;
            Stem firstStem = chords[0].Stem;
            Stem lastStem  = chords[chords.Length - 1].Stem;

            if (firstStem == null || lastStem == null)
            {
                return(false);
            }
            int          measure = chords[0].StartTime / time.Measure;
            NoteDuration dur     = firstStem.Duration;
            NoteDuration dur2    = lastStem.Duration;

            bool dotted8_to_16 = false;

            if (chords.Length == 2 && dur == NoteDuration.DottedEighth &&
                dur2 == NoteDuration.Sixteenth)
            {
                dotted8_to_16 = true;
            }

            if (dur == NoteDuration.Whole || dur == NoteDuration.Half ||
                dur == NoteDuration.DottedHalf || dur == NoteDuration.Quarter ||
                dur == NoteDuration.DottedQuarter ||
                (dur == NoteDuration.DottedEighth && !dotted8_to_16))
            {
                return(false);
            }

            if (numChords == 6)
            {
                if (dur != NoteDuration.Eighth)
                {
                    return(false);
                }
                bool correctTime =
                    ((time.Numerator == 3 && time.Denominator == 4) ||
                     (time.Numerator == 6 && time.Denominator == 8) ||
                     (time.Numerator == 6 && time.Denominator == 4));

                if (!correctTime)
                {
                    return(false);
                }

                if (time.Numerator == 6 && time.Denominator == 4)
                {
                    /* first chord must start at 1st or 4th quarter note */
                    int beat = time.Quarter * 3;
                    if ((chords[0].StartTime % beat) > time.Quarter / 6)
                    {
                        return(false);
                    }
                }
            }
            else if (numChords == 4)
            {
                if (time.Numerator == 3 && time.Denominator == 8)
                {
                    return(false);
                }
                bool correctTime =
                    (time.Numerator == 2 || time.Numerator == 4 || time.Numerator == 8);
                if (!correctTime && dur != NoteDuration.Sixteenth)
                {
                    return(false);
                }

                /* chord must start on quarter note */
                int beat = time.Quarter;
                if (dur == NoteDuration.Eighth)
                {
                    /* 8th note chord must start on 1st or 3rd quarter note */
                    beat = time.Quarter * 2;
                }
                else if (dur == NoteDuration.ThirtySecond)
                {
                    /* 32nd note must start on an 8th beat */
                    beat = time.Quarter / 2;
                }

                if ((chords[0].StartTime % beat) > time.Quarter / 6)
                {
                    return(false);
                }
            }
            else if (numChords == 3)
            {
                bool valid = (dur == NoteDuration.Triplet) ||
                             (dur == NoteDuration.Eighth &&
                              time.Numerator == 12 && time.Denominator == 8);
                if (!valid)
                {
                    return(false);
                }

                /* chord must start on quarter note */
                int beat = time.Quarter;
                if (time.Numerator == 12 && time.Denominator == 8)
                {
                    /* In 12/8 time, chord must start on 3*8th beat */
                    beat = time.Quarter / 2 * 3;
                }
                if ((chords[0].StartTime % beat) > time.Quarter / 6)
                {
                    return(false);
                }
            }

            else if (numChords == 2)
            {
                if (startQuarter)
                {
                    int beat = time.Quarter;
                    if ((chords[0].StartTime % beat) > time.Quarter / 6)
                    {
                        return(false);
                    }
                }
            }

            foreach (ChordSymbol chord in chords)
            {
                if ((chord.StartTime / time.Measure) != measure)
                {
                    return(false);
                }
                if (chord.Stem == null)
                {
                    return(false);
                }
                if (chord.Stem.Duration != dur && !dotted8_to_16)
                {
                    return(false);
                }
                if (chord.Stem.isBeam)
                {
                    return(false);
                }
            }

            /* Check that all stems can point in same direction */
            bool hasTwoStems = false;
            int  direction   = Stem.Up;

            foreach (ChordSymbol chord in chords)
            {
                if (chord.HasTwoStems)
                {
                    if (hasTwoStems && chord.Stem.Direction != direction)
                    {
                        return(false);
                    }
                    hasTwoStems = true;
                    direction   = chord.Stem.Direction;
                }
            }

            /* Get the final stem direction */
            if (!hasTwoStems)
            {
                WhiteNote note1;
                WhiteNote note2;
                note1     = (firstStem.Direction == Stem.Up ? firstStem.Top : firstStem.Bottom);
                note2     = (lastStem.Direction == Stem.Up ? lastStem.Top : lastStem.Bottom);
                direction = StemDirection(note1, note2, chords[0].Clef);
            }

            /* If the notes are too far apart, don't use a beam */
            if (direction == Stem.Up)
            {
                if (Math.Abs(firstStem.Top.Dist(lastStem.Top)) >= 11)
                {
                    return(false);
                }
            }
            else
            {
                if (Math.Abs(firstStem.Bottom.Dist(lastStem.Bottom)) >= 11)
                {
                    return(false);
                }
            }
            return(true);
        }
예제 #5
0
        private SheetMusic sheetmusic;      /** Used to get colors and other options */


        /** Create a new Chord Symbol from the given list of midi notes.
         * All the midi notes will have the same start time.  Use the
         * key signature to get the white key and accidental symbol for
         * each note.  Use the time signature to calculate the duration
         * of the notes. Use the clef when drawing the chord.
         */
        public ChordSymbol(List <MidiNote> midinotes, KeySignature key,
                           TimeSignature time, Clef c, SheetMusic sheet)
        {
            int len = midinotes.Count;
            int i;

            hastwostems = false;
            clef        = c;
            sheetmusic  = sheet;

            starttime = midinotes[0].StartTime;
            endtime   = midinotes[0].EndTime;

            for (i = 0; i < midinotes.Count; i++)
            {
                if (i > 1)
                {
                    if (midinotes[i].Number < midinotes[i - 1].Number)
                    {
                        throw new System.ArgumentException("Chord notes not in increasing order by number");
                    }
                }
                endtime = Math.Max(endtime, midinotes[i].EndTime);
            }

            notedata     = CreateNoteData(midinotes, key, time);
            accidsymbols = CreateAccidSymbols(notedata, clef);


            /* Find out how many stems we need (1 or 2) */
            NoteDuration dur1   = notedata[0].duration;
            NoteDuration dur2   = dur1;
            int          change = -1;

            for (i = 0; i < notedata.Length; i++)
            {
                dur2 = notedata[i].duration;
                if (dur1 != dur2)
                {
                    change = i;
                    break;
                }
            }

            if (dur1 != dur2)
            {
                /* We have notes with different durations.  So we will need
                 * two stems.  The first stem points down, and contains the
                 * bottom note up to the note with the different duration.
                 *
                 * The second stem points up, and contains the note with the
                 * different duration up to the top note.
                 */
                hastwostems = true;
                stem1       = new Stem(notedata[0].whitenote,
                                       notedata[change - 1].whitenote,
                                       dur1,
                                       Stem.Down,
                                       NotesOverlap(notedata, 0, change)
                                       );

                stem2 = new Stem(notedata[change].whitenote,
                                 notedata[notedata.Length - 1].whitenote,
                                 dur2,
                                 Stem.Up,
                                 NotesOverlap(notedata, change, notedata.Length)
                                 );
            }
            else
            {
                /* All notes have the same duration, so we only need one stem. */
                int direction = StemDirection(notedata[0].whitenote,
                                              notedata[notedata.Length - 1].whitenote,
                                              clef);

                stem1 = new Stem(notedata[0].whitenote,
                                 notedata[notedata.Length - 1].whitenote,
                                 dur1,
                                 direction,
                                 NotesOverlap(notedata, 0, notedata.Length)
                                 );
                stem2 = null;
            }

            /* For whole notes, no stem is drawn. */
            if (dur1 == NoteDuration.Whole)
            {
                stem1 = null;
            }
            if (dur2 == NoteDuration.Whole)
            {
                stem2 = null;
            }

            width = MinWidth;
        }
예제 #6
0
        LineUpStemEnds(ChordSymbol[] chords)
        {
            Stem firstStem  = chords[0].Stem;
            Stem lastStem   = chords[chords.Length - 1].Stem;
            Stem middleStem = chords[1].Stem;

            if (firstStem.Direction == Stem.Up)
            {
                /* Find the highest stem. The beam will either:
                 * - Slant downwards (first stem is highest)
                 * - Slant upwards (last stem is highest)
                 * - Be straight (middle stem is highest)
                 */
                WhiteNote top = firstStem.End;
                foreach (ChordSymbol chord in chords)
                {
                    top = WhiteNote.Max(top, chord.Stem.End);
                }
                if (top == firstStem.End && top.Dist(lastStem.End) >= 2)
                {
                    firstStem.End  = top;
                    middleStem.End = top.Add(-1);
                    lastStem.End   = top.Add(-2);
                }
                else if (top == lastStem.End && top.Dist(firstStem.End) >= 2)
                {
                    firstStem.End  = top.Add(-2);
                    middleStem.End = top.Add(-1);
                    lastStem.End   = top;
                }
                else
                {
                    firstStem.End  = top;
                    middleStem.End = top;
                    lastStem.End   = top;
                }
            }
            else
            {
                /* Find the bottommost stem. The beam will either:
                 * - Slant upwards (first stem is lowest)
                 * - Slant downwards (last stem is lowest)
                 * - Be straight (middle stem is highest)
                 */
                WhiteNote bottom = firstStem.End;
                foreach (ChordSymbol chord in chords)
                {
                    bottom = WhiteNote.Min(bottom, chord.Stem.End);
                }

                if (bottom == firstStem.End && lastStem.End.Dist(bottom) >= 2)
                {
                    middleStem.End = bottom.Add(1);
                    lastStem.End   = bottom.Add(2);
                }
                else if (bottom == lastStem.End && firstStem.End.Dist(bottom) >= 2)
                {
                    middleStem.End = bottom.Add(1);
                    firstStem.End  = bottom.Add(2);
                }
                else
                {
                    firstStem.End  = bottom;
                    middleStem.End = bottom;
                    lastStem.End   = bottom;
                }
            }

            /* All middle stems have the same end */
            for (int i = 1; i < chords.Length - 1; i++)
            {
                Stem stem = chords[i].Stem;
                stem.End = middleStem.End;
            }
        }
예제 #7
0
        private int width; /** The width of the chord */

        #endregion Fields

        #region Constructors

        /** Create a new Chord Symbol from the given list of midi notes.
         * All the midi notes will have the same start time.  Use the
         * key signature to get the white key and accidental symbol for
         * each note.  Use the time signature to calculate the duration
         * of the notes. Use the clef when drawing the chord.
         */
        public ChordSymbol(List<MidiNote> midinotes, KeySignature key, 
            TimeSignature time, Clef c, SheetMusic sheet)
        {
            int len = midinotes.Count;
            int i;

            hastwostems = false;
            clef = c;
            sheetmusic = sheet;

            starttime = midinotes[0].StartTime;
            endtime = midinotes[0].EndTime;

            for (i = 0; i < midinotes.Count; i++) {
            if (i > 1) {
                if (midinotes[i].Number < midinotes[i-1].Number) {
                    throw new System.ArgumentException("Chord notes not in increasing order by number");
                }
            }
            endtime = Math.Max(endtime, midinotes[i].EndTime);
            }

            notedata = CreateNoteData(midinotes, key, time);
            accidsymbols = CreateAccidSymbols(notedata, clef);

            /* Find out how many stems we need (1 or 2) */
            NoteDuration dur1 = notedata[0].duration;
            NoteDuration dur2 = dur1;
            int change = -1;
            for (i = 0; i < notedata.Length; i++) {
            dur2 = notedata[i].duration;
            if (dur1 != dur2) {
                change = i;
                break;
            }
            }

            if (dur1 != dur2) {
            /* We have notes with different durations.  So we will need
             * two stems.  The first stem points down, and contains the
             * bottom note up to the note with the different duration.
             *
             * The second stem points up, and contains the note with the
             * different duration up to the top note.
             */
            hastwostems = true;
            stem1 = new Stem(notedata[0].whitenote,
                             notedata[change-1].whitenote,
                             dur1,
                             Stem.Down,
                             NotesOverlap(notedata, 0, change)
                            );

            stem2 = new Stem(notedata[change].whitenote,
                             notedata[notedata.Length-1].whitenote,
                             dur2,
                             Stem.Up,
                             NotesOverlap(notedata, change, notedata.Length)
                            );
            }
            else {
            /* All notes have the same duration, so we only need one stem. */
            int direction = StemDirection(notedata[0].whitenote,
                                          notedata[notedata.Length-1].whitenote,
                                          clef);

            stem1 = new Stem(notedata[0].whitenote,
                             notedata[notedata.Length-1].whitenote,
                             dur1,
                             direction,
                             NotesOverlap(notedata, 0, notedata.Length)
                            );
            stem2 = null;
            }

            /* For whole notes, no stem is drawn. */
            if (dur1 == NoteDuration.Whole)
            stem1 = null;
            if (dur2 == NoteDuration.Whole)
            stem2 = null;

            width = MinWidth;
        }
예제 #8
0
 /** Pair this stem with another Chord.  Instead of drawing a curvy tail,
  * this stem will now have to draw a beam to the given stem pair.  The
  * width (in pixels) to this stem pair is passed as argument.
  */
 public void SetPair(Stem pair, int width_to_pair)
 {
     this.pair          = pair;
     this.width_to_pair = width_to_pair;
 }
예제 #9
0
        private int width_to_pair; /** The width (in pixels) to the chord pair */

        #endregion Fields

        #region Constructors

        /** Create a new stem.  The top note, bottom note, and direction are
         * needed for drawing the vertical line of the stem.  The duration is
         * needed to draw the tail of the stem.  The overlap boolean is true
         * if the notes in the chord overlap.  If the notes overlap, the
         * stem must be drawn on the right side.
         */
        public Stem(WhiteNote bottom, WhiteNote top, 
                NoteDuration duration, int direction, bool overlap)
        {
            this.top = top;
            this.bottom = bottom;
            this.duration = duration;
            this.direction = direction;
            this.notesoverlap = overlap;
            if (direction == Up || notesoverlap)
            side = RightSide;
            else
            side = LeftSide;
            end = CalculateEnd();
            pair = null;
            width_to_pair = 0;
            receiver_in_pair = false;
        }
예제 #10
0
 /** Pair this stem with another Chord.  Instead of drawing a curvy tail,
  * this stem will now have to draw a beam to the given stem pair.  The
  * width (in pixels) to this stem pair is passed as argument.
  */
 public void SetPair(Stem pair, int width_to_pair)
 {
     this.pair = pair;
     this.width_to_pair = width_to_pair;
 }