This pull request fixes Wine's MIDI synthesizer reset process to be the same as Windows'.
When playing Touhou Project games in MIDI BGM mode, the music playback becomes buggy when the BGM changes. The video below is an example of an anomaly that occurs when playing The Fantastic Tales from Tono after playing Crystallized Silver in Touhou 7. https://youtu.be/O69sndJ45Ag
Here's a correct example of The Fantastic Tales from Tono playback: https://youtu.be/XlFAQEbbNDg
Piano sound is clearly missing on Wine. This issue occurs due to an Wine's incorrect reset process for MIDI synthesizer.
When I ran FluidSynth on Windows and checked the log, I found that CC123 and CC121 were executed for each MIDI channel when switching songs. CC123 means All Notes Off, CC121 means Reset All Controllers.
-- v6: Corrected the comment. wineoss: Send All Notes Off and Reset Controllers. winecoreaudio: Send All Notes Off and Reset Controllers. winealsa: Send All Notes Off and Reset Controllers.
From: Keigo Okamoto reimu@hakurei.win
--- dlls/winealsa.drv/alsamidi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/winealsa.drv/alsamidi.c b/dlls/winealsa.drv/alsamidi.c index fbc65bd95d1..efd35e6628c 100644 --- a/dlls/winealsa.drv/alsamidi.c +++ b/dlls/winealsa.drv/alsamidi.c @@ -945,9 +945,9 @@ static UINT midi_out_reset(WORD dev_id) for (chn = 0; chn < 16; chn++) { /* turn off every note */ - midi_out_data(dev_id, (MIDI_CTL_ALL_SOUNDS_OFF << 8) | MIDI_CMD_CONTROL | chn); - /* remove sustain on all channels */ - midi_out_data(dev_id, (MIDI_CTL_SUSTAIN << 8) | MIDI_CMD_CONTROL | chn); + midi_out_data(dev_id, (MIDI_CTL_ALL_NOTES_OFF << 8) | MIDI_CMD_CONTROL | chn); + /* resets controller settings */ + midi_out_data(dev_id, (MIDI_CTL_RESET_CONTROLLERS << 8) | MIDI_CMD_CONTROL | chn); } dests[dev_id].runningStatus = 0; /* FIXME: the LongData buffers must also be returned to the app */
From: Keigo Okamoto reimu@hakurei.win
--- dlls/winecoreaudio.drv/coremidi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winecoreaudio.drv/coremidi.c b/dlls/winecoreaudio.drv/coremidi.c index 113d5d267b4..a85a54978f5 100644 --- a/dlls/winecoreaudio.drv/coremidi.c +++ b/dlls/winecoreaudio.drv/coremidi.c @@ -900,7 +900,7 @@ static UINT midi_out_reset(WORD dev_id) /* turn off every note */ MusicDeviceMIDIEvent(dests[dev_id].synth, 0xB0 | chn, 0x7B, 0, 0); /* remove sustain on channel */ - MusicDeviceMIDIEvent(dests[dev_id].synth, 0xB0 | chn, 0x40, 0, 0); + MusicDeviceMIDIEvent(dests[dev_id].synth, 0xB0 | chn, 0x79, 0, 0); } } else FIXME("MOD_MIDIPORT\n");
From: Keigo Okamoto reimu@hakurei.win
--- dlls/wineoss.drv/ossmidi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/wineoss.drv/ossmidi.c b/dlls/wineoss.drv/ossmidi.c index 99c140266b0..d4cce45fd26 100644 --- a/dlls/wineoss.drv/ossmidi.c +++ b/dlls/wineoss.drv/ossmidi.c @@ -1238,9 +1238,9 @@ static UINT midi_out_reset(WORD dev_id) for (chn = 0; chn < 16; chn++) { /* turn off every note */ - midi_out_data(dev_id, 0x7800 | MIDI_CTL_CHANGE | chn); + midi_out_data(dev_id, (0x7B << 8) | MIDI_CTL_CHANGE | chn); /* remove sustain on all channels */ - midi_out_data(dev_id, (CTL_SUSTAIN << 8) | MIDI_CTL_CHANGE | chn); + midi_out_data(dev_id, (0x79 << 8) | MIDI_CTL_CHANGE | chn); } dest->runningStatus = 0; /* FIXME: the LongData buffers must also be returned to the app */
From: Keigo Okamoto reimu@hakurei.win
--- dlls/winecoreaudio.drv/coremidi.c | 2 +- dlls/wineoss.drv/ossmidi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/winecoreaudio.drv/coremidi.c b/dlls/winecoreaudio.drv/coremidi.c index a85a54978f5..f087d69008e 100644 --- a/dlls/winecoreaudio.drv/coremidi.c +++ b/dlls/winecoreaudio.drv/coremidi.c @@ -899,7 +899,7 @@ static UINT midi_out_reset(WORD dev_id) { /* turn off every note */ MusicDeviceMIDIEvent(dests[dev_id].synth, 0xB0 | chn, 0x7B, 0, 0); - /* remove sustain on channel */ + /* resets controller settings */ MusicDeviceMIDIEvent(dests[dev_id].synth, 0xB0 | chn, 0x79, 0, 0); } } diff --git a/dlls/wineoss.drv/ossmidi.c b/dlls/wineoss.drv/ossmidi.c index d4cce45fd26..8013e20559f 100644 --- a/dlls/wineoss.drv/ossmidi.c +++ b/dlls/wineoss.drv/ossmidi.c @@ -1239,7 +1239,7 @@ static UINT midi_out_reset(WORD dev_id) { /* turn off every note */ midi_out_data(dev_id, (0x7B << 8) | MIDI_CTL_CHANGE | chn); - /* remove sustain on all channels */ + /* resets controller settings */ midi_out_data(dev_id, (0x79 << 8) | MIDI_CTL_CHANGE | chn); } dest->runningStatus = 0;
On Fri Aug 22 23:12:00 2025 +0000, Huw Davies wrote:
Could you update the 'sustain' comments in the last two commits?
Ah, I forgot. I just fixed it.
On Fri Aug 22 23:12:00 2025 +0000, Keigo Okamoto wrote:
Ah, I forgot. I just fixed it.
Could you squash that final commit into the two commits before it (as appropriate)?