Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add modulation wrapper #92

Merged
merged 5 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode
177 changes: 177 additions & 0 deletions fluidsynth.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,77 @@ class fluid_synth_channel_info_t(Structure):
fluid_midi_event_get_velocity = cfunc('fluid_midi_event_get_velocity', c_int,
('evt', c_void_p, 1))

# fluid modulator
new_fluid_mod = cfunc("new_fluid_mod", c_void_p)

delete_fluid_mod = cfunc("delete_fluid_mod", c_void_p, ("mod", c_void_p, 1))

fluid_mod_clone = cfunc(
"fluid_mod_clone", c_void_p, ("mod", c_void_p, 1), ("src", c_void_p, 1),
)

fluid_mod_get_amount = cfunc("fluid_mod_get_amount", c_void_p, ("mod", c_void_p, 1))

fluid_mod_get_dest = cfunc("fluid_mod_get_dest", c_void_p, ("mod", c_void_p, 1))

fluid_mod_get_flags1 = cfunc("fluid_mod_get_flags1", c_void_p, ("mod", c_void_p, 1))

fluid_mod_get_flags2 = cfunc("fluid_mod_get_flags2", c_void_p, ("mod", c_void_p, 1))

fluid_mod_get_source1 = cfunc("fluid_mod_get_source1", c_void_p, ("mod", c_void_p, 1))

fluid_mod_get_source2 = cfunc("fluid_mod_get_source2", c_void_p, ("mod", c_void_p, 1))

fluid_mod_get_transform = cfunc(
"fluid_mod_get_transform", c_void_p, ("mod", c_void_p, 1),
)

fluid_mod_has_dest = cfunc(
"fluid_mod_has_dest", c_void_p, ("mod", c_void_p, 1), ("gen", c_uint, 1),
)

fluid_mod_has_source = cfunc(
"fluid_mod_has_dest",
c_void_p,
("mod", c_void_p, 1),
("cc", c_uint, 1),
("ctrl", c_uint, 1),
)

fluid_mod_set_amount = cfunc(
"fluid_mod_set_amount", c_void_p, ("mod", c_void_p, 1), ("amount", c_double, 1),
)

fluid_mod_set_dest = cfunc(
"fluid_mod_set_dest", c_void_p, ("mod", c_void_p, 1), ("dst", c_int, 1),
)

fluid_mod_set_source1 = cfunc(
"fluid_mod_set_source1",
c_void_p,
("mod", c_void_p, 1),
("src", c_int, 1),
("flags", c_int, 1),
)

fluid_mod_set_source2 = cfunc(
"fluid_mod_set_source2",
c_void_p,
("mod", c_void_p, 1),
("src", c_int, 1),
("flags", c_int, 1),
)

fluid_mod_set_transform = cfunc(
"fluid_mod_set_transform", c_void_p, ("mod", c_void_p, 1), ("type", c_int, 1),
)

fluid_mod_sizeof = cfunc("fluid_mod_sizeof", c_void_p)

fluid_mod_test_identity = cfunc(
"fluid_mod_test_identity", c_void_p, ("mod1", c_void_p, 1), ("mod2", c_void_p, 1),
)

# fluid_player_status returned by fluid_player_get_status()
FLUID_PLAYER_READY = 0
FLUID_PLAYER_PLAYING = 1
Expand Down Expand Up @@ -1094,6 +1165,112 @@ def midi2audio(self, midifile, audiofile = "output.wav"):
delete_fluid_file_renderer(renderer)
delete_fluid_player(player)

class Modulator:
def __init__(self):
"""Create new modulator object"""
self.mod = new_fluid_mod()

def clone(self, src):
response = fluid_mod_clone(self.mod, src)
if response == FLUID_FAILED:
raise Exception("Modulation clone failed")
return response

def get_amount(self):
response = fluid_mod_get_amount(self.mod)
if response == FLUID_FAILED:
raise Exception("Modulation amount get failed")
return response

def get_dest(self):
response = fluid_mod_get_dest(self.mod)
if response == FLUID_FAILED:
raise Exception("Modulation destination get failed")
return response

def get_flags1(self):
response = fluid_mod_get_flags1(self.mod)
if response == FLUID_FAILED:
raise Exception("Modulation flags1 get failed")
return response

def get_flags2(self):
response = fluid_mod_get_flags2(self.mod)
if response == FLUID_FAILED:
raise Exception("Modulation flags2 get failed")
return response

def get_source1(self):
response = fluid_mod_get_source1(self.mod)
if response == FLUID_FAILED:
raise Exception("Modulation source1 get failed")
return response

def get_source2(self):
response = fluid_mod_get_source2(self.mod)
if response == FLUID_FAILED:
raise Exception("Modulation source2 get failed")
return response

def get_transform(self):
response = fluid_mod_get_transform(self.mod)
if response == FLUID_FAILED:
raise Exception("Modulation transform get failed")
return response

def has_dest(self, gen):
response = fluid_mod_has_dest(self.mod, gen)
if response == FLUID_FAILED:
raise Exception("Modulation has destination check failed")
return response

def has_source(self, cc, ctrl):
response = fluid_mod_has_source(self.mod, cc, ctrl)
if response == FLUID_FAILED:
raise Exception("Modulation has source check failed")
return response

def set_amount(self, amount):
response = fluid_mod_set_amount(self.mod, amount)
if response == FLUID_FAILED:
raise Exception("Modulation set amount failed")
return response

def set_dest(self, dest):
response = fluid_mod_set_dest(self.mod, dest)
if response == FLUID_FAILED:
raise Exception("Modulation set dest failed")
return response

def set_source1(self, src, flags):
response = fluid_mod_set_source1(self.mod, src, flags)
if response == FLUID_FAILED:
raise Exception("Modulation set source 1 failed")
return response

def set_source2(self, src, flags):
response = fluid_mod_set_source2(self.mod, src, flags)
if response == FLUID_FAILED:
raise Exception("Modulation set source 2 failed")
return response

def set_transform(self, type):
response = fluid_mod_set_transform(self.mod, type)
if response == FLUID_FAILED:
raise Exception("Modulation set transform failed")
return response

def sizeof(self):
response = fluid_mod_sizeof()
if response == FLUID_FAILED:
raise Exception("Modulation sizeof failed")
return response

def test_identity(self, mod2):
response = fluid_mod_sizeof(self.mod, mod2)
if response == FLUID_FAILED:
raise Exception("Modulation identity check failed")
return response

class Sequencer:
def __init__(self, time_scale=1000, use_system_timer=True):
Expand Down
Empty file.
12 changes: 12 additions & 0 deletions soundFontDefinitions/definitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# src values
FLUID_MOD_NONE = 0
FLUID_MOD_VELOCITY = 2
FLUID_MOD_KEY = 3
FLUID_MOD_KEYPRESSURE = 10
FLUID_MOD_CHANNELPRESSURE = 13
FLUID_MOD_PITCHWHEEL = 14
FLUID_MOD_PITCHWHEELSENS = 16

# Transforms
FLUID_MOD_TRANSFORM_LINEAR = 0
FLUID_MOD_TRANSFORM_ABS = 2
57 changes: 57 additions & 0 deletions test/modulatorTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import unittest

import fluidsynth
import soundFontDefinitions.definitions as d


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)


class TestModulatorMethods(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.fs = fluidsynth.Synth()
cls.modulator = fluidsynth.Modulator()

## Your installation of FluidSynth may require a different driver.
## Use something like:
# fs.start(driver="pulseaudio")
cls.fs.start()
cls.sfid = cls.fs.sfload(local_file_path("example.sf2"))
cls.fs.program_select(0, cls.sfid, 0, 0)

@classmethod
def tearDownClass(cls):
cls.fs.delete()

def test_dest(self):
assert self.modulator.has_dest(5) is None
self.modulator.set_dest(5)
assert self.modulator.has_dest(5) == 1
assert self.modulator.get_dest() == 5

def test_flags(self):
assert self.modulator.get_source1() is None
self.modulator.set_source1(d.FLUID_MOD_KEY, 9)
assert self.modulator.get_source1() == d.FLUID_MOD_KEY
assert self.modulator.get_flags1() == 9

assert self.modulator.get_source2() is None
self.modulator.set_source2(d.FLUID_MOD_VELOCITY, 4)
assert self.modulator.get_source2() == d.FLUID_MOD_VELOCITY
assert self.modulator.get_flags2() == 4

def test_transforms(self):
assert self.modulator.get_transform() is None
self.modulator.set_transform(d.FLUID_MOD_TRANSFORM_ABS)
assert self.modulator.get_transform() == d.FLUID_MOD_TRANSFORM_ABS


if __name__ == "__main__":
unittest.main()
Loading