Changes

Jump to navigation Jump to search
m
Add Technical Info For Driver Developers
Line 500: Line 500:     
<br clear=all>
 
<br clear=all>
 +
 +
 +
==Technical Info For Driver Developers==
 +
 +
Drivers are python module implementing a class. This class can call internal zynthian-ui API, so it has full access to zynthian functionality. It’s not limited by CUIA. No limits, so you can break the UI too :wink:
 +
 +
You can check the full code here:
 +
 +
[https://github.com/zynthian/zynthian-ui/blob/testing/zyngui/zynthian_ctrldev_manager.py zynthian-ui/zyngui/zynthian_ctrldev_manager.py at testing · zynthian/zynthian-ui · GitHub ]
 +
 +
and some example drivers here:
 +
 +
[https://github.com/zynthian/zynthian-ui/tree/testing/zyngui/ctrldev zynthian-ui/zyngui/ctrldev at testing · zynthian/zynthian-ui · GitHub]
 +
 +
All drivers must inherit from ''zynthian_ctrldev_base'', implementing the needed functionality as commented in the base code:
 +
 +
<pre>
 +
 +
#------------------------------------------------------------------------------------------------------------------
 +
# Control device base class
 +
#------------------------------------------------------------------------------------------------------------------
 +
 +
class zynthian_ctrldev_base():
 +
 +
dev_id = None  # String that identifies the device (class variable!)
 +
dev_zynpad = False # Can act as a zynpad trigger device
 +
dev_zynmixer = False # Can act as an audio mixer controller device
 +
dev_pated = False # Can act as a pattern editor device
 +
 +
 +
# Function to initialise class
 +
def __init__(self):
 +
self.idev = 0 # Slot index where the device is connected, starting from 1 (0 = None)
 +
self.zyngui = zynthian_gui_config.zyngui
 +
 +
 +
# Setup the device connected in slot #idev
 +
# Before calling this, the caller (ctrldev-manager) should check that driver's ID string matches device's ID string
 +
def setup(self, idev=None):
 +
if idev != self.idev:
 +
# Release currently selected device, if any ...
 +
self.release()
 +
# Init new selected device
 +
if idev > 0:
 +
self.idev = idev
 +
logging.info("Setting-up {} in slot {}".format(self.dev_id, self.idev))
 +
# Setup routing
 +
lib_zyncore.zmip_set_route_extdev(self.idev - 1, 0)
 +
zynautoconnect.midi_autoconnect(True)
 +
# Initialize new selected device
 +
self.init()
 +
self.refresh(force=True)
 +
 +
 +
def release(self):
 +
if self.idev > 0:
 +
logging.info("Releasing {} in slot {}".format(self.dev_id, self.idev))
 +
# If device is still connected, call end
 +
dev_id = zynautoconnect.get_midi_device_name(self.idev)
 +
if dev_id and dev_id == self.dev_id:
 +
self.end()
 +
# Restore routing
 +
lib_zyncore.zmip_set_route_extdev(self.idev - 1, 1)
 +
zynautoconnect.midi_autoconnect(True)
 +
self.idev = 0
 +
 +
 +
# Refresh device status (LED feedback, etc)
 +
# It *SHOULD* be implemented by child class
 +
def refresh(self, force=False):
 +
logging.debug("Refresh LEDs for {}: NOT IMPLEMENTED!".format(self.dev_id))
 +
 +
 +
# Device MIDI event handler
 +
# It *SHOULD* be implemented by child class
 +
def midi_event(self, ev):
 +
logging.debug("MIDI EVENT FROM '{}'".format(self.dev_id))
 +
 +
 +
# Light-Off LEDs
 +
# It *SHOULD* be implemented by child class
 +
def light_off(self):
 +
logging.debug("Lighting Off LEDs for {}: NOT IMPLEMENTED!".format(self.dev_id))
 +
 +
 +
# Sleep On
 +
# It *COULD* be improved by child class
 +
def sleep_on(self):
 +
self.light_off()
 +
 +
 +
# Sleep On
 +
# It *COULD* be improved by child class
 +
def sleep_off(self):
 +
self.refresh(True)
 +
</pre>
 +
 +
Quite simple, right? This is for basic “generic” drivers.
 +
Zynpad enabled drivers inherit from this base class:
 +
 +
 +
<pre>
 +
# ------------------------------------------------------------------------------------------------------------------
 +
# Zynpad control device base class
 +
# ------------------------------------------------------------------------------------------------------------------
 +
 +
class zynthian_ctrldev_zynpad(zynthian_ctrldev_base):
 +
 +
dev_zynpad = True # Can act as a zynpad trigger device
 +
 +
 +
def __init__(self):
 +
super().__init__()
 +
self.zynpad = self.zyngui.screens["zynpad"]
 +
 +
 +
def refresh(self, force=False):
 +
# When zynpad is shown, this is done by refresh_status, so no need to refresh twice
 +
if force or not self.zynpad.shown:
 +
self.refresh_pads(force)
 +
self.refresh_zynpad_bank()
 +
if force:
 +
self.refresh_zynpad_bank()
 +
 +
 +
# It *SHOULD* be implemented by child class
 +
def refresh_zynpad_bank(self):
 +
pass
 +
 +
 +
def refresh_pads(self, force=False):
 +
if force:
 +
self.light_off()
 +
for pad in range(self.zyngui.zynseq.col_in_bank ** 2):
 +
# It MUST be called for cleaning the dirty bit
 +
changed_state = self.zyngui.zynseq.libseq.hasSequenceChanged(self.zynpad.bank, pad)
 +
if changed_state or force:
 +
mode = self.zyngui.zynseq.libseq.getPlayMode(self.zynpad.bank, pad)
 +
state = self.zynpad.get_pad_state(pad)
 +
self.update_pad(pad, state, mode)
 +
 +
 +
def refresh_pad(self, pad, force=False):
 +
# It MUST be called for cleaning the dirty bit!!
 +
changed_state = self.zyngui.zynseq.libseq.hasSequenceChanged(self.zynpad.bank, pad)
 +
if changed_state or force:
 +
mode = self.zyngui.zynseq.libseq.getPlayMode(self.zynpad.bank, pad)
 +
state = self.zynpad.get_pad_state(pad)
 +
self.update_pad(pad, state, mode)
 +
 +
 +
# It *SHOULD* be implemented by child class
 +
def update_pad(self, pad, state, mode):
 +
pass
 +
#------------------------------------------------------------------------------
 +
</pre>
 +
 +
 +
If you kind-of-understand this, you shouldn’t have problem to understand the driver examples and program your own drivers. Simply copy your driver file in the the zyngui/ctrldev folder and restart zynthian-ui. Refer to this thread for more information [https://discourse.zynthian.org/t/new-control-device-manager-controller-device-drivers/8593/1 NEW: Control-device manager + controller device “drivers”]
222

edits

Navigation menu