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