示例#1
0
        /* create a new quantized MIDI track */
        public static QuantizedTrackRec NewQuantizedTrack()
        {
            QuantizedTrackRec Track = new QuantizedTrackRec();

            Track.EventList = new List <QuantEventRec>();
            return(Track);
        }
示例#2
0
        /* insert new event sorted into the track */
        public static void QuantizedTrackInsertEventSorted(
            QuantizedTrackRec Track,
            QuantEventRec Event)
        {
            FractionRec OurEventStartTime = GetQuantizedEventTime(Event);
            int         Scan = Track.EventList.Count - 1;

            while (Scan >= 0)
            {
                QuantEventRec OtherEvent          = Track.EventList[Scan];
                FractionRec   OtherEventStartTime = GetQuantizedEventTime(OtherEvent);
                if (FractionRec.FracGreaterEqual(OurEventStartTime, OtherEventStartTime))
                {
                    Track.EventList.Insert(Scan + 1, Event);
                    return;
                }
                Scan -= 1;
            }
            Track.EventList.Insert(0, Event);
        }
示例#3
0
 /* get an indexed event from the track */
 public static QuantEventRec GetQuantizedTrackIndexedEvent(
     QuantizedTrackRec Track,
     int Index)
 {
     return(Track.EventList[Index]);
 }
示例#4
0
 /* get the number of events in the track */
 public static int GetQuantizedTrackLength(QuantizedTrackRec Track)
 {
     return(Track.EventList.Count);
 }
        /* convert quantized track into native track */
        public static void ConvertQuantToNote(
            QuantizedTrackRec QuantizedTrack,
            TrackObjectRec NoteTrack)
        {
            FractionRec          CurrentTime;
            int                  Index;
            int                  Limit;
            List <QuantEventRec> FrameArray;
            TieMappingRec        TieMapping;
            int                  OpcodeDurationTableLength;

            OpDurRec[] OpcodeDurationTable = new OpDurRec[4 /*divisions*/ * 2 /*dot*/ * 9 /*notetypes*/];

            /* initialize variables */
            InitializeOpcodeDurationTable(OpcodeDurationTable, out OpcodeDurationTableLength);
            CurrentTime.Integer     = 0;
            CurrentTime.Fraction    = 0;
            CurrentTime.Denominator = 1;
            FrameArray = new List <QuantEventRec>();
            TieMapping = NewTieMapping();
            Limit      = GetQuantizedTrackLength(QuantizedTrack);
            Index      = 0;

            /* iterate over variables */
            while (Index < Limit)
            {
                FractionRec   NextTime;
                QuantEventRec QuantEvent;
                bool          Continue;
                int           InspectScan;

                /* reset frame array */
                FrameArray.Clear();

                /* get the start time of the next available event */
                QuantEvent = GetQuantizedTrackIndexedEvent(QuantizedTrack, Index);
                NextTime   = GetQuantizedEventTime(QuantEvent);
                Debug.Assert(FractionIntMultOf64thDiv3(NextTime)); // non-64div3 start time quantization?

                /* sanity check */
                Debug.Assert(!FractionRec.FracGreaterThan(CurrentTime, NextTime)); // next time inconsistency

                /* get all events starting at this time into FrameArray */
                Continue = true;
                while (Continue && (Index < Limit))
                {
                    FractionRec EventTime;

                    /* get the event */
                    QuantEvent = GetQuantizedTrackIndexedEvent(QuantizedTrack, Index);
                    EventTime  = GetQuantizedEventTime(QuantEvent);
                    Debug.Assert(FractionIntMultOf64thDiv3(EventTime)); // non-64div3 start time quantization?
                    if (FractionRec.FractionsEqual(EventTime, NextTime))
                    {
                        /* add event to the list */
                        FrameArray.Add(QuantEvent);
                        /* go past this event */
                        Index += 1;
                    }
                    else
                    {
                        /* end hit so stop */
                        Continue = false;
                    }
                }

                /* insert rests to bring current time up to next time */
                InsertRests(CurrentTime, NextTime, NoteTrack, OpcodeDurationTable, OpcodeDurationTableLength);

                /* remove command events from list */
                InspectScan = 0;
                while (InspectScan < FrameArray.Count)
                {
                    /* get the event */
                    QuantEvent = FrameArray[InspectScan];
                    /* determine if event is a command */
                    if (QuantizedEventGetType(QuantEvent) == QuantEventType.eQuantizedNoteEvent)
                    {
                        /* note events should be skipped */
                        InspectScan += 1;
                    }
                    else
                    {
                        /* command events should be handled */
                        switch (QuantizedEventGetType(QuantEvent))
                        {
                        default:
                            Debug.Assert(false);
                            throw new InvalidOperationException();

                        case QuantEventType.eQuantizedCommentEvent:
                        {
                            string CommentString;
                            CommandNoteObjectRec Note;
                            FrameObjectRec       Frame;
                            FractionRec          unusedf;
                            double unusedd;

                            GetQuantizedCommentEventInfo(QuantEvent, out unusedf, out unusedd, out CommentString);
                            Note = new CommandNoteObjectRec(NoteTrack);
                            Note.PutCommandStringArg1(CommentString);
                            Note.PutCommandOpcode(NoteCommands.eCmdMarker);
                            Frame = new FrameObjectRec();
                            Frame.Add(Note);
                            NoteTrack.FrameArray.Add(Frame);
                        }
                        break;
                        }
                        /* delete event from array */
                        FrameArray.RemoveAt(InspectScan);
                        /* don't increment InspectScan */
                    }
                }

                /* process remaining notes in FrameArray, computing minimum duration */
                /* and updating CurrentTime with minimum duration. */
                if (FrameArray.Count != 0)
                {
                    NoteFlags      DurationOpcode;
                    FrameObjectRec Frame;
                    int            Scan;
                    int            FrameLimit;
                    FractionRec    MinimumDuration;
                    FractionRec    unusedf;
                    double         unusedd;
                    short          unuseds;

                    /* initialize minimum duration */
                    QuantEvent = FrameArray[0];
                    GetQuantizedNoteEventInfo(QuantEvent, out unusedf, out unusedd, out DurationOpcode,
                                              out unusedd, out unuseds, out unuseds, out unuseds);
                    NoteNoteObjectRec.ConvertDurationFrac(DurationOpcode, out MinimumDuration);
                    Debug.Assert(FractionIntMultOf64thDiv3(MinimumDuration)); // non-64div3 duration quantization?

                    /* allocate frame */
                    Frame = new FrameObjectRec();

                    /* process notes in frame */
                    FrameLimit = FrameArray.Count;
                    for (Scan = 0; Scan < FrameLimit; Scan += 1)
                    {
                        FractionRec       StartTime;
                        double            StartTimeAdjust;
                        NoteFlags         Duration;
                        double            DurationAdjust;
                        short             MIDIPitch;
                        short             MIDIAttackVelocity;
                        short             MIDIReleaseVelocity;
                        NoteNoteObjectRec Note;
                        FractionRec       FracDuration;

                        /* get the note */
                        QuantEvent = FrameArray[Scan];
                        Debug.Assert(QuantizedEventGetType(QuantEvent) == QuantEventType.eQuantizedNoteEvent); // non-note in frame array
                        /* get attributes */
                        GetQuantizedNoteEventInfo(QuantEvent, out StartTime, out StartTimeAdjust,
                                                  out Duration, out DurationAdjust, out MIDIPitch, out MIDIAttackVelocity,
                                                  out MIDIReleaseVelocity);
                        Debug.Assert(IntMultOf64thDiv3(Duration));                        // non-64div3 duration quantization?
                        Debug.Assert(FractionRec.FractionsEqual(StartTime, CurrentTime)); // start time inconsistency
                        /* create note */
                        Note = new NoteNoteObjectRec(NoteTrack);
                        Frame.Add(Note);
                        TieMappingAddPair(TieMapping, QuantEvent, Note);
                        /* set note attributes */
                        Note.PutNoteDuration(Duration & NoteFlags.eDurationMask);
                        Note.PutNoteDurationDivision(Duration & NoteFlags.eDivisionMask);
                        Note.PutNoteDotStatus((Duration & NoteFlags.eDotModifier) != 0);
                        Note.EarlyLateAdjust    = StartTimeAdjust;
                        Note.DurationAdjust     = DurationAdjust;
                        Note.DurationAdjustMode = NoteFlags.eDurationAdjustMultiplicative;
                        Note.PutNotePitch((short)(MIDIPitch - MIDIC + Constants.CENTERNOTE));
                        Note.Accent1 = (MIDIAttackVelocity > 0)
                            ? -Math.Log(MIDIAttackVelocity) / Constants.LOG2 + LN127OVERLN2 : 7;
                        Note.Accent2 = (MIDIReleaseVelocity > 0)
                            ? -Math.Log(MIDIReleaseVelocity) / Constants.LOG2 + LN127OVERLN2 : 7;
                        switch ((MIDIPitch - MIDIC + ((MIDIC / 12 + 1) * 12)) % 12)
                        {
                        default:
                            // midi sharp/flat problem
                            Debug.Assert(false);
                            throw new InvalidOperationException();

                        case 0:     /* C */
                        case 2:     /* D */
                        case 4:     /* E */
                        case 5:     /* F */
                        case 7:     /* G */
                        case 9:     /* A */
                        case 11:    /* B */
                            break;

                        case 1:     /* C# */
                        case 3:     /* D# */
                        case 6:     /* F# */
                        case 8:     /* G# */
                        case 10:    /* A# */
                            Note.PutNoteFlatOrSharpStatus(NoteFlags.eSharpModifier);
                            break;
                        }
                        /* do the minimum duration thing */
                        NoteNoteObjectRec.ConvertDurationFrac(Duration, out FracDuration);
                        Debug.Assert(FractionIntMultOf64thDiv3(FracDuration)); // non-64div3 duration quantization?
                        if (FractionRec.FracGreaterThan(MinimumDuration, FracDuration))
                        {
                            MinimumDuration = FracDuration;
                        }
                    }

                    /* add frame to track */
                    NoteTrack.FrameArray.Add(Frame);

                    /* if minimum duration is greater than time to next event, then */
                    /* add rests (one to this frame) to fill in the gap */
                    if (Index < Limit)
                    {
                        FractionRec NextEventTime;
                        FractionRec Difference;

                        /* get the start time of the next available event */
                        QuantEvent    = GetQuantizedTrackIndexedEvent(QuantizedTrack, Index);
                        NextEventTime = GetQuantizedEventTime(QuantEvent);
                        Debug.Assert(FractionIntMultOf64thDiv3(NextEventTime)); // non-64div3 start time quantization?
                        FractionRec.SubFractions(NextEventTime, CurrentTime, out Difference);
                        if (FractionRec.FracGreaterThan(MinimumDuration, Difference))
                        {
                            NoteNoteObjectRec Note;
                            NoteFlags         RestOpcode;
                            FractionRec       OpcodesDuration;

                            /* insert first rest into frame */
                            RestOpcode = GetMaxDurationOpcode(Difference, out OpcodesDuration,
                                                              OpcodeDurationTable, OpcodeDurationTableLength);
                            Debug.Assert(IntMultOf64thDiv3(RestOpcode)); // non-64div3 duration quantization
                            Note = new NoteNoteObjectRec(NoteTrack);
                            Note.PutNoteDuration(RestOpcode & NoteFlags.eDurationMask);
                            Note.PutNoteDurationDivision(RestOpcode & NoteFlags.eDivisionMask);
                            Note.PutNoteDotStatus((RestOpcode & NoteFlags.eDotModifier) != 0);
                            Note.PutNotePitch(Constants.CENTERNOTE);
                            Note.PutNoteIsItARest(true);
                            Frame.Add(Note);
                            /* put new minimum duration in to reflect new rest we added */
                            NoteNoteObjectRec.ConvertDurationFrac(RestOpcode, out MinimumDuration);
                        }
                    }

                    /* advance thing by minimum duration */
                    FractionRec.AddFractions(MinimumDuration, CurrentTime, out CurrentTime);
                    Debug.Assert(FractionIntMultOf64thDiv3(CurrentTime)); // non-64div3 start time quantization?
                }
            }

            /* patch up ties */
            for (Index = 0; Index < Limit; Index += 1)
            {
                QuantEventRec QuantEvent;

                /* get potential event */
                QuantEvent = GetQuantizedTrackIndexedEvent(QuantizedTrack, Index);
                /* see if it ties somewhere */
                if ((QuantEventType.eQuantizedNoteEvent == QuantizedEventGetType(QuantEvent)) &&
                    (GetQuantizedEventTieTarget(QuantEvent) != null))
                {
                    QuantEventRec     TieTarget;
                    NoteNoteObjectRec Source;
                    NoteNoteObjectRec Target;

                    /* get tie target */
                    TieTarget = GetQuantizedEventTieTarget(QuantEvent);
                    /* look up source and target note events */
                    Source = TieMappingLookup(TieMapping, QuantEvent);
                    Target = TieMappingLookup(TieMapping, TieTarget);
                    /* establish tie */
                    Source.PutNoteTieTarget(Target);
                }
            }

            /* look for track name comment */
            for (Index = 0; Index < Limit; Index += 1)
            {
                QuantEventRec QuantEvent;

                /* get potential event */
                QuantEvent = GetQuantizedTrackIndexedEvent(QuantizedTrack, Index);
                /* see if it ties somewhere */
                if (QuantEventType.eQuantizedCommentEvent == QuantizedEventGetType(QuantEvent))
                {
                    string      CommentString;
                    FractionRec unusedf;
                    double      unusedd;

                    GetQuantizedCommentEventInfo(QuantEvent, out unusedf, out unusedd, out CommentString);
                    /* check for track name */
                    if ((CommentString.Length > 11 /*Prefix*/ + Environment.NewLine.Length) &&
                        CommentString.StartsWith("Track Name" + Environment.NewLine))
                    {
                        string NameString = CommentString.Substring(11, CommentString.Length - (11 + 1));
                        NoteTrack.Name = NameString;
                        goto FinishedSettingTrackName;
                    }
                }
            }
            /* if no track name was found, then use the first comment string */
            for (Index = 0; Index < Limit; Index += 1)
            {
                QuantEventRec QuantEvent;

                /* get potential event */
                QuantEvent = GetQuantizedTrackIndexedEvent(QuantizedTrack, Index);
                /* see if it ties somewhere */
                if (QuantEventType.eQuantizedCommentEvent == QuantizedEventGetType(QuantEvent))
                {
                    string      CommentString;
                    FractionRec unusedf;
                    double      unusedd;

                    GetQuantizedCommentEventInfo(QuantEvent, out unusedf, out unusedd, out CommentString);
                    /* check for track name */
                    if ((CommentString.Length > 8 /*Prefix*/ + Environment.NewLine.Length) &&
                        CommentString.StartsWith("Comment" + Environment.NewLine))
                    {
                        string NameString;

                        NameString     = CommentString.Substring(8, CommentString.Length - (8 + 1));
                        NoteTrack.Name = NameString;
                        goto FinishedSettingTrackName;
                    }
                }
            }
FinishedSettingTrackName:
            ;
        }
        /* 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);
        }