Fix: Correctly reset playback between songs in win32_m driver

This commit is contained in:
Niels Martin Hansen 2019-07-04 21:51:01 +02:00
parent 27b7c5a5fd
commit a0c78c73e3
1 changed files with 60 additions and 55 deletions

View File

@ -36,7 +36,7 @@ static struct {
std::mutex lock; ///< synchronization for playback status fields std::mutex lock; ///< synchronization for playback status fields
bool playing; ///< flag indicating that playback is active bool playing; ///< flag indicating that playback is active
bool do_start; ///< flag for starting playback of next_file at next opportunity int do_start; ///< flag for starting playback of next_file at next opportunity
bool do_stop; ///< flag for stopping playback at next opportunity bool do_stop; ///< flag for stopping playback at next opportunity
byte current_volume; ///< current effective volume setting byte current_volume; ///< current effective volume setting
byte new_volume; ///< volume setting to change to byte new_volume; ///< volume setting to change to
@ -115,7 +115,6 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
std::unique_lock<std::mutex> mutex_lock(_midi.lock, std::defer_lock); std::unique_lock<std::mutex> mutex_lock(_midi.lock, std::defer_lock);
if (!mutex_lock.try_lock()) return; if (!mutex_lock.try_lock()) return;
{
/* check for stop */ /* check for stop */
if (_midi.do_stop) { if (_midi.do_stop) {
DEBUG(driver, 2, "Win32-MIDI: timer: do_stop is set"); DEBUG(driver, 2, "Win32-MIDI: timer: do_stop is set");
@ -126,33 +125,46 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
} }
/* check for start/restart/change song */ /* check for start/restart/change song */
if (_midi.do_start) { if (_midi.do_start != 0) {
DEBUG(driver, 2, "Win32-MIDI: timer: do_start is set"); /* Have a delay between playback start steps, prevents jumbled-together notes at the start of song */
if (_midi.playing) { if (timeGetTime() - _midi.playback_start_time < 50) {
return;
}
DEBUG(driver, 2, "Win32-MIDI: timer: do_start step %d", _midi.do_start);
if (_midi.do_start == 1) {
/* Send "all notes off" */
midiOutReset(_midi.midi_out); midiOutReset(_midi.midi_out);
/* Some songs change the "Pitch bend range" registered _midi.playback_start_time = timeGetTime();
* parameter. If this doesn't get reset, everything else _midi.do_start = 2;
* will start sounding wrong. */
for (int ch = 0; ch < 16; ch++) { return;
/* Running status, only need status for first message */ } else if (_midi.do_start == 2) {
/* Select RPN 00.00, set value to 02.00, and unselect again */ /* Reset the device to General MIDI defaults */
TransmitChannelMsg(MIDIST_CONTROLLER | ch, MIDICT_RPN_SELECT_LO, 0x00); TransmitStandardSysex(MidiSysexMessage::ResetGM);
TransmitChannelMsg(MIDICT_RPN_SELECT_HI, 0x00); _midi.playback_start_time = timeGetTime();
TransmitChannelMsg(MIDICT_DATAENTRY, 0x02); _midi.do_start = 3;
TransmitChannelMsg(MIDICT_DATAENTRY_LO, 0x00);
TransmitChannelMsg(MIDICT_RPN_SELECT_LO, 0x7F); return;
TransmitChannelMsg(MIDICT_RPN_SELECT_HI, 0x7F); } else if (_midi.do_start == 3) {
} /* Set up device-specific effects */
} TransmitStandardSysex(MidiSysexMessage::RolandSetReverb);
_midi.playback_start_time = timeGetTime();
_midi.do_start = 4;
return;
} else if (_midi.do_start == 4) {
/* Load the new file */
_midi.current_file.MoveFrom(_midi.next_file); _midi.current_file.MoveFrom(_midi.next_file);
std::swap(_midi.next_segment, _midi.current_segment); std::swap(_midi.next_segment, _midi.current_segment);
_midi.current_segment.start_block = 0; _midi.current_segment.start_block = 0;
_midi.playback_start_time = timeGetTime(); _midi.playback_start_time = timeGetTime();
_midi.playing = true; _midi.playing = true;
_midi.do_start = false; _midi.do_start = 0;
_midi.current_block = 0; _midi.current_block = 0;
MemSetT<byte>(_midi.channel_volumes, 127, lengthof(_midi.channel_volumes)); MemSetT<byte>(_midi.channel_volumes, 127, lengthof(_midi.channel_volumes));
}
} else if (!_midi.playing) { } else if (!_midi.playing) {
/* not playing, stop the timer */ /* not playing, stop the timer */
DEBUG(driver, 2, "Win32-MIDI: timer: not playing, stopping timer"); DEBUG(driver, 2, "Win32-MIDI: timer: not playing, stopping timer");
@ -169,14 +181,13 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
_midi.current_volume = _midi.new_volume; _midi.current_volume = _midi.new_volume;
volume_throttle = 20 / _midi.time_period; volume_throttle = 20 / _midi.time_period;
for (int ch = 0; ch < 16; ch++) { for (int ch = 0; ch < 16; ch++) {
int vol = ScaleVolume(_midi.channel_volumes[ch], _midi.current_volume); byte vol = ScaleVolume(_midi.channel_volumes[ch], _midi.current_volume);
TransmitChannelMsg(MIDIST_CONTROLLER | ch, MIDICT_CHANVOLUME, vol); TransmitChannelMsg(MIDIST_CONTROLLER | ch, MIDICT_CHANVOLUME, vol);
} }
} else { } else {
volume_throttle--; volume_throttle--;
} }
} }
}
/* skip beginning of file? */ /* skip beginning of file? */
if (_midi.current_segment.start > 0 && _midi.current_block == 0 && _midi.current_segment.start_block == 0) { if (_midi.current_segment.start > 0 && _midi.current_block == 0 && _midi.current_segment.start_block == 0) {
@ -326,7 +337,7 @@ void MusicDriver_Win32::PlaySong(const MusicSongInfo &song)
DEBUG(driver, 2, "Win32-MIDI: PlaySong: setting flag"); DEBUG(driver, 2, "Win32-MIDI: PlaySong: setting flag");
_midi.do_stop = _midi.playing; _midi.do_stop = _midi.playing;
_midi.do_start = true; _midi.do_start = 1;
if (_midi.timer_id == 0) { if (_midi.timer_id == 0) {
DEBUG(driver, 2, "Win32-MIDI: PlaySong: starting timer"); DEBUG(driver, 2, "Win32-MIDI: PlaySong: starting timer");
@ -344,7 +355,7 @@ void MusicDriver_Win32::StopSong()
bool MusicDriver_Win32::IsSongPlaying() bool MusicDriver_Win32::IsSongPlaying()
{ {
return _midi.playing || _midi.do_start; return _midi.playing || (_midi.do_start != 0);
} }
void MusicDriver_Win32::SetVolume(byte vol) void MusicDriver_Win32::SetVolume(byte vol)
@ -375,12 +386,6 @@ const char *MusicDriver_Win32::Start(const char * const *parm)
midiOutReset(_midi.midi_out); midiOutReset(_midi.midi_out);
/* Standard "Enable General MIDI" message */
TransmitStandardSysex(MidiSysexMessage::ResetGM);
/* Roland-specific reverb room control, used by the original game */
TransmitStandardSysex(MidiSysexMessage::RolandSetReverb);
/* prepare multimedia timer */ /* prepare multimedia timer */
TIMECAPS timecaps; TIMECAPS timecaps;
if (timeGetDevCaps(&timecaps, sizeof(timecaps)) == MMSYSERR_NOERROR) { if (timeGetDevCaps(&timecaps, sizeof(timecaps)) == MMSYSERR_NOERROR) {