MIDI: Prevent duplicate MIDI messages

The MIDI parser would send All Notes Off events on all MIDI channels as a
safety measure when stopping playback in various situations without first
checking if a track was actually playing. Depending on the specifics of the
code driving the MIDI parser, this could generate many duplicate All Notes Off,
Sustain off and/or Pitch Bend center messages. This is a problem for slow MIDI
hardware like the MT-32, which needs some time to process all these messages.
As a result, the timing at the beginning of the next track could be wrong.

I've introduced checks in stopPlaying, setTrack, unloadMusic and the MIDI
parser destructor so that allNotesOff is called once when a track is playing,
and not a second time when playback has already stopped. Similarly, unloadMusic
does not execute when no music is loaded to prevent duplicate Pitch Bend
messages.
This commit is contained in:
NMIError 2020-06-27 22:16:43 +02:00 committed by Eugene Sandulenko
parent 315bbc7b5b
commit 3ad8c85af2
5 changed files with 15 additions and 7 deletions

View file

@ -359,7 +359,7 @@ bool MidiParser::setTrack(int track) {
if (_smartJump)
hangAllActiveNotes();
else
else if (isPlaying())
allNotesOff();
resetTracking();
@ -377,7 +377,8 @@ bool MidiParser::setTrack(int track) {
}
void MidiParser::stopPlaying() {
allNotesOff();
if (isPlaying())
allNotesOff();
resetTracking();
_pause = false;
}
@ -508,12 +509,14 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool d
}
void MidiParser::unloadMusic() {
resetTracking();
allNotesOff();
if (_numTracks == 0)
// No music data loaded
return;
stopPlaying();
_numTracks = 0;
_activeTrack = 255;
_abortParse = true;
_pause = false;
if (_centerPitchWheelOnUnload) {
// Center the pitch wheels in preparation for the next piece of