Files
+18 96056559e8 Translations update from Hosted Weblate (#3522)
* 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>
2025-01-20 14:21:46 +01:00

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)