示例#1
0
 /* set MIDI metered timing */
 public static void RawMIDIScoreSetMeteredTime(
     RawMIDIScoreRec RawScore,
     int PartsPerQuarterNote)
 {
     RawScore.TimingMode          = MIDITimingType.eMIDIMeteredTime;
     RawScore.PartsPerQuarterNote = PartsPerQuarterNote;
 }
示例#2
0
 /* set the MIDI file type */
 public static void RawMIDIScoreSetFormatType(
     RawMIDIScoreRec RawScore,
     MIDIFileFormatType Format)
 {
     Debug.Assert((Format == MIDIFileFormatType.eMIDIFormat0SingleTrack) ||
                  (Format == MIDIFileFormatType.eMIDIFormat1ParallelTracks) ||
                  (Format == MIDIFileFormatType.eMIDIFormat2SequentialTracks));
     RawScore.FileFormat = Format;
 }
示例#3
0
 /* set MIDI real time */
 public static void RawMIDIScoreSetRealTime(
     RawMIDIScoreRec RawScore,
     int FramesPerSecond,
     int TicksPerFrame)
 {
     RawScore.TimingMode      = MIDITimingType.eMIDIRealTime;
     RawScore.FramesPerSecond = FramesPerSecond;
     RawScore.TicksPerFrame   = TicksPerFrame;
 }
示例#4
0
        /* create a new MIDI score object */
        public static RawMIDIScoreRec NewRawMIDIScore()
        {
            RawMIDIScoreRec RawScore = new RawMIDIScoreRec();

            RawScore.TrackList           = new List <RawMIDITrackRec>();
            RawScore.TimingMode          = MIDITimingType.eMIDIMeteredTime;
            RawScore.PartsPerQuarterNote = 24;
            RawScore.FramesPerSecond     = 25;
            RawScore.TicksPerFrame       = 40;
            RawScore.FileFormat          = MIDIFileFormatType.eMIDIFormat1ParallelTracks;
            return(RawScore);
        }
示例#5
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();
            }
        }
示例#6
0
        /* attempt to parse a MIDI file */
        public static MIDIParseErrorType ParseMIDIFile(
            BinaryReader InputFile,
            RawMIDIScoreRec Score)
        {
            string CharBuff;
            int    HeaderChunkLength;
            short  FileFormat;
            short  TrackCount;
            ushort TimingCode;

            /* parse header */

            /* 'MThd' */
            CharBuff = InputFile.ReadFixedStringASCII(4);
            if (!String.Equals(CharBuff, "MThd"))
            {
                return(MIDIParseErrorType.eMIDIParseBadFormat);
            }

            /* 4-byte big endian header length (minus 8 for MThd & this length) */
            HeaderChunkLength = InputFile.ReadInt32BigEndian();
            if (HeaderChunkLength != 6)
            {
                return(MIDIParseErrorType.eMIDIParseBadFormat);
            }

            /* 2-byte unsigned big endian format indicator */
            /*   0 = type 0 format (single multi-channel track) */
            /*   1 = type 1 format (multiple tracks in parallel) */
            /*   2 = type 2 format (multiple tracks in sequence) */
            FileFormat = InputFile.ReadInt16BigEndian();
            switch (FileFormat)
            {
            default:
                return(MIDIParseErrorType.eMIDIParseBadFormat);

                break;

            case 0:
                RawMIDIScoreSetFormatType(Score, MIDIFileFormatType.eMIDIFormat0SingleTrack);
                break;

            case 1:
                RawMIDIScoreSetFormatType(Score, MIDIFileFormatType.eMIDIFormat1ParallelTracks);
                break;

            case 2:
                RawMIDIScoreSetFormatType(Score, MIDIFileFormatType.eMIDIFormat2SequentialTracks);
                break;
            }

            /* 2-byte unsigned big endian track count */
            TrackCount = InputFile.ReadInt16BigEndian();

            /* 2-byte timing code */
            /*   if MSB in 0..127, then value is ticks per quarter note */
            /*  else */
            /*   if MSB in 128..255, then value is real time as follows: */
            /*     negation of MSB (256 - MSB) = frames per second */
            /*     LSB = ticks per frame */
            /*   officially, MSB should be -24, -25, -29, or -30 */
            TimingCode = InputFile.ReadUInt16BigEndian();
            if ((((TimingCode >> 8) & 0xff) >= 0) && (((TimingCode >> 8) & 0xff) <= 127))
            {
                RawMIDIScoreSetMeteredTime(Score, TimingCode);
            }
            else
            {
                RawMIDIScoreSetRealTime(Score, 256 - ((TimingCode >> 8) & 0xff), TimingCode & 0xff);
            }

            /* parse tracks */

            /* loop for all tracks */
            while (TrackCount > 0)
            {
                RawMIDITrackRec Track;
                int             TrackChunkLength;
                int             TimeAccumulator;
                byte            RunningStatus = 0;
                bool            RunningStatusValid;

                /* allocate track */
                Track = NewRawMIDITrack();
                RawMIDIScoreAppendTrack(Score, Track);

                /* get chunk type -- skip unknown chunk types */
                do
                {
                    /* get header string */
                    CharBuff = InputFile.ReadFixedStringASCII(4);
                    /* 4-byte big endian header length (minus 8 for header & this) */
                    TrackChunkLength = InputFile.ReadInt32BigEndian();
                    /* skip unknown chunks */
                    if (!String.Equals(CharBuff, "MTrk"))
                    {
                        while (TrackChunkLength > 0)
                        {
                            InputFile.ReadByte();
                            TrackChunkLength -= 1;
                        }
                    }
                } while (!String.Equals(CharBuff, "MTrk"));

                /* parse track contents */

                /* while there is stuff in the track to read */
                TimeAccumulator    = 0;
                RunningStatusValid = false;
                while (TrackChunkLength > 0)
                {
                    int             DeltaTime;
                    byte            UnsignedChar;
                    RawMIDIEventRec Event;

                    /* parse the delta time */
                    DeltaTime = 0;
                    do
                    {
                        UnsignedChar      = InputFile.ReadByte();
                        TrackChunkLength -= 1;
                        DeltaTime         = (DeltaTime << 7) | (UnsignedChar & 0x7f);
                    } while ((UnsignedChar & 0x80) != 0);
                    /* find out what the absolute time is */
                    TimeAccumulator += DeltaTime;

                    /* get the next byte */
                    UnsignedChar      = InputFile.ReadByte();
                    TrackChunkLength -= 1;

                    /* is this byte a status byte? (yes if high bit set) */
                    if (0 != (0x80 & UnsignedChar))
                    {
                        /* it is a status byte */
                        RunningStatusValid = true;
                        RunningStatus      = UnsignedChar;
                        /* read another byte since we consumed this one */
                        UnsignedChar      = InputFile.ReadByte();
                        TrackChunkLength -= 1;
                    }
                    else
                    {
                        if (!RunningStatusValid)
                        {
                            /* first byte must be a status byte */
                            return(MIDIParseErrorType.eMIDIParseBadFormat);
                        }
                    }

                    /* allocate event */
                    Event = NewRawMIDIEvent(TimeAccumulator, RunningStatus);
                    RawMIDITrackAppendEvent(Track, Event);

                    /* handle event */
                    switch ((RunningStatus >> 4) & 0x0f)
                    {
                    default:
                        /* unknown status */
                        return(MIDIParseErrorType.eMIDIParseBadFormat);

                    /* 1000nnnn:  note off event for channel nnnn followed by 2 data bytes */
                    /* 1001nnnn:  note on event for channel nnnn followed by 2 data bytes */
                    /* 1010nnnn:  polyphonic key pressure/after touch followed by */
                    /*   2 data bytes */
                    /* 1011nnnn:  control change followed by 2 data bytes */
                    /* 1110nnnn:  pitch bend change followed by 2 data bytes */
                    case 0x08:
                    case 0x09:
                    case 0x0a:
                    case 0x0b:
                    case 0x0e:
                        RawMIDIEventAppendByte(Event, UnsignedChar);
                        UnsignedChar      = InputFile.ReadByte();
                        TrackChunkLength -= 1;
                        RawMIDIEventAppendByte(Event, UnsignedChar);
                        break;

                    /* 1100nnnn:  program change followed by 1 data byte */
                    /* 1101nnnn:  channel pressure/after touch followed by 1 data byte */
                    case 0x0c:
                    case 0x0d:
                        RawMIDIEventAppendByte(Event, UnsignedChar);
                        break;

                    /* assorted things */
                    case 0x0f:
                        switch (RunningStatus & 0x0f)
                        {
                        default:
                            return(MIDIParseErrorType.eMIDIParseBadFormat);

                        /* 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:
                        {
                            int SysExLength;

                            /* cancel running status */
                            RunningStatusValid = false;

                            /* read SYSEX length */
                            SysExLength = UnsignedChar & 0x7f;
                            if (0 != (UnsignedChar & 0x80))
                            {
                                do
                                {
                                    UnsignedChar      = InputFile.ReadByte();
                                    TrackChunkLength -= 1;
                                    SysExLength       = (SysExLength << 7) | (UnsignedChar & 0x7f);
                                } while ((UnsignedChar & 0x80) != 0);
                            }

                            /* read in bytes for SYSEX message */
                            while (SysExLength > 0)
                            {
                                UnsignedChar      = InputFile.ReadByte();
                                TrackChunkLength -= 1;
                                RawMIDIEventAppendByte(Event, UnsignedChar);
                                SysExLength -= 1;
                            }
                        }
                        break;

                        /* system common messages */
                        /* 11110010:  song position pointer, followed by 2 data bytes */
                        /* 11110011:  song select, followed by 2 data bytes */
                        case 0x02:
                        case 0x03:
                            RawMIDIEventAppendByte(Event, UnsignedChar);
                            UnsignedChar      = InputFile.ReadByte();
                            TrackChunkLength -= 1;
                            RawMIDIEventAppendByte(Event, UnsignedChar);
                            break;

                        /* 11110110:  tune request, no data */
                        case 0x06:
                            break;

                        /* 11111111:  meta event.  followed by type byte (0..127) and */
                        /*   then variable length specifier, then data bytes. */
                        case 0x0f:
                        {
                            int MetaLength;

                            /* cancel running status */
                            RunningStatusValid = false;

                            /* put meta event type */
                            RawMIDIEventAppendByte(Event, UnsignedChar);
                            SetRawMIDIEventTypeByte(Event, UnsignedChar);

                            /* get length of meta event */
                            MetaLength = 0;
                            do
                            {
                                UnsignedChar      = InputFile.ReadByte();
                                TrackChunkLength -= 1;
                                MetaLength        = (MetaLength << 7) | (UnsignedChar & 0x7f);
                            } while ((UnsignedChar & 0x80) != 0);

                            /* read all meta event bytes in */
                            while (MetaLength > 0)
                            {
                                UnsignedChar      = InputFile.ReadByte();
                                TrackChunkLength -= 1;
                                RawMIDIEventAppendByte(Event, UnsignedChar);
                                MetaLength -= 1;
                            }
                        }
                        break;
                        }
                        break;
                    }
                }

                /* end of track parsing */

                /* decrement count */
                TrackCount -= 1;
            }

            /* done */
            return(MIDIParseErrorType.eMIDIParseNoError);
        }
示例#7
0
 /* get an indexed track out of the score */
 public static RawMIDITrackRec GetRawMIDIScoreIndexedTrack(
     RawMIDIScoreRec RawScore,
     int Index)
 {
     return(RawScore.TrackList[Index]);
 }
示例#8
0
 /* get the number of tracks in the score object */
 public static int GetRawMIDIScoreNumTracks(RawMIDIScoreRec RawScore)
 {
     return(RawScore.TrackList.Count);
 }
示例#9
0
 /* append a new track to the score object */
 public static void RawMIDIScoreAppendTrack(
     RawMIDIScoreRec RawScore,
     RawMIDITrackRec Track)
 {
     RawScore.TrackList.Add(Track);
 }
示例#10
0
 /* get the MIDI file type */
 public static MIDIFileFormatType RawMIDIScoreGetFormatType(RawMIDIScoreRec RawScore)
 {
     return(RawScore.FileFormat);
 }
示例#11
0
 /* get MIDI ticks per frame */
 public static int RawMIDIScoreGetTicksPerFrame(RawMIDIScoreRec RawScore)
 {
     Debug.Assert(RawScore.TimingMode == MIDITimingType.eMIDIRealTime);
     return(RawScore.TicksPerFrame);
 }
示例#12
0
 /* get MIDI frames per second */
 public static int RawMIDIScoreGetFramesPerSecond(RawMIDIScoreRec RawScore)
 {
     Debug.Assert(RawScore.TimingMode == MIDITimingType.eMIDIRealTime);
     return(RawScore.FramesPerSecond);
 }
示例#13
0
 /* get MIDI parts per quarter note */
 public static int RawMIDIScoreGetPartsPerQuarterNote(RawMIDIScoreRec RawScore)
 {
     Debug.Assert(RawScore.TimingMode == MIDITimingType.eMIDIMeteredTime);
     return(RawScore.PartsPerQuarterNote);
 }
示例#14
0
 /* get MIDI timing mode */
 public static MIDITimingType RawMIDIScoreGetTimingMode(RawMIDIScoreRec RawScore)
 {
     return(RawScore.TimingMode);
 }