/* quantize the start time */
        private static void QuantizeStartTime(
            int StartTime,
            int QuarterNoteLen,
            NoteFlags QuantizedDuration,
            double QuantizedDurationAdjust,
            out FractionRec StartTimeOut,
            out double StartTimeAdjustOut,
            out double WholeNoteStartTimeAdjust)
        {
            uint        Denominator;
            double      QuantizedStartTime;
            double      OrigDuration;
            FractionRec OrigDurationFractional;

            /* start times must be a multiple of the 64th note.  see rationale */
            /* in comment at top of this file. */
            Denominator = 64;

            NoteNoteObjectRec.ConvertDurationFrac(QuantizedDuration, out OrigDurationFractional);
            OrigDuration = (4 * QuarterNoteLen) * QuantizedDurationAdjust
                           * FractionRec.Fraction2Double(OrigDurationFractional);

            /* compute start time to nearest division they allow */
            FractionRec.Double2Fraction(StartTime / (double)(QuarterNoteLen * 4), Denominator, out StartTimeOut);

            /* set start time adjust (relative to duration) */
            QuantizedStartTime       = FractionRec.Fraction2Double(StartTimeOut) * (4 * QuarterNoteLen);
            StartTimeAdjustOut       = (QuantizedStartTime - StartTime) / OrigDuration;
            WholeNoteStartTimeAdjust = (QuantizedStartTime - StartTime) / (4 * QuarterNoteLen);
        }
        /* convert interval track into quantized track. */
        public static bool ConvertIntervalToQuantized(
            IntervalTrackRec IntervalTrack,
            QuantizedTrackRec QuantizedTrack,
            int MidiQuarterNote)
        {
            int Scan;
            int Limit;

            TimeMatchRec[] MatchingTable = new TimeMatchRec[4 /*divisions*/ * 2 /*dot*/ * 9 /*notetypes*/];
            int            MatchingTableLength;

            /* build duration matching table */
            MatchingTableLength = 0;
            for (Scan = 0; Scan < 4 /*divisions*/ * 2 /*dot*/ * 9 /*notetypes*/; Scan += 1)
            {
                double      MIDIClocks;
                NoteFlags   Descriptor;
                FractionRec DurationFraction;

                /* determine root duration and descriptor */
                switch (Scan % 9)
                {
                default:
                    Debug.Assert(false);
                    throw new InvalidOperationException();

                case 0:
                    Descriptor = NoteFlags.e64thNote;
                    break;

                case 1:
                    Descriptor = NoteFlags.e32ndNote;
                    break;

                case 2:
                    Descriptor = NoteFlags.e16thNote;
                    break;

                case 3:
                    Descriptor = NoteFlags.e8thNote;
                    break;

                case 4:
                    Descriptor = NoteFlags.e4thNote;
                    break;

                case 5:
                    Descriptor = NoteFlags.e2ndNote;
                    break;

                case 6:
                    Descriptor = NoteFlags.eWholeNote;
                    break;

                case 7:
                    Descriptor = NoteFlags.eDoubleNote;
                    break;

                case 8:
                    Descriptor = NoteFlags.eQuadNote;
                    break;
                }

                /* determine if dot is needed */
                if (((Scan / 9) % 2) != 0)
                {
                    /* dot needed */
                    Descriptor |= NoteFlags.eDotModifier;
                }

                /* determine what division is needed */
                switch (((Scan / 9) / 2) % 4)
                {
                default:
                    Debug.Assert(false);
                    throw new InvalidOperationException();

                case 0:
                    break;

                case 1:
                    Descriptor |= NoteFlags.eDiv3Modifier;
                    break;

                case 2:
                    Descriptor |= NoteFlags.eDiv5Modifier;
                    break;

                case 3:
                    Descriptor |= NoteFlags.eDiv7Modifier;
                    break;
                }

                /* how int is this note */
                NoteNoteObjectRec.ConvertDurationFrac(Descriptor, out DurationFraction); /* units of whole notes */
                MIDIClocks = MidiQuarterNote * (4 * FractionRec.Fraction2Double(DurationFraction));

                /* add to table if note can be represented in the timing scheme */
                /* AND only if note is an integer multiple of the 64th div3 (see */
                /* comment at the top of this file for the rationale) */
                if ((MIDIClocks == Math.Floor(MIDIClocks)) && (MIDIClocks >= 1) && IntMultOf64thDiv3(Descriptor))
                {
                    MatchingTable[MatchingTableLength].Ticks      = (int)MIDIClocks;
                    MatchingTable[MatchingTableLength].Descriptor = Descriptor;
                    MatchingTableLength += 1;
                }
            }

            /* quantize note events */
            Limit = GetIntervalTrackLength(IntervalTrack);
            for (Scan = 0; Scan < Limit; Scan += 1)
            {
                IntEventRec Event;

                Event = GetIntervalTrackIndexedEvent(IntervalTrack, Scan);
                switch (IntervalEventGetType(Event))
                {
                default:
                    Debug.Assert(false);
                    throw new InvalidOperationException();

                case IntEventType.eIntervalNoteEvent:
                {
                    /* input values */
                    int   StartTime;
                    int   Duration;
                    short MIDIPitch;
                    short MIDIAttackVelocity;
                    short MIDIReleaseVelocity;
                    /* output values */
                    NoteFlags   QuantizedDuration;
                    double      QuantizedDurationAdjust;
                    int         WholeNoteOverflow;
                    FractionRec QuantizedStartTime;
                    double      QuantizedStartTimeAdjust;
                    double      WholeNoteStartTimeAdjust;    /* auxiliary value */
                    /* stuff */
                    QuantEventRec QuantEvent;

                    /* get the information */
                    GetIntervalNoteEventInfo(Event, out StartTime, out Duration, out MIDIPitch,
                                             out MIDIAttackVelocity, out MIDIReleaseVelocity);

                    /* quantize duration */
                    QuantizeDuration(Duration, MidiQuarterNote, MatchingTable,
                                     MatchingTableLength, out QuantizedDuration, out QuantizedDurationAdjust,
                                     out WholeNoteOverflow);
                    Debug.Assert(IntMultOf64thDiv3(QuantizedDuration));         // non-64div3 duration quantization?

                    /* quantize start time */
                    QuantizeStartTime(StartTime, MidiQuarterNote, QuantizedDuration,
                                      QuantizedDurationAdjust, out QuantizedStartTime, out QuantizedStartTimeAdjust,
                                      out WholeNoteStartTimeAdjust);
                    Debug.Assert(FractionIntMultOf64thDiv3(QuantizedStartTime));         // non-64div3 start time quantization?

                    /* bump start time to end of whole note chain */
                    QuantizedStartTime.Integer += (uint)WholeNoteOverflow;

                    /* create new event & insert into track */
                    QuantEvent = NewQuantizedNoteEvent(QuantizedStartTime,
                                                       QuantizedStartTimeAdjust, QuantizedDuration, QuantizedDurationAdjust,
                                                       MIDIPitch, MIDIAttackVelocity, MIDIReleaseVelocity);
                    QuantizedTrackInsertEventSorted(QuantizedTrack, QuantEvent);

                    /* insert whole notes behind the last note in reverse order */
                    while (WholeNoteOverflow > 0)
                    {
                        QuantEventRec Predecessor;

                        /* create preceding whole note */
                        QuantizedStartTime.Integer -= 1;
                        Predecessor = NewQuantizedNoteEvent(QuantizedStartTime,
                                                            WholeNoteStartTimeAdjust, NoteFlags.eWholeNote, 1, MIDIPitch,
                                                            MIDIAttackVelocity, MIDIReleaseVelocity);
                        QuantizedTrackInsertEventSorted(QuantizedTrack, Predecessor);
                        /* set tie */
                        PutQuantizedEventTieTarget(Predecessor, QuantEvent);
                        QuantEvent = Predecessor;
                        /* step */
                        WholeNoteOverflow -= 1;
                    }
                }
                break;

                case IntEventType.eIntervalCommentEvent:
                {
                    QuantEventRec QuantEvent;
                    /* input values */
                    int    StartTime;
                    string OriginalString;
                    /* output values */
                    FractionRec QuantizedStartTime;

                    /* get the information */
                    GetIntervalCommentEventInfo(Event, out StartTime, out OriginalString);

                    /* compute start time to nearest 64th div3 */
                    FractionRec.Double2Fraction(StartTime / (double)MidiQuarterNote,
                                                64 * 3, out QuantizedStartTime);
                    Debug.Assert(FractionIntMultOf64thDiv3(QuantizedStartTime));         //non-64div3 start time quantization?

                    /* create new event & insert into track */
                    QuantEvent = NewQuantizedCommentEvent(QuantizedStartTime, 0, OriginalString);
                    QuantizedTrackInsertEventSorted(QuantizedTrack, QuantEvent);
                }
                break;
                }
            }

            return(true);
        }