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

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

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}"

Of course, and most importantly, this PR will probably require fluidsynth libfluidsynth and its related libraries to be bundled as part of Bottles's flatpak. Correlated issue: 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).

Copy link
Contributor

github-actions bot commented Dec 18, 2024

Pylint result on modfied files:
************* Module bottles.backend.managers.manager
bottles/backend/managers/manager.py:1:0: C0302: Too many lines in module (1642/1000) (too-many-lines)
bottles/backend/managers/manager.py:182:8: W0106: Expression "self.check_dxvk(install_latest) or rv.set_status(False)" is assigned to nothing (expression-not-assigned)
bottles/backend/managers/manager.py:185:8: W0106: Expression "self.check_vkd3d(install_latest) or rv.set_status(False)" is assigned to nothing (expression-not-assigned)
bottles/backend/managers/manager.py:188:8: W0106: Expression "self.check_nvapi(install_latest) or rv.set_status(False)" is assigned to nothing (expression-not-assigned)
bottles/backend/managers/manager.py:191:8: W0106: Expression "self.check_latencyflex(install_latest) or rv.set_status(False)" is assigned to nothing (expression-not-assigned)
bottles/backend/managers/manager.py:194:8: W0106: Expression "self.check_runtimes(install_latest) or rv.set_status(False)" is assigned to nothing (expression-not-assigned)
bottles/backend/managers/manager.py:197:8: W0106: Expression "self.check_winebridge(install_latest) or rv.set_status(False)" is assigned to nothing (expression-not-assigned)
bottles/backend/managers/manager.py:200:8: W0106: Expression "self.check_runners(install_latest) or rv.set_status(False)" is assigned to nothing (expression-not-assigned)
bottles/backend/managers/manager.py:376:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:381:16: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)
bottles/backend/managers/manager.py:385:31: C0207: Use version.split('\n', maxsplit=1)[0] instead (use-maxsplit-arg)
bottles/backend/managers/manager.py:405:12: C0206: Consider iterating with .items() (consider-using-dict-items)
bottles/backend/managers/manager.py:416:16: W1202: Use lazy % or % formatting in logging functions (logging-format-interpolation)
bottles/backend/managers/manager.py:421:8: R1702: Too many nested blocks (6/5) (too-many-nested-blocks)
bottles/backend/managers/manager.py:467:17: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
bottles/backend/managers/manager.py:496:17: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
bottles/backend/managers/manager.py:633:16: W1202: Use lazy % or % formatting in logging functions (logging-format-interpolation)
bottles/backend/managers/manager.py:638:8: R1702: Too many nested blocks (6/5) (too-many-nested-blocks)
bottles/backend/managers/manager.py:707:8: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:742:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:759:16: W0702: No exception type(s) specified (bare-except)
bottles/backend/managers/manager.py:829:21: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
bottles/backend/managers/manager.py:888:16: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:947:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:955:16: W1202: Use lazy % or % formatting in logging functions (logging-format-interpolation)
bottles/backend/managers/manager.py:967:4: R0913: Too many arguments (7/5) (too-many-arguments)
bottles/backend/managers/manager.py:967:4: R0917: Too many positional arguments (7/5) (too-many-positional-arguments)
bottles/backend/managers/manager.py:992:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1029:8: C0206: Consider iterating with .items() (consider-using-dict-items)
bottles/backend/managers/manager.py:1030:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1038:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1046:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1053:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1060:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1070:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1093:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1099:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1105:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1112:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1115:29: C0201: Consider iterating the dictionary directly instead of calling .keys() (consider-iterating-dictionary)
bottles/backend/managers/manager.py:1128:4: R0913: Too many arguments (14/5) (too-many-arguments)
bottles/backend/managers/manager.py:1128:4: R0917: Too many positional arguments (14/5) (too-many-positional-arguments)
bottles/backend/managers/manager.py:1232:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1253:8: W0702: No exception type(s) specified (bare-except)
bottles/backend/managers/manager.py:1267:12: W0702: No exception type(s) specified (bare-except)
bottles/backend/managers/manager.py:1264:21: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
bottles/backend/managers/manager.py:1317:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/managers/manager.py:1321:15: W0125: Using a conditional statement with a constant value (using-constant-test)
bottles/backend/managers/manager.py:1316:8: R1702: Too many nested blocks (6/5) (too-many-nested-blocks)
bottles/backend/managers/manager.py:1316:8: R1702: Too many nested blocks (7/5) (too-many-nested-blocks)
bottles/backend/managers/manager.py:1316:8: R1702: Too many nested blocks (7/5) (too-many-nested-blocks)
bottles/backend/managers/manager.py:1404:21: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
bottles/backend/managers/manager.py:1565:8: W1510: 'subprocess.run' used without explicitly defining the value for 'check'. (subprocess-run-check)
bottles/backend/managers/manager.py:1604:4: R0913: Too many arguments (7/5) (too-many-arguments)
bottles/backend/managers/manager.py:1604:4: R0917: Too many positional arguments (7/5) (too-many-positional-arguments)
bottles/backend/managers/manager.py:77:0: R0904: Too many public methods (24/20) (too-many-public-methods)
************* Module bottles.backend.wine.start
bottles/backend/wine/start.py:14:4: R0913: Too many arguments (9/5) (too-many-arguments)
bottles/backend/wine/start.py:14:4: R0917: Too many positional arguments (9/5) (too-many-positional-arguments)
************* Module bottles.backend.wine.wineprogram
bottles/backend/wine/wineprogram.py:39:4: R0913: Too many arguments (11/5) (too-many-arguments)
bottles/backend/wine/wineprogram.py:39:4: R0917: Too many positional arguments (11/5) (too-many-positional-arguments)
************* Module bottles.backend.wine.executor
bottles/backend/wine/executor.py:27:4: R0913: Too many arguments (19/5) (too-many-arguments)
bottles/backend/wine/executor.py:27:4: R0917: Too many positional arguments (19/5) (too-many-positional-arguments)
bottles/backend/wine/executor.py:155:4: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
bottles/backend/wine/executor.py:213:8: E1111: Assigning result of a function call, where the function has no return (assignment-from-no-return)
bottles/backend/wine/executor.py:308:8: E1111: Assigning result of a function call, where the function has no return (assignment-from-no-return)
bottles/backend/wine/executor.py:319:8: E1111: Assigning result of a function call, where the function has no return (assignment-from-no-return)
bottles/backend/wine/executor.py:356:21: W1202: Use lazy % or % formatting in logging functions (logging-format-interpolation)
************* Module bottles.backend.wine.winecommand
bottles/backend/wine/winecommand.py:90:4: W0102: Dangerous default value {} as argument (dangerous-default-value)
bottles/backend/wine/winecommand.py:90:4: R0913: Too many arguments (13/5) (too-many-arguments)
bottles/backend/wine/winecommand.py:90:4: R0917: Too many positional arguments (13/5) (too-many-positional-arguments)
bottles/backend/wine/winecommand.py:143:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/wine/winecommand.py:149:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/wine/winecommand.py:410:20: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/wine/winecommand.py:414:51: E1136: Value 'gpu['prime']['integrated']' is unsubscriptable (unsubscriptable-object)
bottles/backend/wine/winecommand.py:416:20: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/wine/winecommand.py:193:8: W0612: Unused variable 'is_nvidia' (unused-variable)
bottles/backend/wine/winecommand.py:462:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/wine/winecommand.py:471:12: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/wine/winecommand.py:487:4: R0913: Too many arguments (8/5) (too-many-arguments)
bottles/backend/wine/winecommand.py:487:4: R0917: Too many positional arguments (8/5) (too-many-positional-arguments)
bottles/backend/wine/winecommand.py:524:32: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)
bottles/backend/wine/winecommand.py:531:21: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
bottles/backend/wine/winecommand.py:540:21: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
bottles/backend/wine/winecommand.py:556:20: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/wine/winecommand.py:561:20: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/wine/winecommand.py:566:20: W0105: String statement has no effect (pointless-string-statement)
bottles/backend/wine/winecommand.py:677:8: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)
bottles/backend/wine/winecommand.py:688:8: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)
bottles/backend/wine/winecommand.py:726:12: R1705: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it (no-else-return)
bottles/backend/wine/winecommand.py:747:23: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)
************* Module bottles.frontend.cli.cli
bottles/frontend/cli/cli.py:34:0: C0103: Constant name "pkgdatadir" doesn't conform to UPPER_CASE naming style (invalid-name)
bottles/frontend/cli/cli.py:36:0: C0103: Constant name "gresource_path" doesn't conform to UPPER_CASE naming style (invalid-name)
bottles/frontend/cli/cli.py:41:0: C0413: Import "from gi.repository import Gio" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:43:0: C0413: Import "from bottles.frontend.params import APP_ID" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:44:0: C0413: Import "from bottles.backend.globals import Paths" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:45:0: C0413: Import "from bottles.backend.health import HealthChecker" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:46:0: C0413: Import "from bottles.backend.managers.manager import Manager" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:47:0: C0413: Import "from bottles.backend.models.config import BottleConfig" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:48:0: C0413: Import "from bottles.backend.wine.cmd import CMD" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:49:0: C0413: Import "from bottles.backend.wine.control import Control" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:50:0: C0413: Import "from bottles.backend.wine.executor import WineExecutor" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:51:0: C0413: Import "from bottles.backend.wine.winecommand import WineCommand" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:52:0: C0413: Import "from bottles.backend.wine.reg import Reg" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:53:0: C0413: Import "from bottles.backend.wine.winepath import WinePath" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:54:0: C0413: Import "from bottles.backend.wine.regedit import Regedit" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:55:0: C0413: Import "from bottles.backend.wine.taskmgr import Taskmgr" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:56:0: C0413: Import "from bottles.backend.wine.uninstaller import Uninstaller" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:57:0: C0413: Import "from bottles.backend.wine.winecfg import WineCfg" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:58:0: C0413: Import "from bottles.backend.wine.explorer import Explorer" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:59:0: C0413: Import "from bottles.backend.wine.regkeys import RegKeys" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:60:0: C0413: Import "from bottles.backend.runner import Runner" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:61:0: C0413: Import "from bottles.backend.utils import json" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:62:0: C0413: Import "from bottles.backend.utils.manager import ManagerUtils" should be placed at the top of the module (wrong-import-position)
bottles/frontend/cli/cli.py:304:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:309:16: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:330:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:360:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:362:8: C0206: Consider iterating with .items() (consider-using-dict-items)
bottles/frontend/cli/cli.py:377:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:385:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:403:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:441:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:449:16: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:457:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:491:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:500:16: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:525:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:535:20: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:564:16: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:574:16: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:584:16: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:594:16: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:660:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:668:16: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:672:16: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:707:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:720:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:739:12: R1722: Consider using 'sys.exit' instead (consider-using-sys-exit)
bottles/frontend/cli/cli.py:754:13: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
bottles/frontend/cli/cli.py:239:4: W0238: Unused private member `CLI.__clear()` (unused-private-member)
************* Module bottles.frontend.utils.filters
bottles/frontend/utils/filters.py:23:5: W0511: TODO: Investigate why `filter.add_mime_type(...)` does not show filter in all distributions. (fixme)
bottles/frontend/utils/filters.py:45:5: W0511: TODO: Investigate why `filter.add_mime_type(...)` does not show filter in all distributions. (fixme)
bottles/frontend/utils/filters.py:21:4: W0622: Redefining built-in 'filter' (redefined-builtin)
bottles/frontend/utils/filters.py:34:4: W0622: Redefining built-in 'filter' (redefined-builtin)
bottles/frontend/utils/filters.py:43:4: W0622: Redefining built-in 'filter' (redefined-builtin)
bottles/frontend/utils/filters.py:55:4: W0622: Redefining built-in 'filter' (redefined-builtin)
************* Module bottles.frontend.windows.launchoptions
bottles/frontend/windows/launchoptions.py:18:0: E0611: No name 'Adw' in module 'gi.repository' (no-name-in-module)
bottles/frontend/windows/launchoptions.py:201:31: W0613: Unused argument 'widget' (unused-argument)
bottles/frontend/windows/launchoptions.py:201:39: W0613: Unused argument 'state' (unused-argument)
bottles/frontend/windows/launchoptions.py:208:50: W0613: Unused argument 'global_value' (unused-argument)
bottles/frontend/windows/launchoptions.py:215:4: R1711: Useless return at end of function or method (useless-return)
bottles/frontend/windows/launchoptions.py:266:19: E1101: Instance of 'Error' has no 'code' member (no-member)
bottles/frontend/windows/launchoptions.py:274:20: W0107: Unnecessary pass statement (unnecessary-pass)
bottles/frontend/windows/launchoptions.py:298:19: E1101: Instance of 'Error' has no 'code' member (no-member)
bottles/frontend/windows/launchoptions.py:29:0: R0903: Too few public methods (1/2) (too-few-public-methods)
bottles/frontend/windows/launchoptions.py:23:0: C0411: standard import "gettext.gettext" should be placed before third party import "gi.repository.Gtk" and first party imports "bottles.backend.utils.manager.ManagerUtils", "bottles.backend.logger.Logger", "bottles.frontend.utils.filters.add_all_filters"  (wrong-import-order)

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 3 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 2 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
Done through garbage collector's reference counting. In case of multiple programs running with the same soundfont at once, instance is only terminated after ALL of them exit.
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.

3 participants