public bool JumpToTick(uint tick, bool fireEvents = false, bool stopNotes = true, bool dontSendNoteOn = false)
{
if (ActiveTrack >= NumTracks)
return false;
Debug.Assert(!_jumpingToTick); // This function is not re-entrant
_jumpingToTick = true;
Tracker currentPos = new Tracker(Position);
var currentEvent = new EventInfo(_nextEvent);
ResetTracking();
Position.PlayPos = Tracks[ActiveTrack].Position;
ParseNextEvent(_nextEvent);
if (tick > 0)
{
while (true)
{
EventInfo info = _nextEvent;
if (Position.LastEventTick + info.Delta >= tick)
{
Position.PlayTime += (int)(tick - Position.LastEventTick) * _psecPerTick;
Position.PlayTick = (int)tick;
break;
}
Position.LastEventTick += info.Delta;
Position.LastEventTime += (int)info.Delta * _psecPerTick;
Position.PlayTick = (int)Position.LastEventTick;
Position.PlayTime = Position.LastEventTime;
// Some special processing for the fast-forward case
if (info.Command == 0x9 && dontSendNoteOn)
{
// Don't send note on; doing so creates a "warble" with
// some instruments on the MT-32. Refer to patch #3117577
}
else if (info.Event == 0xFF && info.MetaType == 0x2F)
{
// End of track
// This means that we failed to find the right tick.
Position = currentPos;
_nextEvent = currentEvent;
_jumpingToTick = false;
return false;
}
else
{
ProcessEvent(info, fireEvents);
}
ParseNextEvent(_nextEvent);
}
}
if (stopNotes)
{
if (_smartJump || currentPos.PlayPos == 0)
{
AllNotesOff();
}
else
{
var targetEvent = new EventInfo(_nextEvent);
var targetPosition = new Tracker(Position);
Position = currentPos;
_nextEvent = currentEvent;
HangAllActiveNotes();
_nextEvent = targetEvent;
Position = targetPosition;
}
}
AbortParse = true;
_jumpingToTick = false;
return true;
}