/// <summary> /// Loads a MIDI file from the stream. /// </summary> /// <param name="stream">The data stream used to load the MIDI file.</param> /// <param name="loopType">The type of the loop extension to be used.</param> public MidiFile(Stream stream, MidiFileLoopType loopType) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } Load(stream, 0, loopType); }
/// <summary> /// Loads a MIDI file from the file. /// </summary> /// <param name="path">The MIDI file name and path.</param> /// <param name="loopType">The type of the loop extension to be used.</param> public MidiFile(string path, MidiFileLoopType loopType) { if (path == null) { throw new ArgumentNullException(nameof(path)); } using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { Load(stream, 0, loopType); } }
public static Message Common(byte status, byte data1, byte data2, MidiFileLoopType loopType) { byte channel = (byte)(status & 0x0F); byte command = (byte)(status & 0xF0); if (command == 0xB0) { switch (loopType) { case MidiFileLoopType.RpgMaker: if (data1 == 111) { return(LoopStart()); } break; case MidiFileLoopType.IncredibleMachine: if (data1 == 110) { return(LoopStart()); } if (data1 == 111) { return(LoopEnd()); } break; case MidiFileLoopType.FinalFantasy: if (data1 == 116) { return(LoopStart()); } if (data1 == 117) { return(LoopEnd()); } break; } } return(new Message(channel, command, data1, data2)); }
private static void ReadTrack(BinaryReader reader, MidiFileLoopType loopType, out List <Message> messages, out List <int> ticks) { var chunkType = reader.ReadFourCC(); if (chunkType != "MTrk") { throw new InvalidDataException($"The chunk type must be 'MTrk', but was '{chunkType}'."); } reader.ReadInt32BigEndian(); messages = new List <Message>(); ticks = new List <int>(); int tick = 0; byte lastStatus = 0; while (true) { var delta = reader.ReadIntVariableLength(); var first = reader.ReadByte(); try { tick = checked (tick + delta); } catch (OverflowException) { throw new NotSupportedException("Long MIDI file is not supported."); } if ((first & 128) == 0) { var command = lastStatus & 0xF0; if (command == 0xC0 || command == 0xD0) { messages.Add(Message.Common(lastStatus, first)); ticks.Add(tick); } else { var data2 = reader.ReadByte(); messages.Add(Message.Common(lastStatus, first, data2, loopType)); ticks.Add(tick); } continue; } switch (first) { case 0xF0: // System Exclusive DiscardData(reader); break; case 0xF7: // System Exclusive DiscardData(reader); break; case 0xFF: // Meta Event switch (reader.ReadByte()) { case 0x2F: // End of Track reader.ReadByte(); messages.Add(Message.EndOfTrack()); ticks.Add(tick); return; case 0x51: // Tempo messages.Add(Message.TempoChange(ReadTempo(reader))); ticks.Add(tick); break; default: DiscardData(reader); break; } break; default: var command = first & 0xF0; if (command == 0xC0 || command == 0xD0) { var data1 = reader.ReadByte(); messages.Add(Message.Common(first, data1)); ticks.Add(tick); } else { var data1 = reader.ReadByte(); var data2 = reader.ReadByte(); messages.Add(Message.Common(first, data1, data2, loopType)); ticks.Add(tick); } break; } lastStatus = first; } }
private void Load(Stream stream, int loopPoint, MidiFileLoopType loopType) { using (var reader = new BinaryReader(stream, Encoding.ASCII, true)) { var chunkType = reader.ReadFourCC(); if (chunkType != "MThd") { throw new InvalidDataException($"The chunk type must be 'MThd', but was '{chunkType}'."); } var size = reader.ReadInt32BigEndian(); if (size != 6) { throw new InvalidDataException($"The MThd chunk has invalid data."); } var format = reader.ReadInt16BigEndian(); if (!(format == 0 || format == 1)) { throw new NotSupportedException($"The format {format} is not supported."); } trackCount = reader.ReadInt16BigEndian(); resolution = reader.ReadInt16BigEndian(); var messageLists = new List <Message> [trackCount]; var tickLists = new List <int> [trackCount]; for (var i = 0; i < trackCount; i++) { List <Message> messageList; List <int> tickList; ReadTrack(reader, loopType, out messageList, out tickList); messageLists[i] = messageList; tickLists[i] = tickList; } if (loopPoint != 0) { var tickList = tickLists[0]; var messageList = messageLists[0]; if (loopPoint <= tickList.Last()) { for (var i = 0; i < tickList.Count; i++) { if (tickList[i] >= loopPoint) { tickList.Insert(i, loopPoint); messageList.Insert(i, Message.LoopStart()); break; } } } else { tickList.Add(loopPoint); messageList.Add(Message.LoopStart()); } } MergeTracks(messageLists, tickLists, resolution, out messages, out times); } }