Exemplo n.º 1
0
        /// <summary>Creates an object creation expression for an event.</summary>
        /// <param name="ev">The event to create.</param>
        /// <returns>The object creation expression for the event.</returns>
        private static CodeObjectCreateExpression CreateSystemEvent(MidiEvent ev)
        {
            CodeObjectCreateExpression newEvent = null;
            CodeExpression             delta    = new CodePrimitiveExpression(ev.DeltaTime);

            // SYSTEM EXCLUSIVE
            if (ev is SystemExclusiveMidiEvent)
            {
                SystemExclusiveMidiEvent midiEvent = (SystemExclusiveMidiEvent)ev;
                newEvent = new CodeObjectCreateExpression(
                    typeof(SystemExclusiveMidiEvent),
                    new CodeExpression[] {
                    delta,
                    CreateDataArray(midiEvent.Data)
                });
            }

            // Return the event
            return(newEvent);
        }
Exemplo n.º 2
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); }
        }