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.
-- v5: wineoss: 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 */
On Fri Aug 22 10:27:34 2025 +0000, Huw Davies wrote:
Generally looks good, thanks! However, could you reword the commit message to be something like: `winealsa: Send All Notes Off and Reset Controllers.` ? Also, could you update the similar code in `winecoreaudio.drv/coremidi.c`? There, we already send 0x7b first, so it's just a question of replacing the 0x40 with a 0x79 and updating the comment. This change can go as a second commit in this same MR. I appreciate that you probably can't compile on macOS, but the CI will catch any errors in this trivial change.
Similar process exists not only in Core Audio but also in OSS, so I fixed that as well.
Could you update the 'sustain' comments in the last two commits?