Control Busses
This page introduces the feature known as control busses, which was introduced on Tidal 1.7.
Control busses let you route an effect via a bus. In practice, this means you can pattern the effects of a sound while it's playing.
Why we need control busses
Let's say we want to modify the sax
sample as it's playing, applying distinct values of the squiz
effect:
d1 $ sound "sax" # legato 1 # squiz "1 2 5 1.5"
This won't work. As the structure is defined by sound "sax"
there is only one event per cycle, so squiz
will always take the first value (1
).
There are some workarounds we can try:
d1 $ sound "sax" # legato 1 >| squiz "1 2 5 1.5"
Now the structure is taken from the right part, so there will be 4
events per cycle, each one with a different squiz
value. But the sample will be triggered 4
times from the beginning. We'd like to modify squiz
as the sample is playing, not by retriggering it.
Another idea is using chop
:
d1 $ chop 4 $ sound "sax" # legato 1 # squiz "1 2 5 1.5"
This cuts the sax
sample into four pieces, and applies one of the squiz
values to each piece. As the sample doesn't last for exactly one cycle, there is a noticeable change in sound at the cut points, and sound is not smooth.
Using control busses
The above problem can be easily solved using a control bus:
d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5"
Now we are modifying the squiz
amount while the sample is playing.
squizbus
is defined like this:
Type: squizbus :: Pattern Int -> Pattern Double -> ControlPattern
The first parameters is an identification for the control bus. It needs to be unique, so if you were controlling two effects separately you would need to use different numbers:
d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5" # lpfbus 2 "400 2000 3000" # lpq 0.2
This identification needs to be unique across all patterns, unless you wanted two subpatterns to be controlled from the same source. In that case, you would probably have e.g. one control pattern like lpfbus 2 "1000 5000"
and others receiving only like hpfrecv 2
:
d1 $ sound "sax" # legato 1 # lpfbus 2 "400 2000 5000" # lpq 0.4 # pan 0
d2 $ sound "sax" # legato 1 # hpfrecv 2 # pan 1
Here, you can hear how the low pass filter and the high pass filter change as the sample plays, but using both the same values.
hpfrecv
is defined like this:
Type: hpfrecv :: Pattern Int -> ControlPattern
You can even pattern that identification:
d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5" # lpfbus 2 "400 2000 5000" # lpq 0.4 # pan 0
d2 $ sound "sax" # legato 1 # hpfrecv "<2 1>" # pan 1
Most effects have a bus
and a recv
function to be used this way.
Control busses can also be used to create LFOs on effects:
d1 $ slow 6 $ note "c'maj" # s "superpiano" # legato 2 # lpq 0.2 # (lpfbus 1 $ segment 512 $ fast 4 $ range 200 2000 $ sine)
d1 $ slow 6 $ note "c'maj" # s "superpiano" # legato 2 # lpq 0.2 # (lpfbus 1 $ segment 512 $ fast 4 $ smooth "200 2000")
Note that in these examples, we use segment
to sample the value of sine
and smooth
, as these are continuous patterns and won't work directly.
Additionally, you can prepare patterns to receive control signals, and then send them from other patterns:
d1 $ s "ade" # panrecv 1 # lpfrecv 2
once $ slow 4 $ panbus 1 $ segment 128 $ range (-1) 1 $ fast 4 $ sine
d2 $ lpfbus 2 $ segment 128 $ smooth "2000 0"
Limitations
Not all control parameters can be controlled via a bus. The following is the whole list of parameters that can't be:
midinote, note, n, octave, begin, end, sustain, legato, loop, unit, length, fadeTime, fadeInTime, speed, endSpeed, gain, overgain,
channel, lag, offset, sound, array, midichan, control, ccn, ccv, polyTouch, midibend, miditouch, ctlNum, frameRate, frames,
hours, midicmd, minutes, progNum, seconds, songPtr, uid, val, timescale, timescalewin, accelerate
Note that note
, n
, gain
and accelerate
are in this list, but amp
is not.
If you try to use a bus on one of these parameters, you will receive an error message like this:
d1 $ sound "sax" # nbus 1 "0 1 2"
Error in pattern: Control parameter 'n' can't be sent to a bus.
panbus
will work, but in the range -1 to 1 instead of 0 to 1:
d1 $ sound "sax" # panbus 1 "-1 0 1"
Control busses and MIDI
It is possible to map MIDI CC numbers to control busses, and use an external MIDI controller to modify parameters in real time.
d1 $ n "<d6'm9 g6'dom7'ii>" # s "superhoover" # djfbus 1 (cF 0.5 "21")
In the above example, CC number 21
is mapped to djf
. cF
indicates that the MIDI CC value is to be treated as a float, and the 0-127
value from the MIDI signal is automatically converted to a 0-1
range. 0.5
is the default starting value.
d1 $ n "<d6'm9 g6'dom7'ii>" # s "superhoover" # roombus 3 ("^23")
In this example, roombus 3 ("^23")
maps CC number 23
to the room
parameter, without specifying any initial value.
In some cases, you'll need to adapt the default CC values range:
d1 $ n "<d6'm9 g6'dom7'ii>" # s "superhoover" # squizbus 2 (7 * "^22" + 1)
squiz
amount doesn't have a 0-1 range for its values. We need values greater or equal than 1
for this.
In the last example, the 0-1
range is modified, getting a range from 1
to 8
, which are good values for squiz
.
The whole example and the resulting sound is available at this forum post by @cleary.