/* 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); }