mirror of
https://github.com/bottlesdevs/Bottles.git
synced 2026-10-29 07:17:00 +08:00
+18









Weblate (bot)
Hari Rana
EmoonX
Hugo Carvalho
Gilad the Grain
AsciiWolf
arnas
Aindriú Mac Giolla Eoin
Martin
Yaron Shahrabani
vikdevelop
albanobattistella
Arif Budiman
Isaac Afonso
Lang Q
Temuri Doghonadze
Danial Behzadi
Florian Schaupp
Diego Siqueira
LucasMZ
rezarria
Cezary Frej
Balázs Meskó
Ricky Tigg
John Peter Sa
Степан Наумов
PC
Mirko Brombin
96056559e8
* filters: Introduce `__set_filter` This will be used as a wrapper method for setting filters. Co-authored-by: Hari Rana <theevilskeleton@riseup.net> * filters: Use `__set_filter` private method to every function Co-authored-by: Hari Rana <theevilskeleton@riseup.net> * backend: Add support for MIDI SoundFont Co-authored-by: Hari Rana <theevilskeleton@riseup.net> * frontend: Add support for MIDI SoundFont Co-authored-by: Hari Rana <theevilskeleton@riseup.net> * chore: Bump requirements and update pypi-deps * Translated using Weblate (Portuguese) Currently translated at 100.0% (640 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pt/ * Translated using Weblate (Hebrew) Currently translated at 26.4% (169 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/he/ * Translated using Weblate (Hebrew) Currently translated at 34.6% (222 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/he/ * Translated using Weblate (Czech) Currently translated at 98.2% (629 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/cs/ * Translated using Weblate (Lithuanian) Currently translated at 12.0% (77 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/lt/ * Added translation using Weblate (Irish) * Translated using Weblate (Irish) Currently translated at 100.0% (677 of 677 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/ga/ * Translated using Weblate (Czech) Currently translated at 99.0% (634 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/cs/ * Translated using Weblate (Hebrew) Currently translated at 34.8% (223 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/he/ * Translated using Weblate (Czech) Currently translated at 100.0% (640 of 640 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/cs/ * Translated using Weblate (Italian) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/it/ * Translated using Weblate (Indonesian) Currently translated at 48.6% (329 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/id/ * Translated using Weblate (Czech) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/cs/ * Translated using Weblate (Portuguese) Currently translated at 99.8% (675 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pt/ * Translated using Weblate (Belarusian) Currently translated at 23.8% (161 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/be/ * Added translation using Weblate (Georgian) * Translated using Weblate (Georgian) Currently translated at 28.9% (197 of 680 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/ka/ * Translated using Weblate (Persian) Currently translated at 44.6% (302 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/fa/ * Translated using Weblate (Persian) Currently translated at 55.6% (376 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/fa/ * Translated using Weblate (German) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/de/ * Translated using Weblate (Portuguese) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pt/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.8% (675 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pt_BR/ * Translated using Weblate (Vietnamese) Currently translated at 41.2% (279 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/vi/ * Translated using Weblate (Polish) Currently translated at 98.9% (669 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pl/ * Translated using Weblate (Hungarian) Currently translated at 97.0% (656 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/hu/ * Translated using Weblate (Finnish) Currently translated at 91.8% (621 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/fi/ * Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pt_BR/ * Translated using Weblate (Russian) Currently translated at 100.0% (676 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/ru/ * Translated using Weblate (Polish) Currently translated at 99.7% (674 of 676 strings) Translation: Bottles/Bottles Translate-URL: https://hosted.weblate.org/projects/bottles/bottles/pl/ --------- Co-authored-by: EmoonX <emoon@emoon.dev> Co-authored-by: Hari Rana <theevilskeleton@riseup.net> Co-authored-by: Hugo Carvalho <hugokarvalho@hotmail.com> Co-authored-by: Gilad the Grain <main.gilad.edu@gmail.com> Co-authored-by: AsciiWolf <mail@asciiwolf.com> Co-authored-by: arnas <Arnas@users.noreply.hosted.weblate.org> Co-authored-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com> Co-authored-by: Martin <havelis007martin@gmail.com> Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com> Co-authored-by: vikdevelop <vikdevelop@proton.me> Co-authored-by: albanobattistella <albano_battistella@hotmail.com> Co-authored-by: Arif Budiman <arifpedia@gmail.com> Co-authored-by: Isaac Afonso <is0214656@gmail.com> Co-authored-by: Lang Q <artyrkloskisky@gmail.com> Co-authored-by: Temuri Doghonadze <temuri.doghonadze@gmail.com> Co-authored-by: Danial Behzadi <dani.behzi@ubuntu.com> Co-authored-by: Florian Schaupp <fschaupp@hotmail.com> Co-authored-by: Diego Siqueira <diegopereirasiqueira@gmail.com> Co-authored-by: LucasMZ <git@lucasmz.dev> Co-authored-by: rezarria <votanamcb@outlook.com> Co-authored-by: Cezary Frej <frejcezary@gmail.com> Co-authored-by: Balázs Meskó <meskobalazs@mailbox.org> Co-authored-by: Ricky Tigg <ricky.tigg@gmail.com> Co-authored-by: John Peter Sa <johnppetersa@gmail.com> Co-authored-by: Степан Наумов <st250492@yandex.ru> Co-authored-by: PC <antyinteligent@proton.me> Co-authored-by: Mirko Brombin <send@mirko.pm>
111 lines
3.8 KiB
Python
111 lines
3.8 KiB
Python
# midi.py
|
|
#
|
|
# Copyright 2025 The Bottles Contributors
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, in version 3 of the License.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from typing import Self
|
|
|
|
from ctypes import c_void_p
|
|
from fluidsynth import cfunc, Synth # type: ignore [import-untyped]
|
|
|
|
from bottles.backend.logger import Logger
|
|
from bottles.backend.models.config import BottleConfig
|
|
from bottles.backend.wine.reg import Reg
|
|
|
|
logging = Logger()
|
|
|
|
|
|
class FluidSynth:
|
|
"""FluidSynth instance bounded to a unique SoundFont (.sf2, .sf3) file."""
|
|
|
|
__active_instances: dict[int, Self] = {}
|
|
|
|
@classmethod
|
|
def find_or_create(cls, soundfont_path: str) -> Self:
|
|
"""
|
|
Search for running FluidSynth instance and return it.
|
|
If nonexistent, create and add it to active ones beforehand.
|
|
"""
|
|
|
|
for fs in cls.__active_instances.values():
|
|
if fs.soundfont_path == soundfont_path:
|
|
fs.program_count += 1
|
|
return fs
|
|
|
|
fs = cls(soundfont_path)
|
|
cls.__active_instances[fs.id] = fs
|
|
return fs
|
|
|
|
def __init__(self, soundfont_path: str):
|
|
"""Build a new FluidSynth object from SoundFont file path."""
|
|
self.soundfont_path = soundfont_path
|
|
self.id = self.__get_vacant_id()
|
|
self.__start()
|
|
self.program_count = 1
|
|
|
|
@classmethod
|
|
def __get_vacant_id(cls) -> int:
|
|
"""Get smallest 0-indexed ID currently not in use by a SoundFont."""
|
|
n = len(cls.__active_instances)
|
|
return next(i for i in range(n + 1) if i not in cls.__active_instances)
|
|
|
|
def __start(self):
|
|
"""Start FluidSynth synthetizer with loaded SoundFont."""
|
|
logging.info(
|
|
"Starting new FluidSynth server with SoundFont"
|
|
f" #{self.id} ('{self.soundfont_path}')…"
|
|
)
|
|
synth = Synth(channels=16)
|
|
synth.start()
|
|
sfid = synth.sfload(self.soundfont_path)
|
|
synth.program_select(0, sfid, 0, 0)
|
|
self.synth = synth
|
|
|
|
def register_as_current(self, config: BottleConfig):
|
|
"""
|
|
Update Wine registry with this instance's ID, instructing
|
|
MIDI mapping to load the correct instrument set on program startup.
|
|
"""
|
|
reg = Reg(config)
|
|
reg.add(
|
|
key="HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap",
|
|
value="CurrentInstrument",
|
|
data=f"#{self.id}",
|
|
value_type="REG_SZ",
|
|
)
|
|
|
|
def decrement_program_counter(self):
|
|
"""Decrement program counter; if it reaches zero, delete this instance."""
|
|
self.program_count -= 1
|
|
if self.program_count == 0:
|
|
self.__delete()
|
|
|
|
def __delete(self):
|
|
"""Kill underlying synthetizer and remove FluidSynth instance from dict."""
|
|
|
|
def __delete_synth(synth: Synth):
|
|
"""Bind missing function and run deletion routines."""
|
|
delete_fluid_midi_driver = cfunc(
|
|
"delete_fluid_midi_driver", c_void_p, ("driver", c_void_p, 1)
|
|
)
|
|
delete_fluid_midi_driver(synth.midi_driver)
|
|
synth.delete()
|
|
|
|
logging.info(
|
|
"Killing FluidSynth server with SoundFont"
|
|
f" #{self.id} ('{self.soundfont_path}')…"
|
|
)
|
|
__delete_synth(self.synth)
|
|
self.__active_instances.pop(self.id)
|