Example #1
0
        /// <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;
 }