audioworkstation.libs.audio.fluidsynth のソースコード

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Piano playing practice with MIDI keyboard.

Use this module from Kivy as a separate thread.

Module 'concurrent.futures.ThreadPoolExecutor' is recommended.

:referrence: https://www.fluidsynth.org/api/
"""

from typing import Union, Callable, Any
from enum import IntEnum, IntFlag, auto
from json import load
from time import sleep
from ctypes.util import find_library
import logging as LFS
import ctypes as CFS
from pathlib import Path

# Logger
logger = LFS.getLogger(__name__)
# level: NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL
logger.setLevel(LFS.WARNING)
_logger_formatter = LFS.Formatter("%(asctime)s %(levelname)s %(message)s")
# Logger FileHandler
_logger_fh = LFS.FileHandler("logs/fluidsynth.log")
_logger_fh.setFormatter(_logger_formatter)
logger.addHandler(_logger_fh)
# Logger StreamHandler
_logger_sh = LFS.StreamHandler()
_logger_sh.setFormatter(_logger_formatter)
logger.addHandler(_logger_sh)

# fluidsynth
FLUID_FAILED = -1
FLUID_OK = 0

# Handle exception


[ドキュメント]class FSError(Exception): """Exceptions sent out from errcheck func.""" def __init__(self, *args: object) -> None: super().__init__(*args) logger.error(f"FSError: {args}")
def _errcheck(result: Any, cfunc: Callable, args: tuple) -> Any: if result == FLUID_FAILED: raise FSError((cfunc, args)) return result """libfluidsynth""" _libfs = CFS.CDLL(name=find_library(name="fluidsynth"), use_errno=True) def _prototype(restype: Any, name: str, *params: tuple) -> Any: """Returns a foreign function exported by a shared library. :param Any restype: foreign function restype :param str name: foreign function name :param tuple params: type, flag, name[, default] :return: foreign function object """ if hasattr(_libfs, name): argtypes: list = list([]) paramflags: list = list([]) for param in params: argtypes.append(param[0]) paramflags.append(param[1:]) func_spec = (name, _libfs) return CFS.CFUNCTYPE(restype, *argtypes, use_errno=True)( func_spec, tuple(paramflags) ) else: return None # Audio output # Audio output - Audio driver # [API prototype] new_fluid_audio_driver = _prototype( CFS.c_void_p, "new_fluid_audio_driver", (CFS.c_void_p, 1, "settings"), (CFS.c_void_p, 1, "synth"), ) new_fluid_audio_driver.errcheck = _errcheck delete_fluid_audio_driver = _prototype( None, "delete_fluid_audio_driver", (CFS.c_void_p, 1, "driver") ) fluid_audio_driver_register = _prototype( CFS.c_int, "fluid_audio_driver_register", (CFS.POINTER(CFS.c_char_p), 1, "adrivers") ) fluid_audio_driver_register.errcheck = _errcheck # Audio output - File Renderer # Command Interface # Command Interface - Command Handler # [API prototype] new_fluid_cmd_handler = _prototype( CFS.c_void_p, "new_fluid_cmd_handler", (CFS.c_void_p, 1, "synth"), (CFS.c_void_p, 1, "router"), ) new_fluid_cmd_handler.errcheck = _errcheck delete_fluid_cmd_handler = _prototype( None, "delete_fluid_cmd_handler", (CFS.c_void_p, 1, "handler") ) # Command Interface - Command Server # Command Interface - Command Shell # Logging # [ENUM]
[ドキュメント]class FLUID_LOG_LEVEL(IntEnum): PANIC = 0 ERR = auto() WARN = auto() INFO = auto() DBG = auto() LAST_LOG_LEVEL = auto()
# [user defined data type]
[ドキュメント]class LogUserData(CFS.Structure): """Structure of data for Log function handler""" pass
# [Typedef] FLUID_LOG_FUNCTION_T = CFS.CFUNCTYPE( None, CFS.c_int, CFS.c_char_p, CFS.POINTER(LogUserData) ) """Log function handler callback type used by fluid_set_log_function() :param c_int level: :param c_char_p message: :param POINTER(LogUserData) data: """ # [API prototype] fluid_default_log_function = _prototype( None, "fluid_default_log_function", (CFS.c_int, 1, "level"), (CFS.c_char_p, 1, "message"), (CFS.POINTER(LogUserData), 1, "data"), ) fluid_log = _prototype( CFS.c_int, "fluid_log", (CFS.c_int, 1, "level"), (CFS.c_char_p, 1, "fmt"), (CFS.c_char_p, 1, "message"), ) fluid_set_log_function = _prototype( FLUID_LOG_FUNCTION_T, "fluid_set_log_function", (CFS.c_int, 1, "level"), (FLUID_LOG_FUNCTION_T, 1, "fun"), (CFS.POINTER(LogUserData), 1, "data"), ) fluid_set_log_function.errcheck = _errcheck # [user function] @FLUID_LOG_FUNCTION_T def _log_func(level, message, data) -> None: mes = bytes(message).decode() if int(level) == FLUID_LOG_LEVEL.PANIC: logger.critical(f"{mes}") elif int(level) == FLUID_LOG_LEVEL.ERR: logger.error(f"{mes}") elif int(level) == FLUID_LOG_LEVEL.WARN: logger.warning(f"{mes}") elif int(level) == FLUID_LOG_LEVEL.INFO: logger.info(f"{mes}") elif int(level) == FLUID_LOG_LEVEL.DBG: logger.debug(f"{mes}") # MIDI Input # [typedef] handle_midi_event_func_t HANDLE_MIDI_EVENT_FUNC_T = CFS.CFUNCTYPE(CFS.c_int, CFS.c_void_p, CFS.c_void_p) """Generic callback function prototype for MIDI event handler. :param c_void_p data: :param c_void_p event: :return: """ # [API prototype] fluid_synth_handle_midi_event = _prototype( CFS.c_int, "fluid_synth_handle_midi_event", (CFS.c_void_p, 1, "data"), (CFS.c_void_p, 1, "event"), ) fluid_synth_handle_midi_event.errcheck = _errcheck # MIDI Input - MIDI Driver # [API prototype] new_fluid_midi_driver = _prototype( CFS.c_void_p, "new_fluid_midi_driver", (CFS.c_void_p, 1, "settings"), (CFS.c_void_p, 1, "handler"), (CFS.c_void_p, 1, "event_handler_data"), ) new_fluid_midi_driver.errcheck = _errcheck delete_fluid_midi_driver = _prototype( None, "delete_fluid_midi_driver", (CFS.c_void_p, 1, "driver") ) # MIDI Input - MIDI Event # MIDI Input - MIDI File Player # [ENUM]
[ドキュメント]class FLUID_PLAYER_SET_TEMPO_TYEP(IntEnum): # Available from version 2.2.0 INTERNAL = 0 EXTERNAL_BPM = auto() EXTERNAL_MIDI = auto()
[ドキュメント]class FLUID_PLAYER_STATUS(IntEnum): READY = 0 PLAYING = auto() # STOPPING = auto() # Available from version 2.2.0 DONE = auto()
# [API prototype] new_fluid_player = _prototype( CFS.c_void_p, "new_fluid_player", (CFS.c_void_p, 1, "synth") ) new_fluid_player.errcheck = _errcheck delete_fluid_player = _prototype( None, "delete_fluid_player", (CFS.c_void_p, 1, "player") ) fluid_player_set_playback_callback = _prototype( CFS.c_int, "fluid_player_set_playback_callback", (CFS.c_void_p, 1, "player"), (CFS.c_void_p, 1, "handler"), (CFS.c_void_p, 1, "handler_data"), ) fluid_player_set_playback_callback.errcheck = _errcheck fluid_player_add = _prototype( CFS.c_int, "fluid_player_add", (CFS.c_void_p, 1, "player"), (CFS.c_char_p, 1, "midifile"), ) fluid_player_add.errcheck = _errcheck fluid_player_add_mem = _prototype( CFS.c_int, "fluid_player_add_mem", (CFS.c_void_p, 1, "player"), (CFS.POINTER(CFS.c_char), 1, "buffer"), (CFS.c_size_t, 1, "len"), ) fluid_player_add_mem.errcheck = _errcheck fluid_player_play = _prototype( CFS.c_int, "fluid_player_play", (CFS.c_void_p, 1, "player") ) fluid_player_play.errcheck = _errcheck fluid_player_get_status = _prototype( CFS.c_int, "fluid_player_get_status", (CFS.c_void_p, 1, "player") ) fluid_player_get_status.errcheck = _errcheck fluid_player_stop = _prototype( CFS.c_int, "fluid_player_stop", (CFS.c_void_p, 1, "player") ) fluid_player_stop.errcheck = _errcheck fluid_player_join = _prototype( CFS.c_int, "fluid_player_join", (CFS.c_void_p, 1, "player") ) fluid_player_join.errcheck = _errcheck fluid_player_get_total_ticks = _prototype( CFS.c_int, "fluid_player_get_total_ticks", (CFS.c_void_p, 1, "player") ) fluid_player_get_total_ticks.errcheck = _errcheck fluid_player_get_current_tick = _prototype( CFS.c_int, "fluid_player_get_current_tick", (CFS.c_void_p, 1, "player") ) fluid_player_get_current_tick.errcheck = _errcheck fluid_player_seek = _prototype( CFS.c_int, "fluid_player_seek", (CFS.c_void_p, 1, "player"), (CFS.c_int, 1, "ticks") ) fluid_player_seek.errcheck = _errcheck fluid_player_set_loop = _prototype( CFS.c_int, "fluid_player_set_loop", (CFS.c_void_p, 1, "player"), (CFS.c_int, 1, "loop"), ) fluid_player_set_loop.errcheck = _errcheck # MIDI Input - MIDI Router # [ENUM]
[ドキュメント]class FLUID_MIDI_ROUTER_RULE_TYPE(IntEnum): NOTE = 0 CC = auto() PROG_CHANGER = auto() PITCH_BEND = auto() CHANNEL_PRESSURE = auto() KEY_PRESSURE = auto() COUNT = auto()
# [API prototype] new_fluid_midi_router = _prototype( CFS.c_void_p, "new_fluid_midi_router", (CFS.c_void_p, 1, "settings"), (CFS.c_void_p, 1, "handler"), (CFS.c_void_p, 1, "event_handler_data"), ) new_fluid_midi_router.errcheck = _errcheck delete_fluid_midi_router = _prototype( None, "delete_fluid_midi_router", (CFS.c_void_p, 1, "router") ) fluid_midi_dump_postrouter = _prototype( CFS.c_int, "fluid_midi_dump_postrouter", (CFS.c_void_p, 1, "data"), (CFS.c_void_p, 1, "event"), ) fluid_midi_dump_postrouter.errcheck = _errcheck fluid_midi_dump_prerouter = _prototype( CFS.c_int, "fluid_midi_dump_prerouter", (CFS.c_void_p, 1, "data"), (CFS.c_void_p, 1, "event"), ) fluid_midi_dump_prerouter.errcheck = _errcheck fluid_midi_router_handle_midi_event = _prototype( CFS.c_int, "fluid_midi_router_handle_midi_event", (CFS.c_void_p, 1, "data"), (CFS.c_void_p, 1, "event"), ) fluid_midi_router_handle_midi_event.errcheck = _errcheck fluid_midi_router_clear_rules = _prototype( CFS.c_int, "fluid_midi_router_clear_rules", (CFS.c_void_p, 1, "router") ) fluid_midi_router_clear_rules.errcheck = _errcheck fluid_midi_router_set_default_rules = _prototype( CFS.c_int, "fluid_midi_router_set_default_rules", (CFS.c_void_p, 1, "router") ) fluid_midi_router_set_default_rules.errcheck = _errcheck new_fluid_midi_router_rule = _prototype(CFS.c_void_p, "new_fluid_midi_router_rule") new_fluid_midi_router_rule.errcheck = _errcheck delete_fluid_midi_router_rule = _prototype( None, "delete_fluid_midi_router_rule", (CFS.c_void_p, 1, "rule") ) fluid_midi_router_rule_set_chan = _prototype( None, "fluid_midi_router_rule_set_chan", (CFS.c_void_p, 1, "rule"), (CFS.c_int, 1, "min"), (CFS.c_int, 1, "max"), (CFS.c_float, 1, "mul"), (CFS.c_int, 1, "add"), ) fluid_midi_router_rule_set_param1 = _prototype( None, "fluid_midi_router_rule_set_param1", (CFS.c_void_p, 1, "rule"), (CFS.c_int, 1, "min"), (CFS.c_int, 1, "max"), (CFS.c_float, 1, "mul"), (CFS.c_int, 1, "add"), ) fluid_midi_router_rule_set_param2 = _prototype( None, "fluid_midi_router_rule_set_param2", (CFS.c_void_p, 1, "rule"), (CFS.c_int, 1, "min"), (CFS.c_int, 1, "max"), (CFS.c_float, 1, "mul"), (CFS.c_int, 1, "add"), ) fluid_midi_router_add_rule = _prototype( CFS.c_int, "fluid_midi_router_add_rule", (CFS.c_void_p, 1, "router"), (CFS.c_void_p, 1, "rule"), (CFS.c_int, 1, "type"), ) fluid_midi_router_add_rule.errcheck = _errcheck # MIDI sequencer # [user defined data type]
[ドキュメント]class EventUserData(CFS.Structure): """Structure of data for Sequencer event callback function""" pass
# [typedef] FLUID_EVENT_CALLBACK_T = CFS.CFUNCTYPE( None, CFS.c_uint, CFS.c_void_p, CFS.c_void_p, CFS.POINTER(EventUserData) ) """Event callback function prototype for destination clients. :param c_uint time: Current sequencer tick value :param c_void_p event: The event being received :param c_void_p seq: The sequencer instance :param POINTER(EventUserData) data: User defined data registered with the client """ # [API prototype] new_fluid_sequencer2 = _prototype( CFS.c_void_p, "new_fluid_sequencer2", (CFS.c_int, 1, "use_system_timer") ) new_fluid_sequencer2.errcheck = _errcheck delete_fluid_sequencer = _prototype( None, "delete_fluid_sequencer", (CFS.c_void_p, 1, "seq") ) fluid_sequencer_register_fluidsynth = _prototype( CFS.c_short, "fluid_sequencer_register_fluidsynth", (CFS.c_void_p, 1, "seq"), (CFS.c_void_p, 1, "synth"), ) fluid_sequencer_register_fluidsynth.errcheck = _errcheck fluid_sequencer_register_client = _prototype( CFS.c_short, "fluid_sequencer_register_client", (CFS.c_void_p, 1, "seq"), (CFS.c_char_p, 1, "name"), (FLUID_EVENT_CALLBACK_T, 1, "callback"), (CFS.POINTER(EventUserData), 1, "data"), ) fluid_sequencer_register_client.errcheck = _errcheck fluid_sequencer_unregister_client = _prototype( None, "fluid_sequencer_unregister_client", (CFS.c_void_p, 1, "seq"), (CFS.c_short, 1, "id"), ) fluid_sequencer_get_client_name = _prototype( CFS.c_char_p, "fluid_sequencer_get_client_name", (CFS.c_void_p, 1, "seq"), (CFS.c_void_p, 1, "id"), ) fluid_sequencer_get_client_name.errcheck = _errcheck fluid_sequencer_get_tick = _prototype( CFS.c_uint, "fluid_sequencer_get_tick", (CFS.c_void_p, 1, "seq") ) fluid_sequencer_get_tick.errcheck = _errcheck fluid_sequencer_set_time_scale = _prototype( None, "fluid_sequencer_set_time_scale", (CFS.c_void_p, 1, "seq"), (CFS.c_double, 1, "scale", CFS.c_double(1000)), ) fluid_sequencer_get_time_scale = _prototype( CFS.c_double, "fluid_sequencer_get_time_scale", (CFS.c_void_p, 1, "seq") ) fluid_sequencer_get_time_scale.errcheck = _errcheck fluid_sequencer_send_at = _prototype( CFS.c_int, "fluid_sequencer_send_at", (CFS.c_void_p, 1, "seq"), (CFS.c_void_p, 1, "evt"), (CFS.c_uint, 1, "time"), (CFS.c_int, 1, "absolute"), ) fluid_sequencer_send_at.errcheck = _errcheck # MIDI Sequencer - Sequencer Events # [API prototype] new_fluid_event = _prototype(CFS.c_void_p, "new_fluid_event") new_fluid_event.errcheck = _errcheck delete_fluid_event = _prototype(None, "delete_fluid_event", (CFS.c_void_p, 1, "evt")) fluid_event_set_dest = _prototype( None, "fluid_event_set_dest", (CFS.c_void_p, 1, "evt"), (CFS.c_short, 1, "dest") ) fluid_event_set_source = _prototype( None, "fluid_event_set_source", (CFS.c_void_p, 1, "evt"), (CFS.c_short, 1, "src") ) fluid_event_note = _prototype( None, "fluid_event_note", (CFS.c_void_p, 1, "evt"), (CFS.c_int, 1, "channel"), (CFS.c_short, 1, "key"), (CFS.c_short, 1, "vel"), (CFS.c_uint, 1, "duration"), ) fluid_event_timer = _prototype( None, "fluid_event_timer", (CFS.c_void_p, 1, "evt"), (CFS.c_void_p, 1, "data") ) # Miscellaneous # [API prototype] fluid_free = _prototype(None, "fluid_free", (CFS.POINTER(CFS.c_int), 1, "ptr")) fluid_is_midifile = _prototype( CFS.c_int, "fluid_is_midifile", (CFS.c_char_p, 1, "filename") ) fluid_is_midifile.errcheck = _errcheck fluid_is_soundfont = _prototype( CFS.c_int, "fluid_is_soundfont", (CFS.c_char_p, 1, "filename") ) fluid_is_soundfont.errcheck = _errcheck fluid_version_str = _prototype(CFS.c_char_p, "fluid_version_str") fluid_version_str.errcheck = _errcheck # Settings # [ENUM]
[ドキュメント]class FLUID_TYPE(IntEnum): NO = -1 NUM = auto() INT = auto() STR = auto() SET = auto()
[ドキュメント]class FLUID_HINT(IntFlag): BOUNDED_BELOW = 0x1 BOUNDED_ABOVE = 0x2 TOGGLED = 0x4 RANGE = BOUNDED_BELOW | BOUNDED_ABOVE ON_OFF = RANGE | TOGGLED
FLUID_HINT_OPTIONLIST = 0x02 # [typedef] FLUID_SETTINGS_FOREACH_OPTION_T = CFS.CFUNCTYPE( None, CFS.c_void_p, CFS.c_char_p, CFS.c_char_p ) """Callback function type used with fluid_settings_foreach_option() :param c_void_p data: :param c_char_p name: :param c_char_p option: """ FLUID_SETTINGS_FOREACH_T = CFS.CFUNCTYPE(None, CFS.c_void_p, CFS.c_char_p, CFS.c_int) """Callback function type used with fluid_settings_foreach() :param c_void_p data: :param c_char_p name: :param c_int type: """ # [API prototype] new_fluid_settings = _prototype(CFS.c_void_p, "new_fluid_settings") new_fluid_settings.errcheck = _errcheck delete_fluid_settings = _prototype( None, "delete_fluid_settings", (CFS.c_void_p, 1, "settings") ) fluid_settings_setnum = _prototype( CFS.c_int, "fluid_settings_setnum", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.c_double, 1, "value"), ) fluid_settings_setnum.errcheck = _errcheck fluid_settings_getnum = _prototype( CFS.c_int, "fluid_settings_getnum", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.POINTER(CFS.c_double), 3, "val"), ) fluid_settings_getnum.errcheck = _errcheck fluid_settings_getnum_default = _prototype( CFS.c_int, "fluid_settings_getnum_default", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.POINTER(CFS.c_double), 3, "val"), ) fluid_settings_getnum_default.errcheck = _errcheck fluid_settings_getnum_range = _prototype( CFS.c_int, "fluid_settings_getnum_range", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.POINTER(CFS.c_double), 3, "min"), (CFS.POINTER(CFS.c_double), 3, "max"), ) fluid_settings_getnum_range.errcheck = _errcheck fluid_settings_setint = _prototype( CFS.c_int, "fluid_settings_setint", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.c_int, 1, "val"), ) fluid_settings_setint.errcheck = _errcheck fluid_settings_getint = _prototype( CFS.c_int, "fluid_settings_getint", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.POINTER(CFS.c_int), 3, "val"), ) fluid_settings_getint.errcheck = _errcheck fluid_settings_getint_default = _prototype( CFS.c_int, "fluid_settings_getint_default", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.POINTER(CFS.c_int), 3, "val"), ) fluid_settings_getint_default.errcheck = _errcheck fluid_settings_getint_range = _prototype( CFS.c_int, "fluid_settings_getint_range", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.POINTER(CFS.c_int), 3, "min"), (CFS.POINTER(CFS.c_int), 3, "max"), ) fluid_settings_getint_range.errcheck = _errcheck fluid_settings_setstr = _prototype( CFS.c_int, "fluid_settings_setstr", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.c_char_p, 1, "str"), ) fluid_settings_setstr.errcheck = _errcheck fluid_settings_getstr_default = _prototype( CFS.c_int, "fluid_settings_getstr_default", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.POINTER(CFS.c_char_p), 3, "str"), ) fluid_settings_getstr_default.errcheck = _errcheck fluid_settings_copystr = _prototype( CFS.c_int, "fluid_settings_copystr", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.c_char_p, 1, "str"), (CFS.c_int, 1, "len"), ) fluid_settings_copystr.errcheck = _errcheck fluid_settings_foreach = _prototype( None, "fluid_settings_foreach", (CFS.c_void_p, 1, "settings"), (CFS.c_void_p, 1, "data"), (FLUID_SETTINGS_FOREACH_T, 1, "func"), ) fluid_settings_foreach_option = _prototype( None, "fluid_settings_foreach_option", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.c_void_p, 1, "data"), (FLUID_SETTINGS_FOREACH_OPTION_T, 1, "func"), ) fluid_settings_get_hints = _prototype( CFS.c_int, "fluid_settings_get_hints", (CFS.c_void_p, 1, "settings"), (CFS.c_char_p, 1, "name"), (CFS.POINTER(CFS.c_int), 3, "hints"), ) fluid_settings_get_hints.errcheck = _errcheck # SoundFonts # SoundFonts - SoundFont Generators # SoundFonts - SoundFont Loader # [API prototype] fluid_synth_get_channel_preset = _prototype( CFS.c_void_p, "fluid_synth_get_channel_preset", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), ) fluid_synth_get_channel_preset.errcheck = _errcheck fluid_sfont_get_preset = _prototype( CFS.c_void_p, "fluid_sfont_get_preset", (CFS.c_void_p, 1, "sfont"), (CFS.c_int, 1, "bank"), (CFS.c_int, 1, "prenum"), ) fluid_sfont_get_preset.errcheck = _errcheck fluid_preset_get_banknum = _prototype( CFS.c_int, "fluid_preset_get_banknum", (CFS.c_void_p, 1, "preset") ) fluid_preset_get_banknum.errcheck = _errcheck fluid_preset_get_name = _prototype( CFS.c_char_p, "fluid_preset_get_name", (CFS.c_void_p, 1, "preset") ) fluid_preset_get_name.errcheck = _errcheck fluid_preset_get_num = _prototype( CFS.c_int, "fluid_preset_get_num", (CFS.c_void_p, 1, "preset") ) fluid_preset_get_num.errcheck = _errcheck fluid_preset_get_sfont = _prototype( CFS.c_void_p, "fluid_preset_get_sfont", (CFS.c_void_p, 1, "preset") ) fluid_preset_get_sfont.errcheck = _errcheck fluid_sfont_get_id = _prototype( CFS.c_int, "fluid_sfont_get_id", (CFS.c_void_p, 1, "sfont") ) fluid_sfont_get_id.errcheck = _errcheck # SoundFonts - SoundFont Modulators # SoundFonts - SoundFont Maniplation # Synthesizer # [API prototype] new_fluid_synth = _prototype( CFS.c_void_p, "new_fluid_synth", (CFS.c_void_p, 1, "settings") ) new_fluid_synth.errcheck = _errcheck delete_fluid_synth = _prototype(None, "delete_fluid_synth", (CFS.c_void_p, 1, "synth")) # Synthesizer - Audio Rendering # Synthesizer - Effect - Chorus # Synthesizer - Effect - IIR Filter # Synthesizer - Effect - LADSPA # Synthesizer - Effect - Reverb # Synthesizer - MIDI Channel Messages # [API prototype] fluid_synth_all_notes_off = _prototype( CFS.c_int, "fluid_synth_all_notes_off", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), ) fluid_synth_all_notes_off.errcheck = _errcheck fluid_synth_all_sounds_off = _prototype( CFS.c_int, "fluid_synth_all_sounds_off", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), ) fluid_synth_all_sounds_off.errcheck = _errcheck fluid_synth_cc = _prototype( CFS.c_int, "fluid_synth_cc", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), (CFS.c_int, 1, "num"), (CFS.c_int, 1, "val"), ) fluid_synth_cc.errcheck = _errcheck fluid_synth_get_cc = _prototype( CFS.c_int, "fluid_synth_get_cc", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), (CFS.c_int, 1, "num"), (CFS.POINTER(CFS.c_int), 3, "pval"), ) fluid_synth_get_cc.errcheck = _errcheck fluid_synth_pitch_bend = _prototype( CFS.c_int, "fluid_synth_pitch_bend", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), (CFS.c_int, 1, "val"), ) fluid_synth_pitch_bend.errcheck = _errcheck fluid_synth_get_pitch_bend = _prototype( CFS.c_int, "fluid_synth_get_pitch_bend", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), (CFS.POINTER(CFS.c_int), 3, "ppitch_bend"), ) fluid_synth_get_pitch_bend.errcheck = _errcheck fluid_synth_pitch_wheel_sens = _prototype( CFS.c_int, "fluid_synth_pitch_wheel_sens", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), (CFS.c_int, 1, "val"), ) fluid_synth_pitch_wheel_sens.errcheck = _errcheck fluid_synth_get_pitch_wheel_sens = _prototype( CFS.c_int, "fluid_synth_get_pitch_wheel_sens", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), (CFS.POINTER(CFS.c_int), 3, "pval"), ) fluid_synth_get_pitch_wheel_sens.errcheck = _errcheck fluid_synth_sysex = _prototype( CFS.c_int, "fluid_synth_sysex", (CFS.c_void_p, 1, "synth"), (CFS.c_char_p, 1, "data"), (CFS.c_int, 1, "len"), (CFS.c_char_p, 1, "response"), (CFS.POINTER(CFS.c_int), 1, "response_len"), (CFS.POINTER(CFS.c_int), 1, "handled"), (CFS.c_int, 1, "dryrun"), ) fluid_synth_sysex.errcheck = _errcheck fluid_synth_program_select = _prototype( CFS.c_int, "fluid_synth_program_select", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), (CFS.c_int, 1, "sfont_id"), (CFS.c_int, 1, "bank_num"), (CFS.c_int, 1, "preset_num"), ) fluid_synth_program_select.errcheck = _errcheck fluid_synth_noteon = _prototype( CFS.c_int, "fluid_synth_noteon", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), (CFS.c_int, 1, "key"), (CFS.c_int, 1, "vel"), ) fluid_synth_noteon.errcheck = _errcheck fluid_synth_noteoff = _prototype( CFS.c_int, "fluid_synth_noteoff", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "chan"), (CFS.c_int, 1, "key"), ) fluid_synth_noteoff.errcheck = _errcheck fluid_synth_system_reset = _prototype( CFS.c_int, "fluid_synth_system_reset", (CFS.c_void_p, 1, "synth") ) fluid_synth_system_reset.errcheck = _errcheck # Synthesizer - MIDI Channel Setup # Synthesizer - MIDI Tuning # Synthesizer - SoundFont managiment # [API prototype] fluid_synth_add_sfont = _prototype( CFS.c_int, "fluid_synth_add_sfont", (CFS.c_void_p, 1, "synth"), (CFS.c_void_p, 1, "sfont"), ) fluid_synth_add_sfont.errcheck = _errcheck fluid_synth_sfload = _prototype( CFS.c_int, "fluid_synth_sfload", (CFS.c_void_p, 1, "synth"), (CFS.c_char_p, 1, "filename"), (CFS.c_int, 1, "reset_preset"), ) fluid_synth_sfload.errcheck = _errcheck fluid_synth_sfreload = _prototype( CFS.c_int, "fluid_synth_sfreload", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "id") ) fluid_synth_sfreload.errcheck = _errcheck fluid_synth_sfcount = _prototype( CFS.c_int, "fluid_synth_sfcount", (CFS.c_void_p, 1, "synth") ) fluid_synth_sfcount.errcheck = _errcheck fluid_synth_get_sfont = _prototype( CFS.c_void_p, "fluid_synth_get_sfont", (CFS.c_void_p, 1, "synth"), (CFS.c_uint, 1, "num"), ) fluid_synth_get_sfont.errcheck = _errcheck fluid_synth_get_sfont_by_id = _prototype( CFS.c_void_p, "fluid_synth_get_sfont_by_id", (CFS.c_void_p, 1, "synth"), (CFS.c_int, 1, "id"), ) fluid_synth_get_sfont_by_id.errcheck = _errcheck # Synthesizer - Synthesis Parameters # [API prototype] fluid_synth_get_gain = _prototype( CFS.c_float, "fluid_synth_get_gain", (CFS.c_void_p, 1, "synth") ) fluid_synth_get_gain.errcheck = _errcheck fluid_synth_set_gain = _prototype( None, "fluid_synth_set_gain", (CFS.c_void_p, 1, "synth"), (CFS.c_float, 1, "gain") ) # Synthesizer - Voice Control # [typing alias] PRESET = dict[str, Union[int, str, None]]
[ドキュメント]class Synthesizer: """SoundFont synthesizer. :param dict kwargs: kwargs = { 'settings':'config/settings.json', 'soundfont':['sf2/FluidR3_GM.sf2', 'sf2/SGM-V2.01.sf2']} """ def __init__(self, **kwargs: dict[str, Any]) -> None: try: for i in range(FLUID_LOG_LEVEL.LAST_LOG_LEVEL): fluid_set_log_function(level=i, fun=_log_func, data=None) self._settings: int = int(new_fluid_settings()) if "settings" in kwargs: self._customaize_settings(json_filename=str(kwargs["settings"])) self._synth: int = int( new_fluid_synth(settings=CFS.c_void_p(self._settings)) ) self._soundfonts: dict[str, int] = dict() # filename, sfont id if "soundfont" in kwargs: for s_name in kwargs["soundfont"]: self._soundfonts[s_name] = int( fluid_synth_sfload( synth=CFS.c_void_p(self._synth), filename=s_name.encode(), reset_preset=CFS.c_int(True), ) ) else: c_name = CFS.c_char_p() fluid_settings_getstr_default( settings=CFS.c_void_p(self._settings), name=b"synth.default-soundfont", str=CFS.byref(c_name), ) if c_name.value is not None: self._soundfonts[c_name.value.decode()] = int( fluid_synth_sfload( synth=CFS.c_void_p(self._synth), filename=c_name.value, reset_preset=CFS.c_int(True), ) ) self._gm_system_on() self._log(level=FLUID_LOG_LEVEL.INFO, message="gm system on") if type(self) == Synthesizer: self._assign_audio_driver() except FSError as msg: self._log( level=FLUID_LOG_LEVEL.ERR, message=f"Synthesizer failed. {str(msg)}" ) self.__del__() else: self._log( level=FLUID_LOG_LEVEL.INFO, message=f"libfluidsynth version: {self.version()}", ) def __del__(self) -> None: if type(self) == Synthesizer: self._delete_auido_driver() delete_fluid_synth(synth=CFS.c_void_p(self._synth)) delete_fluid_settings(settings=CFS.c_void_p(self._settings)) self._log(level=FLUID_LOG_LEVEL.INFO, message="good-bye") def _log(self, level: FLUID_LOG_LEVEL, message: str) -> None: fluid_log(level=CFS.c_int(level), fmt=b"%s", message=message.encode()) def _customaize_settings(self, json_filename: str) -> None: with open(file=json_filename, mode="r") as fp: settings_json = load(fp) for name, dicts in settings_json.items(): if ( isinstance(dicts["value"], float) and FLUID_TYPE(dicts["type"]) == FLUID_TYPE.NUM ): fluid_settings_setnum( settings=CFS.c_void_p(self._settings), name=str(name).encode(), value=CFS.c_double(dicts["value"]), ) elif ( isinstance(dicts["value"], int) and FLUID_TYPE(dicts["type"]) == FLUID_TYPE.INT ): fluid_settings_setint( settings=CFS.c_void_p(self._settings), name=str(name).encode(), val=CFS.c_int(dicts["value"]), ) elif ( isinstance(dicts["value"], str) and FLUID_TYPE(dicts["type"]) == FLUID_TYPE.STR ): fluid_settings_setstr( settings=CFS.c_void_p(self._settings), name=str(name).encode(), str=str(dicts["value"]).encode(), ) def _assign_audio_driver(self) -> int: self._audio_driver = int( new_fluid_audio_driver( settings=CFS.c_void_p(self._settings), synth=CFS.c_void_p(self._synth) ) ) return self._audio_driver def _delete_auido_driver(self) -> None: if hasattr(self, "_audio_driver"): delete_fluid_audio_driver(driver=CFS.c_void_p(self._audio_driver))
[ドキュメント] def version(self) -> str: """version _summary_ :return: _description_ """ return bytes(fluid_version_str()).decode()
def _gm_system_on(self) -> int: return int( fluid_synth_sysex( synth=CFS.c_void_p(self._synth), data=(CFS.c_char * 3)( CFS.c_char(0x7E), CFS.c_char(0x09), CFS.c_char(0x01) ), len=CFS.c_int(3), response=None, response_len=None, handled=None, dryrun=CFS.c_int(False), ) ) def _all_notes_off(self, chan: int = -1) -> int: return fluid_synth_all_notes_off( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan) ) def _all_sounds_off(self, chan: int = -1) -> int: return fluid_synth_all_sounds_off( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan) ) def _panic(self) -> int: return fluid_synth_system_reset(synth=CFS.c_void_p(self._synth)) @property def gain(self) -> float: """float: gain - defalt 0.2, Min 0.0, Max 10.0""" return float(fluid_synth_get_gain(synth=CFS.c_void_p(self._synth))) @gain.setter def gain(self, value: float) -> float: fluid_synth_set_gain(synth=CFS.c_void_p(self._synth), gain=CFS.c_float(value)) return float(fluid_synth_get_gain(synth=CFS.c_void_p(self._synth))) @property def soundfonts(self) -> list: """list(str): sonundfont file names""" return list(self._soundfonts.keys()) # filename
[ドキュメント] def gm_sound_set(self) -> tuple: # list[list[PRESET]]: """Get list of Sound Set (GM system level 1) from soundfont. :return: gm sound set - list[list[PRESET]] :return: gm percussion sound set - list[list[PRESET]] - soundfont - bank - PRESET(dict) - "name": str | None - "num" : int | None - "bank": int | None - "sfont_id": int | None """ sound_set: list = list() percussion_sound_set: list = list() # bank = 128: percussion for sfont_index in range( int(fluid_synth_sfcount(synth=CFS.c_void_p(self._synth))) - 1, -1, -1 ): sfont = int( fluid_synth_get_sfont( synth=CFS.c_void_p(self._synth), num=CFS.c_uint(sfont_index) ) ) if sound_set == []: sound_set = self._sfont_sound_set(sfont, 0) else: for preset in self._sfont_sound_set(sfont, 0): if isinstance(preset["num"], int): sound_set[preset["num"]] = preset if percussion_sound_set == []: percussion_sound_set = self._sfont_sound_set(sfont, 128) else: for preset in self._sfont_sound_set(sfont, 128): if isinstance(preset["num"], int): percussion_sound_set[preset["num"]] = preset return sound_set, percussion_sound_set
def _sfont_sound_set(self, sfont: int, bank: int) -> list[PRESET]: """_sfont_sound_set _summary_ :param int sfont: soundfont id :param int bank: bank :return: preset list - PRESET(dict) - "name": str | None - "num" : int | None - "bank": int | None - "sfont_id": int | None """ result: list[PRESET] = list() for n in range(128): preset = fluid_sfont_get_preset( sfont=CFS.c_void_p(sfont), bank=CFS.c_int(bank), prenum=CFS.c_int(n) ) result += [self._preset(preset)] return result
[ドキュメント] def channels_preset(self) -> list[PRESET]: """Get a list of presets per channel :return: preset list - PRESET(dict) - "name": str | None - "num" : int | None - "bank": int | None - "sfont_id": int | None """ result: list[PRESET] = list() for chan in range(15): result += [self._channel_preset(chan)] return result
def _channel_preset(self, chan: int) -> PRESET: """_channel_preset _summary_ :param int chan: channel number :return: preset - PRESET(dict) - "name": str | None - "num" : int | None - "bank": int | None - "sfont_id": int | None """ preset = int( fluid_synth_get_channel_preset( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan) ) ) return self._preset(preset) def _preset(self, preset: int) -> PRESET: """_preset _summary_ :param int preset: _description_ :return: preset - PRESET(dict) - "name": str | None - "num" : int | None - "bank": int | None - "sfont_id": int | None """ result: dict[str, Union[str, int, None]] = dict() if preset: result["name"] = bytes( fluid_preset_get_name(preset=CFS.c_void_p(preset)) ).decode() result["num"] = fluid_preset_get_num(preset=CFS.c_void_p(preset)) result["bank"] = fluid_preset_get_banknum(preset=CFS.c_void_p(preset)) result["sfont_id"] = fluid_sfont_get_id( sfont=fluid_preset_get_sfont(preset=CFS.c_void_p(preset)) ) else: result["name"] = None result["num"] = None result["bank"] = None result["sfont_id"] = None return result
[ドキュメント] def pitch_bend(self, chan: int, val: int) -> int: """pitch_bend _summary_ :param int chan: _description_ :param int val: _description_ :return: _description_ """ return fluid_synth_pitch_bend( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan), val=CFS.c_int(val) )
[ドキュメント] def pitch_wheel_sens(self, chan: int, val: int) -> int: """pitch_wheel_sens _summary_ :param int chan: _description_ :param int val: _description_ :return: _description_ """ return fluid_synth_pitch_wheel_sens( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan), val=CFS.c_int(val) )
[ドキュメント] def program_select(self, chan: int, sfont_id: int, bank: int, preset: int) -> int: """program_select _summary_ :param int chan: _description_ :param int sfont_id: _description_ :param int bank: _description_ :param int preset: _description_ :return: _description_ """ return fluid_synth_program_select( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan), sfont_id=CFS.c_int(sfont_id), bank_num=CFS.c_int(bank), preset_num=CFS.c_int(preset), )
[ドキュメント] def note_on(self, channel: int, keyNumber: int, velocity: int) -> int: """note_on _summary_ :param int channel: _description_ :param int keyNumber: _description_ :param int velocity: _description_ :return: _description_ """ return fluid_synth_noteon( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(channel), key=CFS.c_int(keyNumber), vel=CFS.c_int(velocity), )
[ドキュメント] def note_off(self, channel: int, keyNumber: int) -> int: """note_off _summary_ :param int channel: _description_ :param int keyNumber: _description_ :return: _description_ """ try: fluid_synth_noteoff( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(channel), key=CFS.c_int(keyNumber), ) return FLUID_OK except FSError as msg: self._log(level=FLUID_LOG_LEVEL.ERR, message=f"synth noteoff. {str(msg)}") return FLUID_FAILED
[ドキュメント] def modulation_wheel(self, chan: int, val: int) -> int: """The sound amplifies like vibrato. :param int chan: _description_ :param int val: _description_ :return: _description_ """ return fluid_synth_cc( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan), num=CFS.c_int(0x01), val=CFS.c_int(val), )
[ドキュメント] def volume(self, chan: int, val: int) -> int: """Set the maximum allowable value of velocity. :param int chan: _description_ :param int val: _description_ :return: _description_ """ return fluid_synth_cc( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan), num=CFS.c_int(0x07), val=CFS.c_int(val), )
[ドキュメント] def sustain_on(self, chan: int) -> int: """The sound echoes for a long time. :param int chan: _description_ :return: _description_ """ return fluid_synth_cc( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan), num=CFS.c_int(0x40), val=CFS.c_int(0b00100000), )
[ドキュメント] def sustain_off(self, chan: int) -> int: """sustain_off _summary_ :param int chan: _description_ :return: _description_ """ return fluid_synth_cc( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan), num=CFS.c_int(0x40), val=CFS.c_int(0b00000000), )
[ドキュメント] def pan(self, chan: int, val: int) -> int: """pan _summary_ :param int chan: _description_ :param int val: _description_ :return: _description_ """ return fluid_synth_cc( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan), num=CFS.c_int(0x0A), val=CFS.c_int(val), )
[ドキュメント] def expression(self, chan: int, val: int) -> int: """Temporary velocity can be set above volume. :param int chan: _description_ :param int val: _description_ :return: _description_ """ return fluid_synth_cc( synth=CFS.c_void_p(self._synth), chan=CFS.c_int(chan), num=CFS.c_int(0x0B), val=CFS.c_int(val), )
[ドキュメント]class Sequencer(Synthesizer): """Send MIDI events scheduled by the sequencer to the synthesizer. :param dict kwargs: kwargs = { 'settings':'config/settings.json', 'soundfont':['sf2/FluidR3_GM.sf2', 'sf2/SGM-V2.01.sf2']} """ clients: list[int] = list() def __init__(self, **kwargs: dict[str, Any]) -> None: super().__init__(**kwargs) try: self._sequencer: int self._bps: float = 120.0 self._quaternote: int = 240 self._callbacks: list[Callable] = list() self._sequencer = int( new_fluid_sequencer2(use_system_timer=CFS.c_int(False)) ) self.clients += [ int( fluid_sequencer_register_fluidsynth( seq=CFS.c_void_p(self._sequencer), synth=CFS.c_void_p(self._synth), ) ) ] self._set_time_scale() self._assign_audio_driver() except FSError as msg: self._log( level=FLUID_LOG_LEVEL.ERR, message=f"Sequencer failed. {str(msg)}" ) self.__del__() def __del__(self) -> None: self._delete_auido_driver() for client_id in self.clients[::-1]: fluid_sequencer_unregister_client( seq=CFS.c_void_p(self._sequencer), id=CFS.c_short(client_id) ) delete_fluid_sequencer(seq=CFS.c_void_p(self._sequencer)) super().__del__()
[ドキュメント] def client_name(self, id: int) -> str: """client_name _summary_ :param int id: _description_ :return: _description_ """ return fluid_sequencer_get_client_name( seq=CFS.c_void_p(self._sequencer), id=CFS.c_void_p(id) ).decode()
[ドキュメント] def register_client( self, name: str, callback: Union[Callable[..., None], None] = None, data: Union[EventUserData, None] = None, ) -> int: """Register a sequencer client. :param str name: Name of sequencer client :param Callable callback: Sequencer client callback or NULL for a source client. :param EventUserData data: User data to pass to the callback :return: Unique sequencer ID or FLUID_FAILED on error """ if callback: callback = FLUID_EVENT_CALLBACK_T(callback) self._callbacks += [callback] self.clients += [ int( fluid_sequencer_register_client( seq=CFS.c_void_p(self._sequencer), name=name.encode(), callback=callback if callback else None, data=CFS.byref(data) if data else None, ) ) ] return self.clients[len(self.clients) - 1]
@property def time_scale(self) -> float: """Ticks per second""" return float(fluid_sequencer_get_time_scale(seq=CFS.c_void_p(self._sequencer))) @property def bps(self) -> float: """Number of quarternotes per second""" return self._bps @bps.setter def bps(self, value: float) -> None: self._bps = value self._set_time_scale() @property def tick(self) -> int: """current tick of the sequencer scaled by the time scale currently set""" return int(fluid_sequencer_get_tick(seq=CFS.c_void_p(self._sequencer))) def _set_time_scale(self): fluid_sequencer_set_time_scale( seq=CFS.c_void_p(self._sequencer), scale=CFS.c_double(self._quaternote / (60 / self._bps)), )
[ドキュメント] def note_at( self, ticks: int, channel: int, key_number: int, velocity: int, duration: int, source: int = -1, destination: int = -1, absolute: bool = True, ) -> None: """note_at _summary_ :param int ticks: _description_ :param int channel: _description_ :param int key_number: _description_ :param int velocity: _description_ :param int duration: _description_ :param int source: _description_, defaults to -1 :param int destination: _description_, defaults to -1 :param bool absolute: _description_, defaults to True """ event = self._assign_event(source=source, destination=destination) fluid_event_note( evt=CFS.c_void_p(event), channel=CFS.c_int(channel), key=CFS.c_short(key_number), vel=CFS.c_short(velocity), duration=CFS.c_uint(duration), ) self._send_event_at(event=event, ticks=ticks, absolute=absolute)
[ドキュメント] def timer_at( self, ticks: int, data: Union[EventUserData, None] = None, source: int = -1, destination: int = -1, absolute: bool = True, ) -> None: """timer_at _summary_ :param int ticks: _description_ :param Union[EventUserData, None] data: _description_, defaults to None :param int source: _description_, defaults to -1 :param int destination: _description_, defaults to -1 :param bool absolute: _description_, defaults to True """ event = self._assign_event(source=source, destination=destination) fluid_event_timer( evt=CFS.c_void_p(event), data=CFS.pointer(data) if data else None ) self._send_event_at(event=event, ticks=ticks, absolute=absolute)
def _assign_event(self, source: int, destination: int) -> int: event = new_fluid_event() fluid_event_set_source(evt=event, src=CFS.c_short(source)) fluid_event_set_dest(evt=event, dest=CFS.c_short(destination)) return int(event) def _send_event_at(self, event: int, ticks: int, absolute: bool) -> int: result = fluid_sequencer_send_at( seq=CFS.c_void_p(self._sequencer), evt=CFS.c_void_p(event), time=CFS.c_uint(ticks), absolute=CFS.c_int(absolute), ) delete_fluid_event(evt=CFS.c_void_p(event)) return int(result)
[ドキュメント]class MidiRouter(Synthesizer): """Rule based transformation and filtering of MIDI events. :param dict kwargs: kwargs = { 'settings':'config/settings.json', 'soundfont':['sf2/FluidR3_GM.sf2', 'sf2/SGM-V2.01.sf2']} """ def __init__(self, **kwargs: dict[str, Any]) -> None: super().__init__(**kwargs) try: handler = fluid_synth_handle_midi_event self._midi_router: int = int( new_fluid_midi_router( settings=CFS.c_void_p(self._settings), handler=handler, event_handler_data=CFS.c_void_p(self._synth), ) ) self._cmd_handler: int = int( new_fluid_cmd_handler( synth=CFS.c_void_p(self._synth), router=CFS.c_void_p(self._midi_router), ) ) except FSError as msg: self._log(level=FLUID_LOG_LEVEL.ERR, message=f"Midi Router. {str(msg)}") self.__del__() def __del__(self) -> None: delete_fluid_cmd_handler(handler=CFS.c_void_p(self._cmd_handler)) delete_fluid_midi_router(router=CFS.c_void_p(self._midi_router)) super().__del__()
[ドキュメント] def apply_rules(self, rule_file: Union[str, None] = None) -> bool: """Apply rules for MIDI events. :param str rule_file: Rule file to be applied in json file, or default rules if none :return: True, or False """ try: fluid_midi_router_clear_rules(router=CFS.c_void_p(self._midi_router)) if rule_file is None: fluid_midi_router_set_default_rules( router=CFS.c_void_p(self._midi_router) ) else: with open(rule_file, "r") as fp: rules_json = load(fp) for rd in rules_json.values(): rule = new_fluid_midi_router_rule() if rd["chan"] is not None: fluid_midi_router_rule_set_chan(rule, *rd["chan"].values()) if rd["param1"] is not None: fluid_midi_router_rule_set_param1(rule, *rd["param1"].values()) if rd["param2"] is not None: fluid_midi_router_rule_set_param2(rule, *rd["param2"].values()) fluid_midi_router_add_rule(self._midi_router, rule, rd["type"]) except FSError as msg: self._log(level=FLUID_LOG_LEVEL.ERR, message=f"Midi Router Rule {str(msg)}") return False else: return True
[ドキュメント]class MidiDriver(MidiRouter): """Sends MIDI events received at the MIDI input to the synthesizer. :param dict kwargs: kwargs = { 'settings':'config/settings.json', 'soundfont':['sf2/FluidR3_GM.sf2', 'sf2/SGM-V2.01.sf2'], 'handler': fluid_midi_dump_prerouter} """ def __init__(self, **kwargs: dict[str, Any]) -> None: super().__init__(**kwargs) try: if "handler" in kwargs: callback = kwargs["handler"] else: callback = fluid_midi_router_handle_midi_event self._midi_driver: int = int( new_fluid_midi_driver( settings=CFS.c_void_p(self._settings), handler=callback, event_handler_data=CFS.c_void_p(self._midi_router), ) ) self._assign_audio_driver() except FSError as msg: self._log(level=FLUID_LOG_LEVEL.ERR, message=f"Midi Driver. {str(msg)}") self.__del__() def __del__(self) -> None: self._delete_auido_driver() delete_fluid_midi_driver(driver=CFS.c_void_p(self._midi_driver)) super().__del__()
[ドキュメント]class MidiPlayer(MidiRouter): """Parse standard MIDI files and emit MIDI events. :param dict kwargs: kwargs = { "settings":"config/settings.json", "soundfont":["sf2/FluidR3_GM.sf2", "sf2/SGM-V2.01.sf2"], "handler": fluid_midi_dump_prerouter, "standardmidifile": ["mid/SenBonZakura.mid", "mid/111867.MID"]} """ def __init__(self, **kwargs: dict[str, Any]) -> None: super().__init__(**kwargs) try: self._player: int = int(new_fluid_player(synth=CFS.c_void_p(self._synth))) if "handler" in kwargs: callback = kwargs["handler"] else: callback = fluid_midi_router_handle_midi_event fluid_player_set_playback_callback( player=CFS.c_void_p(self._player), handler=callback, handler_data=CFS.c_void_p(self._midi_router), ) for filename in kwargs["standardmidifile"]: if fluid_is_midifile(filename.encode()): print(filename) ptr: bytes = Path(filename).read_bytes() fluid_player_add_mem( player=CFS.c_void_p(self._player), buffer=ptr, len=CFS.c_size_t(len(ptr)), ) self._assign_audio_driver() except FSError as msg: self._log(level=FLUID_LOG_LEVEL.ERR, message=f"Midi Player. {str(msg)}") self.__del__() def __del__(self) -> None: self._delete_auido_driver() delete_fluid_player(player=CFS.c_void_p(self._player)) super().__del__()
[ドキュメント] def playback(self, start_tick: int = 0) -> None: """Start playback. :param start_tick: tick at the position where you want to start """ fluid_player_play(player=CFS.c_void_p(self._player)) sleep(0.1) # Wait for seekable fluid_player_seek( player=CFS.c_void_p(self._player), ticks=CFS.c_int(start_tick) ) fluid_player_join(player=CFS.c_void_p(self._player))
[ドキュメント] def stop(self) -> int: """Stop or end playback. :return: ticks when stopped """ fluid_player_stop(player=CFS.c_void_p(self._player)) fluid_player_join(player=CFS.c_void_p(self._player)) self._all_sounds_off() # Wait to clear Ringbuffer after EOT. return self.tick
@property def tick(self) -> int: """Get the number of tempo ticks passed.""" return int(fluid_player_get_current_tick(player=CFS.c_void_p(self._player))) @property def total_ticks(self) -> int: """Get total ticks.""" return int(fluid_player_get_total_ticks(player=CFS.c_void_p(self._player)))
if __name__ == "__main__": print(__file__)