private static MidiTrack ParseMidiTrack(MidiFileFormatReader mffr, uint trackNumber) { uint time = 0; uint runningStatus = 0; MidiTrack result = new MidiTrack(); // // Verify magic number // string marker = mffr.ReadString(4); if (marker != MidiFileFormat.midiTrackMarker) { throw new FormatException(string.Format("Invalid track marker for file {0}, expected {1} found {2}", mffr.Filename, MidiFileFormat.midiTrackMarker, marker)); } // // Get the length of the track (bytes) // uint length = mffr.ReadUInt32(); // // Read all the events in the track // for (mffr.ResetBytesRead(); mffr.BytesRead < length;) { // Parse event MidiEvent midiEvent = ParseMidiEvent(mffr, trackNumber, time, runningStatus); // Adjust time time = midiEvent.TrackTime; // Running status runningStatus = midiEvent.Message.RunningStatus; // Add to list result.EventList.AddLast(midiEvent); } return(result); }
static private MidiMetaMessage ParseMidiMetaMessage(MidiFileFormatReader mffr) { MidiMetaMessage result = null; // Get message type EMetaEventType type = (EMetaEventType)mffr.ReadUInt8(); // Get body length uint length = mffr.ReadVarLengthQuantity(); switch (type) { case EMetaEventType.TrackSequenceNumber: result = new MidiMetaTrackSequenceNumberMessage(mffr.ReadUInt16()); break; case EMetaEventType.TextEvent: case EMetaEventType.Copyright: case EMetaEventType.SequenceTrackName: case EMetaEventType.TrackInstrumentName: case EMetaEventType.Lyric: case EMetaEventType.Marker: case EMetaEventType.CuePoint: case EMetaEventType.ProgramName: case EMetaEventType.DeviceName: case EMetaEventType.MidiChannel: result = new MidiMetaTextMessage(type, mffr.ReadString(length)); break; case EMetaEventType.MidiPort: result = new MidiMetaMidiPortMessage(mffr.ReadUInt8()); break; case EMetaEventType.EndTrack: // No extra data for the end of track message result = new MidiMetaMessage(type); break; case EMetaEventType.SetTempo: result = new MidiMetaTempoMessage(mffr.ReadUInt24()); break; case EMetaEventType.SmpteOffset: break; case EMetaEventType.TimeSignature: result = new MidiMetaTimeSignatureMessage(mffr.ReadUInt8(), mffr.ReadUInt8(), mffr.ReadUInt8(), mffr.ReadUInt8()); break; case EMetaEventType.KeySignature: result = new MidiMetaKeySignatureMessage(mffr.ReadUInt8(), (mffr.ReadUInt8() != 0)); break; case EMetaEventType.SequencerSpecific: // Read body byte[] body = new byte[length]; for (int i = 0; i < length; i++) { body[i] = mffr.ReadUInt8(); } result = new MidiMetaMessage(type, body); break; default: throw new FormatException(string.Format("Found unknown or unsupported metaevent code {0}", type)); } return(result); }
public static MidiSequence ParseMidiFile(string filename) { MidiFileFormatReader mffr = new MidiFileFormatReader(filename); using (mffr) { // // Verify magic number // string marker = mffr.ReadString(4); if (marker != MidiFileFormat.midiFileMarker) { throw new FormatException(string.Format("Invalid marker for file {0}, expected {1} found {2}", filename, MidiFileFormat.midiFileMarker, marker)); } // Verify header size uint headerLength = mffr.ReadUInt32(); if (headerLength != MidiFileFormat.midiFileHeaderLength) { throw new FormatException(string.Format("Invalid header length for file {0}, expected {1} found {2}", filename, MidiFileFormat.midiFileHeaderLength, headerLength)); } // // Parse header // // // The 6 next bytes are 16-bits values, defining // the format, #tracks, and ppqn // uint midiVersion = mffr.ReadUInt16(); // Midi version (0, 1, 2) uint numberOfTracks = mffr.ReadUInt16(); // Number of tracks uint resolution = mffr.ReadUInt16(); // PPQN uint ppqn = 0; uint smpteTempo = 0; // // ppqn: Pulse per quarter note: The number of tics // per quarter notes. The length of a tic is the // tempo (length of a quarter note) divided by ppqn. // // // if ppqn is < 0, then it is NOT a ppqn, it is a // tempo in SMTPE format (??) // if (0 != (resolution & 0x8000)) { ppqn = 0; smpteTempo = resolution & 0x7FFF; } else { ppqn = resolution; smpteTempo = 0; } // // Create the midi sequence // MidiSequence result = new MidiSequence(midiVersion, ppqn, smpteTempo, filename); // // Create and parse the tracks // for (uint t = 0; t < numberOfTracks; t++) { result.Tracks.Add(ParseMidiTrack(mffr, t)); } // Return the sequence return(result); } }