protected MidiParser() { ActiveNotes = new ushort[128]; HangingNotes = new NoteTimer[32]; for (int i = 0; i < HangingNotes.Length; i++) { HangingNotes[i] = new NoteTimer(); } Tracks = new Track[120]; TimerRate = 0x4A0000; _ppqn = 96; tempo = 500000; _psecPerTick = 5208;// 500000 / 96 _nextEvent = new EventInfo(); _nextEvent.Start = 0; _nextEvent.Delta = 0; _nextEvent.Event = 0; Position = new Tracker(); }
protected abstract void ParseNextEvent(EventInfo info);
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; }
bool ProcessEvent(EventInfo info, bool fireEvents = true) { if (info.Event == 0xF0) { // SysEx event // Check for trailing 0xF7 -- if present, remove it. if (fireEvents) { if (info.Data[info.Data.Length - 1] == 0xF7) MidiDriver.SysEx(info.Data, (ushort)(info.Data.Length - 1)); else MidiDriver.SysEx(info.Data, (ushort)info.Data.Length); } } else if (info.Event == 0xFF) { // META event if (info.MetaType == 0x2F) { // End of Track must be processed by us, // as well as sending it to the output device. if (_autoLoop) { JumpToTick(0); ParseNextEvent(_nextEvent); } else { StopPlaying(); if (fireEvents) MidiDriver.MetaEvent((byte)info.MetaType, info.Data, (ushort)info.Data.Length); } return false; } else if (info.MetaType == 0x51) { if (info.Data.Length >= 3) { Tempo = (info.Data[0] << 16 | info.Data[1] << 8 | info.Data[2]); } } if (fireEvents) MidiDriver.MetaEvent((byte)info.MetaType, info.Data, (ushort)info.Data.Length); } else { if (fireEvents) SendToDriver(info.Event, info.Param1, info.Param2); } return true; }
public EventInfo(EventInfo info) { Start = info.Start; Delta = info.Delta; Event = info.Event; Param1 = info.Param1; Param2 = info.Param2; MetaType = info.MetaType; Data = info.Data; }