string GetDebugInfo(int nTrackIndex, int nTrackOffset, int delta) { ushort msg16 = FileHandle.Get16Bit(nTrackIndex, nTrackOffset); byte msg8 = (byte)(msg16 & 0xFF); // we want to skip a two-byte header? byte msg8Plus1 = FileHandle.Get8Bit(nTrackIndex, nTrackOffset + 2); CurrentStatus = msg16; return($"{{ Track Index: {nTrackIndex}, Track Offset: {nTrackOffset}, delta: {delta} }}\n" + $"{{ 16 Bit Message: {msg16:X4}, 8 Bit Message: {msg8:X2}, next 8 Bit Message: {msg8Plus1:X2};"); }
/// <inheritdoc/> public string GetMessageString(int pTrackIndex, int pTrackOffset) { var msg32 = FileHandle.Get16Bit(pTrackIndex, pTrackOffset); switch ((StatusWord)msg32) { case StatusWord.SequenceNumber: /* 0xFF00 */ return(MetaHelpers.meta_FF00(FileHandle[pTrackIndex, pTrackOffset + 3], FileHandle[pTrackIndex, pTrackOffset + 4])); case StatusWord.ChannelPrefix: /* 0xFF20 */ case StatusWord.PortMessage: /* 0xFF21 */ return(FileHandle[pTrackIndex, pTrackOffset + 3].ToString()); case StatusWord.SetTempo: /* 0xFF51 */ return(MetaHelpers.meta_FF51(Convert.ToInt32(FileHandle[pTrackIndex].ReadU24(pTrackOffset + 3)))); case StatusWord.SMPTEOffset: /* 0xFF54 */ return(MetaHelpers.meta_FF54(this, pTrackOffset)); case StatusWord.TimeSignature: /* 0xFF58 */ return(MetaHelpers.meta_FF58(FileHandle[pTrackIndex], pTrackOffset)); case StatusWord.KeySignature: /* 0xFF59 */ return(MetaHelpers.PrintKeysignature(FileHandle[pTrackIndex], pTrackOffset)); case StatusWord.EndOfTrack: /* 0xFF2F */ return(MetaHelpers.meta_FF2F()); case StatusWord.SequencerSpecific_FF70: /* 0xFF70 */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF71: /* 0xFF71 */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF72: /* 0xFF72 */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF73: /* 0xFF73 */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF74: /* 0xFF74 */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF75: /* 0xFF75 */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF76: /* 0xFF76 */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF77: /* 0xFF77 */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF78: /* 0xFF78 */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF79: /* 0xFF79 */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF7A: /* 0xFF7A */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF7B: /* 0xFF7B */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF7C: /* 0xFF7C */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF7D: /* 0xFF7D */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific_FF7E: /* 0xFF7E */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SequencerSpecific: /* 0xFF7F */ return(GetMetadataBytes(pTrackIndex, pTrackOffset).StringifyHex()); case StatusWord.SystemExclusive: /* 0xF0 */ int nlength = FileHandle[pTrackIndex].GetEndOfSystemExclusive(pTrackOffset) - pTrackOffset; int noffset = pTrackOffset; string nresult = FileHandle[pTrackIndex, pTrackOffset, nlength].StringifyHex(); return(nresult); default: // check for a channel message if (CurrentRunningStatus8 == 0xF0) { long ro = 0; int no = FileHandle.ReadDelta(pTrackIndex, pTrackOffset + 1, out ro) - pTrackOffset; return(FileHandle[pTrackIndex, pTrackOffset, Convert.ToInt32(ro) + 2].StringifyHex()); } // string msg = string.Format(StringRes.String_Unknown_Message, CurrentRunningStatus8, FileHandle[pTrackIndex, pTrackOffset, 2].StringifyHex()); return(Strings.Encoding.GetString(FileHandle[pTrackIndex, pTrackOffset, FileHandle[pTrackIndex, pTrackOffset + 2] + 3])); } }
/// <summary> /// In MIDI Format 1, this would be the first track (index = 0). /// Otherwise Format 0: index = 0 and with /// Format 2, each track will essentially be like a Format 0 track. /// /// This method collects information from the 'tempo map' track such as /// /// - Tempo Information /// - SMPTE Offset /// - Time Signature /// - Key Signatuer /// - Sequencer Specific Data /// - System Exclusive Data (in tempo map) /// </summary> int GetTempoMap(int nTrackIndex, int nTrackOffset, int delta) { int DELTA_Returned = delta; var msg16 = FileHandle.Get16Bit(nTrackIndex, nTrackOffset); byte msg8 = (byte)(msg16 & 0xFF); CurrentStatus = msg16; // This is just an attempt at aligning running status. // var hexMsg = $"{msg16:X2}"; if (msg16 >= 0xFF00 && msg16 <= 0xFF0C) { DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); return(++DELTA_Returned); } switch (msg16) { // text case Stat16.SequenceNumber: // 0xFF00 case Stat16.ChannelPrefix: // 0xFF20 case Stat16.PortMessage: /* 0xFF21 */ DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.EndOfTrack: /* 0xFF2F */ DELTA_Returned = FileHandle.Tracks[nTrackIndex].Data.Length - 1; break; case Stat16.SetTempo: // 0xFF51 var muspqn = FileHandle[ReaderIndex].ReadU24(nTrackOffset + 3); TempoMap.Push(muspqn, Division, CurrentTrackPulse); DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.SMPTEOffset: // 0xFF54 SMPTE.SetSMPTE( FileHandle.Tracks[nTrackIndex].Data[nTrackOffset + 3], FileHandle.Tracks[nTrackIndex].Data[nTrackOffset + 4], FileHandle.Tracks[nTrackIndex].Data[nTrackOffset + 5], FileHandle.Tracks[nTrackIndex].Data[nTrackOffset + 6], FileHandle.Tracks[nTrackIndex].Data[nTrackOffset + 7] ); DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.TimeSignature: // 0xFF58 TimeSignature.SetSignature( (int)this[nTrackIndex, nTrackOffset + 3], (int)Math.Pow(-this[nTrackIndex, nTrackOffset + 4], 2), (int)this[nTrackIndex, nTrackOffset + 5], (int)this[nTrackIndex, nTrackOffset + 6] ); DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.KeySignature: // 0xFF59 KeySignature.SetSignature( this[nTrackIndex, nTrackOffset + 3], this[nTrackIndex, nTrackOffset + 4]); DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.SequencerSpecific_70: // 0xFF70 case Stat16.SequencerSpecific_71: // 0xFF71 case Stat16.SequencerSpecific_72: // 0xFF72 case Stat16.SequencerSpecific_73: // 0xFF73 case Stat16.SequencerSpecific_74: // 0xFF74 case Stat16.SequencerSpecific_75: // 0xFF75 case Stat16.SequencerSpecific_76: // 0xFF76 case Stat16.SequencerSpecific_77: // 0xFF77 case Stat16.SequencerSpecific_78: // 0xFF78 case Stat16.SequencerSpecific_79: // 0xFF79 case Stat16.SequencerSpecific_7A: // 0xFF7A case Stat16.SequencerSpecific_7B: // 0xFF7B case Stat16.SequencerSpecific_7C: // 0xFF7C case Stat16.SequencerSpecific_7D: // 0xFF7D case Stat16.SequencerSpecific_7E: // 0xFF7E case Stat16.SequencerSpecific: // 0xFF7F DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.SystemExclusive: var pLastIndex = FileHandle[nTrackIndex].GetEndOfSystemExclusive(nTrackOffset); DELTA_Returned = pLastIndex; break; default: { if (FileHandle.Tracks[nTrackIndex].Data[nTrackOffset] < 0x80) { CurrentStatus = CurrentRunningStatus16; // Running Status // int ExpandedRSE = CurrentTrackRunningStatus;// << 8; int ExpandedRSE = CurrentRunningStatus8;// << 8; int delta1 = -1; if ((delta1 = Increment(nTrackOffset)) == -1) { int test = GetOffset(nTrackIndex, nTrackOffset); Debug.Assert(false, string.Format("warning… {0:X2}, {1:X}|{1:N0}", ExpandedRSE, test)); } else { DELTA_Returned = delta1; } } else if (StatusQuery.IsMidiMessage(msg8)) { CurrentRunningStatus8 = msg8; CurrentRunningStatus16 = msg16; DELTA_Returned = Increment(nTrackOffset + 1); return(++DELTA_Returned); } else { throw new FormatException("Bad format!\nThere is probably a problem with the Input File unless we made an error reading it!)"); } } break; } return(++DELTA_Returned); }
/// <summary> /// provides **default parser semantic** in that from here we delegate /// each message to <see cref="MessageHandler"/>. /// `MessageHandler` can be set via the constructor, or explicitly after /// initializing (creating/.ctor) `Reader`. /// /// Additionally, <see cref="OnMidiMessage(MidiMsgType, int, int, int, byte, long, int, bool)"/> /// exists and can be set as the default message-handler in which case any assigned /// event handler(s) (`ProcessMidiMessage`) or delegates (`MessageHandler`) /// can and will be used. /// </summary> public virtual int GetNTrackMessage(int nTrackIndex, int nTrackOffset, int delta) { int DELTA_Returned = delta; ushort msg16 = FileHandle.Get16Bit(nTrackIndex, nTrackOffset); byte msg8 = (byte)(msg16 & 0xFF); CurrentStatus = msg16; // var hexMsg = $"{msg16:X2}"; if (msg16 >= 0xFF00 && msg16 <= 0xFF0C) { MessageHandler(MidiMsgType.MetaStr, nTrackIndex, nTrackOffset, msg16, msg8, CurrentTrackPulse, CurrentRunningStatus8, false); DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); return(++DELTA_Returned); } switch (msg16) { case Stat16.EndOfTrack: // FF2F MessageHandler(MidiMsgType.EOT, nTrackIndex, nTrackOffset, msg16, msg8, CurrentTrackPulse, CurrentRunningStatus8, false); DELTA_Returned = FileHandle.Tracks[nTrackIndex].Data.Length; break; case Stat16.SequenceNumber: // 0xFF00 case Stat16.ChannelPrefix: // FF20 case Stat16.PortMessage: // FF21? case Stat16.SetTempo: // FF51 MessageHandler(MidiMsgType.MetaInf, nTrackIndex, nTrackOffset, msg16, msg8, CurrentTrackPulse, CurrentRunningStatus8, false); DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.SMPTEOffset: // FF54 MessageHandler(MidiMsgType.MetaInf, nTrackIndex, nTrackOffset, msg16, msg8, CurrentTrackPulse, CurrentRunningStatus8, false); DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.TimeSignature: // FF58 case Stat16.KeySignature: // FF59 MessageHandler(MidiMsgType.MetaInf, nTrackIndex, nTrackOffset, msg16, msg8, CurrentTrackPulse, CurrentRunningStatus8, false); DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.SequencerSpecific_70: // 0xFF70 case Stat16.SequencerSpecific_71: // 0xFF71 case Stat16.SequencerSpecific_72: // 0xFF72 case Stat16.SequencerSpecific_73: // 0xFF73 case Stat16.SequencerSpecific_74: // 0xFF74 case Stat16.SequencerSpecific_75: // 0xFF75 case Stat16.SequencerSpecific_76: // 0xFF76 case Stat16.SequencerSpecific_77: // 0xFF77 case Stat16.SequencerSpecific_78: // 0xFF78 case Stat16.SequencerSpecific_79: // 0xFF79 case Stat16.SequencerSpecific_7A: // 0xFF7A case Stat16.SequencerSpecific_7B: // 0xFF7B case Stat16.SequencerSpecific_7C: // 0xFF7C case Stat16.SequencerSpecific_7D: // 0xFF7D case Stat16.SequencerSpecific_7E: // 0xFF7E // we have FF70LLNN where LL is a byte length (assumed: variable bit) and NN is the data we're being provided. // MPC Pro software generates it. // Theoretically, this could probably happen for other FF70-FF7E? MessageHandler(MidiMsgType.SequencerSpecificUnknown, nTrackIndex, nTrackOffset, msg16, msg8, CurrentTrackPulse, CurrentRunningStatus8, false); DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.SequencerSpecific: // FF7F MessageHandler(MidiMsgType.SequencerSpecific, nTrackIndex, nTrackOffset, msg16, msg8, CurrentTrackPulse, CurrentRunningStatus8, false); DELTA_Returned = FileHandle.Tracks[nTrackIndex].DeltaSeek(nTrackOffset); break; case Stat16.SystemExclusive: // 0xF0 MessageHandler(MidiMsgType.SystemExclusive, nTrackIndex, nTrackOffset, msg16, msg8, CurrentTrackPulse, CurrentRunningStatus8, false); DELTA_Returned = FileHandle[nTrackIndex].GetEndOfSystemExclusive(nTrackOffset); break; default: { if (FileHandle.Tracks[nTrackIndex].Data[nTrackOffset] < 0x80) // running-status message { // Running Status CurrentStatus = CurrentRunningStatus16; int ExpandedRSE = CurrentRunningStatus8;// << 8; int delta1 = -1; if ((delta1 = Increment(nTrackOffset)) == -1) { int test = GetOffset(nTrackIndex, nTrackOffset); Debug.Assert(false, string.Format("warning… {0:X2}, {1:X}|{1:N0}", ExpandedRSE, test)); } else { DELTA_Returned = delta1; MessageHandler(GetMidiMessageType(CurrentRunningStatus8), nTrackIndex, nTrackOffset, CurrentRunningStatus16, (byte)CurrentRunningStatus8, CurrentTrackPulse, CurrentRunningStatus8, true); } } //else if (StatusQuery.IsMidiMessage(msg32)) else if (StatusQuery.IsMidiMessage(msg8)) { //CurrentTrackRunningStatus = (FileHandle[nTrackIndex, nTrackOffset]); CurrentRunningStatus8 = msg8; CurrentRunningStatus16 = msg16; DELTA_Returned = Increment(nTrackOffset + 1); MessageHandler(GetMidiMessageType(CurrentRunningStatus8), nTrackIndex, nTrackOffset, msg16, msg8, CurrentTrackPulse, CurrentRunningStatus8, false); DELTA_Returned++; return(DELTA_Returned); } else { throw new FormatException( $"Bad format(?)!\n" + $"There is probably a problem with the Input File (unless we made an error reading it)!\n" + $"Here is some debug info: {GetDebugInfo(nTrackIndex, nTrackOffset, delta)}"); } } break; } return(++DELTA_Returned); }