Template reference
zcx contains several features for applying a common definition across multiple controls, or for dynamically configuring a control based on factors such as its position in a group.
template strings¶
In many parts of a control's config, you can use a special syntax to dynamically insert values into a string, such as an action list:
-
color: red
gestures:
pressed: PLAY ${me.Index}
-
color: green
gestures:
pressed: PLAY ${me.Index}
-
color: blue
gestures:
pressed: PLAY ${me.Index}
The key part is ${me.Index}
. In zcx, when you see part of a string enclosed with a leading ${
and a trailing }
, you are looking at a template string. zcx will dynamically evaluate this string each time the control is pressed.
The example above would evaluate to:
Let's break down what's happening here.
${
— indicates the start of an expressionme
— is the individual control in which a template string appearsIndex
— this is a property that belongs to this control}
— indicates the end of an expression
As you may notice, zcx template strings behave similarly to Variables in ClyphX Pro.
what is a property?¶
In this context, a property is some value that is associated with a particular control. You can see the properties associated with each control in the control reference.
We can see from the control reference that me.Index
refers to this control's position with its containing section.
basic expressions¶
We can even execute simple Python expressions within the braces:
complex expressions¶
There may be times when then value you want to fill is impractical or impossible to write inside the braces. In this case you can use the vars
option in your yaml config.
vars
is a dict, where each key is a variable, and each value is an expression. The variable will be assigned to the result of that expression. We can then reference that variable within a template string. For instance:
my_control:
vars:
foo: 1 + 1
gestures:
pressed:
msg: The value of foo is ${foo} # "The value of foo is 2"
In ClyphX terms, you can imagine the above as:
%foo% = 1 + 1 ; msg "The value of foo is %foo%"
Or in Python as:
That was a very basic example to illustrate the concept. This example better explains a use case:
drum_pad_section:
vars:
offset: 8
clips_per: 2
clip_1a: (me.index * clips_per) + 1 + offset
clip_1b: (clip_1a + clips_per) - 1
gestures:
released_immediately: >
"beats" / PLAY RND${clip_1a}-${clip_1b}
This is a control template that, when applied to a matrix section, will produce the following ouput:
And later, we can easily expand this config to add extra functionality:
drum_pad_section:
vars:
offset: 8
clips_per: 2
shift_offset: 32
clip_1a: (me.index * clips_per) + 1 + offset
clip_1b: (clip_1a + clips_per) - 1
clip_2a: clip_1a + shift_offset
clip_2b: clip_2b + shift_offset
gestures:
released_immediately: >
"beats" / PLAY RND${clip_1a}-${clip_1b}
released_immediately__shift: >
"beats" / PLAY RND${clip_2a}-${clip_2b}
pad 1: "beats" / PLAY RND9-10
pad 1 (with shift): "beats" / PLAY RND41-42
pad 2: "beats" / PLAY RND11-12
pad 2 (with shift): "beats" / PLAY RND43-44
Notes
- Variables defined in
vars
are calculated anew every time they are required, i.e. they do not persist between presses of a control. - You cannot reference ClyphX Pro variables from inside an expression, e.g.
PLAY ${ %my_num% + 10 }
, but you can combine zcx templating with ClyphX variables, e.g.%my_track% / PLAY ${me.Index}
group templates¶
zcx allows you to define any arbitrary selection of controls as a group of controls. By grouping controls, we can apply a common configuration across all of them.
The syntax for defining a group is different for named controls and controls that are part of the matrix.
named controls¶
__scene_group:
includes: [scene_1, scene_2, scene_3, scene_4]
color: red
controls:
scene_2:
color: blue
gestures:
pressed: SCENE ${me.group_Index}
For named controls, we create a new entry that starts with a double underscore (__
). What follows the __
is the group name, in this case scene_group
. This group name is up to you.
The includes
key is a list of controls that belong to this group. Each member of the group will inherit all properties defined on the group. In this case each control in the group will launch a scene, relative to its position in that group.
overwriting properties¶
We can overwrite some or all of the group's properties for each member. This is done via the controls
key:
controls
is a dict of control definitions. Each key of controls
is the name of a control in this group. In this scene_2
key we can overwrite part or all of the group definition. We can also add properties that weren't defined on the group:
matrix controls¶
As matrix controls do not have names, the syntax used to group them is slightly different.
Groups vs Sections
Do not confuse matrix sections with groups.
Every matrix control inherently belongs to a matrix section. Groups can be used within a section, or ignored entirely.
Look at the config for hypothetical matrix section actions_right.yaml
:
-
color: yellow
gestures:
pressed: SEL / MUTE
-
color: blue
gestures:
pressed: SEL / SOLO
-
pad_group: my_pad_group
color: purple
gestures:
pressed: ${me.group_Index} / SEL
controls:
-
-
-
-
-
color: pink
gestures:
pressed_delayed: METRO
Here we have defined the first two controls in this section individually.
The third entry in the section has the key pad_group
. This indicates that we're looking at the definition for a group named my_pad_group
within this section
Note
It is not required that pad_group
be the first key in a group definition, though it is recommended for clarity.
You are not required to give a pad group a name. It can be left nameless like so:
The controls
key is required. This is a list, and every item in the list represents another member of the group:
Each of these dashes is a blank or 'null' entry in this list. By looking at controls
, we can see that four controls belong to this group. Like above, we are able to overwrite or extend individual group members:
Now all controls in this group will take the group definition, except the third control, which will be purple.
This is a representation of how zcx processes this section under the hood:
-
color: yellow
gestures:
pressed: SEL / MUTE
-
color: blue
gestures:
pressed: SEL / SOLO
# group definition is expanded
-
color: purple
gestures:
pressed: 1 / SEL
-
color: purple
gestures:
pressed: 2 / SEL
-
color: green # this property was overwritten
gestures:
pressed: 3 / SEL
-
color: purple
gestures:
pressed: 4 / SEL
# group definition ends
-
color: pink
gestures:
pressed_delayed: METRO
whole-section templates¶
It is possible to define an entire matrix section with one group definition. To do this, the yaml file for the section should contain a single dict, instead of the usual list:
This template will be applied for every control in the section. You can imagine the expanded output like this:
-
color: pink
gestures:
pressed: CLIP PLAY 1
-
color: pink
gestures:
pressed: CLIP PLAY 2
-
color: pink
gestures:
pressed: CLIP PLAY 3
...
control templates¶
In control_templates.yaml
, you may create a control definition that is available for any control to inherit from. Any properties defined on the template will be inherited on the child control. In the case of a conflict (the template and child define the same property), the child will overwrite the template.
__global__:
color: 127
hold_warning:
gestures:
released_immediately: >
MSG "You must hold this control to trigger it!"
play:
template: hold_warning
# color: 127 __global__ property, overwritten
color: green
gestures:
pressed_delayed: SETPLAY
released_immediately: > # added from `hold_warning` template
MSG "You must hold this control to trigger it!"
There is also a special template called __global__
. This definition will apply to every control in your zcx script. You can optionally prevent a control from inheriting from __global__
like so:
multiple inheritance¶
You can apply multiple templates sequentially to a control, like so:
__global__:
color: 127
foo:
color: red
gestures:
pressed: msg "I was pressed!"
bar:
color: blue
gestures:
released: msg "I was released!"
baz:
color: pink
This config will result in this control:
Notice that all four templates defined a color
option.
When using multiple templates, zcx merges the template definitions from left to right, in the same order you define them in.
When the same option is defined on multiple templates, and the difference is irreconcilable, the rightmost template wins.
In this case, the control is pink
.
foo
and bar
both have a gestures
key, but the gestures defined within are compatible, and so my_control
gets both the pressed
and released
gesture.