/* create a new raw MIDI track */
        public static RawMIDITrackRec NewRawMIDITrack()
        {
            RawMIDITrackRec RawTrack = new RawMIDITrackRec();

            RawTrack.EventList = new List <RawMIDIEventRec>();
            return(RawTrack);
        }
Exemple #2
0
        /* import midi file from existing file pointer */
        public static void ImportMIDIFileSpecified(string Where)
        {
            RawMIDIScoreRec Score = NewRawMIDIScore();

            using (Stream stream = new FileStream(Where, FileMode.Open, FileAccess.Read, FileShare.Read, Constants.BufferSize))
            {
                using (BinaryReader BufferedFile = new BinaryReader(stream))
                {
                    MIDIParseErrorType result = MIDIParseErrorType.eMIDIParseFileReadError;
                    try
                    {
                        result = ParseMIDIFile(BufferedFile, Score);
                    }
                    catch (InvalidDataException)
                    {
                        // generally - unexpected eof
                        Debug.Assert(result == MIDIParseErrorType.eMIDIParseFileReadError);
                    }
                    switch (result)
                    {
                    default:
                        Debug.Assert(false);
                        throw new ArgumentException();

                    case MIDIParseErrorType.eMIDIParseNoError:
                        break;

                    case MIDIParseErrorType.eMIDIParseFileReadError:
                        MessageBox.Show(
                            "An error occurred while reading the file. Attempting to import as much of the file as possible.",
                            "Import Error",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                        break;

                    case MIDIParseErrorType.eMIDIParseBadFormat:
                        MessageBox.Show(
                            "The file is not a valid MIDI file. Attempting to import as much of the file as possible.",
                            "Import Error",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                        break;
                    }
                }
            }
            if (GetRawMIDIScoreNumTracks(Score) > 0)
            {
                /* create the new document to put the tracks into */
                bool     TrackWasCreated = false;
                Document Document        = new Document();

                /* iterate over MIDI tracks */
                int TrackLimit = GetRawMIDIScoreNumTracks(Score);
                for (int TrackScan = 0; TrackScan < TrackLimit; TrackScan++)
                {
                    /* get track */
                    RawMIDITrackRec Track = GetRawMIDIScoreIndexedTrack(Score, TrackScan);

                    /* process channels */
                    for (short ChannelScan = 1; ChannelScan <= 16; ChannelScan++)
                    {
                        bool             KeepFlag;
                        IntervalTrackRec IntervalTrack = NewIntervalTrack();
                        ConvertRawToInterval(Track, IntervalTrack, ChannelScan, out KeepFlag);

                        /* process cooked track into one of our track objects */
                        if (KeepFlag)
                        {
                            QuantizedTrackRec QuantizedTrack;
                            TrackObjectRec    DocumentTrack;

                            /* make sure we can handle this track */
                            if (MIDITimingType.eMIDIMeteredTime != RawMIDIScoreGetTimingMode(Score))
                            {
                                MessageBox.Show(
                                    "Can't import real-time MIDI files.",
                                    "Import Error",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Stop);
                                return;
                            }

                            QuantizedTrack = NewQuantizedTrack();
                            ConvertIntervalToQuantized(IntervalTrack, QuantizedTrack,
                                                       RawMIDIScoreGetPartsPerQuarterNote(Score));

                            DocumentTrack = new TrackObjectRec(Document);
                            Document.TrackList.Add(DocumentTrack);
                            TrackWasCreated = true;
                            ConvertQuantToNote(QuantizedTrack, DocumentTrack);

                            /* set track release point 1 to be from end */
                            DocumentTrack.DefaultReleasePoint1ModeFlag = NoteFlags.eRelease1FromEnd;
                        }
                    }
                }

                /* clear the dirty flag, since nothing was actually modified */
                Document.Modified = false;

                /* remove track if we didn't actually find anything in the file */
                if (!TrackWasCreated)
                {
                    MessageBox.Show(
                        "No tracks were found in the MIDI file.",
                        "Import Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information);
                    return;
                }

                MainWindow MainWindow = new MainWindow(Document, null);
                MainWindow.Show();
            }
        }
        /* convert raw track into an interval track.  MIDITrackNum should be in 1..16 */
        /* *KeepFlag is set if there were real events in this track. */
        public static void ConvertRawToInterval(
            RawMIDITrackRec RawTrack,
            IntervalTrackRec IntervalTrack,
            short MIDITrackNum,
            out bool KeepFlag)
        {
            int Limit;

            PitchEventRec[] EventTracker = new PitchEventRec[128];

            Debug.Assert((MIDITrackNum >= 1) || (MIDITrackNum <= 16));
            MIDITrackNum -= 1;
            KeepFlag      = false;

            /* initialize correlation tracker */
            for (int i = 0; i < 128; i += 1)
            {
                EventTracker[i].NoteOn = false;
            }

            /* scan all low level events */
            Limit = GetRawMIDITrackLength(RawTrack);
            for (int i = 0; i < Limit; i += 1)
            {
                byte TypeByte;

                RawMIDIEventRec RawEvent   = GetRawMIDITrackIndexedEvent(RawTrack, i);
                byte            StatusByte = GetRawMIDIEventStatus(RawEvent);
                switch ((StatusByte >> 4) & 0x0f)
                {
                /* ignore events we don't know about */
                default:
                    break;

                /* 1000nnnn:  note off event for channel nnnn followed by 2 data bytes */
                case 0x08:
NoteOffPoint:
                    if ((StatusByte & 0x0f) == MIDITrackNum)
                    {
                        short Pitch;
                        short ReleaseVelocity;

                        /* data byte 1:  velocity 0..127 */
                        /* data byte 2:  pitch 0..127 */
                        if (GetRawMIDIEventMessageLength(RawEvent) >= 2)
                        {
                            ReleaseVelocity = (short)(0x7f & GetRawMIDIEventMessageByte(RawEvent, 1));
                        }
                        else
                        {
                            ReleaseVelocity = 0;
                        }
                        if (GetRawMIDIEventMessageLength(RawEvent) >= 1)
                        {
                            Pitch = (short)(0x7f & GetRawMIDIEventMessageByte(RawEvent, 0));
                        }
                        else
                        {
                            Pitch = 0;
                        }
                        if (EventTracker[Pitch].NoteOn)
                        {
                            IntEventRec IntervalEvent = NewIntervalNoteEvent(
                                EventTracker[Pitch].StartTime,
                                GetRawMIDIEventTime(RawEvent) - EventTracker[Pitch].StartTime,
                                Pitch,
                                EventTracker[Pitch].StartVelocity,
                                ReleaseVelocity);
                            IntervalTrackInsertEventSorted(IntervalTrack, IntervalEvent);
                            EventTracker[Pitch].NoteOn = false;
                        }
                        else
                        {
                            /* no note-on event? */
                        }
                        KeepFlag = true;
                    }
                    break;

                /* 1001nnnn:  note on event for channel nnnn followed by 2 data bytes */
                case 0x09:
                    if ((StatusByte & 0x0f) == MIDITrackNum)
                    {
                        short Pitch;
                        short Velocity;

                        /* data byte 1:  velocity 0..127 */
                        /* data byte 2:  pitch 0..127 */
                        if (GetRawMIDIEventMessageLength(RawEvent) >= 2)
                        {
                            Velocity = (short)(0x7f & GetRawMIDIEventMessageByte(RawEvent, 1));
                        }
                        else
                        {
                            Velocity = 64;
                        }
                        if (Velocity == 0)
                        {
                            /* note on velocity 0 actually means note off */
                            goto NoteOffPoint;
                        }
                        if (GetRawMIDIEventMessageLength(RawEvent) >= 1)
                        {
                            Pitch = (short)(0x7f & GetRawMIDIEventMessageByte(RawEvent, 0));
                        }
                        else
                        {
                            Pitch = 0;
                        }
                        if (!EventTracker[Pitch].NoteOn)
                        {
                            EventTracker[Pitch].StartTime     = GetRawMIDIEventTime(RawEvent);
                            EventTracker[Pitch].StartVelocity = Velocity;
                            EventTracker[Pitch].NoteOn        = true;
                        }
                        else
                        {
                            /* note already on? */
                        }
                        KeepFlag = true;
                    }
                    break;

                /* 1010nnnn:  polyphonic key pressure/after touch followed by */
                /*   2 data bytes */
                case 0x0a:
                    break;

                /* 1011nnnn:  control change followed by 2 data bytes */
                case 0x0b:
                    break;

                /* 1110nnnn:  pitch bend change followed by 2 data bytes */
                case 0x0e:
                    break;

                /* 1100nnnn:  program change followed by 1 data byte */
                case 0x0c:
                    break;

                /* 1101nnnn:  channel pressure/after touch followed by 1 data byte */
                case 0x0d:
                    break;

                /* assorted thangs */
                case 0x0f:
                    switch (StatusByte & 0x0f)
                    {
                    default:
                        break;

                    /* 11110000:  initial or solitary SYSEX message.  followed by a */
                    /*   variable length field.  solitary message is terminated by */
                    /*   0xf7 (which is not part of the message, but is included in */
                    /*   length).  continuing message does not end with 0xf7. */
                    /*   NOTE:  SYSEX also cancels the running status. */
                    /* 11110111:  continuing SYSEX message.  same format as initial. */
                    case 0x00:
                    case 0x07:
                    {
                        StringBuilder sb = new StringBuilder();
                        if ((StatusByte & 0x0f) == 0x00)
                        {
                            sb.AppendLine("System Exclusive $F0");
                        }
                        else
                        {
                            sb.AppendLine("System Exclusive $F7");
                        }
                        int c = GetRawMIDIEventMessageLength(RawEvent);
                        for (int j = 0; j < c; j += 1)
                        {
                            byte b = GetRawMIDIEventMessageByte(RawEvent, j);
                            sb.Append('$');
                            sb.Append(HexBuf[(b >> 4) & 0x0f]);
                            sb.Append(HexBuf[b & 0x0f]);
                            if (((j + 1) % SYSEXBYTESPERLINE) == 0)
                            {
                                sb.AppendLine();
                            }
                            else
                            {
                                sb.Append(' ');
                            }
                        }
                        IntEventRec IntervalEvent = NewIntervalCommentEvent(GetRawMIDIEventTime(RawEvent), sb.ToString());
                        IntervalTrackInsertEventSorted(IntervalTrack, IntervalEvent);
                    }
                    break;

                    /* 11110010:  song position pointer, followed by 2 data bytes */
                    case 0x02:
                    {
                        StringBuilder String;
                        string        Buffer;
                        IntEventRec   IntervalEvent;

                        String = new StringBuilder();
                        String.Append("Song Position Pointer" + Environment.NewLine);
                        if (GetRawMIDIEventMessageLength(RawEvent) >= 2)
                        {
                            String.Append((int)((GetRawMIDIEventMessageByte(RawEvent, 0) & 0x7f)
                                                | ((GetRawMIDIEventMessageByte(RawEvent, 1) & 0x7f) << 7)));
                        }
                        else
                        {
                            String.Append((int)0);
                        }
                        Buffer        = String.ToString();
                        IntervalEvent = NewIntervalCommentEvent(GetRawMIDIEventTime(RawEvent), Buffer);
                        IntervalTrackInsertEventSorted(IntervalTrack, IntervalEvent);
                    }
                    break;

                    /* 11110011:  song select, followed by 2 data bytes */
                    case 0x03:
                    {
                        StringBuilder String;
                        string        Buffer;
                        IntEventRec   IntervalEvent;

                        String = new StringBuilder();
                        String.Append("Song Select" + Environment.NewLine);
                        if (GetRawMIDIEventMessageLength(RawEvent) >= 2)
                        {
                            String.Append((int)((GetRawMIDIEventMessageByte(RawEvent, 0) & 0x7f)
                                                | ((GetRawMIDIEventMessageByte(RawEvent, 1) & 0x7f) << 7)));
                        }
                        else
                        {
                            String.Append((int)0);
                        }
                        Buffer        = String.ToString();
                        IntervalEvent = NewIntervalCommentEvent(GetRawMIDIEventTime(RawEvent), Buffer);
                        IntervalTrackInsertEventSorted(IntervalTrack, IntervalEvent);
                    }
                    break;

                    /* 11110110:  tune request, no data */
                    case 0x06:
                    {
                        string      String;
                        IntEventRec IntervalEvent;

                        String        = "Tune Request";
                        IntervalEvent = NewIntervalCommentEvent(GetRawMIDIEventTime(RawEvent), String);
                        IntervalTrackInsertEventSorted(IntervalTrack, IntervalEvent);
                    }
                    break;

                    /* 11111111:  meta event.  followed by type byte (0..127) and */
                    /*   then variable length specifier, then data bytes. */
                    case 0x0f:
                        /* check out the auxilliary type */
                        TypeByte = GetRawMIDIEventTypeByte(RawEvent);
                        switch (TypeByte)
                        {
                        default:
                            break;

                        /* (FF) 01 <len> <text>:  text event */
                        /* (FF) 02 <len> <text>:  copyright */
                        /* (FF) 03 <len> <text>:  sequence/track name */
                        /* (FF) 04 <len> <text>:  instrument name */
                        /* (FF) 05 <len> <text>:  lyric */
                        /* (FF) 06 <len> <text>:  marker */
                        /* (FF) 07 <len> <text>:  cue point */
                        case 0x01:
                        case 0x02:
                        case 0x03:
                        case 0x04:
                        case 0x05:
                        case 0x06:
                        case 0x07:
                        {
                            string      String;
                            char[]      Text;
                            IntEventRec IntervalEvent;
                            string      Combined;
                            int         Length;
                            int         Scan2;

                            switch (GetRawMIDIEventTypeByte(RawEvent))
                            {
                            default:
                                Debug.Assert(false);
                                throw new InvalidOperationException();

                            /* (FF) 01 <len> <text>:  text event */
                            /* (FF) 02 <len> <text>:  copyright */
                            /* (FF) 03 <len> <text>:  sequence/track name */
                            /* (FF) 04 <len> <text>:  instrument name */
                            /* (FF) 05 <len> <text>:  lyric */
                            /* (FF) 06 <len> <text>:  marker */
                            /* (FF) 07 <len> <text>:  cue point */
                            case 0x01:
                                String = "Comment" + Environment.NewLine;
                                break;

                            case 0x02:
                                String = "Copright" + Environment.NewLine;
                                break;

                            case 0x03:
                                String = "Track Name" + Environment.NewLine;
                                break;

                            case 0x04:
                                String = "Instrument Name" + Environment.NewLine;
                                break;

                            case 0x05:
                                String = "Lyric" + Environment.NewLine;
                                break;

                            case 0x06:
                                String = "Marker" + Environment.NewLine;
                                break;

                            case 0x07:
                                String = "Cue Point" + Environment.NewLine;
                                break;
                            }
                            Length = GetRawMIDIEventMessageLength(RawEvent);
                            if (Length > 0)
                            {
                                /* don't deal with the first character since it */
                                /* isn't part of the text */
                                Length -= 1;
                            }
                            Text = new char[Length + Environment.NewLine.Length];
                            for (Scan2 = 0; Scan2 < Length; Scan2 += 1)
                            {
                                Text[Scan2] = (char)GetRawMIDIEventMessageByte(RawEvent, Scan2 + 1 /*skip first character*/);
                            }
                            Text[Length]     = Environment.NewLine[0];
                            Text[Length + 1] = Environment.NewLine[1];
                            Combined         = String.Concat(String, new String(Text));
                            IntervalEvent    = NewIntervalCommentEvent(GetRawMIDIEventTime(RawEvent), Combined);
                            IntervalTrackInsertEventSorted(IntervalTrack, IntervalEvent);
                        }
                        break;

                            /* (FF) 00 <02> ss ss:  sequence number */
                            /* (FF) 2F <00>:  end of track */
                            /* (FF) 51 <03> tt tt tt:  set tempo (microsec/quarter note) */
                            /* (FF) 54 <05> hr mn se fr ff:  SMTPE offset */
                            /* (FF) 58 <04> nn dd cc bb: time signature */
                            /*    nn/dd is numerator/denominator.  dd is a negative power */
                            /*    of two (2=quarter note, 3=eighth note). */
                            /*    cc = midi clocks per metronome click. */
                            /*    bb = number of 32nd notes per quarter note (24 clocks) */
                            /* (FF) 59 <02> sf mi:  key signature */
                            /*    sf: -7..-1 flats, 0 = normal, 1..7 = sharps */
                            /*    mi = 0 or major, 1 for minor */
                            /* (FF) 7F <len> <data>:  sequencer meta event */
                        }
                        break;
                    }
                    break;
                }
            }
        }
Exemple #4
0
 /* append a new track to the score object */
 public static void RawMIDIScoreAppendTrack(
     RawMIDIScoreRec RawScore,
     RawMIDITrackRec Track)
 {
     RawScore.TrackList.Add(Track);
 }
 /* get an indexed event from the track */
 public static RawMIDIEventRec GetRawMIDITrackIndexedEvent(
     RawMIDITrackRec RawTrack,
     int Index)
 {
     return(RawTrack.EventList[Index]);
 }
 /* get the number of events in the track */
 public static int GetRawMIDITrackLength(RawMIDITrackRec RawTrack)
 {
     return(RawTrack.EventList.Count);
 }
 /* append a new MIDI event to the track */
 public static void RawMIDITrackAppendEvent(
     RawMIDITrackRec RawTrack,
     RawMIDIEventRec Event)
 {
     RawTrack.EventList.Add(Event);
 }