private List<MidiEvent> ReadTrack(MidiFileReader file)
{
List<MidiEvent> result = new List<MidiEvent>(20);
int starttime = 0;
string id = file.ReadAscii(4);
if (id != "MTrk") {
throw new MidiFileException("Bad MTrk header", file.GetOffset() - 4);
}
int tracklen = file.ReadInt();
int trackend = tracklen + file.GetOffset();
int eventflag = 0;
while (file.GetOffset() < trackend) {
// If the midi file is truncated here, we can still recover.
// Just return what we've parsed so far.
int startoffset, deltatime;
byte peekevent;
try {
startoffset = file.GetOffset();
deltatime = file.ReadVarlen();
starttime += deltatime;
peekevent = file.Peek();
}
catch (MidiFileException e) {
return result;
}
MidiEvent mevent = new MidiEvent();
result.Add(mevent);
mevent.DeltaTime = deltatime;
mevent.StartTime = starttime;
if (peekevent >= EventNoteOff) {
mevent.HasEventflag = true;
eventflag = file.ReadByte();
}
// Console.WriteLine("offset {0}: event {1} {2} start {3} delta {4}",
// startoffset, eventflag, EventName(eventflag),
// starttime, mevent.DeltaTime);
if (eventflag >= EventNoteOn && eventflag < EventNoteOn + 16) {
mevent.EventFlag = EventNoteOn;
mevent.Channel = (byte)(eventflag - EventNoteOn);
mevent.Notenumber = file.ReadByte();
mevent.Velocity = file.ReadByte();
}
else if (eventflag >= EventNoteOff && eventflag < EventNoteOff + 16) {
mevent.EventFlag = EventNoteOff;
mevent.Channel = (byte)(eventflag - EventNoteOff);
mevent.Notenumber = file.ReadByte();
mevent.Velocity = file.ReadByte();
}
else if (eventflag >= EventKeyPressure &&
eventflag < EventKeyPressure + 16) {
mevent.EventFlag = EventKeyPressure;
mevent.Channel = (byte)(eventflag - EventKeyPressure);
mevent.Notenumber = file.ReadByte();
mevent.KeyPressure = file.ReadByte();
}
else if (eventflag >= EventControlChange &&
eventflag < EventControlChange + 16) {
mevent.EventFlag = EventControlChange;
mevent.Channel = (byte)(eventflag - EventControlChange);
mevent.ControlNum = file.ReadByte();
mevent.ControlValue = file.ReadByte();
}
else if (eventflag >= EventProgramChange &&
eventflag < EventProgramChange + 16) {
mevent.EventFlag = EventProgramChange;
mevent.Channel = (byte)(eventflag - EventProgramChange);
mevent.Instrument = file.ReadByte();
}
else if (eventflag >= EventChannelPressure &&
eventflag < EventChannelPressure + 16) {
mevent.EventFlag = EventChannelPressure;
mevent.Channel = (byte)(eventflag - EventChannelPressure);
mevent.ChanPressure = file.ReadByte();
}
else if (eventflag >= EventPitchBend &&
eventflag < EventPitchBend + 16) {
mevent.EventFlag = EventPitchBend;
mevent.Channel = (byte)(eventflag - EventPitchBend);
mevent.PitchBend = file.ReadShort();
}
else if (eventflag == SysexEvent1) {
mevent.EventFlag = SysexEvent1;
mevent.Metalength = file.ReadVarlen();
mevent.Value = file.ReadBytes(mevent.Metalength);
}
else if (eventflag == SysexEvent2) {
mevent.EventFlag = SysexEvent2;
mevent.Metalength = file.ReadVarlen();
mevent.Value = file.ReadBytes(mevent.Metalength);
}
else if (eventflag == MetaEvent) {
mevent.EventFlag = MetaEvent;
mevent.Metaevent = file.ReadByte();
mevent.Metalength = file.ReadVarlen();
mevent.Value = file.ReadBytes(mevent.Metalength);
if (mevent.Metaevent == MetaEventTimeSignature) {
if (mevent.Metalength < 2) {
// throw new MidiFileException(
// "Meta Event Time Signature len == " + mevent.Metalength +
// " != 4", file.GetOffset());
mevent.Numerator = (byte)0;
mevent.Denominator = (byte)4;
}
else if (mevent.Metalength >= 2 && mevent.Metalength < 4) {
mevent.Numerator = (byte)mevent.Value[0];
mevent.Denominator = (byte)System.Math.Pow(2, mevent.Value[1]);
}
else {
mevent.Numerator = (byte)mevent.Value[0];
mevent.Denominator = (byte)System.Math.Pow(2, mevent.Value[1]);
}
}
else if (mevent.Metaevent == MetaEventTempo) {
if (mevent.Metalength != 3) {
throw new MidiFileException(
"Meta Event Tempo len == " + mevent.Metalength +
" != 3", file.GetOffset());
}
mevent.Tempo = ( (mevent.Value[0] << 16) | (mevent.Value[1] << 8) | mevent.Value[2]);
}
else if (mevent.Metaevent == MetaEventEndOfTrack) {
/* break; */
}
}
else {
throw new MidiFileException("Unknown event " + mevent.EventFlag,
file.GetOffset()-1);
}
}
return result;
}