diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/midiparser.cpp | 138 | ||||
-rw-r--r-- | audio/midiparser.h | 6 |
2 files changed, 74 insertions, 70 deletions
diff --git a/audio/midiparser.cpp b/audio/midiparser.cpp index 9c144c2479..2454575413 100644 --- a/audio/midiparser.cpp +++ b/audio/midiparser.cpp @@ -44,7 +44,8 @@ _centerPitchWheelOnUnload(false), _sendSustainOffOnNotesOff(false), _numTracks(0), _activeTrack(255), -_abortParse(0) { +_abortParse(false), +_jumpingToTick(false) { memset(_activeNotes, 0, sizeof(_activeNotes)); memset(_tracks, 0, sizeof(_tracks)); _nextEvent.start = NULL; @@ -204,49 +205,22 @@ void MidiParser::onTimer() { return; } - if (info.event == 0xF0) { - // SysEx event - // Check for trailing 0xF7 -- if present, remove it. - if (info.ext.data[info.length-1] == 0xF7) - _driver->sysEx(info.ext.data, (uint16)info.length-1); + if (info.command() == 0x8) { + activeNote(info.channel(), info.basic.param1, false); + } else if (info.command() == 0x9) { + if (info.length > 0) + hangingNote(info.channel(), info.basic.param1, info.length * _psecPerTick - (endTime - eventTime)); else - _driver->sysEx(info.ext.data, (uint16)info.length); - } else if (info.event == 0xFF) { - // META event - if (info.ext.type == 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(); - _driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length); - } - return; - } else if (info.ext.type == 0x51) { - if (info.length >= 3) { - setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]); - } - } - _driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length); - } else { - if (info.command() == 0x8) { - activeNote(info.channel(), info.basic.param1, false); - } else if (info.command() == 0x9) { - if (info.length > 0) - hangingNote(info.channel(), info.basic.param1, info.length * _psecPerTick - (endTime - eventTime)); - else - activeNote(info.channel(), info.basic.param1, true); - } - sendToDriver(info.event, info.basic.param1, info.basic.param2); + activeNote(info.channel(), info.basic.param1, true); } + processEvent(info); - if (!_abortParse) { - _position._lastEventTime = eventTime; - parseNextEvent(_nextEvent); - } + if (_abortParse) + break; + + _position._lastEventTime = eventTime; + parseNextEvent(_nextEvent); } if (!_abortParse) { @@ -255,6 +229,45 @@ void MidiParser::onTimer() { } } +void MidiParser::processEvent(const EventInfo &info, bool fireEvents) { + if (info.event == 0xF0) { + // SysEx event + // Check for trailing 0xF7 -- if present, remove it. + if (fireEvents) { + if (info.ext.data[info.length-1] == 0xF7) + _driver->sysEx(info.ext.data, (uint16)info.length-1); + else + _driver->sysEx(info.ext.data, (uint16)info.length); + } + } else if (info.event == 0xFF) { + // META event + if (info.ext.type == 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) + _driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length); + } + _abortParse = true; + return; + } else if (info.ext.type == 0x51) { + if (info.length >= 3) { + setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]); + } + } + if (fireEvents) + _driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length); + } else { + if (fireEvents) + sendToDriver(info.event, info.basic.param1, info.basic.param2); + } +} + + void MidiParser::allNotesOff() { if (!_driver) return; @@ -370,6 +383,9 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool d if (_activeTrack >= _numTracks) return false; + assert(!_jumpingToTick); // This function is not re-entrant + _jumpingToTick = true; + Tracker currentPos(_position); EventInfo currentEvent(_nextEvent); @@ -390,34 +406,19 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool d _position._playTick = _position._lastEventTick; _position._playTime = _position._lastEventTime; - if (info.event == 0xFF) { - if (info.ext.type == 0x2F) { // End of track - _position = currentPos; - _nextEvent = currentEvent; - return false; - } else { - if (info.ext.type == 0x51 && info.length >= 3) // Tempo - setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]); - if (fireEvents) - _driver->metaEvent(info.ext.type, info.ext.data, (uint16) info.length); - } - } else if (fireEvents) { - if (info.event == 0xF0) { - if (info.ext.data[info.length-1] == 0xF7) - _driver->sysEx(info.ext.data, (uint16)info.length-1); - else - _driver->sysEx(info.ext.data, (uint16)info.length); - } else { - // The note on sending code is used by the SCUMM engine. Other engine using this code - // (such as SCI) have issues with this, as all the notes sent can be heard when a song - // is fast-forwarded. Thus, if the engine requests it, don't send note on events. - 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 { - sendToDriver(info.event, info.basic.param1, info.basic.param2); - } - } + // 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.ext.type == 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); @@ -441,6 +442,7 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool d } _abortParse = true; + _jumpingToTick = false; return true; } diff --git a/audio/midiparser.h b/audio/midiparser.h index bb9749b97f..05d0cbe1db 100644 --- a/audio/midiparser.h +++ b/audio/midiparser.h @@ -105,8 +105,8 @@ struct EventInfo { ///< will occur, and the MidiParser will have to generate one itself. ///< For all other events, this value should always be zero. - byte channel() { return event & 0x0F; } ///< Separates the MIDI channel from the event. - byte command() { return event >> 4; } ///< Separates the command code from the event. + byte channel() const { return event & 0x0F; } ///< Separates the MIDI channel from the event. + byte command() const { return event >> 4; } ///< Separates the command code from the event. }; /** @@ -287,12 +287,14 @@ protected: ///< so each event is parsed only once; this permits ///< simulated events in certain formats. bool _abortParse; ///< If a jump or other operation interrupts parsing, flag to abort. + bool _jumpingToTick; ///< True if currently inside jumpToTick protected: static uint32 readVLQ(byte * &data); virtual void resetTracking(); virtual void allNotesOff(); virtual void parseNextEvent(EventInfo &info) = 0; + virtual void processEvent(const EventInfo &info, bool fireEvents = true); void activeNote(byte channel, byte note, bool active); void hangingNote(byte channel, byte note, uint32 ticksLeft, bool recycle = true); |