//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); }
//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); }
//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); }