Example #1
0
//- loading -------------------------------------------------------------------

        //read in a midi seqence from a standard midi file
        public static Sequence readMidiFile(String filename)
        {
            MidiInStream stream = new MidiInStream(filename);

            //read midi file header
            String sig        = stream.getString(4);
            uint   hdrsize    = stream.getFour();
            int    fileFormat = stream.getTwo();
            int    trackCount = stream.getTwo();
            int    division   = stream.getTwo();

            if (!sig.Equals("MThd") || hdrsize != 6)
            {
                throw new MidiFileException(filename + " is not a valid MIDI file ", 0);
            }

            Sequence seq = new Sequence(division);

            loadTrackZeroData(stream, seq);

            //read midi track data
            for (int trackNum = 1; trackNum < trackCount; trackNum++)
            {
                curTrackNum = trackNum;
                loadTrackData(stream, seq, trackNum);
            }

            finalizeTracks(seq);
            return(seq);
        }
Example #2
0
        //read data for a single event in a track's data, convert the event's delta time to an absolute track time
        private static Event loadEventData(MidiInStream stream)
        {
            Event evt = null;

            int status = stream.getOne();

            if (status < 0x80)                              //running status
            {
                stream.pushBack(1);
                status = runningStatus;
            }
            if (status >= 0x80 && status < 0xff)             //message event
            {
                Message msg = loadMessageData(stream, status);
                runningStatus = status;
                evt           = new MessageEvent(msg);
            }
            else if (status == 0xff)                        //meta event
            {
                evt = loadMetaEventData(stream);            //this may return null for unrecognized events
            }
            else
            {
                throw new MidiFileException(stream.filename + " has an invalid event at", stream.getDataPos() - 8);
            }
            return(evt);
        }
Example #3
0
        //read data from a single track chunk
        private static void loadTrackData(MidiInStream stream, Sequence seq, int trackNum)
        {
            //read track header
            String trackSig        = stream.getString(4);
            uint   trackDataLength = stream.getFour();

            if (!trackSig.Equals("MTrk"))
            {
                throw new MidiFileException(stream.filename + " has an invalid track at ", stream.getDataPos() - 8);
            }

            Track track = seq.addTrack();                           //get new track from sequence

            track.setName("Track " + trackNum.ToString());

            int currentTime = 0;                //event time in ticks

            runningStatus = 0;
            sysexCont     = false;
            prevSysEx     = null;
            Event evt = null;

            int startpos = stream.getDataPos();

            while ((stream.getDataPos() - startpos) < trackDataLength)
            {
                currentTime += (int)stream.getVariableLengthVal();      //add delta time to current num of ticks
                evt          = loadEventData(stream);
                if ((evt != null) && !(evt is EndofTrackEvent ||
                                       evt is MarkerEvent || evt is CuePointEvent || //these are ignored in tracks other than track 0
                                       evt is TempoEvent || evt is SMPTEOffsetEvent ||
                                       evt is TimeSignatureEvent || evt is KeySignatureEvent))
                {
                    track.addEvent(evt, currentTime);
                }
            }

            //last event in track must be an "end of track" event
            if ((evt != null) && !(evt is EndofTrackEvent))
            {
                throw new MidiFileException(stream.filename + ": track " + curTrackNum.ToString() +
                                            "missing end of track event at ", stream.getDataPos() - 8);
            }
        }
Example #4
0
        //build the tempo, meter and marker maps from tempo message from track 0
        private static void loadTrackZeroData(MidiInStream stream, Sequence seq)
        {
            //read track header
            String trackSig        = stream.getString(4);
            uint   trackDataLength = stream.getFour();

            if (!trackSig.Equals("MTrk"))
            {
                throw new MidiFileException(stream.filename + " has an invalid track 0 at ", stream.getDataPos() - 8);
            }

            int currentTime = 0;        //event time in ticks

            runningStatus = 0;
            sysexCont     = false;
            prevSysEx     = null;
            Event evt;

            Meter prevMeter = null;

            int startpos = stream.getDataPos();

            while ((stream.getDataPos() - startpos) < trackDataLength)
            {
                currentTime += (int)stream.getVariableLengthVal();      //add delta time to current num of ticks
                evt          = loadEventData(stream);

                if (evt is TempoEvent)
                {
                    Tempo tempo = new Tempo(currentTime, ((TempoEvent)evt).tempo);
                    seq.tempoMap.addTempo(tempo);
                }
                else if (evt is SMPTEOffsetEvent)       //not handling smpte timing yet
                {
                }
                else if (evt is TimeSignatureEvent)
                {
                    int   keysig = (prevMeter != null) ? prevMeter.keysig : 0;
                    Meter meter  = new Meter(currentTime, ((TimeSignatureEvent)evt).numer, ((TimeSignatureEvent)evt).denom, keysig);
                    seq.meterMap.addMeter(meter);
                    prevMeter = meter;
                }
                else if (evt is KeySignatureEvent)
                {
                    int numer = 4;
                    int denom = 4;
                    if (prevMeter != null)
                    {
                        numer = prevMeter.numer;
                        denom = prevMeter.denom;
                    }
                    Meter meter = new Meter(currentTime, numer, denom, ((KeySignatureEvent)evt).keySig);
                    seq.meterMap.addMeter(meter);
                    prevMeter = meter;
                }
                else if (evt is MarkerEvent)
                {
                }
                else if (evt is CuePointEvent)
                {
                }
            }
        }
Example #5
0
        //read data for known meta events & skip any we don't recognize
        private static MetaEvent loadMetaEventData(MidiInStream stream)
        {
            MetaEvent meta     = null;
            int       metatype = stream.getOne();
            int       metalen  = (int)stream.getVariableLengthVal();

            switch (metatype)
            {
            case 0x00:
                if (metalen == 0)
                {
                    meta = new SequenceNumberEvent(curTrackNum);
                }
                if (metalen >= 2)
                {
                    int val = stream.getTwo();
                    metalen -= 2;
                    meta     = new SequenceNumberEvent(val);
                }
                break;

            //text events
            case 0x01:
                String txt = stream.getString(metalen);
                metalen = 0;
                meta    = new TextEvent(txt);
                break;

            case 0x02:
                String copyright = stream.getString(metalen);
                metalen = 0;
                meta    = new CopyrightEvent(copyright);
                break;

            case 0x03:
                String trackname = stream.getString(metalen);
                metalen = 0;
                meta    = new TrackNameEvent(trackname);
                break;

            case 0x04:
                String instrument = stream.getString(metalen);
                metalen = 0;
                meta    = new InstrumentEvent(instrument);
                break;

            case 0x05:
                String lyric = stream.getString(metalen);
                metalen = 0;
                meta    = new LyricEvent(lyric);
                break;

            case 0x06:
                String marker = stream.getString(metalen);
                metalen = 0;
                meta    = new MarkerEvent(marker);
                break;

            case 0x07:
                String cue = stream.getString(metalen);
                metalen = 0;
                meta    = new CuePointEvent(cue);
                break;

            case 0x08:
                String patchname = stream.getString(metalen);
                metalen = 0;
                meta    = new PatchNameEvent(patchname);
                break;

            case 0x09:
                String devname = stream.getString(metalen);
                metalen = 0;
                meta    = new DeviceNameEvent(devname);
                break;

            //obsolete events
            case 0x20:
                int chanNum = stream.getOne();
                metalen -= 1;
                meta     = new MidiChannelEvent(chanNum);
                break;

            case 0x21:
                int portNum = stream.getOne();
                metalen -= 1;
                meta     = new MidiPortEvent(portNum);
                break;

            //end of track event
            case 0x2f:
                meta = new EndofTrackEvent();
                break;

            //timing events
            case 0x51:
                int t1    = stream.getTwo();
                int t2    = stream.getOne();
                int tempo = (t1 * 256) + t2;
                metalen -= 3;
                meta     = new TempoEvent(tempo);
                break;

            case 0x54:
                int hr = stream.getOne();
                int rr = (hr / 32) % 4;
                int hh = hr % 32;
                int mn = stream.getOne();
                int se = stream.getOne();
                int fr = stream.getOne();
                int ff = stream.getOne();
                metalen -= 5;
                meta     = new SMPTEOffsetEvent(rr, hh, mn, se, fr, ff);
                break;

            case 0x58:
                int nn = stream.getOne();
                int b1 = stream.getOne();
                int dd = (int)Math.Pow(2.0, b1);
                int cc = stream.getOne();
                int bb = stream.getOne();
                metalen -= 4;
                meta     = new TimeSignatureEvent(nn, dd, cc, bb);
                break;

            case 0x59:
                int sf = stream.getOne();
                int mi = stream.getOne();
                metalen -= 2;
                meta     = new KeySignatureEvent(sf, mi);
                break;

            //other people's events
            case 0x7f:
                List <byte> propdata = stream.getRange(metalen);
                metalen = 0;
                meta    = new ProprietaryEvent(propdata);
                break;

            //skip any other events
            default:
                break;
            }
            stream.skipBytes(metalen);      //skip unknown events & any extra bytes at the end of known events
            runningStatus = 0;              //meta events cancel running status

            return(meta);
        }
Example #6
0
        //read data for a midi message (80 - ff), handle sysex continuation and escape sequences
        private static Message loadMessageData(MidiInStream stream, int status)
        {
            Message msg = null;

            if (status < 0xF0)          //midi channel message
            {
                int msgtype = status / 16;
                int channel = status % 16;

                int b1 = stream.getOne();
                int b2 = 0;
                if ((msgtype != 0xC) && (msgtype != 0xD))
                {
                    b2 = stream.getOne();
                }

                msg = Message.getChannelMessage(msgtype, channel, b1, b2);
            }
            else if (status == 0xF0)            //sysex message
            {
                int         len       = stream.getOne();
                List <byte> sysExData = stream.getRange(len);
                sysexCont     = (sysExData[sysExData.Count - 1] != 0xf7);   //is the last byte of sysex data a F7?
                msg           = new SysExMessage(sysExData);
                prevSysEx     = (SysExMessage)msg;
                runningStatus = 0;                      //sysex msg cancel running status
            }
            else if (status == 0xF7)
            {
                if (sysexCont)                  //sysex continuation - append this data to prev sysex message
                {
                    int         len      = stream.getOne();
                    List <byte> contData = stream.getRange(len);
                    sysexCont = (contData[contData.Count - 1] != 0xf7);       //is the last byte of sysex data a F7?
                    prevSysEx.sysExData.AddRange(contData);
                }
                else
                {                                   //escape sequence
                    int         len     = stream.getOne();
                    List <byte> escData = stream.getRange(len);
                    msg = new EscapeMessage(escData);
                }
                runningStatus = 0;
            }
            else
            {                                   //system common msgs shouldn't occur here, but if they do, we need to skip them
                int b1      = 0;
                int b2      = 0;
                int datalen = SystemMessage.SysMsgLen[status - 0xF0] - 1;
                if (datalen > 0)
                {
                    b1 = stream.getOne();
                }
                if (datalen > 1)
                {
                    b2 = stream.getOne();
                    b1 = ((b1 % 128) * 128) + (b2 % 128);
                }
                msg           = new SystemMessage(status, b1);
                runningStatus = 0;
            }

            return(msg);
        }