Line 2:
Line 2:
This section contain documentation for some of this controller drivers.
This section contain documentation for some of this controller drivers.
−
−
{{NoteBox|This documentation is valid for the "oram" development branch. It's only partially valid for the current testing branch so you could find some differences.}}
<br clear=all>
<br clear=all>
Line 41:
Line 39:
* Start/stop '''sequences of a row''', pressing the corresponding SOFT KEY (without modifiers). If there are any sequence playing, they will stop. If there are no sequences playing, it will start those not empty. The action to be run is shown by the LED status (lit will stop, off will start).
* Start/stop '''sequences of a row''', pressing the corresponding SOFT KEY (without modifiers). If there are any sequence playing, they will stop. If there are no sequences playing, it will start those not empty. The action to be run is shown by the LED status (lit will stop, off will start).
−
* Use knobs to modify '''chains' volume or balance'''. The function is given by current KNOB CTRL selected: <code>VOLUME</code> or <code>PAN</code> (for balance). To change the function, press <code>SHIFT</code> + <code>VOLUME</code> or <code>SHIFT</code> + <code>PAN</code>. The knobs are also affected by current controller's bank.
+
* Use the knobs to modify '''chains' volume or balance'''. The function is given by current KNOB CTRL selected: <code>VOLUME</code> or <code>PAN</code> (for balance). To change the function, press <code>SHIFT</code> + <code>VOLUME</code> or <code>SHIFT</code> + <code>PAN</code>. The knobs are also affected by current controller's bank. Each knob will affect a chain, independently of the selected chain. (K1 -> chain 1, K2 -> chain 2, ...)
* Use <code>SHIFT</code> + <code>KNOB k1</code> to change volume or balance for main chain (what changes is selected by the current KNOB CTRL function).
* Use <code>SHIFT</code> + <code>KNOB k1</code> to change volume or balance for main chain (what changes is selected by the current KNOB CTRL function).
Line 53:
Line 51:
* '''Stop all sequences''' of current scene (but not audio/midi playback or recording), doing a ''short'' press on <code>STOP ALL CLIPS</code> button; ''bold'' press to stop all sequences on all scenes.
* '''Stop all sequences''' of current scene (but not audio/midi playback or recording), doing a ''short'' press on <code>STOP ALL CLIPS</code> button; ''bold'' press to stop all sequences on all scenes.
−
* Open the '''StepSeq mode''' for a given sequence, pressing <code>SHIFT</code> + a pad button.
+
* Open the '''StepSeq mode''' for a given sequence, pressing <code>SHIFT</code> + a pad button (more info about this mode in the following section).
−
* '''Clear a sequence''', pressing any track button + the sequence pad.
+
* '''Clear a sequence''', pressing any track button + the sequence pad (use SELECT function, and the selected chain's button to avoid changing other settings).
−
* Start '''recording a pattern'''. For this, press <code>RECORD</code> + a pad button, which will 1) select the chain associated with the group of the sequence, 2) open the pattern editor for that sequence, 3) start playing the sequence and 4) start recording that sequence. If you press the pad again (without holding any other button), the recording will stop. Press again to stop playback too. You can also control the playback/recording with <code>PLAY/PAUSE</code> and <code>SHIFT</code> + <code>RECORD</code> buttons.
+
* Start '''recording a pattern'''. For this, press <code>RECORD</code> + a pad button, which will 1) select the chain associated with the group of the sequence, 2) open the pattern editor for that sequence, 3) start playing the sequence and 4) start recording that sequence. If you press the pad again (without holding any other button), the recording will stop. Press again to stop playback too. You can also control the playback/recording with <code>PLAY/PAUSE</code> or <code>SHIFT</code> + <code>RECORD</code> buttons.
* If the pattern editor is open, press <code>SHIFT</code> + <code>UP arrow</code> to '''go back to ZynPad'''. Press it again to go to mixer screen.
* If the pattern editor is open, press <code>SHIFT</code> + <code>UP arrow</code> to '''go back to ZynPad'''. Press it again to go to mixer screen.
Line 91:
Line 89:
This mode allows you to control Zynthian's step sequencer (and also the pattern editor). You can activate it by pressing <code>SHIFT</code> + <code>SEND</code>, or in '''Mixpad''' mode pressing <code>SHIFT</code> + a sequence pad. In this mode, the pad matrix is divided in two parts: first four rows (from top to bottom) are '''the steps''' of current pattern. The last row is used to assign notes or '''instruments''' for easy access (called ''NotePads'' in this document). With this mode, you can:
This mode allows you to control Zynthian's step sequencer (and also the pattern editor). You can activate it by pressing <code>SHIFT</code> + <code>SEND</code>, or in '''Mixpad''' mode pressing <code>SHIFT</code> + a sequence pad. In this mode, the pad matrix is divided in two parts: first four rows (from top to bottom) are '''the steps''' of current pattern. The last row is used to assign notes or '''instruments''' for easy access (called ''NotePads'' in this document). With this mode, you can:
+
+
* Press and hold <code>SHIFT</code> to '''show the status''':
+
** Buttons <code>UP</code>, <code>DOWN</code>, <code>LEFT</code> and <code>RIGHT</code> will lit indicating the current Notepad page selected (1, 2, 3 or 4, respectively).
+
** Button <code>SEND</code> will lit indicating this mode is selected.
* '''Open the pattern editor''' in Zynthian's UI with the current pattern, pressing <code>SHIFT</code> + <code>DOWN</code>. Press <code>SHIFT</code> + <code>UP</code> to go back.
* '''Open the pattern editor''' in Zynthian's UI with the current pattern, pressing <code>SHIFT</code> + <code>DOWN</code>. Press <code>SHIFT</code> + <code>UP</code> to go back.
Line 107:
Line 109:
* '''Play current sequence''' pressing the <code>PLAY</code> button. You will see the playhead (in white) moving along the steps. Pressing <code>SHIFT</code> + <code>PLAY</code> will start stage-play, which will update the pattern as it moves along the current track (press any pad to stop stage-play). Press <code>PLAY</code> again to stop playing.
* '''Play current sequence''' pressing the <code>PLAY</code> button. You will see the playhead (in white) moving along the steps. Pressing <code>SHIFT</code> + <code>PLAY</code> will start stage-play, which will update the pattern as it moves along the current track (press any pad to stop stage-play). Press <code>PLAY</code> again to stop playing.
+
+
<p style="margin: 1em 0 1.5em; padding: 1em; background-color: #fef6e7; display:table-cell">
+
'''NOTE''': Remember to set the ''clock source'' of Zynthian to '''Internal Send'''. Otherwise, the playhead will not be shown!
+
</p>
* '''Panic stop''' all sounds, pressing <code>SHIFT</code> + <code>STOP ALL CLIPS</code>. Any sound will stop immediately.
* '''Panic stop''' all sounds, pressing <code>SHIFT</code> + <code>STOP ALL CLIPS</code>. Any sound will stop immediately.
Line 494:
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/oram/zyngine/zynthian_ctrldev_manager.py zynthian-ui/zyngui/zynthian_ctrldev_manager.py zynthian/zyngine · GitHub]
+
+
and some example drivers here:
+
+
[https://github.com/zynthian/zynthian-ui/tree/oram/zyngine/ctrldev zynthian-ui/zyngine/ctrldev/ · 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”]