/* insert rests */ private static void InsertRests( FractionRec Now, FractionRec Target, TrackObjectRec NoteTrack, OpDurRec[] OpcodeDurationTable, int OpcodeDurationTableLength) { while (FractionRec.FracGreaterThan(Target, Now)) { FractionRec Difference; NoteFlags Opcode; FractionRec OpcodesDuration; NoteNoteObjectRec Note; FrameObjectRec Frame; /* how much time left */ FractionRec.SubFractions(Target, Now, out Difference); /* search for appropriate opcode */ Opcode = GetMaxDurationOpcode(Difference, out OpcodesDuration, OpcodeDurationTable, OpcodeDurationTableLength); /* add duration to Now */ FractionRec.AddFractions(Now, OpcodesDuration, out Now); /* create the note */ Note = new NoteNoteObjectRec(NoteTrack); Note.PutNoteDuration(Opcode & NoteFlags.eDurationMask); Note.PutNoteDurationDivision(Opcode & NoteFlags.eDivisionMask); Note.PutNoteDotStatus((Opcode & NoteFlags.eDotModifier) != 0); Note.PutNotePitch(Constants.CENTERNOTE); Note.PutNoteIsItARest(true); /* create the frame */ Frame = new FrameObjectRec(); Frame.Add(Note); NoteTrack.FrameArray.Add(Frame); } }
/* 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: ; }