diff --git a/fluidsynth.py b/fluidsynth.py index 5f9d699..017f170 100644 --- a/fluidsynth.py +++ b/fluidsynth.py @@ -23,19 +23,32 @@ """ from ctypes import ( - CDLL, CFUNCTYPE, POINTER, Structure, byref, c_void_p, create_string_buffer, c_char, - c_char_p, c_double, c_float, c_int, c_short, c_uint + CDLL, + CFUNCTYPE, + POINTER, + Structure, + byref, + c_void_p, + create_string_buffer, + c_char, + c_char_p, + c_double, + c_float, + c_int, + c_short, + c_uint, ) from ctypes.util import find_library import os # DLL search method changed in Python 3.8 # https://docs.python.org/3/library/os.html#os.add_dll_directory -if hasattr(os, 'add_dll_directory'): +if hasattr(os, "add_dll_directory"): os.add_dll_directory(os.getcwd()) - os.add_dll_directory('C:\\tools\\fluidsynth\\bin') + os.add_dll_directory("C:\\tools\\fluidsynth\\bin") # Workaround bug in find_library, it doesn't recognize add_dll_directory - os.environ['PATH'] += ';C:\\tools\\fluidsynth\\bin' + os.environ["PATH"] += ";C:\\tools\\fluidsynth\\bin" + # A function to find the FluidSynth library # (mostly needed for Windows distributions of libfluidsynth supplied with QSynth) @@ -59,12 +72,14 @@ def load_libfluidsynth(debug_print: bool = False) -> str: return lib raise ImportError("Couldn't find the FluidSynth library.") + lib = load_libfluidsynth() # Dynamically link the FluidSynth library # Architecture (32-/64-bit) must match your Python version _fl = CDLL(lib) + # Helper function for declaring function prototypes def cfunc(name, result, *args): """Build and apply a ctypes prototype complete with parameter flags""" @@ -75,21 +90,25 @@ def cfunc(name, result, *args): atypes.append(arg[1]) aflags.append((arg[2], arg[0]) + arg[3:]) return CFUNCTYPE(result, *atypes)((name, _fl), tuple(aflags)) - else: # Handle Fluidsynth 1.x, 2.x, etc. API differences + else: # Handle Fluidsynth 1.x, 2.x, etc. API differences return None + # Bump this up when changing the interface for users -api_version = '1.3.4' +api_version = "1.3.4" # Function prototypes for C versions of functions FLUID_OK = 0 FLUID_FAILED = -1 -fluid_version = cfunc('fluid_version', c_void_p, - ('major', POINTER(c_int), 1), - ('minor', POINTER(c_int), 1), - ('micro', POINTER(c_int), 1)) +fluid_version = cfunc( + "fluid_version", + c_void_p, + ("major", POINTER(c_int), 1), + ("minor", POINTER(c_int), 1), + ("micro", POINTER(c_int), 1), +) majver = c_int() fluid_version(majver, c_int(), c_int()) @@ -99,385 +118,529 @@ def cfunc(name, result, *args): FLUIDSETTING_EXISTS = 1 # fluid settings -new_fluid_settings = cfunc('new_fluid_settings', c_void_p) - -fluid_settings_setstr = cfunc('fluid_settings_setstr', c_int, - ('settings', c_void_p, 1), - ('name', c_char_p, 1), - ('str', c_char_p, 1)) - -fluid_settings_setnum = cfunc('fluid_settings_setnum', c_int, - ('settings', c_void_p, 1), - ('name', c_char_p, 1), - ('val', c_double, 1)) - -fluid_settings_setint = cfunc('fluid_settings_setint', c_int, - ('settings', c_void_p, 1), - ('name', c_char_p, 1), - ('val', c_int, 1)) - -fluid_settings_copystr = cfunc('fluid_settings_copystr', c_int, - ('settings', c_void_p, 1), - ('name', c_char_p, 1), - ('str', c_char_p, 1), - ('len', c_int, 1)) - -fluid_settings_getnum = cfunc('fluid_settings_getnum', c_int, - ('settings', c_void_p, 1), - ('name', c_char_p, 1), - ('val', POINTER(c_double), 1)) - -fluid_settings_getint = cfunc('fluid_settings_getint', c_int, - ('settings', c_void_p, 1), - ('name', c_char_p, 1), - ('val', POINTER(c_int), 1)) - -delete_fluid_settings = cfunc('delete_fluid_settings', None, - ('settings', c_void_p, 1)) - -fluid_synth_activate_key_tuning = cfunc('fluid_synth_activate_key_tuning', c_int, - ('synth', c_void_p, 1), - ('bank', c_int, 1), - ('prog', c_int, 1), - ('name', c_char_p, 1), - ('pitch', POINTER(c_double), 1), - ('apply', c_int, 1)) - -fluid_synth_activate_tuning = cfunc('fluid_synth_activate_tuning', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('bank', c_int, 1), - ('prog', c_int, 1), - ('apply', c_int, 1)) - -fluid_synth_deactivate_tuning = cfunc('fluid_synth_deactivate_tuning', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('apply', c_int, 1)) - -fluid_synth_tuning_dump = cfunc('fluid_synth_tuning_dump', c_int, - ('synth', c_void_p, 1), - ('bank', c_int, 1), - ('prog', c_int, 1), - ('name', c_char_p, 1), - ('length', c_int, 1), - ('pitch', POINTER(c_double), 1)) +new_fluid_settings = cfunc("new_fluid_settings", c_void_p) + +fluid_settings_setstr = cfunc( + "fluid_settings_setstr", + c_int, + ("settings", c_void_p, 1), + ("name", c_char_p, 1), + ("str", c_char_p, 1), +) + +fluid_settings_setnum = cfunc( + "fluid_settings_setnum", + c_int, + ("settings", c_void_p, 1), + ("name", c_char_p, 1), + ("val", c_double, 1), +) + +fluid_settings_setint = cfunc( + "fluid_settings_setint", + c_int, + ("settings", c_void_p, 1), + ("name", c_char_p, 1), + ("val", c_int, 1), +) + +fluid_settings_copystr = cfunc( + "fluid_settings_copystr", + c_int, + ("settings", c_void_p, 1), + ("name", c_char_p, 1), + ("str", c_char_p, 1), + ("len", c_int, 1), +) + +fluid_settings_getnum = cfunc( + "fluid_settings_getnum", + c_int, + ("settings", c_void_p, 1), + ("name", c_char_p, 1), + ("val", POINTER(c_double), 1), +) + +fluid_settings_getint = cfunc( + "fluid_settings_getint", + c_int, + ("settings", c_void_p, 1), + ("name", c_char_p, 1), + ("val", POINTER(c_int), 1), +) + +delete_fluid_settings = cfunc("delete_fluid_settings", None, ("settings", c_void_p, 1)) + +fluid_synth_activate_key_tuning = cfunc( + "fluid_synth_activate_key_tuning", + c_int, + ("synth", c_void_p, 1), + ("bank", c_int, 1), + ("prog", c_int, 1), + ("name", c_char_p, 1), + ("pitch", POINTER(c_double), 1), + ("apply", c_int, 1), +) + +fluid_synth_activate_tuning = cfunc( + "fluid_synth_activate_tuning", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("bank", c_int, 1), + ("prog", c_int, 1), + ("apply", c_int, 1), +) + +fluid_synth_deactivate_tuning = cfunc( + "fluid_synth_deactivate_tuning", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("apply", c_int, 1), +) + +fluid_synth_tuning_dump = cfunc( + "fluid_synth_tuning_dump", + c_int, + ("synth", c_void_p, 1), + ("bank", c_int, 1), + ("prog", c_int, 1), + ("name", c_char_p, 1), + ("length", c_int, 1), + ("pitch", POINTER(c_double), 1), +) # fluid synth -new_fluid_synth = cfunc('new_fluid_synth', c_void_p, - ('settings', c_void_p, 1)) - -delete_fluid_synth = cfunc('delete_fluid_synth', None, - ('synth', c_void_p, 1)) - -fluid_synth_sfload = cfunc('fluid_synth_sfload', c_int, - ('synth', c_void_p, 1), - ('filename', c_char_p, 1), - ('update_midi_presets', c_int, 1)) - -fluid_synth_sfunload = cfunc('fluid_synth_sfunload', c_int, - ('synth', c_void_p, 1), - ('sfid', c_int, 1), - ('update_midi_presets', c_int, 1)) - -fluid_synth_program_select = cfunc('fluid_synth_program_select', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('sfid', c_int, 1), - ('bank', c_int, 1), - ('preset', c_int, 1)) - -fluid_synth_noteon = cfunc('fluid_synth_noteon', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('key', c_int, 1), - ('vel', c_int, 1)) - -fluid_synth_noteoff = cfunc('fluid_synth_noteoff', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('key', c_int, 1)) - -fluid_synth_pitch_bend = cfunc('fluid_synth_pitch_bend', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('val', c_int, 1)) - -fluid_synth_cc = cfunc('fluid_synth_cc', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('ctrl', c_int, 1), - ('val', c_int, 1)) - -fluid_synth_get_cc = cfunc('fluid_synth_get_cc', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('num', c_int, 1), - ('pval', POINTER(c_int), 1)) - -fluid_synth_program_change = cfunc('fluid_synth_program_change', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('prg', c_int, 1)) - -fluid_synth_unset_program = cfunc('fluid_synth_unset_program', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1)) - -fluid_synth_get_program = cfunc('fluid_synth_get_program', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('sfont_id', POINTER(c_int), 1), - ('bank_num', POINTER(c_int), 1), - ('preset_num', POINTER(c_int), 1)) - -fluid_synth_bank_select = cfunc('fluid_synth_bank_select', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('bank', c_int, 1)) - -fluid_synth_sfont_select = cfunc('fluid_synth_sfont_select', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('sfid', c_int, 1)) - -fluid_synth_program_reset = cfunc('fluid_synth_program_reset', c_int, - ('synth', c_void_p, 1)) - -fluid_synth_system_reset = cfunc('fluid_synth_system_reset', c_int, - ('synth', c_void_p, 1)) - -fluid_synth_write_s16 = cfunc('fluid_synth_write_s16', c_void_p, - ('synth', c_void_p, 1), - ('len', c_int, 1), - ('lbuf', c_void_p, 1), - ('loff', c_int, 1), - ('lincr', c_int, 1), - ('rbuf', c_void_p, 1), - ('roff', c_int, 1), - ('rincr', c_int, 1)) - -fluid_synth_all_notes_off = cfunc('fluid_synth_all_notes_off', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1)) - -fluid_synth_all_sounds_off = cfunc('fluid_synth_all_sounds_off', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1)) +new_fluid_synth = cfunc("new_fluid_synth", c_void_p, ("settings", c_void_p, 1)) + +delete_fluid_synth = cfunc("delete_fluid_synth", None, ("synth", c_void_p, 1)) + +fluid_synth_sfload = cfunc( + "fluid_synth_sfload", + c_int, + ("synth", c_void_p, 1), + ("filename", c_char_p, 1), + ("update_midi_presets", c_int, 1), +) + +fluid_synth_sfunload = cfunc( + "fluid_synth_sfunload", + c_int, + ("synth", c_void_p, 1), + ("sfid", c_int, 1), + ("update_midi_presets", c_int, 1), +) + +fluid_synth_program_select = cfunc( + "fluid_synth_program_select", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("sfid", c_int, 1), + ("bank", c_int, 1), + ("preset", c_int, 1), +) + +fluid_synth_noteon = cfunc( + "fluid_synth_noteon", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("key", c_int, 1), + ("vel", c_int, 1), +) + +fluid_synth_noteoff = cfunc( + "fluid_synth_noteoff", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("key", c_int, 1), +) + +fluid_synth_pitch_bend = cfunc( + "fluid_synth_pitch_bend", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("val", c_int, 1), +) + +fluid_synth_cc = cfunc( + "fluid_synth_cc", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("ctrl", c_int, 1), + ("val", c_int, 1), +) + +fluid_synth_get_cc = cfunc( + "fluid_synth_get_cc", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("num", c_int, 1), + ("pval", POINTER(c_int), 1), +) + +fluid_synth_program_change = cfunc( + "fluid_synth_program_change", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("prg", c_int, 1), +) + +fluid_synth_unset_program = cfunc( + "fluid_synth_unset_program", c_int, ("synth", c_void_p, 1), ("chan", c_int, 1) +) + +fluid_synth_get_program = cfunc( + "fluid_synth_get_program", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("sfont_id", POINTER(c_int), 1), + ("bank_num", POINTER(c_int), 1), + ("preset_num", POINTER(c_int), 1), +) + +fluid_synth_bank_select = cfunc( + "fluid_synth_bank_select", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("bank", c_int, 1), +) + +fluid_synth_sfont_select = cfunc( + "fluid_synth_sfont_select", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("sfid", c_int, 1), +) + +fluid_synth_program_reset = cfunc( + "fluid_synth_program_reset", c_int, ("synth", c_void_p, 1) +) + +fluid_synth_system_reset = cfunc( + "fluid_synth_system_reset", c_int, ("synth", c_void_p, 1) +) + +fluid_synth_write_s16 = cfunc( + "fluid_synth_write_s16", + c_void_p, + ("synth", c_void_p, 1), + ("len", c_int, 1), + ("lbuf", c_void_p, 1), + ("loff", c_int, 1), + ("lincr", c_int, 1), + ("rbuf", c_void_p, 1), + ("roff", c_int, 1), + ("rincr", c_int, 1), +) + +fluid_synth_all_notes_off = cfunc( + "fluid_synth_all_notes_off", c_int, ("synth", c_void_p, 1), ("chan", c_int, 1) +) + +fluid_synth_all_sounds_off = cfunc( + "fluid_synth_all_sounds_off", c_int, ("synth", c_void_p, 1), ("chan", c_int, 1) +) class fluid_synth_channel_info_t(Structure): _fields_ = [ - ('assigned', c_int), - ('sfont_id', c_int), - ('bank', c_int), - ('program', c_int), - ('name', c_char*32), - ('reserved', c_char*32)] - -fluid_synth_get_channel_info = cfunc('fluid_synth_get_channel_info', c_int, - ('synth', c_void_p, 1), - ('chan', c_int, 1), - ('info', POINTER(fluid_synth_channel_info_t), 1)) - -fluid_synth_set_reverb_full = cfunc('fluid_synth_set_reverb_full', c_int, - ('synth', c_void_p, 1), - ('set', c_int, 1), - ('roomsize', c_double, 1), - ('damping', c_double, 1), - ('width', c_double, 1), - ('level', c_double, 1)) - -fluid_synth_set_chorus_full = cfunc('fluid_synth_set_chorus_full', c_int, - ('synth', c_void_p, 1), - ('set', c_int, 1), - ('nr', c_int, 1), - ('level', c_double, 1), - ('speed', c_double, 1), - ('depth_ms', c_double, 1), - ('type', c_int, 1)) - -fluid_synth_set_reverb = cfunc('fluid_synth_set_reverb', c_int, - ('synth', c_void_p, 1), - ('roomsize', c_double, 1), - ('damping', c_double, 1), - ('width', c_double, 1), - ('level', c_double, 1)) - -fluid_synth_set_chorus = cfunc('fluid_synth_set_chorus', c_int, - ('synth', c_void_p, 1), - ('nr', c_int, 1), - ('level', c_double, 1), - ('speed', c_double, 1), - ('depth_ms', c_double, 1), - ('type', c_int, 1)) - -fluid_synth_set_reverb_roomsize = cfunc('fluid_synth_set_reverb_roomsize', c_int, - ('synth', c_void_p, 1), - ('roomsize', c_double, 1)) - -fluid_synth_set_reverb_damp = cfunc('fluid_synth_set_reverb_damp', c_int, - ('synth', c_void_p, 1), - ('damping', c_double, 1)) - -fluid_synth_set_reverb_level = cfunc('fluid_synth_set_reverb_level', c_int, - ('synth', c_void_p, 1), - ('level', c_double, 1)) - -fluid_synth_set_reverb_width = cfunc('fluid_synth_set_reverb_width', c_int, - ('synth', c_void_p, 1), - ('width', c_double, 1)) - -fluid_synth_set_chorus_nr = cfunc('fluid_synth_set_chorus_nr', c_int, - ('synth', c_void_p, 1), - ('nr', c_int, 1)) - -fluid_synth_set_chorus_level = cfunc('fluid_synth_set_chorus_level', c_int, - ('synth', c_void_p, 1), - ('level', c_double, 1)) - -fluid_synth_set_chorus_speed = cfunc('fluid_synth_set_chorus_speed', c_int, - ('synth', c_void_p, 1), - ('speed', c_double, 1)) - -fluid_synth_set_chorus_depth = cfunc('fluid_synth_set_chorus_depth', c_int, - ('synth', c_void_p, 1), - ('depth_ms', c_double, 1)) - -fluid_synth_set_chorus_type = cfunc('fluid_synth_set_chorus_type', c_int, - ('synth', c_void_p, 1), - ('type', c_int, 1)) - -fluid_synth_get_reverb_roomsize = cfunc('fluid_synth_get_reverb_roomsize', c_double, - ('synth', c_void_p, 1)) - -fluid_synth_get_reverb_damp = cfunc('fluid_synth_get_reverb_damp', c_double, - ('synth', c_void_p, 1)) - -fluid_synth_get_reverb_level = cfunc('fluid_synth_get_reverb_level', c_double, - ('synth', c_void_p, 1)) - -fluid_synth_get_reverb_width = cfunc('fluid_synth_get_reverb_width', c_double, - ('synth', c_void_p, 1)) - - -fluid_synth_get_chorus_nr = cfunc('fluid_synth_get_chorus_nr', c_int, - ('synth', c_void_p, 1)) - -fluid_synth_get_chorus_level = cfunc('fluid_synth_get_chorus_level', c_double, - ('synth', c_void_p, 1)) - -fluid_synth_get_chorus_speed_Hz = cfunc('fluid_synth_get_chorus_speed_Hz', c_double, - ('synth', c_void_p, 1)) - -fluid_synth_get_chorus_depth_ms = cfunc('fluid_synth_get_chorus_depth_ms', c_double, - ('synth', c_void_p, 1)) - -fluid_synth_get_chorus_type = cfunc('fluid_synth_get_chorus_type', c_int, - ('synth', c_void_p, 1)) - -fluid_synth_set_midi_router = cfunc('fluid_synth_set_midi_router', None, - ('synth', c_void_p, 1), - ('router', c_void_p, 1)) + ("assigned", c_int), + ("sfont_id", c_int), + ("bank", c_int), + ("program", c_int), + ("name", c_char * 32), + ("reserved", c_char * 32), + ] + + +fluid_synth_get_channel_info = cfunc( + "fluid_synth_get_channel_info", + c_int, + ("synth", c_void_p, 1), + ("chan", c_int, 1), + ("info", POINTER(fluid_synth_channel_info_t), 1), +) + +fluid_synth_set_reverb_full = cfunc( + "fluid_synth_set_reverb_full", + c_int, + ("synth", c_void_p, 1), + ("set", c_int, 1), + ("roomsize", c_double, 1), + ("damping", c_double, 1), + ("width", c_double, 1), + ("level", c_double, 1), +) + +fluid_synth_set_chorus_full = cfunc( + "fluid_synth_set_chorus_full", + c_int, + ("synth", c_void_p, 1), + ("set", c_int, 1), + ("nr", c_int, 1), + ("level", c_double, 1), + ("speed", c_double, 1), + ("depth_ms", c_double, 1), + ("type", c_int, 1), +) + +fluid_synth_set_reverb = cfunc( + "fluid_synth_set_reverb", + c_int, + ("synth", c_void_p, 1), + ("roomsize", c_double, 1), + ("damping", c_double, 1), + ("width", c_double, 1), + ("level", c_double, 1), +) + +fluid_synth_set_chorus = cfunc( + "fluid_synth_set_chorus", + c_int, + ("synth", c_void_p, 1), + ("nr", c_int, 1), + ("level", c_double, 1), + ("speed", c_double, 1), + ("depth_ms", c_double, 1), + ("type", c_int, 1), +) -fluid_synth_handle_midi_event = cfunc('fluid_synth_handle_midi_event', c_int, - ('data', c_void_p, 1), - ('event', c_void_p, 1)) +fluid_synth_set_reverb_roomsize = cfunc( + "fluid_synth_set_reverb_roomsize", + c_int, + ("synth", c_void_p, 1), + ("roomsize", c_double, 1), +) + +fluid_synth_set_reverb_damp = cfunc( + "fluid_synth_set_reverb_damp", + c_int, + ("synth", c_void_p, 1), + ("damping", c_double, 1), +) + +fluid_synth_set_reverb_level = cfunc( + "fluid_synth_set_reverb_level", + c_int, + ("synth", c_void_p, 1), + ("level", c_double, 1), +) + +fluid_synth_set_reverb_width = cfunc( + "fluid_synth_set_reverb_width", + c_int, + ("synth", c_void_p, 1), + ("width", c_double, 1), +) + +fluid_synth_set_chorus_nr = cfunc( + "fluid_synth_set_chorus_nr", c_int, ("synth", c_void_p, 1), ("nr", c_int, 1) +) + +fluid_synth_set_chorus_level = cfunc( + "fluid_synth_set_chorus_level", + c_int, + ("synth", c_void_p, 1), + ("level", c_double, 1), +) + +fluid_synth_set_chorus_speed = cfunc( + "fluid_synth_set_chorus_speed", + c_int, + ("synth", c_void_p, 1), + ("speed", c_double, 1), +) + +fluid_synth_set_chorus_depth = cfunc( + "fluid_synth_set_chorus_depth", + c_int, + ("synth", c_void_p, 1), + ("depth_ms", c_double, 1), +) + +fluid_synth_set_chorus_type = cfunc( + "fluid_synth_set_chorus_type", c_int, ("synth", c_void_p, 1), ("type", c_int, 1) +) + +fluid_synth_get_reverb_roomsize = cfunc( + "fluid_synth_get_reverb_roomsize", c_double, ("synth", c_void_p, 1) +) + +fluid_synth_get_reverb_damp = cfunc( + "fluid_synth_get_reverb_damp", c_double, ("synth", c_void_p, 1) +) + +fluid_synth_get_reverb_level = cfunc( + "fluid_synth_get_reverb_level", c_double, ("synth", c_void_p, 1) +) + +fluid_synth_get_reverb_width = cfunc( + "fluid_synth_get_reverb_width", c_double, ("synth", c_void_p, 1) +) + + +fluid_synth_get_chorus_nr = cfunc( + "fluid_synth_get_chorus_nr", c_int, ("synth", c_void_p, 1) +) + +fluid_synth_get_chorus_level = cfunc( + "fluid_synth_get_chorus_level", c_double, ("synth", c_void_p, 1) +) + +fluid_synth_get_chorus_speed_Hz = cfunc( + "fluid_synth_get_chorus_speed_Hz", c_double, ("synth", c_void_p, 1) +) + +fluid_synth_get_chorus_depth_ms = cfunc( + "fluid_synth_get_chorus_depth_ms", c_double, ("synth", c_void_p, 1) +) + +fluid_synth_get_chorus_type = cfunc( + "fluid_synth_get_chorus_type", c_int, ("synth", c_void_p, 1) +) + +fluid_synth_set_midi_router = cfunc( + "fluid_synth_set_midi_router", None, ("synth", c_void_p, 1), ("router", c_void_p, 1) +) + +fluid_synth_handle_midi_event = cfunc( + "fluid_synth_handle_midi_event", + c_int, + ("data", c_void_p, 1), + ("event", c_void_p, 1), +) # fluid sequencer -new_fluid_sequencer2 = cfunc('new_fluid_sequencer2', c_void_p, - ('use_system_timer', c_int, 1)) +new_fluid_sequencer2 = cfunc( + "new_fluid_sequencer2", c_void_p, ("use_system_timer", c_int, 1) +) -fluid_sequencer_process = cfunc('fluid_sequencer_process', None, - ('seq', c_void_p, 1), - ('msec', c_uint, 1)) +fluid_sequencer_process = cfunc( + "fluid_sequencer_process", None, ("seq", c_void_p, 1), ("msec", c_uint, 1) +) -fluid_sequencer_register_fluidsynth = cfunc('fluid_sequencer_register_fluidsynth', c_short, - ('seq', c_void_p, 1), - ('synth', c_void_p, 1)) +fluid_sequencer_register_fluidsynth = cfunc( + "fluid_sequencer_register_fluidsynth", + c_short, + ("seq", c_void_p, 1), + ("synth", c_void_p, 1), +) -fluid_sequencer_register_client = cfunc('fluid_sequencer_register_client', c_short, - ('seq', c_void_p, 1), - ('name', c_char_p, 1), - ('callback', CFUNCTYPE(None, c_uint, c_void_p, c_void_p, c_void_p), 1), - ('data', c_void_p, 1)) +fluid_sequencer_register_client = cfunc( + "fluid_sequencer_register_client", + c_short, + ("seq", c_void_p, 1), + ("name", c_char_p, 1), + ("callback", CFUNCTYPE(None, c_uint, c_void_p, c_void_p, c_void_p), 1), + ("data", c_void_p, 1), +) -fluid_sequencer_get_tick = cfunc('fluid_sequencer_get_tick', c_uint, - ('seq', c_void_p, 1)) +fluid_sequencer_get_tick = cfunc( + "fluid_sequencer_get_tick", c_uint, ("seq", c_void_p, 1) +) -fluid_sequencer_set_time_scale = cfunc('fluid_sequencer_set_time_scale', None, - ('seq', c_void_p, 1), - ('scale', c_double, 1)) +fluid_sequencer_set_time_scale = cfunc( + "fluid_sequencer_set_time_scale", None, ("seq", c_void_p, 1), ("scale", c_double, 1) +) -fluid_sequencer_get_time_scale = cfunc('fluid_sequencer_get_time_scale', c_double, - ('seq', c_void_p, 1)) +fluid_sequencer_get_time_scale = cfunc( + "fluid_sequencer_get_time_scale", c_double, ("seq", c_void_p, 1) +) -fluid_sequencer_send_at = cfunc('fluid_sequencer_send_at', c_int, - ('seq', c_void_p, 1), - ('evt', c_void_p, 1), - ('time', c_uint, 1), - ('absolute', c_int, 1)) +fluid_sequencer_send_at = cfunc( + "fluid_sequencer_send_at", + c_int, + ("seq", c_void_p, 1), + ("evt", c_void_p, 1), + ("time", c_uint, 1), + ("absolute", c_int, 1), +) -delete_fluid_sequencer = cfunc('delete_fluid_sequencer', None, - ('seq', c_void_p, 1)) +delete_fluid_sequencer = cfunc("delete_fluid_sequencer", None, ("seq", c_void_p, 1)) # fluid event -new_fluid_event = cfunc('new_fluid_event', c_void_p) +new_fluid_event = cfunc("new_fluid_event", c_void_p) -fluid_event_set_source = cfunc('fluid_event_set_source', None, - ('evt', c_void_p, 1), - ('src', c_void_p, 1)) +fluid_event_set_source = cfunc( + "fluid_event_set_source", None, ("evt", c_void_p, 1), ("src", c_void_p, 1) +) -fluid_event_set_dest = cfunc('fluid_event_set_dest', None, - ('evt', c_void_p, 1), - ('dest', c_void_p, 1)) +fluid_event_set_dest = cfunc( + "fluid_event_set_dest", None, ("evt", c_void_p, 1), ("dest", c_void_p, 1) +) -fluid_event_timer = cfunc('fluid_event_timer', None, - ('evt', c_void_p, 1), - ('data', c_void_p, 1)) +fluid_event_timer = cfunc( + "fluid_event_timer", None, ("evt", c_void_p, 1), ("data", c_void_p, 1) +) -fluid_event_note = cfunc('fluid_event_note', None, - ('evt', c_void_p, 1), - ('channel', c_int, 1), - ('key', c_short, 1), - ('vel', c_short, 1), - ('duration', c_uint, 1)) +fluid_event_note = cfunc( + "fluid_event_note", + None, + ("evt", c_void_p, 1), + ("channel", c_int, 1), + ("key", c_short, 1), + ("vel", c_short, 1), + ("duration", c_uint, 1), +) -fluid_event_noteon = cfunc('fluid_event_noteon', None, - ('evt', c_void_p, 1), - ('channel', c_int, 1), - ('key', c_short, 1), - ('vel', c_short, 1)) +fluid_event_noteon = cfunc( + "fluid_event_noteon", + None, + ("evt", c_void_p, 1), + ("channel", c_int, 1), + ("key", c_short, 1), + ("vel", c_short, 1), +) -fluid_event_noteoff = cfunc('fluid_event_noteoff', None, - ('evt', c_void_p, 1), - ('channel', c_int, 1), - ('key', c_short, 1)) +fluid_event_noteoff = cfunc( + "fluid_event_noteoff", + None, + ("evt", c_void_p, 1), + ("channel", c_int, 1), + ("key", c_short, 1), +) -delete_fluid_event = cfunc('delete_fluid_event', None, - ('evt', c_void_p, 1)) +delete_fluid_event = cfunc("delete_fluid_event", None, ("evt", c_void_p, 1)) -fluid_midi_event_get_channel = cfunc('fluid_midi_event_get_channel', c_int, - ('evt', c_void_p, 1)) +fluid_midi_event_get_channel = cfunc( + "fluid_midi_event_get_channel", c_int, ("evt", c_void_p, 1) +) -fluid_midi_event_get_control = cfunc('fluid_midi_event_get_control', c_int, - ('evt', c_void_p, 1)) +fluid_midi_event_get_control = cfunc( + "fluid_midi_event_get_control", c_int, ("evt", c_void_p, 1) +) -fluid_midi_event_get_program = cfunc('fluid_midi_event_get_program', c_int, - ('evt', c_void_p, 1)) +fluid_midi_event_get_program = cfunc( + "fluid_midi_event_get_program", c_int, ("evt", c_void_p, 1) +) -fluid_midi_event_get_key = cfunc('fluid_midi_event_get_key', c_int, - ('evt', c_void_p, 1)) +fluid_midi_event_get_key = cfunc( + "fluid_midi_event_get_key", c_int, ("evt", c_void_p, 1) +) -fluid_midi_event_get_type = cfunc('fluid_midi_event_get_type', c_int, - ('evt', c_void_p, 1)) +fluid_midi_event_get_type = cfunc( + "fluid_midi_event_get_type", c_int, ("evt", c_void_p, 1) +) -fluid_midi_event_get_value = cfunc('fluid_midi_event_get_value', c_int, - ('evt', c_void_p, 1)) +fluid_midi_event_get_value = cfunc( + "fluid_midi_event_get_value", c_int, ("evt", c_void_p, 1) +) -fluid_midi_event_get_velocity = cfunc('fluid_midi_event_get_velocity', c_int, - ('evt', c_void_p, 1)) +fluid_midi_event_get_velocity = cfunc( + "fluid_midi_event_get_velocity", c_int, ("evt", c_void_p, 1) +) # fluid_player_status returned by fluid_player_get_status() FLUID_PLAYER_READY = 0 @@ -490,154 +653,200 @@ class fluid_synth_channel_info_t(Structure): FLUID_PLAYER_TEMPO_EXTERNAL_BPM = 1 FLUID_PLAYER_TEMPO_EXTERNAL_MIDI = 2 -new_fluid_player = cfunc('new_fluid_player', c_void_p, - ('synth', c_void_p, 1)) +new_fluid_player = cfunc("new_fluid_player", c_void_p, ("synth", c_void_p, 1)) -delete_fluid_player = cfunc('delete_fluid_player', None, - ('player', c_void_p, 1)) +delete_fluid_player = cfunc("delete_fluid_player", None, ("player", c_void_p, 1)) -fluid_player_add = cfunc('fluid_player_add', c_int, - ('player', c_void_p, 1), - ('filename', c_char_p, 1)) +fluid_player_add = cfunc( + "fluid_player_add", c_int, ("player", c_void_p, 1), ("filename", c_char_p, 1) +) -fluid_player_get_status = cfunc('fluid_player_get_status', c_int, - ('player', c_void_p, 1)) -fluid_player_join = cfunc('fluid_player_join', c_int, - ('player', c_void_p, 1)) +fluid_player_get_status = cfunc( + "fluid_player_get_status", c_int, ("player", c_void_p, 1) +) +fluid_player_join = cfunc("fluid_player_join", c_int, ("player", c_void_p, 1)) -fluid_player_play = cfunc('fluid_player_play', c_int, - ('player', c_void_p, 1)) +fluid_player_play = cfunc("fluid_player_play", c_int, ("player", c_void_p, 1)) -fluid_player_set_playback_callback = cfunc('fluid_player_set_playback_callback', c_int, - ('player', c_void_p, 1), - ('handler', CFUNCTYPE(c_int, c_void_p, c_void_p), 1), - ('event_handler_data', c_void_p, 1)) +fluid_player_set_playback_callback = cfunc( + "fluid_player_set_playback_callback", + c_int, + ("player", c_void_p, 1), + ("handler", CFUNCTYPE(c_int, c_void_p, c_void_p), 1), + ("event_handler_data", c_void_p, 1), +) -fluid_player_set_tempo = cfunc('fluid_player_set_tempo', c_int, - ('player', c_void_p, 1), - ('tempo_type', c_int, 1), - ('tempo', c_double, 1)) +fluid_player_set_tempo = cfunc( + "fluid_player_set_tempo", + c_int, + ("player", c_void_p, 1), + ("tempo_type", c_int, 1), + ("tempo", c_double, 1), +) -fluid_player_seek = cfunc('fluid_player_seek', c_int, - ('player', c_void_p, 1), - ('ticks', c_int, 1)) +fluid_player_seek = cfunc( + "fluid_player_seek", c_int, ("player", c_void_p, 1), ("ticks", c_int, 1) +) -fluid_player_stop = cfunc('fluid_player_stop', c_int, - ('player', c_void_p, 1)) +fluid_player_stop = cfunc("fluid_player_stop", c_int, ("player", c_void_p, 1)) # fluid audio driver -new_fluid_audio_driver = cfunc('new_fluid_audio_driver', c_void_p, - ('settings', c_void_p, 1), - ('synth', c_void_p, 1)) +new_fluid_audio_driver = cfunc( + "new_fluid_audio_driver", + c_void_p, + ("settings", c_void_p, 1), + ("synth", c_void_p, 1), +) -delete_fluid_audio_driver = cfunc('delete_fluid_audio_driver', None, - ('driver', c_void_p, 1)) +delete_fluid_audio_driver = cfunc( + "delete_fluid_audio_driver", None, ("driver", c_void_p, 1) +) # fluid midi driver -new_fluid_midi_driver = cfunc('new_fluid_midi_driver', c_void_p, - ('settings', c_void_p, 1), - ('handler', CFUNCTYPE(c_int, c_void_p, c_void_p), 1), - ('event_handler_data', c_void_p, 1)) +new_fluid_midi_driver = cfunc( + "new_fluid_midi_driver", + c_void_p, + ("settings", c_void_p, 1), + ("handler", CFUNCTYPE(c_int, c_void_p, c_void_p), 1), + ("event_handler_data", c_void_p, 1), +) # fluid midi router rule class fluid_midi_router_t(Structure): _fields_ = [ - ('synth', c_void_p), - ('rules_mutex', c_void_p), - ('rules', c_void_p*6), - ('free_rules', c_void_p), - ('event_handler', c_void_p), - ('event_handler_data', c_void_p), - ('nr_midi_channels', c_int), - ('cmd_rule', c_void_p), - ('cmd_rule_type', POINTER(c_int))] - -delete_fluid_midi_router_rule = cfunc('delete_fluid_midi_router_rule', c_int, - ('rule', c_void_p, 1)) - -new_fluid_midi_router_rule = cfunc('new_fluid_midi_router_rule', c_void_p) - -fluid_midi_router_rule_set_chan = cfunc('fluid_midi_router_rule_set_chan', None, - ('rule', c_void_p, 1), - ('min', c_int, 1), - ('max', c_int, 1), - ('mul', c_float, 1), - ('add', c_int, 1)) - -fluid_midi_router_rule_set_param1 = cfunc('fluid_midi_router_rule_set_param1', None, - ('rule', c_void_p, 1), - ('min', c_int, 1), - ('max', c_int, 1), - ('mul', c_float, 1), - ('add', c_int, 1)) - -fluid_midi_router_rule_set_param2 = cfunc('fluid_midi_router_rule_set_param2', None, - ('rule', c_void_p, 1), - ('min', c_int, 1), - ('max', c_int, 1), - ('mul', c_float, 1), - ('add', c_int, 1)) + ("synth", c_void_p), + ("rules_mutex", c_void_p), + ("rules", c_void_p * 6), + ("free_rules", c_void_p), + ("event_handler", c_void_p), + ("event_handler_data", c_void_p), + ("nr_midi_channels", c_int), + ("cmd_rule", c_void_p), + ("cmd_rule_type", POINTER(c_int)), + ] + + +delete_fluid_midi_router_rule = cfunc( + "delete_fluid_midi_router_rule", c_int, ("rule", c_void_p, 1) +) + +new_fluid_midi_router_rule = cfunc("new_fluid_midi_router_rule", c_void_p) + +fluid_midi_router_rule_set_chan = cfunc( + "fluid_midi_router_rule_set_chan", + None, + ("rule", c_void_p, 1), + ("min", c_int, 1), + ("max", c_int, 1), + ("mul", c_float, 1), + ("add", c_int, 1), +) + +fluid_midi_router_rule_set_param1 = cfunc( + "fluid_midi_router_rule_set_param1", + None, + ("rule", c_void_p, 1), + ("min", c_int, 1), + ("max", c_int, 1), + ("mul", c_float, 1), + ("add", c_int, 1), +) + +fluid_midi_router_rule_set_param2 = cfunc( + "fluid_midi_router_rule_set_param2", + None, + ("rule", c_void_p, 1), + ("min", c_int, 1), + ("max", c_int, 1), + ("mul", c_float, 1), + ("add", c_int, 1), +) # fluid midi router -new_fluid_midi_router = cfunc('new_fluid_midi_router', POINTER(fluid_midi_router_t), - ('settings', c_void_p, 1), - ('handler', CFUNCTYPE(c_int, c_void_p, c_void_p), 1), - ('event_handler_data', c_void_p, 1)) +new_fluid_midi_router = cfunc( + "new_fluid_midi_router", + POINTER(fluid_midi_router_t), + ("settings", c_void_p, 1), + ("handler", CFUNCTYPE(c_int, c_void_p, c_void_p), 1), + ("event_handler_data", c_void_p, 1), +) -fluid_midi_router_handle_midi_event = cfunc('fluid_midi_router_handle_midi_event', c_int, - ('data', c_void_p, 1), - ('event', c_void_p, 1)) +fluid_midi_router_handle_midi_event = cfunc( + "fluid_midi_router_handle_midi_event", + c_int, + ("data", c_void_p, 1), + ("event", c_void_p, 1), +) -fluid_midi_router_clear_rules = cfunc('fluid_midi_router_clear_rules', c_int, - ('router', POINTER(fluid_midi_router_t), 1)) +fluid_midi_router_clear_rules = cfunc( + "fluid_midi_router_clear_rules", c_int, ("router", POINTER(fluid_midi_router_t), 1) +) -fluid_midi_router_set_default_rules = cfunc('fluid_midi_router_set_default_rules', c_int, - ('router', POINTER(fluid_midi_router_t), 1)) +fluid_midi_router_set_default_rules = cfunc( + "fluid_midi_router_set_default_rules", + c_int, + ("router", POINTER(fluid_midi_router_t), 1), +) -fluid_midi_router_add_rule = cfunc('fluid_midi_router_add_rule', c_int, - ('router', POINTER(fluid_midi_router_t), 1), - ('rule', c_void_p, 1), - ('type', c_int, 1)) +fluid_midi_router_add_rule = cfunc( + "fluid_midi_router_add_rule", + c_int, + ("router", POINTER(fluid_midi_router_t), 1), + ("rule", c_void_p, 1), + ("type", c_int, 1), +) # fluidsynth 2.x -new_fluid_cmd_handler=cfunc('new_fluid_cmd_handler', c_void_p, - ('synth', c_void_p, 1), - ('router', c_void_p, 1)) +new_fluid_cmd_handler = cfunc( + "new_fluid_cmd_handler", c_void_p, ("synth", c_void_p, 1), ("router", c_void_p, 1) +) -fluid_synth_get_sfont_by_id = cfunc('fluid_synth_get_sfont_by_id', c_void_p, - ('synth', c_void_p, 1), - ('id', c_int, 1)) +fluid_synth_get_sfont_by_id = cfunc( + "fluid_synth_get_sfont_by_id", c_void_p, ("synth", c_void_p, 1), ("id", c_int, 1) +) -fluid_sfont_get_preset = cfunc('fluid_sfont_get_preset', c_void_p, - ('sfont', c_void_p, 1), - ('banknum', c_int, 1), - ('prenum', c_int, 1)) +fluid_sfont_get_preset = cfunc( + "fluid_sfont_get_preset", + c_void_p, + ("sfont", c_void_p, 1), + ("banknum", c_int, 1), + ("prenum", c_int, 1), +) -fluid_preset_get_name = cfunc('fluid_preset_get_name', c_char_p, - ('preset', c_void_p, 1)) +fluid_preset_get_name = cfunc( + "fluid_preset_get_name", c_char_p, ("preset", c_void_p, 1) +) -fluid_synth_set_reverb = cfunc('fluid_synth_set_reverb', c_int, - ('synth', c_void_p, 1), - ('roomsize', c_double, 1), - ('damping', c_double, 1), - ('width', c_double, 1), - ('level', c_double, 1)) +fluid_synth_set_reverb = cfunc( + "fluid_synth_set_reverb", + c_int, + ("synth", c_void_p, 1), + ("roomsize", c_double, 1), + ("damping", c_double, 1), + ("width", c_double, 1), + ("level", c_double, 1), +) -fluid_synth_set_chorus = cfunc('fluid_synth_set_chorus', c_int, - ('synth', c_void_p, 1), - ('nr', c_int, 1), - ('level', c_double, 1), - ('speed', c_double, 1), - ('depth_ms', c_double, 1), - ('type', c_int, 1)) +fluid_synth_set_chorus = cfunc( + "fluid_synth_set_chorus", + c_int, + ("synth", c_void_p, 1), + ("nr", c_int, 1), + ("level", c_double, 1), + ("speed", c_double, 1), + ("depth_ms", c_double, 1), + ("type", c_int, 1), +) -fluid_synth_get_chorus_speed = cfunc('fluid_synth_get_chorus_speed', c_double, - ('synth', c_void_p, 1)) +fluid_synth_get_chorus_speed = cfunc( + "fluid_synth_get_chorus_speed", c_double, ("synth", c_void_p, 1) +) -fluid_synth_get_chorus_depth = cfunc('fluid_synth_get_chorus_depth', c_double, - ('synth', c_void_p, 1)) +fluid_synth_get_chorus_depth = cfunc( + "fluid_synth_get_chorus_depth", c_double, ("synth", c_void_p, 1) +) def fluid_synth_write_s16_stereo(synth, len): @@ -647,6 +856,7 @@ def fluid_synth_write_s16_stereo(synth, len): """ import numpy + buf = create_string_buffer(len * 4) fluid_synth_write_s16(synth, len, buf, 0, 2, buf, 1, 2) return numpy.frombuffer(buf[:], dtype=numpy.int16) @@ -654,8 +864,10 @@ def fluid_synth_write_s16_stereo(synth, len): # Object-oriented interface, simplifies access to functions + class Synth: """Synth represents a FluidSynth synthesizer""" + def __init__(self, gain=0.2, samplerate=44100, channels=256, **kwargs): """Create new synthesizer object to control sound generation @@ -666,15 +878,16 @@ def __init__(self, gain=0.2, samplerate=44100, channels=256, **kwargs): added capability for passing arbitrary fluid settings using args """ self.settings = new_fluid_settings() - self.setting('synth.gain', gain) - self.setting('synth.sample-rate', float(samplerate)) - self.setting('synth.midi-channels', channels) - for opt,val in kwargs.items(): + self.setting("synth.gain", gain) + self.setting("synth.sample-rate", float(samplerate)) + self.setting("synth.midi-channels", channels) + for opt, val in kwargs.items(): self.setting(opt, val) self.synth = new_fluid_synth(self.settings) self.audio_driver = None self.midi_driver = None self.router = None + def setting(self, opt, val): """change an arbitrary synth setting, type-smart""" if isinstance(val, (str, bytes)): @@ -683,16 +896,26 @@ def setting(self, opt, val): fluid_settings_setint(self.settings, opt.encode(), val) elif isinstance(val, float): fluid_settings_setnum(self.settings, opt.encode(), c_double(val)) + def get_setting(self, opt): """get current value of an arbitrary synth setting""" val = c_int() - if fluid_settings_getint(self.settings, opt.encode(), byref(val)) == FLUIDSETTING_EXISTS: + if ( + fluid_settings_getint(self.settings, opt.encode(), byref(val)) + == FLUIDSETTING_EXISTS + ): return val.value strval = create_string_buffer(32) - if fluid_settings_copystr(self.settings, opt.encode(), strval, 32) == FLUIDSETTING_EXISTS: + if ( + fluid_settings_copystr(self.settings, opt.encode(), strval, 32) + == FLUIDSETTING_EXISTS + ): return strval.value.decode() num = c_double() - if fluid_settings_getnum(self.settings, opt.encode(), byref(num)) == FLUIDSETTING_EXISTS: + if ( + fluid_settings_getnum(self.settings, opt.encode(), byref(num)) + == FLUIDSETTING_EXISTS + ): return round(num.value, 6) return None @@ -709,25 +932,33 @@ def start(self, driver=None, device=None, midi_driver=None, midi_router=None): midi_driver : the midi driver to use for communicating with midi devices see http://www.fluidsynth.org/api/fluidsettings.xml for allowed values and defaults by platform """ - driver = driver or self.get_setting('audio.driver') - device = device or self.get_setting('audio.%s.device' % driver) - midi_driver = midi_driver or self.get_setting('midi.driver') + driver = driver or self.get_setting("audio.driver") + device = device or self.get_setting("audio.%s.device" % driver) + midi_driver = midi_driver or self.get_setting("midi.driver") - self.setting('audio.driver', driver) - self.setting('audio.%s.device' % driver, device) + self.setting("audio.driver", driver) + self.setting("audio.%s.device" % driver, device) self.audio_driver = new_fluid_audio_driver(self.settings, self.synth) - self.setting('midi.driver', midi_driver) - self.router = new_fluid_midi_router(self.settings, fluid_synth_handle_midi_event, self.synth) + self.setting("midi.driver", midi_driver) + self.router = new_fluid_midi_router( + self.settings, fluid_synth_handle_midi_event, self.synth + ) if new_fluid_cmd_handler: new_fluid_cmd_handler(self.synth, self.router) else: fluid_synth_set_midi_router(self.synth, self.router) - if midi_router is None: ## Use fluidsynth to create a MIDI event handler - self.midi_driver = new_fluid_midi_driver(self.settings, fluid_midi_router_handle_midi_event, self.router) + if midi_router is None: ## Use fluidsynth to create a MIDI event handler + self.midi_driver = new_fluid_midi_driver( + self.settings, fluid_midi_router_handle_midi_event, self.router + ) self.custom_router_callback = None - else: ## Supply an external MIDI event handler - self.custom_router_callback = CFUNCTYPE(c_int, c_void_p, c_void_p)(midi_router) - self.midi_driver = new_fluid_midi_driver(self.settings, self.custom_router_callback, self.router) + else: ## Supply an external MIDI event handler + self.custom_router_callback = CFUNCTYPE(c_int, c_void_p, c_void_p)( + midi_router + ) + self.midi_driver = new_fluid_midi_driver( + self.settings, self.custom_router_callback, self.router + ) return FLUID_OK def delete(self): @@ -735,89 +966,111 @@ def delete(self): delete_fluid_audio_driver(self.audio_driver) delete_fluid_synth(self.synth) delete_fluid_settings(self.settings) + def sfload(self, filename, update_midi_preset=0): """Load SoundFont and return its ID""" return fluid_synth_sfload(self.synth, filename.encode(), update_midi_preset) + def sfunload(self, sfid, update_midi_preset=0): """Unload a SoundFont and free memory it used""" return fluid_synth_sfunload(self.synth, sfid, update_midi_preset) + def program_select(self, chan, sfid, bank, preset): """Select a program""" return fluid_synth_program_select(self.synth, chan, sfid, bank, preset) + def program_unset(self, chan): """Set the preset of a MIDI channel to an unassigned state""" return fluid_synth_unset_program(self.synth, chan) + def channel_info(self, chan): """get soundfont, bank, prog, preset name of channel""" if fluid_synth_get_channel_info is not None: - info=fluid_synth_channel_info_t() + info = fluid_synth_channel_info_t() fluid_synth_get_channel_info(self.synth, chan, byref(info)) return (info.sfont_id, info.bank, info.program, info.name) else: (sfontid, banknum, presetnum) = self.program_info(chan) presetname = self.sfpreset_name(sfontid, banknum, presetnum) return (sfontid, banknum, presetnum, presetname) + def program_info(self, chan): """get active soundfont, bank, prog on a channel""" if fluid_synth_get_program is not None: - sfontid=c_int() - banknum=c_int() - presetnum=c_int() - fluid_synth_get_program(self.synth, chan, byref(sfontid), byref(banknum), byref(presetnum)) + sfontid = c_int() + banknum = c_int() + presetnum = c_int() + fluid_synth_get_program( + self.synth, chan, byref(sfontid), byref(banknum), byref(presetnum) + ) return (sfontid.value, banknum.value, presetnum.value) else: (sfontid, banknum, prognum, presetname) = self.channel_info(chan) return (sfontid, banknum, prognum) + def sfpreset_name(self, sfid, bank, prenum): """Return name of a soundfont preset""" if fluid_synth_get_sfont_by_id is not None: - sfont=fluid_synth_get_sfont_by_id(self.synth, sfid) - preset=fluid_sfont_get_preset(sfont, bank, prenum) + sfont = fluid_synth_get_sfont_by_id(self.synth, sfid) + preset = fluid_sfont_get_preset(sfont, bank, prenum) if not preset: return None - return fluid_preset_get_name(preset).decode('ascii') + return fluid_preset_get_name(preset).decode("ascii") else: return None + def router_clear(self): if self.router is not None: fluid_midi_router_clear_rules(self.router) + def router_default(self): if self.router is not None: fluid_midi_router_set_default_rules(self.router) + def router_begin(self, type): """types are [note|cc|prog|pbend|cpress|kpress]""" if self.router is not None: - if type=='note': - self.router.cmd_rule_type=0 - elif type=='cc': - self.router.cmd_rule_type=1 - elif type=='prog': - self.router.cmd_rule_type=2 - elif type=='pbend': - self.router.cmd_rule_type=3 - elif type=='cpress': - self.router.cmd_rule_type=4 - elif type=='kpress': - self.router.cmd_rule_type=5 - if 'self.router.cmd_rule' in globals(): + if type == "note": + self.router.cmd_rule_type = 0 + elif type == "cc": + self.router.cmd_rule_type = 1 + elif type == "prog": + self.router.cmd_rule_type = 2 + elif type == "pbend": + self.router.cmd_rule_type = 3 + elif type == "cpress": + self.router.cmd_rule_type = 4 + elif type == "kpress": + self.router.cmd_rule_type = 5 + if "self.router.cmd_rule" in globals(): delete_fluid_midi_router_rule(self.router.cmd_rule) self.router.cmd_rule = new_fluid_midi_router_rule() + def router_end(self): if self.router is not None: if self.router.cmd_rule is None: return - if fluid_midi_router_add_rule(self.router, self.router.cmd_rule, self.router.cmd_rule_type)<0: + if ( + fluid_midi_router_add_rule( + self.router, self.router.cmd_rule, self.router.cmd_rule_type + ) + < 0 + ): delete_fluid_midi_router_rule(self.router.cmd_rule) - self.router.cmd_rule=None + self.router.cmd_rule = None + def router_chan(self, min, max, mul, add): if self.router is not None: fluid_midi_router_rule_set_chan(self.router.cmd_rule, min, max, mul, add) + def router_par1(self, min, max, mul, add): if self.router is not None: fluid_midi_router_rule_set_param1(self.router.cmd_rule, min, max, mul, add) + def router_par2(self, min, max, mul, add): if self.router is not None: fluid_midi_router_rule_set_param2(self.router.cmd_rule, min, max, mul, add) + def set_reverb(self, roomsize=-1.0, damping=-1.0, width=-1.0, level=-1.0): """ roomsize Reverb room size value (0.0-1.0) @@ -828,16 +1081,19 @@ def set_reverb(self, roomsize=-1.0, damping=-1.0, width=-1.0, level=-1.0): if fluid_synth_set_reverb is not None: return fluid_synth_set_reverb(self.synth, roomsize, damping, width, level) else: - flags=0 - if roomsize>=0: - flags+=0b0001 - if damping>=0: - flags+=0b0010 - if width>=0: - flags+=0b0100 - if level>=0: - flags+=0b1000 - return fluid_synth_set_reverb_full(self.synth, flags, roomsize, damping, width, level) + flags = 0 + if roomsize >= 0: + flags += 0b0001 + if damping >= 0: + flags += 0b0010 + if width >= 0: + flags += 0b0100 + if level >= 0: + flags += 0b1000 + return fluid_synth_set_reverb_full( + self.synth, flags, roomsize, damping, width, level + ) + def set_chorus(self, nr=-1, level=-1.0, speed=-1.0, depth=-1.0, type=-1): """ nr Chorus voice count (0-99, CPU time consumption proportional to this value) @@ -849,87 +1105,108 @@ def set_chorus(self, nr=-1, level=-1.0, speed=-1.0, depth=-1.0, type=-1): if fluid_synth_set_chorus is not None: return fluid_synth_set_chorus(self.synth, nr, level, speed, depth, type) else: - set=0 - if nr>=0: - set+=0b00001 - if level>=0: - set+=0b00010 - if speed>=0: - set+=0b00100 - if depth>=0: - set+=0b01000 - if type>=0: - set+=0b10000 - return fluid_synth_set_chorus_full(self.synth, set, nr, level, speed, depth, type) + set = 0 + if nr >= 0: + set += 0b00001 + if level >= 0: + set += 0b00010 + if speed >= 0: + set += 0b00100 + if depth >= 0: + set += 0b01000 + if type >= 0: + set += 0b10000 + return fluid_synth_set_chorus_full( + self.synth, set, nr, level, speed, depth, type + ) + def set_reverb_roomsize(self, roomsize): if fluid_synth_set_reverb_roomsize is not None: return fluid_synth_set_reverb_roomsize(self.synth, roomsize) else: return self.set_reverb(roomsize=roomsize) + def set_reverb_damp(self, damping): if fluid_synth_set_reverb_damp is not None: return fluid_synth_set_reverb_damp(self.synth, damping) else: return self.set_reverb(damping=damping) + def set_reverb_level(self, level): if fluid_synth_set_reverb_level is not None: return fluid_synth_set_reverb_level(self.synth, level) else: return self.set_reverb(level=level) + def set_reverb_width(self, width): if fluid_synth_set_reverb_width is not None: return fluid_synth_set_reverb_width(self.synth, width) else: return self.set_reverb(width=width) + def set_chorus_nr(self, nr): if fluid_synth_set_chorus_nr is not None: return fluid_synth_set_chorus_nr(self.synth, nr) else: return self.set_chorus(nr=nr) + def set_chorus_level(self, level): if fluid_synth_set_chorus_level is not None: return fluid_synth_set_chorus_level(self.synth, level) else: return self.set_chorus(level=level) + def set_chorus_speed(self, speed): if fluid_synth_set_chorus_speed is not None: return fluid_synth_set_chorus_speed(self.synth, speed) else: return self.set_chorus(speed=speed) + def set_chorus_depth(self, depth_ms): if fluid_synth_set_chorus_depth is not None: return fluid_synth_set_chorus_depth(self.synth, depth_ms) else: return self.set_chorus(depth=depth_ms) + def set_chorus_type(self, type): if fluid_synth_set_chorus_type is not None: return fluid_synth_set_chorus_type(self.synth, type) else: return self.set_chorus(type=type) + def get_reverb_roomsize(self): return fluid_synth_get_reverb_roomsize(self.synth) + def get_reverb_damp(self): return fluid_synth_get_reverb_damp(self.synth) + def get_reverb_level(self): return fluid_synth_get_reverb_level(self.synth) + def get_reverb_width(self): return fluid_synth_get_reverb_width(self.synth) + def get_chorus_nr(self): return fluid_synth_get_chorus_nr(self.synth) + def get_chorus_level(self): return fluid_synth_get_reverb_level(self.synth) + def get_chorus_speed(self): if fluid_synth_get_chorus_speed is not None: return fluid_synth_get_chorus_speed(self.synth) else: return fluid_synth_get_chorus_speed_Hz(self.synth) + def get_chorus_depth(self): if fluid_synth_get_chorus_depth is not None: return fluid_synth_get_chorus_depth(self.synth) else: return fluid_synth_get_chorus_depth_ms(self.synth) + def get_chorus_type(self): return fluid_synth_get_chorus_type(self.synth) + def noteon(self, chan, key, vel): """Play a note""" if key < 0 or key > 127: @@ -939,6 +1216,7 @@ def noteon(self, chan, key, vel): if vel < 0 or vel > 127: return False return fluid_synth_noteon(self.synth, chan, key, vel) + def noteoff(self, chan, key): """Stop a note""" if key < 0 or key > 127: @@ -946,6 +1224,7 @@ def noteoff(self, chan, key): if chan < 0: return False return fluid_synth_noteoff(self.synth, chan, key) + def pitch_bend(self, chan, val): """Adjust pitch of a playing channel by small amounts @@ -956,6 +1235,7 @@ def pitch_bend(self, chan, val): """ return fluid_synth_pitch_bend(self.synth, chan, max(0, min(val + 8192, 16383))) + def cc(self, chan, ctrl, val): """Send control change value @@ -971,31 +1251,40 @@ def cc(self, chan, ctrl, val): 93 : chorus """ return fluid_synth_cc(self.synth, chan, ctrl, val) + def get_cc(self, chan, num): - i=c_int() + i = c_int() fluid_synth_get_cc(self.synth, chan, num, byref(i)) return i.value + def program_change(self, chan, prg): """Change the program""" return fluid_synth_program_change(self.synth, chan, prg) + def bank_select(self, chan, bank): """Choose a bank""" return fluid_synth_bank_select(self.synth, chan, bank) + def all_notes_off(self, chan): """Turn off all notes on a channel (release all keys)""" return fluid_synth_all_notes_off(self.synth, chan) + def all_sounds_off(self, chan): """Turn off all sounds on a channel (equivalent to mute)""" return fluid_synth_all_sounds_off(self.synth, chan) + def sfont_select(self, chan, sfid): """Choose a SoundFont""" return fluid_synth_sfont_select(self.synth, chan, sfid) + def program_reset(self): """Reset the programs on all channels""" return fluid_synth_program_reset(self.synth) + def system_reset(self): """Stop all notes and reset all programs""" return fluid_synth_system_reset(self.synth) + def get_samples(self, len=1024): """Generate audio samples @@ -1005,6 +1294,7 @@ def get_samples(self, len=1024): """ return fluid_synth_write_s16_stereo(self.synth, len) + def tuning_dump(self, bank, prog): """Get tuning information for given bank and preset @@ -1017,16 +1307,22 @@ def tuning_dump(self, bank, prog): def midi_event_get_type(self, event): return fluid_midi_event_get_type(event) + def midi_event_get_velocity(self, event): return fluid_midi_event_get_velocity(event) + def midi_event_get_key(self, event): return fluid_midi_event_get_key(event) + def midi_event_get_channel(self, event): return fluid_midi_event_get_channel(event) + def midi_event_get_control(self, event): return fluid_midi_event_get_control(event) + def midi_event_get_program(self, event): return fluid_midi_event_get_program(event) + def midi_event_get_value(self, event): return fluid_midi_event_get_value(event) @@ -1035,7 +1331,9 @@ def play_midi_file(self, filename): if self.player is None: return FLUID_FAILED if self.custom_router_callback is not None: - fluid_player_set_playback_callback(self.player, self.custom_router_callback, self.synth) + fluid_player_set_playback_callback( + self.player, self.custom_router_callback, self.synth + ) status = fluid_player_add(self.player, filename.encode()) if status == FLUID_FAILED: return status @@ -1054,7 +1352,6 @@ def player_set_tempo(self, tempo_type, tempo): return fluid_player_set_tempo(self.player, tempo_type, tempo) - class Sequencer: def __init__(self, time_scale=1000, use_system_timer=True): """Create new sequencer object to control and schedule timing of midi events @@ -1075,7 +1372,9 @@ def register_fluidsynth(self, synth): def register_client(self, name, callback, data=None): c_callback = CFUNCTYPE(None, c_uint, c_void_p, c_void_p, c_void_p)(callback) - response = fluid_sequencer_register_client(self.sequencer, name.encode(), c_callback, data) + response = fluid_sequencer_register_client( + self.sequencer, name.encode(), c_callback, data + ) if response == FLUID_FAILED: raise Exception("Registering client failed") @@ -1084,13 +1383,17 @@ def register_client(self, name, callback, data=None): return response - def note(self, time, channel, key, velocity, duration, source=-1, dest=-1, absolute=True): + def note( + self, time, channel, key, velocity, duration, source=-1, dest=-1, absolute=True + ): evt = self._create_event(source, dest) fluid_event_note(evt, channel, key, velocity, duration) self._schedule_event(evt, time, absolute) delete_fluid_event(evt) - def note_on(self, time, channel, key, velocity=127, source=-1, dest=-1, absolute=True): + def note_on( + self, time, channel, key, velocity=127, source=-1, dest=-1, absolute=True + ): evt = self._create_event(source, dest) fluid_event_noteon(evt, channel, key, velocity) self._schedule_event(evt, time, absolute) @@ -1128,6 +1431,7 @@ def process(self, msec): def delete(self): delete_fluid_sequencer(self.sequencer) + def raw_audio_string(data): """Return a string of bytes to send to soundcard @@ -1136,4 +1440,5 @@ def raw_audio_string(data): """ import numpy + return (data.astype(numpy.int16)).tobytes() diff --git a/setup.py b/setup.py index 54608f3..15141a9 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,13 @@ from setuptools import setup -setup (name = 'pyFluidSynth', - version = '1.3.4', - author = 'Nathan Whitehead', - author_email = 'nwhitehe@gmail.com', - url = 'https://github.com/nwhitehead/pyfluidsynth', - description = 'Python bindings for FluidSynth, a MIDI synthesizer that uses SoundFont instruments', - long_description = ''' +setup( + name="pyFluidSynth", + version="1.3.4", + author="Nathan Whitehead", + author_email="nwhitehe@gmail.com", + url="https://github.com/nwhitehead/pyfluidsynth", + description="Python bindings for FluidSynth, a MIDI synthesizer that uses SoundFont instruments", + long_description=""" This module contains python bindings for FluidSynth. FluidSynth is a software synthesizer for generating music. It works like a MIDI synthesizer. You load patches, set parameters, then send NOTEON and @@ -14,6 +15,7 @@ generally files with the extension SF2. FluidSynth can either be used to play audio itself, or you can call a function that returns chunks of audio data and output the data to the soundcard yourself. -''', - py_modules = ['fluidsynth'], - install_requires = ['numpy']) +""", + py_modules=["fluidsynth"], + install_requires=["numpy"], +) diff --git a/test/sequencerTest.py b/test/sequencerTest.py index ac06011..f47dc5e 100644 --- a/test/sequencerTest.py +++ b/test/sequencerTest.py @@ -5,55 +5,95 @@ seqduration = 1000 + def schedule_next_callback(): - # I want to be called back before the end of the next sequence - callbackdate = int(now + seqduration/2) - sequencer.timer(callbackdate, dest=mySeqID) + # I want to be called back before the end of the next sequence + callbackdate = int(now + seqduration / 2) + sequencer.timer(callbackdate, dest=mySeqID) + def schedule_next_sequence(): - global now - # the sequence to play - # the beat : 2 beats per sequence - sequencer.note(int(now + seqduration * 1/2), 0, 60, duration=250, velocity=80, dest=synthSeqID) - sequencer.note(int(now + seqduration * 2/2), 0, 60, duration=250, velocity=80, dest=synthSeqID) - # melody - sequencer.note(int(now + seqduration*1/10), 1, 45, duration=250, velocity=int(127*2/3), dest=synthSeqID) - sequencer.note(int(now + seqduration*4/10), 1, 50, duration=250, velocity=int(127*2/3), dest=synthSeqID) - sequencer.note(int(now + seqduration*8/10), 1, 55, duration=250, velocity=int(127*3/3), dest=synthSeqID) - # so that we are called back early enough to schedule the next sequence - schedule_next_callback() - - now = now + seqduration + global now + # the sequence to play + # the beat : 2 beats per sequence + sequencer.note( + int(now + seqduration * 1 / 2), + 0, + 60, + duration=250, + velocity=80, + dest=synthSeqID, + ) + sequencer.note( + int(now + seqduration * 2 / 2), + 0, + 60, + duration=250, + velocity=80, + dest=synthSeqID, + ) + # melody + sequencer.note( + int(now + seqduration * 1 / 10), + 1, + 45, + duration=250, + velocity=int(127 * 2 / 3), + dest=synthSeqID, + ) + sequencer.note( + int(now + seqduration * 4 / 10), + 1, + 50, + duration=250, + velocity=int(127 * 2 / 3), + dest=synthSeqID, + ) + sequencer.note( + int(now + seqduration * 8 / 10), + 1, + 55, + duration=250, + velocity=int(127 * 3 / 3), + dest=synthSeqID, + ) + # so that we are called back early enough to schedule the next sequence + schedule_next_callback() + + now = now + seqduration + def seq_callback(time, event, seq, data): - schedule_next_sequence() + schedule_next_sequence() + def local_file_path(file_name: str) -> str: - """ - Return a file path to a file that is in the same directory as this file. - """ - from os.path import dirname, join - - return join(dirname(__file__), file_name) - -if __name__=="__main__": - global sequencer, fs, mySeqID, synthSeqID, now - fs = fluidsynth.Synth() - fs.start() - # you might have to use other drivers: - #fs.start(driver="alsa", midi_driver="alsa_seq") - - sfid = fs.sfload(local_file_path("example.sf2")) - fs.program_select(0, sfid, 0, 0) - fs.program_select(1, sfid, 0, 0) # use the same program for channel 2 for cheapness - - sequencer = fluidsynth.Sequencer() - synthSeqID = sequencer.register_fluidsynth(fs) - mySeqID = sequencer.register_client("mycallback", seq_callback) - now = sequencer.get_tick() - schedule_next_sequence() - - time.sleep(10) - - sequencer.delete() - fs.delete() + """ + Return a file path to a file that is in the same directory as this file. + """ + from os.path import dirname, join + + return join(dirname(__file__), file_name) + + +if __name__ == "__main__": + global sequencer, fs, mySeqID, synthSeqID, now + fs = fluidsynth.Synth() + fs.start() + # you might have to use other drivers: + # fs.start(driver="alsa", midi_driver="alsa_seq") + + sfid = fs.sfload(local_file_path("example.sf2")) + fs.program_select(0, sfid, 0, 0) + fs.program_select(1, sfid, 0, 0) # use the same program for channel 2 for cheapness + + sequencer = fluidsynth.Sequencer() + synthSeqID = sequencer.register_fluidsynth(fs) + mySeqID = sequencer.register_client("mycallback", seq_callback) + now = sequencer.get_tick() + schedule_next_sequence() + + time.sleep(10) + + sequencer.delete() + fs.delete() diff --git a/test/test1.py b/test/test1.py index 70b9a14..25d1337 100644 --- a/test/test1.py +++ b/test/test1.py @@ -1,13 +1,15 @@ import time import fluidsynth + def local_file_path(file_name: str) -> str: - """ - Return a file path to a file that is in the same directory as this file. - """ - from os.path import dirname, join + """ + Return a file path to a file that is in the same directory as this file. + """ + from os.path import dirname, join + + return join(dirname(__file__), file_name) - return join(dirname(__file__), file_name) fs = fluidsynth.Synth() fs.start() diff --git a/test/test2.py b/test/test2.py index 535544e..997ffd7 100644 --- a/test/test2.py +++ b/test/test2.py @@ -2,20 +2,18 @@ import pyaudio import fluidsynth + def local_file_path(file_name: str) -> str: - """ - Return a file path to a file that is in the same directory as this file. - """ - from os.path import dirname, join + """ + Return a file path to a file that is in the same directory as this file. + """ + from os.path import dirname, join + + return join(dirname(__file__), file_name) - return join(dirname(__file__), file_name) pa = pyaudio.PyAudio() -strm = pa.open( - format = pyaudio.paInt16, - channels = 2, - rate = 44100, - output = True) +strm = pa.open(format=pyaudio.paInt16, channels=2, rate=44100, output=True) s = [] @@ -46,5 +44,5 @@ def local_file_path(file_name: str) -> str: samps = fluidsynth.raw_audio_string(s) print(len(samps)) -print('Starting playback') +print("Starting playback") strm.write(samps) diff --git a/test/test3.py b/test/test3.py index 7897c44..b49e895 100644 --- a/test/test3.py +++ b/test/test3.py @@ -2,13 +2,15 @@ import fluidsynth + def local_file_path(file_name: str) -> str: - """ - Return a file path to a file that is in the same directory as this file. - """ - from os.path import dirname, join + """ + Return a file path to a file that is in the same directory as this file. + """ + from os.path import dirname, join + + return join(dirname(__file__), file_name) - return join(dirname(__file__), file_name) fs = fluidsynth.Synth() fs.start() diff --git a/test/test4.py b/test/test4.py index b657e36..9bce07a 100644 --- a/test/test4.py +++ b/test/test4.py @@ -1,13 +1,15 @@ import time import fluidsynth + def local_file_path(file_name: str) -> str: - """ - Return a file path to a file that is in the same directory as this file. - """ - from os.path import dirname, join + """ + Return a file path to a file that is in the same directory as this file. + """ + from os.path import dirname, join + + return join(dirname(__file__), file_name) - return join(dirname(__file__), file_name) fs = fluidsynth.Synth() fs.start()