pyfluidsynth
pyfluidsynth copied to clipboard
Some extensive changes and enhancements
This PR is more of a request for comment than an actual merge request.
I heavily extended and changed the module, but I tried to separate the commits into distinct units of functionality. But I also re-formatted and re-arranged the code and the docstrings and I wasn't able to separate these changes from the functional ones. So it might be difficult to cherry-pick from theses changes. But if you are interested in incorporating only some of these changes, I'll see what I can do. I'll also understand if these changes are too extensive to incorporate. I've started this fork mainly with the goal to have a special version of pyfluidsynth to incorporate into an application, but since this could be useful to others I wanted at least to open some kind of PR.
Enhancements & new features:
- Integrated, fixed and enhanced fluidsynth 2 compatibility work done by Bill Peterson (#17).
- Added support for support for fluidsynth MIDI player and renderer and a new
Player
class for an object-oriented API to these. - Added support for
fluidsynth_settings_get*
functions. - Enhanced
Synth.settings
to act as a settings retrieval method as well. - Added support for passing bool values to
Synth.setting
. - Added support for passing bytes string values to
Synth.settings
. - Added
all_notes_off
method toSynth
class. - Added
RouterRule
class (see below). - Added MIDI router debug handler function bindings.
- Added tests scripts for fluidsynth MIDI file renderer.
- Described parameter names and types for most important functions and methods with Sphinx-compatible syntax.
- Added module-level constants for fluid setting types (
FLUID_*_TYPE
), MIDI router (FLUID_MIDI_ROUTER_RULE_*
rule types, and MIDI player state (FLUID_PLAYER_*
). - Added module-level constants
AUDIO_DRIVER_NAMES
andMIDI_DRIVER_NAMES
listing known audio and MIDI drivers. - Added module-level constant
AUDIO_FILE_TYPES
listing known audio file types for rendering. - Added
.gitignore
file. - Added configuration for
flake8
,pylint
andisort
QA tools.
Changes:
-
Bumped
api_version
to "2.0". -
Updated copyright note at top of module source.
-
Replaced use of
future
module for Python 2 compatibility with (simpler)six
module. -
Changed import of
ctypes
module to explicitly import used names instead of star import to enable checking for undefined names with code linters. -
Changed
Synth.setting
to return result offluid_setting_set*
calls. -
Changed API to add MIDI router rules to be more object-oriented:
- Added
RouterRule
class. - Added
router_add_rule
method ofSynth
class, which takes aRouterRule
instance as argument. - Removed
router_begin
,router_end
,router_chan
,router_par1
,router_par2
methods fromSynth
class.
- Added
-
Updated list of available audio and MIDI drivers in code and documentation.
-
Synth.start()
now raisesValueError
if unknown driver name is passed. -
Ordered function bindings by fluidsynth header file.
-
Re-ordered module level constants, functions and classes to be more consistent and in accordance with general Python best practices.
-
Re-formatted code for PEP-8 compliance, better consistency, no overlong lines and better separation of code blocks.
-
Moved notes about changes from module docstring to this change log.
Fixes:
- Replaced raising of undefined
Error
exception withOSError
. - Cleaned up docstrings formatting and punctuation.
- Made sure tests scripts find example soundfont when called from another directory.
- Fixed Python 3 incompatibilities in test scripts.
Seems to need a fix to prevent an AttributeError with fluid_player_seek, otherwise pretty great work!:
#FS 1.0 doesn't have this.
try:
fluid_player_seek = cfunc(
'fluid_player_seek',
c_int,
('player', c_void_p, 1),
('ticks', c_int, 1))
except AttributeError:
pass
@EternityForest Thanks for the hint, I'll look into that.
I also have a couple of additions to my fork, which I need to sort out into separate commits.
Oh! One more thing!
In this section, I don't understand the "pointer" part. It seems to crash with some kind of "expected a cfunctype instance instead of a cfunctype"
# Fluid MIDI driver
new_fluid_midi_driver = cfunc(
'new_fluid_midi_driver',
c_void_p,
('settings', c_void_p, 1),
('handler', CFUNCTYPE(POINTER(c_int), c_void_p, c_void_p), 1),
('event_handler_data', c_void_p, 1))
delete_fluid_midi_driver = cfunc(
'delete_fluid_midi_driver',
None,
('driver', c_void_p, 1))
Changing to a plain int at least lets me call start() without a crash:
# 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))
delete_fluid_midi_driver = cfunc(
'delete_fluid_midi_driver',
None,
('driver', c_void_p, 1))
But I have not tested if it actually works.
Just curious what the status is for this PR and related ones (e.g., #17) that fix FluidSynth 2 compatibility. I'm especially wondering because there haven't been any new commits to this repo since December, 2018. @nwhitehead do you have plans to update the project? Or is there a different fork I should switch to using? Thanks!
For now, I've been using a slightly tweaked fork and a custom wrapper, the standard API was just a lot lower level than I wanted to work with.
Although it does need a few dependancies like sf2utils to work correctly, it seems to be reliable with JACK on Linux, but I haven't really had time to get it working with anything else, or fully document.
https://github.com/EternityForest/scullery/tree/master/scullery
On Fri, Mar 27, 2020, 10:49 AM cghawthorne [email protected] wrote:
Just curious what the status is for this PR and related ones (e.g., #17 https://github.com/nwhitehead/pyfluidsynth/pull/17) that fix FluidSynth 2 compatibility. I'm especially wondering because there haven't been any new commits to this repo since December, 2018. @nwhitehead https://github.com/nwhitehead do you have plans to update the project? Or is there a different fork I should switch to using? Thanks!
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/nwhitehead/pyfluidsynth/pull/21#issuecomment-605151941, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFZCH67QA6HSS635ZWHEJ3RJTRJTANCNFSM4HYXK7NA .
I totally understand that @nwhitehead would be reluctant to merge these extensive changes without further discussion and probably some amendments.
The thing is, I have done some even more extensive changes to my fork, which I - unfortunately - haven't even comitted and pushed yet, because I wanted to break them up into smaller pieces. But I never got around to doing that and the project I needed pyfluidsynth for didn't go as planned, so my work on pyfluidsynth hasn't progressed since quite some time (June 2019).
Anyway, I just commited and pushed these changes into a new branch of my fork, in case anyone wants to have a look or build on it:
https://github.com/SpotlightKid/pyfluidsynth/tree/feature/more-refactoring
@SpotlightKid , I have tried to use this PR on a Raspberry Pi (Raspbian Buster) in a Python 3 project. fluidsynth is still on version 1.1.11 in Raspbian Buster, which seems to be incompatible with your changes (with the code in #17 import fluidsynth
was still possible):
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/pi/[snip]/env/lib/python3.7/site-packages/fluidsynth.py", line 669, in <module>
('ticks', c_int, 1))
File "/home/pi/[snip]/env/lib/python3.7/site-packages/fluidsynth.py", line 89, in cfunc
return CFUNCTYPE(result, *atypes)((name, _fl), tuple(aflags))
AttributeError: /usr/lib/arm-linux-gnueabihf/libfluidsynth.so.1: undefined symbol: fluid_player_seek
Just out of curiosity: Is compatibility to Fluidsynth 1.x one of your goals with your fork or not?
Is compatibility to Fluidsynth 1.x one of your goals with your fork or not?
Only a low priority one. I have made provision in the code to maintain it, but it is not extensively tested.
fluid_player_seek
was added in fluidsynth 2.0.0. It would be easy to make the function import on line 578 and the Player method conditional.
In the newer branch linked above, unsupported functions when using fluidsynth 1.x should never lead to an ImportError, but can still lead to runtime errors, when trying to use function that does not exist in the used fluidsynth library yet/anymore.
In the newer branch linked above, unsupported functions when using fluidsynth 1.x should never lead to an ImportError, but can still lead to runtime errors, when trying to use function that does not exist in the used fluidsynth library yet/anymore.
Thanks, it seems to work fine with the fork linked in https://github.com/nwhitehead/pyfluidsynth/pull/21#issuecomment-605272797 on Raspbian Buster/fluidsynth 1.1.11. Since I'm only using 1.x API for now, I should be fine I guess...
Quick note: iteritems
can be un-import
ed if line 1157 or 1164, depending on version, is:
for opt, val in kwargs.items():
instead of:
for opt, val in iteritems(kwargs):
@alextz: the whole point of using six.iteritems
instead of dict.items
is to have the same semantics on Python 2 and 3. Anyway, this PR is going nowhere, it seems, so it's a moot point.
dict.items()
goes back to Python V1. LIke {}.keys()
and {}.values()
These aren't going away, even when Python and JavaScript are merged in 2040. :)
Yep, it looks like the thing to do is to snatch one of the two updated versions of fluidsynth.py referred to in this PR's comments. Lotta nice work done on 'em!
dict.items()
goes back to Python V1.
@alextz: Yes, but they behave differently. The Python 2 version builds a list, the Python 3 a type of iterator. Look it up in the Python 3.0 "What's new" docs. Things like these are exactly the reason why six
exists.
At lot of the features in this fork and in https://github.com/SpotlightKid/pyfluidsynth/tree/feature/more-refactoring could be useful, if they can be incorporated into the current master. I'll spend some time looking at how to go about that, but if anyone wants to offer thoughts or contribute time/effort that would be appreciated :)
@SpotlightKid Please rebase to resolve git conflicts.
See my last comment above.