Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIDI playback support with custom SoundFonts #3613

Merged
merged 5 commits into from
Jan 19, 2025

Conversation

EmoonX
Copy link
Contributor

@EmoonX EmoonX commented Dec 18, 2024

Description

Introducing a new launch option as a GUI-oriented user-friendly way to deal with MIDI playback, for programs (mainly old games) that contain MIDI sequencer audio tracks.

image

Makes use of FluidSynth as MIDI synthesizer, and PipeWire ALSA as the audio driver (though PulseAudio and Pipewire also work). An user-supplied SoundFont file is required (either in .sf2 or .sf3 formats — both tested to work). This allows different games to be run individually and simultaneously with distinct instrument sets.

A registry add/update is also applied, to make the game pick the right instrument set at launch (when more than one fluidsynth instance is running at once). See: https://gitlab.winehq.org/wine/wine/-/wikis/MIDI#selecting-the-output---the-midi-mapper

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Multimedia\MIDIMap]
"CurrentInstrument"="#{id}"

Closes flathub/com.usebottles.bottles#466

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

First of all, make sure fluidsynth is installed on your system libfluidsynth and its related libraries (libinstpatch-1.0, libportaudio, libportaudiocpp) are installed and reachable from the flatpak sandbox.

Set the MIDI SoundFont launch option for a MIDI-driven game, choosing a .sf2/.sf3 file as you wish. MIDI playback should now work and a FluidSynth server will start upon launch.

Setting another SoundFont for a different game — and running it without closing the first — will have said game playing audio with the second instrument set, by running another FluidSynth instance. Both should coexist without interference.

Closing any of the games should kill the respective fluidsynth instance. Further loaded instances will be given the vacant IDs of past ones (e.g by having three distinct-SoundFont open games — #​0, #​1 and #​2 — and closing the one with instrument set #​1, next game with unique SoundFont will be given ID #​1).

This comment was marked as outdated.

bottles/backend/wine/midi.py Outdated Show resolved Hide resolved
bottles/backend/wine/winecommand.py Outdated Show resolved Hide resolved
bottles/backend/wine/winecommand.py Outdated Show resolved Hide resolved
@EmoonX EmoonX marked this pull request as draft December 28, 2024 13:35
@keenanweaver
Copy link

Just a question, apologies as I haven't built & tested myself. Is the scope for the whole bottle only, or can the options be set per program? My use-case would be to have multiple shortcuts to the same game in the same bottle with different soundfonts.

@EmoonX
Copy link
Contributor Author

EmoonX commented Dec 30, 2024

@keenanweaver Funnily enough, right now it's actually the other way around: you are able to set different soundfonts for each program (i.e what you need), but there isn't a global soundfont chooser. Shouldn't be hard though to add that option in a commit up next.

I'm just not sure yet about bundling a default one. gm.sf2 is the contender that comes to mind for that old-classic-Windows-like music, but it sounds kinda dated to my ears. Thankfully there are some nice libre ones, just gotta see with the necktie people around here the actual proper way to include/attribute those.

@keenanweaver
Copy link

I'm pretty much all Nuked SC55 these days, but before that I used the Trevor0402 SC-55 soundfont. It's really tough finding a 'universal' soundfont when it sounds incredible in one game and terrible in another. Like most things, my default barometer is Doom--if it sounds good there, it probably sounds good in other games. I'm of the opinion one shouldn't be bundled in here. People that will use this feature know what they're wanting, and those dipping their toes into the soundfont pond for the first time will easily find discussions and recommendations all over the web.

@EmoonX
Copy link
Contributor Author

EmoonX commented Dec 30, 2024

I'm of the opinion one shouldn't be bundled in here. People that will use this feature know what they're wanting, and those dipping their toes into the soundfont pond for the first time will easily find discussions and recommendations all over the web.

I like the reasoning. On the one hand, it could feel kinda incomplete not having a required feature working out-of-the-box. On the other hand, MIDI audio playing by default would make some people unaware of even the option to swap it for a custom soundfont ("this game sounds so bad and apparently I can't do anything about it" moment).

For the best of both worlds, perhaps we could simply leave the default setting empty (midi_soundfont: null for the global bottle settings) and then bundle a simple one (like the aforementioned gm.sf2) just for the sake of it, choosable through the file explorer. That would please both the lazy and the adventurous ones.

@EmoonX EmoonX force-pushed the midi-playback branch 5 times, most recently from 4205cfc to d442151 Compare December 31, 2024 23:11
@EmoonX EmoonX marked this pull request as ready for review January 1, 2025 02:21
@EmoonX EmoonX force-pushed the midi-playback branch 3 times, most recently from 013a6c7 to a1c9b2b Compare January 1, 2025 02:46
@EmoonX
Copy link
Contributor Author

EmoonX commented Jan 1, 2025

I think that's it. All functionalities should work as described.

As for the rest, a global MIDI settings menu is in the plans. We can then have stuff like:

  • choosable audio driver (ALSA, PulseAudio or Pipewire)
  • default SoundFont file to be used
  • volume gain factor
  • turn on/off reverb
  • sample rate (44100, 48000, etc)

But that's definitely better left for another PR further on. This one got too long and _Complex already.

@EmoonX EmoonX requested a review from TheEvilSkeleton January 1, 2025 14:27
@EmoonX EmoonX force-pushed the midi-playback branch 2 times, most recently from 977d652 to 4bd9f99 Compare January 1, 2025 15:38
@mholl1983
Copy link

Very cool to see this being developed! Is there a way to test it out?

@EmoonX
Copy link
Contributor Author

EmoonX commented Jan 15, 2025

@mholl1983 Yep, certainly. Just clone/checkout my branch, build it, and then follow the How Has This Been Tested? instructions up above.

Copy link
Member

@TheEvilSkeleton TheEvilSkeleton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested the app just yet, because building Bottles and its dependencies takes a lot of time. If you could rebase this branch to main, I'll be able to install using the artifacts, test and provide design suggestions.

I would like to have it merged after #3691. However, if this is desperately needed/wanted and literally prevents users from using Bottles, then I'll merge it once it's ready. I'm quite unfamiliar with MIDI, so the functionality is incomprehensible for me. I can only comment on code and widget.

bottles/frontend/windows/launchoptions.py Outdated Show resolved Hide resolved
bottles/backend/wine/executor.py Show resolved Hide resolved
bottles/backend/wine/executor.py Outdated Show resolved Hide resolved
bottles/frontend/utils/filters.py Outdated Show resolved Hide resolved
bottles/backend/utils/midi.py Outdated Show resolved Hide resolved
bottles/backend/wine/executor.py Show resolved Hide resolved
bottles/frontend/windows/launchoptions.py Outdated Show resolved Hide resolved
bottles/backend/wine/executor.py Outdated Show resolved Hide resolved
bottles/frontend/windows/launchoptions.py Outdated Show resolved Hide resolved
bottles/frontend/utils/filters.py Outdated Show resolved Hide resolved
bottles/backend/wine/executor.py Outdated Show resolved Hide resolved
@EmoonX EmoonX force-pushed the midi-playback branch 2 times, most recently from 01af1f0 to 256b6fb Compare January 18, 2025 16:33
Copy link
Member

@TheEvilSkeleton TheEvilSkeleton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The overall code seems to be good so far. I just have a small suggestion with the docstrings, but other than that, I have nothing to criticize. The only thing needed now is to rebase and properly write the commits.

Here's how I suggest in order:

  1. A commit for adding the __set_filter private method
  2. A commit for porting every previous filter implementation to __set_filter
  3. A commit for implementing support for MIDI SoundFont (in the backend) and updating the pypi-deps.yaml and requirements.txt files with the inclusion of pyfluidsynth
  4. A commit for bumping every dependency in requirements.txt
  5. Final commit for exposing the feature in the frontend

After that, I can merge it :)

bottles/backend/utils/midi.py Outdated Show resolved Hide resolved
EmoonX and others added 2 commits January 18, 2025 22:38
This will be used as a wrapper method for setting filters.

Co-authored-by: Hari Rana <[email protected]>
@TheEvilSkeleton TheEvilSkeleton force-pushed the midi-playback branch 2 times, most recently from a856200 to 49c752b Compare January 19, 2025 04:19
Copy link
Member

@TheEvilSkeleton TheEvilSkeleton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As stated in private, I rebased and reorganized the commit messages. Everything looks good to me in terms of code. As I said, I'm unfamiliar with MIDI, so maintenance on my end will be rather limited.

@TheEvilSkeleton TheEvilSkeleton merged commit 225849b into bottlesdevs:main Jan 19, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

MIDI support
4 participants