/// <summary>Parses a byte array into a track's worth of events.</summary> /// <param name="data">The data to be parsed.</param> /// <returns>The track containing the parsed events.</returns> public static MidiTrack ParseToTrack(byte [] data) { long pos = 0; // current position in data bool running = false; // whether we're in running status int status = 0; // the current status byte bool sysExContinue = false; // whether we're in a multi-segment system exclusive message byte [] sysExData = null; // system exclusive data up to this point from a multi-segment message try { // Create the new track MidiTrack track = new MidiTrack(); // Process all bytes, turning them into events while(pos < data.Length) { // Read in the delta time long deltaTime = ReadVariableLength(data, ref pos); // Get the next character byte nextValue = data[pos]; // Are we continuing a sys ex? If so, the next value better be 0x7F if (sysExContinue && (nextValue != 0x7f)) throw new MidiParserException("Expected to find a system exclusive continue byte.", pos); // Are we in running status? Determine whether we're running and // what the current status byte is. if ((nextValue & 0x80) == 0) { // We're now in running status... if the last status was 0, uh oh! if (status == 0) throw new MidiParserException("Status byte required for running status.", pos); // Keep the last iteration's status byte, and now we're in running mode running = true; } else { // Not running, so store the current status byte and mark running as false status = nextValue; running = false; } // Grab the 4-bit identifier byte messageType = (byte)((status >> 4) & 0xF); MidiEvent tempEvent = null; // Handle voice events if (messageType >= 0x8 && messageType <= 0xE) { if (!running) pos++; // if we're running, we don't advance; if we're not running, we do byte channel = (byte)(status & 0xF); // grab the channel from the status byte tempEvent = ParseVoiceEvent(deltaTime, messageType, channel, data, ref pos); } // Handle meta events else if (status == 0xFF) { pos++; byte eventType = data[pos]; pos++; tempEvent = ParseMetaEvent(deltaTime, eventType, data, ref pos); } // Handle system exclusive events else if (status == 0xF0) { pos++; long length = ReadVariableLength(data, ref pos); // figure out how much data to read // If this is single-segment message, process the whole thing if (data[pos+length-1] == 0xF7) { sysExData = new byte[length-1]; Array.Copy(data, (int)pos, sysExData, 0, (int)length-1); tempEvent = new SystemExclusiveMidiEvent(deltaTime, sysExData); } // It's multi-segment, so add the new data to the previously aquired data else { // Add to previously aquired sys ex data int oldLength = (sysExData == null ? 0 : sysExData.Length); byte [] newSysExData = new byte[oldLength + length]; if (sysExData != null) sysExData.CopyTo(newSysExData, 0); Array.Copy(data, (int)pos, newSysExData, oldLength, (int)length); sysExData = newSysExData; sysExContinue = true; } pos += length; } // Handle system exclusive continuations else if (status == 0xF7) { if (!sysExContinue) sysExData = null; // Figure out how much data there is pos++; long length = ReadVariableLength(data, ref pos); // Add to previously aquired sys ex data int oldLength = (sysExData == null ? 0 : sysExData.Length); byte [] newSysExData = new byte[oldLength + length]; if (sysExData != null) sysExData.CopyTo(newSysExData, 0); Array.Copy(data, (int)pos, newSysExData, oldLength, (int)length); sysExData = newSysExData; // Make it a system message if necessary (i.e. if we find an end marker) if (data[pos+length-1] == 0xF7) { tempEvent = new SystemExclusiveMidiEvent(deltaTime, sysExData); sysExData = null; sysExContinue = false; } } // Nothing we know about else throw new MidiParserException("Invalid status byte found.", pos); // Add the newly parsed event if we got one if (tempEvent != null) track.Events.Add(tempEvent); } // Return the newly populated track return track; } // Let MidiParserExceptions through catch(MidiParserException) { throw; } // Wrap all other exceptions in MidiParserExceptions catch(Exception exc) { throw new MidiParserException("Failed to parse MIDI file.", exc, pos); } }
public static MidiTrack ParseToTrack(byte[] data) { MidiTrack track2; long pos = 0L; bool flag = false; int num2 = 0; bool flag2 = false; byte[] destinationArray = null; try { MidiTrack track = new MidiTrack(); while (pos < data.Length) { long deltaTime = ReadVariableLength(data, ref pos); byte num4 = data[(int) ((IntPtr) pos)]; if (flag2 && (num4 != 0x7f)) { throw new MidiParserException("Expected to find a system exclusive continue byte.", pos); } if ((num4 & 0x80) == 0) { if (num2 == 0) { throw new MidiParserException("Status byte required for running status.", pos); } flag = true; } else { num2 = num4; flag = false; } byte messageType = (byte) ((num2 >> 4) & 15); MidiEvent message = null; if ((messageType >= 8) && (messageType <= 14)) { if (!flag) { pos += 1L; } byte channel = (byte) (num2 & 15); message = ParseVoiceEvent(deltaTime, messageType, channel, data, ref pos); } else if (num2 == 0xff) { pos += 1L; byte eventType = data[(int) ((IntPtr) pos)]; pos += 1L; message = ParseMetaEvent(deltaTime, eventType, data, ref pos); } else if (num2 == 240) { pos += 1L; long num8 = ReadVariableLength(data, ref pos); if (data[(int) ((IntPtr) ((pos + num8) - 1L))] == 0xf7) { destinationArray = new byte[num8 - 1L]; Array.Copy(data, (int) pos, destinationArray, 0, ((int) num8) - 1); message = new SystemExclusiveMidiEvent(deltaTime, destinationArray); } else { int destinationIndex = (destinationArray == null) ? 0 : destinationArray.Length; byte[] array = new byte[destinationIndex + num8]; if (destinationArray != null) { destinationArray.CopyTo(array, 0); } Array.Copy(data, (int) pos, array, destinationIndex, (int) num8); destinationArray = array; flag2 = true; } pos += num8; } else { if (num2 != 0xf7) { throw new MidiParserException("Invalid status byte found.", pos); } if (!flag2) { destinationArray = null; } pos += 1L; long num10 = ReadVariableLength(data, ref pos); int num11 = (destinationArray == null) ? 0 : destinationArray.Length; byte[] buffer3 = new byte[num11 + num10]; if (destinationArray != null) { destinationArray.CopyTo(buffer3, 0); } Array.Copy(data, (int) pos, buffer3, num11, (int) num10); destinationArray = buffer3; if (data[(int) ((IntPtr) ((pos + num10) - 1L))] == 0xf7) { message = new SystemExclusiveMidiEvent(deltaTime, destinationArray); destinationArray = null; flag2 = false; } } if (message != null) { track.Events.Add(message); } } track2 = track; } catch (MidiParserException) { throw; } catch (Exception exception) { throw new MidiParserException("Failed to parse MIDI file.", exception, pos); } return track2; }