public void OnTimer()
{
uint endTime;
uint eventTime;
if (Position.PlayPos == 0 || MidiDriver == null)
return;
AbortParse = false;
endTime = (uint)Position.PlayTime + TimerRate;
// Scan our hanging notes for any
// that should be turned off.
if (HangingNotesCount != 0)
{
foreach (var ptr in HangingNotes)
{
if (ptr.TimeLeft != 0)
{
if (ptr.TimeLeft <= TimerRate)
{
SendToDriver(0x80 | ptr.Channel, ptr.Note, 0);
ptr.TimeLeft = 0;
--HangingNotesCount;
}
else
{
ptr.TimeLeft -= (int)TimerRate;
}
}
}
}
while (!AbortParse)
{
var info = _nextEvent;
eventTime = (uint)(Position.LastEventTime + info.Delta * _psecPerTick);
if (eventTime > endTime)
break;
// Process the next info.
Position.LastEventTick += info.Delta;
if (info.Event < 0x80)
{
// Console.Error.WriteLine("Bad command or running status {0:X2}", info.Event);
Position.PlayPos = 0;
return;
}
if (info.Command == 0x8)
{
ActiveNote(info.Channel, info.Param1, false);
}
else if (info.Command == 0x9)
{
if (info.Data.Length > 0)
HangingNote(info.Channel, info.Param1, (int)(info.Data.Length * _psecPerTick - (endTime - eventTime)));
else
ActiveNote(info.Channel, info.Param1, true);
}
// Player::metaEvent() in SCUMM will delete the parser object,
// so return immediately if that might have happened.
bool ret = ProcessEvent(info);
if (!ret)
return;
if (!AbortParse)
{
Position.LastEventTime = (int)eventTime;
ParseNextEvent(_nextEvent);
}
}
if (!AbortParse)
{
Position.PlayTime = (int)endTime;
Position.PlayTick = (int)((Position.PlayTime - Position.LastEventTime) / _psecPerTick + Position.LastEventTick);
}
}
}