public int Compare(MidiEvent x, MidiEvent y) { long num = x.AbsoluteTime; long num2 = y.AbsoluteTime; if (num == num2) { MetaEvent metaEvent = x as MetaEvent; MetaEvent metaEvent2 = y as MetaEvent; if (metaEvent != null) { if (metaEvent.MetaEventType == MetaEventType.EndTrack) { num = long.MaxValue; } else { num = long.MinValue; } } if (metaEvent2 != null) { if (metaEvent2.MetaEventType == MetaEventType.EndTrack) { num2 = long.MaxValue; } else { num2 = long.MinValue; } } } return(num.CompareTo(num2)); }
/// <summary> /// Reads a meta-event from a stream /// </summary> /// <param name="br">A binary reader based on the stream of MIDI data</param> /// <returns>A new MetaEvent object</returns> public static MetaEvent ReadMetaEvent(BinaryReader br) { MetaEventType metaEvent = (MetaEventType) br.ReadByte(); int length = ReadVarInt(br); MetaEvent me = new MetaEvent(); switch(metaEvent) { case MetaEventType.TrackSequenceNumber: // Sets the track's sequence number. me = new TrackSequenceNumberEvent(br,length); break; case MetaEventType.TextEvent: // Text event case MetaEventType.Copyright: // Copyright case MetaEventType.SequenceTrackName: // Sequence / Track Name case MetaEventType.TrackInstrumentName: // Track instrument name case MetaEventType.Lyric: // lyric case MetaEventType.Marker: // marker case MetaEventType.CuePoint: // cue point case MetaEventType.ProgramName: case MetaEventType.DeviceName: me = new TextEvent(br,length); break; case MetaEventType.EndTrack: // This event must come at the end of each track if(length != 0) { throw new FormatException("End track length"); } break; case MetaEventType.SetTempo: // Set tempo me = new TempoEvent(br,length); break; case MetaEventType.TimeSignature: // Time signature me = new TimeSignatureEvent(br,length); break; case MetaEventType.KeySignature: // Key signature me = new KeySignatureEvent(br, length); break; case MetaEventType.SequencerSpecific: // Sequencer specific information me = new SequencerSpecificEvent(br, length); break; case MetaEventType.SmpteOffset: me = new SmpteOffsetEvent(br, length); break; default: //System.Windows.Forms.MessageBox.Show(String.Format("Unsupported MetaEvent {0} length {1} pos {2}",metaEvent,length,br.BaseStream.Position)); me.data = br.ReadBytes(length); if (me.data.Length != length) { throw new FormatException("Failed to read metaevent's data fully"); } break; } me.metaEvent = metaEvent; me.metaDataLength = length; return me; }
/// <summary> /// Determines if this is an end track event /// </summary> public static bool IsEndTrack(MidiEvent midiEvent) { if (midiEvent != null) { MetaEvent me = midiEvent as MetaEvent; if (me != null) { return(me.MetaEventType == MetaEventType.EndTrack); } } return(false); }
/// <summary> /// Reads a meta-event from a stream /// </summary> /// <param name="br">A binary reader based on the stream of MIDI data</param> /// <returns>A new MetaEvent object</returns> public static MetaEvent ReadMetaEvent(BinaryReader br) { MetaEventType metaEvent = (MetaEventType)br.ReadByte(); int length = ReadVarInt(br); MetaEvent me = new MetaEvent(); switch (metaEvent) { case MetaEventType.TextEvent: // Text event case MetaEventType.Copyright: // Copyright case MetaEventType.SequenceTrackName: // Sequence / Track Name case MetaEventType.TrackInstrumentName: // Track instrument name case MetaEventType.Lyric: // lyric case MetaEventType.Marker: // marker case MetaEventType.CuePoint: // cue point case MetaEventType.ProgramName: case MetaEventType.DeviceName: me = new TextEvent(br, length); break; case MetaEventType.EndTrack: // This event must come at the end of each track if (length != 0) { throw new FormatException("End track length"); } break; case MetaEventType.SetTempo: // Set tempo me = new TempoEvent(br, length); break; case MetaEventType.TimeSignature: // Time signature me = new TimeSignatureEvent(br, length); break; default: //System.Windows.Forms.MessageBox.Show(String.Format("Unsupported MetaEvent {0} length {1} pos {2}",metaEvent,length,br.BaseStream.Position)); me.data = br.ReadBytes(length); if (me.data.Length != length) { throw new FormatException("Failed to read metaevent's data fully"); } break; } me.metaEvent = metaEvent; me.metaDataLength = length; return(me); }
/// <summary> /// Compares two MidiEvents /// Sorts by time, with EndTrack always sorted to the end /// </summary> public int Compare(MidiEvent x, MidiEvent y) { long xTime = x.AbsoluteTime; long yTime = y.AbsoluteTime; if (xTime == yTime) { // sort meta events before note events, except end track MetaEvent xMeta = x as MetaEvent; MetaEvent yMeta = y as MetaEvent; if (xMeta != null) { if (xMeta.MetaEventType == MetaEventType.EndTrack) { xTime = Int64.MaxValue; } else { xTime = Int64.MinValue; } } if (yMeta != null) { if (yMeta.MetaEventType == MetaEventType.EndTrack) { yTime = Int64.MaxValue; } else { yTime = Int64.MinValue; } } } return(xTime.CompareTo(yTime)); }
private MidiFile(Stream inputStream, bool strictChecking, bool ownInputStream) { this.strictChecking = strictChecking; var br = new BinaryReader(inputStream); try { string chunkHeader = Encoding.UTF8.GetString(br.ReadBytes(4)); if (chunkHeader != "MThd") { throw new FormatException("Not a MIDI file - header chunk missing"); } uint chunkSize = SwapUInt32(br.ReadUInt32()); if (chunkSize != 6) { throw new FormatException("Unexpected header chunk length"); } // 0 = single track, 1 = multi-track synchronous, 2 = multi-track asynchronous fileFormat = SwapUInt16(br.ReadUInt16()); int tracks = SwapUInt16(br.ReadUInt16()); deltaTicksPerQuarterNote = SwapUInt16(br.ReadUInt16()); events = new MidiEventCollection((fileFormat == 0) ? 0 : 1, deltaTicksPerQuarterNote); for (int n = 0; n < tracks; n++) { events.AddTrack(); } long absoluteTime = 0; for (int track = 0; track < tracks; track++) { if (fileFormat == 1) { absoluteTime = 0; } chunkHeader = Encoding.UTF8.GetString(br.ReadBytes(4)); if (chunkHeader != "MTrk") { throw new FormatException("Invalid chunk header"); } chunkSize = SwapUInt32(br.ReadUInt32()); long startPos = br.BaseStream.Position; MidiEvent me = null; var outstandingNoteOns = new List <NoteOnEvent>(); while (br.BaseStream.Position < startPos + chunkSize) { try { me = MidiEvent.ReadNextEvent(br, me); } catch (InvalidDataException) { if (strictChecking) { throw; } continue; } catch (FormatException) { if (strictChecking) { throw; } continue; } absoluteTime += me.DeltaTime; me.AbsoluteTime = absoluteTime; events[track].Add(me); if (me.CommandCode == MidiCommandCode.NoteOn) { var ne = (NoteEvent)me; if (ne.Velocity > 0) { outstandingNoteOns.Add((NoteOnEvent)ne); } else { // don't remove the note offs, even though // they are annoying // events[track].Remove(me); FindNoteOn(ne, outstandingNoteOns); } } else if (me.CommandCode == MidiCommandCode.NoteOff) { FindNoteOn((NoteEvent)me, outstandingNoteOns); } else if (me.CommandCode == MidiCommandCode.MetaEvent) { MetaEvent metaEvent = (MetaEvent)me; if (metaEvent.MetaEventType == MetaEventType.EndTrack) { //break; // some dodgy MIDI files have an event after end track if (strictChecking) { if (br.BaseStream.Position < startPos + chunkSize) { throw new FormatException( $"End Track event was not the last MIDI event on track {track}"); } } } } } if (outstandingNoteOns.Count > 0) { if (strictChecking) { throw new FormatException( $"Note ons without note offs {outstandingNoteOns.Count} (file format {fileFormat})"); } } if (br.BaseStream.Position != startPos + chunkSize) { throw new FormatException($"Read too far {chunkSize}+{startPos}!={br.BaseStream.Position}"); } } } finally { if (ownInputStream) { #if NET35 br.Close(); #else br.Dispose(); #endif } } }
/// <summary> /// Opens a MIDI file for reading /// </summary> /// <param name="filename">Name of MIDI file</param> /// <param name="strictChecking">If true will error on non-paired note events</param> public MidiFile(string filename, bool strictChecking) { this.strictChecking = strictChecking; BinaryReader br = new BinaryReader(File.OpenRead(filename)); using (br) { string chunkHeader = Encoding.ASCII.GetString(br.ReadBytes(4)); if (chunkHeader != "MThd") { throw new FormatException("Not a MIDI file - header chunk missing"); } uint chunkSize = SwapUInt32(br.ReadUInt32()); if (chunkSize != 6) { throw new FormatException("Unexpected header chunk length"); } // 0 = single track, 1 = multi-track synchronous, 2 = multi-track asynchronous fileFormat = SwapUInt16(br.ReadUInt16()); int tracks = SwapUInt16(br.ReadUInt16()); deltaTicksPerQuarterNote = SwapUInt16(br.ReadUInt16()); events = new MidiEventCollection((fileFormat == 0) ? 0 : 1, deltaTicksPerQuarterNote); for (int n = 0; n < tracks; n++) { events.AddTrack(); } long absoluteTime = 0; for (int track = 0; track < tracks; track++) { if (fileFormat == 1) { absoluteTime = 0; } chunkHeader = Encoding.ASCII.GetString(br.ReadBytes(4)); if (chunkHeader != "MTrk") { throw new FormatException("Invalid chunk header"); } chunkSize = SwapUInt32(br.ReadUInt32()); long startPos = br.BaseStream.Position; MidiEvent me = null; List <NoteOnEvent> outstandingNoteOns = new List <NoteOnEvent>(); while (br.BaseStream.Position < startPos + chunkSize) { me = MidiEvent.ReadNextEvent(br, me); absoluteTime += me.DeltaTime; me.AbsoluteTime = absoluteTime; events[track].Add(me); if (me.CommandCode == MidiCommandCode.NoteOn) { NoteEvent ne = (NoteEvent)me; if (ne.Velocity > 0) { outstandingNoteOns.Add((NoteOnEvent)ne); } else { // don't remove the note offs, even though // they are annoying // events[track].Remove(me); FindNoteOn(ne, outstandingNoteOns); } } else if (me.CommandCode == MidiCommandCode.NoteOff) { FindNoteOn((NoteEvent)me, outstandingNoteOns); } else if (me.CommandCode == MidiCommandCode.MetaEvent) { MetaEvent metaEvent = (MetaEvent)me; if (metaEvent.MetaEventType == MetaEventType.EndTrack) { //break; // some dodgy MIDI files have an event after end track if (strictChecking) { if (br.BaseStream.Position < startPos + chunkSize) { throw new FormatException(String.Format("End Track event was not the last MIDI event on track {0}", track)); } } } } } if (outstandingNoteOns.Count > 0) { if (strictChecking) { throw new FormatException(String.Format("Note ons without note offs {0} (file format {1})", outstandingNoteOns.Count, fileFormat)); } } if (br.BaseStream.Position != startPos + chunkSize) { throw new FormatException(String.Format("Read too far {0}+{1}!={2}", chunkSize, startPos, br.BaseStream.Position)); } } } }
/// <summary> /// Constructs a MidiEvent from a BinaryStream /// </summary> /// <param name="br">The binary stream of MIDI data</param> /// <param name="previous">The previous MIDI event (pass null for first event)</param> /// <returns>A new MidiEvent</returns> public static MidiEvent ReadNextEvent(BinaryReader br, MidiEvent previous) { int deltaTime = MidiEvent.ReadVarInt(br); MidiCommandCode commandCode; int channel = 1; byte b = br.ReadByte(); if ((b & 0x80) == 0) { // a running command - command & channel are same as previous commandCode = previous.CommandCode; channel = previous.Channel; br.BaseStream.Position--; // need to push this back } else { if ((b & 0xF0) == 0xF0) { // both bytes are used for command code in this case commandCode = (MidiCommandCode)b; } else { commandCode = (MidiCommandCode)(b & 0xF0); channel = (b & 0x0F) + 1; } } MidiEvent me; switch (commandCode) { case MidiCommandCode.NoteOn: me = new NoteOnEvent(br); break; case MidiCommandCode.NoteOff: case MidiCommandCode.KeyAfterTouch: me = new NoteEvent(br); break; case MidiCommandCode.ControlChange: me = new ControlChangeEvent(br); break; case MidiCommandCode.PatchChange: me = new PatchChangeEvent(br); break; case MidiCommandCode.ChannelAfterTouch: me = new ChannelAfterTouchEvent(br); break; case MidiCommandCode.PitchWheelChange: me = new PitchWheelChangeEvent(br); break; case MidiCommandCode.TimingClock: case MidiCommandCode.StartSequence: case MidiCommandCode.ContinueSequence: case MidiCommandCode.StopSequence: me = new MidiEvent(); break; case MidiCommandCode.Sysex: me = SysexEvent.ReadSysexEvent(br); break; case MidiCommandCode.MetaEvent: me = MetaEvent.ReadMetaEvent(br); break; default: throw new FormatException(String.Format("Unsupported MIDI Command Code {0:X2}", (byte)commandCode)); } me.channel = channel; me.deltaTime = deltaTime; me.commandCode = commandCode; return(me); }
/// <summary> /// Constructs a MidiEvent from a BinaryStream /// </summary> /// <param name="br">The binary stream of MIDI data</param> /// <param name="previous">The previous MIDI event (pass null for first event)</param> /// <returns>A new MidiEvent</returns> // Token: 0x060004C8 RID: 1224 RVA: 0x0000FF78 File Offset: 0x0000E178 public static MidiEvent ReadNextEvent(BinaryReader br, MidiEvent previous) { int num = MidiEvent.ReadVarInt(br); int num2 = 1; byte b = br.ReadByte(); MidiCommandCode midiCommandCode; if ((b & 128) == 0) { midiCommandCode = previous.CommandCode; num2 = previous.Channel; br.BaseStream.Position -= 1L; } else if ((b & 240) == 240) { midiCommandCode = (MidiCommandCode)b; } else { midiCommandCode = (MidiCommandCode)(b & 240); num2 = (int)((b & 15) + 1); } MidiCommandCode midiCommandCode2 = midiCommandCode; MidiEvent midiEvent; if (midiCommandCode2 <= MidiCommandCode.ControlChange) { if (midiCommandCode2 <= MidiCommandCode.NoteOn) { if (midiCommandCode2 != MidiCommandCode.NoteOff) { if (midiCommandCode2 != MidiCommandCode.NoteOn) { goto IL_15F; } midiEvent = new NoteOnEvent(br); goto IL_175; } } else if (midiCommandCode2 != MidiCommandCode.KeyAfterTouch) { if (midiCommandCode2 != MidiCommandCode.ControlChange) { goto IL_15F; } midiEvent = new ControlChangeEvent(br); goto IL_175; } midiEvent = new NoteEvent(br); goto IL_175; } if (midiCommandCode2 <= MidiCommandCode.ChannelAfterTouch) { if (midiCommandCode2 == MidiCommandCode.PatchChange) { midiEvent = new PatchChangeEvent(br); goto IL_175; } if (midiCommandCode2 == MidiCommandCode.ChannelAfterTouch) { midiEvent = new ChannelAfterTouchEvent(br); goto IL_175; } } else { if (midiCommandCode2 == MidiCommandCode.PitchWheelChange) { midiEvent = new PitchWheelChangeEvent(br); goto IL_175; } if (midiCommandCode2 == MidiCommandCode.Sysex) { midiEvent = SysexEvent.ReadSysexEvent(br); goto IL_175; } switch (midiCommandCode2) { case MidiCommandCode.TimingClock: case MidiCommandCode.StartSequence: case MidiCommandCode.ContinueSequence: case MidiCommandCode.StopSequence: midiEvent = new MidiEvent(); goto IL_175; case MidiCommandCode.MetaEvent: midiEvent = MetaEvent.ReadMetaEvent(br); goto IL_175; } } IL_15F: throw new FormatException(string.Format("Unsupported MIDI Command Code {0:X2}", (byte)midiCommandCode)); IL_175: midiEvent.channel = num2; midiEvent.deltaTime = num; midiEvent.commandCode = midiCommandCode; return(midiEvent); }
public static MetaEvent ReadMetaEvent(BinaryReader br) { MetaEventType metaEventType = (MetaEventType)br.ReadByte(); int num = MidiEvent.ReadVarInt(br); MetaEvent metaEvent = new MetaEvent(); MetaEventType metaEventType2 = metaEventType; if (metaEventType2 <= MetaEventType.SetTempo) { switch (metaEventType2) { case MetaEventType.TrackSequenceNumber: metaEvent = new TrackSequenceNumberEvent(br, num); goto IL_E9; case MetaEventType.TextEvent: case MetaEventType.Copyright: case MetaEventType.SequenceTrackName: case MetaEventType.TrackInstrumentName: case MetaEventType.Lyric: case MetaEventType.Marker: case MetaEventType.CuePoint: case MetaEventType.ProgramName: case MetaEventType.DeviceName: metaEvent = new TextEvent(br, num); goto IL_E9; default: if (metaEventType2 != MetaEventType.EndTrack) { if (metaEventType2 == MetaEventType.SetTempo) { metaEvent = new TempoEvent(br, num); goto IL_E9; } } else { if (num != 0) { throw new FormatException("End track length"); } goto IL_E9; } break; } } else { if (metaEventType2 == MetaEventType.SmpteOffset) { metaEvent = new SmpteOffsetEvent(br, num); goto IL_E9; } switch (metaEventType2) { case MetaEventType.TimeSignature: metaEvent = new TimeSignatureEvent(br, num); goto IL_E9; case MetaEventType.KeySignature: metaEvent = new KeySignatureEvent(br, num); goto IL_E9; default: if (metaEventType2 == MetaEventType.SequencerSpecific) { metaEvent = new SequencerSpecificEvent(br, num); goto IL_E9; } break; } } metaEvent.data = br.ReadBytes(num); if (metaEvent.data.Length != num) { throw new FormatException("Failed to read metaevent's data fully"); } IL_E9: metaEvent.metaEvent = metaEventType; metaEvent.metaDataLength = num; return(metaEvent); }
/// <summary> /// Opens a MIDI file for reading /// </summary> /// <param name="filename">Name of MIDI file</param> /// <param name="strictChecking">If true will error on non-paired note events</param> // Token: 0x0600050B RID: 1291 RVA: 0x00010D64 File Offset: 0x0000EF64 public MidiFile(string filename, bool strictChecking) { this.strictChecking = strictChecking; BinaryReader binaryReader = new BinaryReader(File.OpenRead(filename)); using (binaryReader) { string @string = Encoding.UTF8.GetString(binaryReader.ReadBytes(4)); if (@string != "MThd") { throw new FormatException("Not a MIDI file - header chunk missing"); } uint num = MidiFile.SwapUInt32(binaryReader.ReadUInt32()); if (num != 6u) { throw new FormatException("Unexpected header chunk length"); } this.fileFormat = MidiFile.SwapUInt16(binaryReader.ReadUInt16()); int num2 = (int)MidiFile.SwapUInt16(binaryReader.ReadUInt16()); this.deltaTicksPerQuarterNote = MidiFile.SwapUInt16(binaryReader.ReadUInt16()); this.events = new MidiEventCollection((this.fileFormat == 0) ? 0 : 1, (int)this.deltaTicksPerQuarterNote); for (int i = 0; i < num2; i++) { this.events.AddTrack(); } long num3 = 0L; for (int j = 0; j < num2; j++) { if (this.fileFormat == 1) { num3 = 0L; } @string = Encoding.UTF8.GetString(binaryReader.ReadBytes(4)); if (@string != "MTrk") { throw new FormatException("Invalid chunk header"); } num = MidiFile.SwapUInt32(binaryReader.ReadUInt32()); long position = binaryReader.BaseStream.Position; MidiEvent midiEvent = null; List <NoteOnEvent> list = new List <NoteOnEvent>(); while (binaryReader.BaseStream.Position < position + (long)((ulong)num)) { midiEvent = MidiEvent.ReadNextEvent(binaryReader, midiEvent); num3 += (long)midiEvent.DeltaTime; midiEvent.AbsoluteTime = num3; this.events[j].Add(midiEvent); if (midiEvent.CommandCode == MidiCommandCode.NoteOn) { NoteEvent noteEvent = (NoteEvent)midiEvent; if (noteEvent.Velocity > 0) { list.Add((NoteOnEvent)noteEvent); } else { this.FindNoteOn(noteEvent, list); } } else if (midiEvent.CommandCode == MidiCommandCode.NoteOff) { this.FindNoteOn((NoteEvent)midiEvent, list); } else if (midiEvent.CommandCode == MidiCommandCode.MetaEvent) { MetaEvent metaEvent = (MetaEvent)midiEvent; if (metaEvent.MetaEventType == MetaEventType.EndTrack && strictChecking && binaryReader.BaseStream.Position < position + (long)((ulong)num)) { throw new FormatException(string.Format("End Track event was not the last MIDI event on track {0}", j)); } } } if (list.Count > 0 && strictChecking) { throw new FormatException(string.Format("Note ons without note offs {0} (file format {1})", list.Count, this.fileFormat)); } if (binaryReader.BaseStream.Position != position + (long)((ulong)num)) { throw new FormatException(string.Format("Read too far {0}+{1}!={2}", num, position, binaryReader.BaseStream.Position)); } } } }