You are on page 1of 12

Tidal patterning, an intermediate tutorial (part 1)

August 5, 2021

In this multi-part tutorial, I will be showing some tricks about using Tidal that are usually
not explained to beginners. This includes logistical principles about organizing your code,
some rather complicated but also powerful functions, and other kinds of trickery.

This tutorial is aimed at people who already know some Tidal. I don’t expect you to know
all of the functions beforehand, but I assume that you know the mini-notation, know how
to use continuous patterns, and understand what a higher-order function is. If you’ve read
the old tutorial on TidalCycles’s website, you’re good to go. Weeks 1-4 of Tidal Club are
probably enough, but keep the documentation close at hand.

My focus here will be on patterning, or sequencing events in time and space, and how to
do so in a way that is expressive and flexible. I won’t say much about other subjects, such
as manipulating samples, which I don’t have much experience with.

This was going to be a very, very long post, but I decided to split it into parts for
everyone’s sanity. Part 1 is still rather long, so take your time, experiment with what you
learn and go through it in multiple sittings, if you need to.

Note: most of the things I am going to say will be very opinionated. I’ll always be talking
about what works for me, but one of the reasons Tidal is a beautiful tool is that it allows you
to express yourself in a very personal way. If at any point you feel a need to deviate from my
suggestions, please do so!

Before we begin, a simple synth


I will use many code examples throughout the article and suggest that you try out all of
them! For the sake of simplicity, I will only be using samples that you get with your
standard SuperDirt installation. However, we will also need a simple synth, because I love
synths!

SynthDef(\simplefm, {

arg out, sustain, pan = 0.5, note = 60, pitchval = 1, pitchenv = 0.01, detun
= 1, gain, fmfreq=1, fmamt=1;

var env, freq, sig, glide, fm;

env = EnvGen.ar(Env.perc(0.001, sustain, gain), doneAction:2);

glide = XLine.kr(pitchval,1,pitchenv);

freq = note.midicps * detune * glide;

fm = SinOsc.ar(freq*fmfreq, 0, fmamt);

sig = LeakDC.ar(SinOsc.ar(freq*fm, 0, env));

OffsetOut.ar (out, DirtPan.ar (sig, ~dirt.numChannels, pan));

}).add

This is a simple FM synth with a percussive envelope. Don’t worry if you don’t understand
everything, we won’t be touching SC anymore. To use it, simply copy-paste the above
block of code into the SuperCollider IDE and evaluate it with Ctrl-Enter. To manipulate the
FM parameters, you will also need to evaluate the following block of code, this time in
Tidal:

let fmfreq = pF "fmfreq"

fmamt = pF "fmamt"

Notes on notation
Before we dive into some cool patterns, a few words about how to write them. Writing
style has a lot of influence over how you understand and think about your code, so you
should take some time to work out how you want to lay it out. Some properties you may
want your code to exhibit are:

Readability: you want to be able to know, at a glance, where everything is. This allows
you to edit your code with less effort and to quickly understand what something does
a year after writing it. It’s also very nice for your audience, even if they don’t speak
Tidal!
Flexibility: you want to write things in a way that will allow you to easily make
variations and change what the code does. This is especially important if you’re live
coding, since you are always changing things up and bringing things into new
directions. Generally speaking, you want to make room for the kind of changes you
think you might want to introduce in the future, even if you’re still not quite sure of
what those are.
Brevity: this not only helps with readability but also helps you live code faster.

Sometimes you will have to figure out what’s readable or flexible depending on the
current context. However, developing a consistent writing style can help a lot. My main tip
is that different building blocks in your pattern should be graphically separated. The most
obvious way to do this is to write each conceptual unit (functions, patterns) on a different
line.

For example, this pattern (which I find very hard to read):


Example 1

d1 $ off 0.125 (|* speed "2") $ every 4 (fast 2) $ iter 6 $ sound "bd sn drum dr

could easily be rewritten as:


Example 2

d1

$ off 0.125 (|* speed "2")

$ every 4 (fast 2)

$ iter 6

$ sound "bd sn drum drum"

This is much easier on my eyes! I immediately understand what’s going on: we have a
drum pattern, expressed in mini-notation, which is being modified by three functions
(iter, every and off). Each of these functions modifies the product of the previous one,
and their logical order is clearly represented by them being on different lines. Some of
these are higher-order functions, and their function arguments are on the same lines as
them, which makes a lot of sense if you think, for example, of fast 2 “being contained in”
or “belonging to” every 4. There is also ample room for comments!

Writing one function per line helps you see the whole pattern as a series of complex
modifications applied, in a specific order, to a simple base pattern. If you’re familiar with
anything from guitar pedals to modular synths to DAW mixing, you’ve probably heard of
an effects chain, a series of effects that modify a sound in a certain order. In analogy to
that, I will be referring to this as a function chain.

Note how every line except for the first one starts with a dollar sign. You don’t have to do
this, but I think it’s both pleasant and useful to place your punctuation such that every line
starts with punctuation of some kind.

Applying this rule can sometimes be tricky, especially when working with lists of patterns:
Example 3

d1

$ fast 2

$ stack [

sound "bd sn"

sound "hh hh hh" ]

# gain 0.8

# speed 1.2

Here, the lines starting with sound look misaligned, which can look ugly and confusing.
However, there is a way out, which requires us to do the Haskell function id. That’s the
identity function, which does absolutely nothing:
Example 4

d1

$ fast 2

$ stack [ id

$ sound "bd sn"

, id

$ sound "hh hh hh" ]

# gain 0.8

# speed 1.2

By using id to do nothing to the patterns inside the list, we managed to fit a couple dollar
signs in.
This is the notation that I’m going to use to write the examples from now on. Take some
time to try things out and find a way to write code that makes sense to you, both visually
and conceptually.

One last tip, regarding both readability and flexibility: never, or almost never, write in
decimals what can be written in fractions. To understand why, let’s go back to Example 2.

You are playing this nice drum pattern, which features, among other things, the off
function with a first argument of 0.125, making a copy of the pattern delayed by one
eighth of a cycle. It’s easy to understand why it does that, because 0.125 is a relatively
simple number. What if you’re live coding, and now you want to halve that number? Well
it’s easy, you replace it with 0.0625. Halve it again? 0.03125, obviously. Now halve that,
and multiply it by 0.75 so it’s a bit syncopated? Can you do that while playing in front of
an audience? If you save that file and see the result one year from now, are you going to
remember what that number is supposed to mean?

Now compare this to having it written as (1/8). You halve it to (1/16), then again to
(1/32). Halve it, then multiply by 3/4? It’s (1/64), then (3/256), which you may prefer to
write as (3/(64*4)).

The second kind of calculation is much easier to do because you’re working with integers,
and you can almost always write numbers like that, because temporal relationships in
music are usually ratios between simple integers. As long as you can use fractions over
decimals, your code will be more readable and flexible if you do so.

Now let’s make some patterns.

Stacking
For many reasons, you often want to play multiple patterns at the same time. Resources
for beginners usually show you multiple ways to do it, but they don’t go too deep into the
pros and cons of the different options.

Let’s start small. First off, there is the obvious way:


Example 5

d1 $ sound "bd*2"

d2 $ sound "hh*3"

This works, but it quickly becomes unsatisfying. The most annoying thing is, you can’t
evaluate both patterns at the same time. This means that not only can’t you make them
start simultaneously, you also cannot edit them in tandem and have the changes go off
together. The main benefit you get is that it’s very easy to silence one of the patterns while
the other one(s) keep going.

But you probably know a way to make them start together, right?
Example 6

d1 $ sound "[bd*2, hh*3]"

This loses a lot of power compared to the previous technique, though. You can’t apply a
function to only one of the patterns: it is automatically applied to all of them. You can’t
always easily mute only one of them. Isn’t there a better way?

Of course. Enter do:

Example 7

do

d1

$ sound "bd*2"

# gain "0.9"

d2

$ sound "hh*3"

This is like example 5, but improved: we are evaluating completely separate patterns at the
same time! The indentation also looks very nice and helps separate the different patterns.
But there is still a thing we cannot do: we cannot apply a function to all of the patterns at
the same time.

I saved the best for last, of course.


Example 8

d1

$ iter 4

$ stack [ id

$ fast 2

$ sound "bd*2"

, id

$ sound "hh*3"]

stack is your most powerful tool, covering all the use cases we have seen so far. It takes a
list of patterns and combines it into a single pattern, so that you can apply transformation
either to single patterns inside the list (like fast 2 in this example) or to the whole stack
(like iter 4). This means that it’s usually much better than everything we’ve seen so far,
and you should probably default to it unless you have a good reason not to.

stack is great because it lets you combine patterns that may be completely different and
unrelated to each other. What if you want your patterns to be related to each other,
though? What if you wanted your code to express that clearly? Take the following
example:
Example 9

d1

$ fast 2

$ stack [ id

$ sound "bd drum ~ sn"

, id

$ iter 8

$ sound "bd drum ~ sn"

, id

$ sound "hh*2"]

Here, we are playing a simple drum pattern against an iterated version of itself. If we
want this relationship between the first and the second element of the list to hold, editing
this pattern is bothersome, because we have to make any change twice.

How can we write the pattern just a single time?


Example 10

let pat = sound "bd drum ~ sn"

in

d1

$ fast 2

$ stack [ id

$ pat

, id

$ iter 8

$ pat

, id

$ sound "hh*2"]

let is a good friend, whose utility is easy to overlook. Whenever you have to write
something multiple times, and expect all of its instances to change together, you should
consider doing this, as it makes everything shorter and more flexible. If you think you will
want your patterns to become completely different from each other later, you should not
use let, and write both of them down instead.

However, let is not the only way to accomplish this:

Example 11

d1

$ fast 2

$ stack [ id

$ superimpose (iter 8)

$ sound "bd drum ~ sn"

, id

$ sound "hh*2"]

superimpose (iter 8) makes a copy of a pattern, applies iter 8 to it, and stacks the
pattern with its copy. This is much shorter than Example 10, and it also has another
benefit: if at some point you decide that you want to apply this function to the whole
stack, you only need to cut that line and paste it just after fast 2:

Example 12
d1

$ fast 2

$ superimpose (iter 8)

$ stack [ id

$ sound "bd drum ~ sn"

, id

$ sound "hh*2"]

This is another reason why “one dollar per line” is a good rule: to change a function’s
position in the function chain, you only need to cut-and-paste the line where that function
is.

superimpose takes only one function as argument. So what are we supposed to do if we


want to apply more than one function to the superimposed pattern? As you may know,
functions can be composed with the dot operator:
Example 13

d1

$ fast 2

$ superimpose (iter 8 . (|* speed 1.5))

$ stack [ id

$ sound "bd drum ~ sn"

, id

$ sound "hh*2"]

Here, the . in (iter 8 . (|* speed 1.5)) composes its two operands, meaning that it
takes the two functions and smashes them together in a single function. Now the whole
stack is being superimposed on an iterated version of itself with increased sample speed.
You can chain as many dots as you like.

superimpose can be very useful: it is sometimes, although by no means always, a better


alternative to let. But superimpose is just a special case of a much more powerful
function.

Superimpositions
Let’s take a very simple synth pattern:
Example 14

d1

$ superimpose (|+ note 7)

$ note "50 ~ ~ 50 ~ ~ 48 ~"

# sound "simplefm"

# sustain 0.5

# gain 0.8

# fmamt 2

We have a note pattern and replicate it a perfect fifth (meaning “seven semitones” in
music theoryese) above. Now what if we didn’t want the superimposed pattern to play
exactly at the same time as the original? What if we wanted it to be slightly… off?

Example 15

d1

$ off (1/8) (|+ note 7)

$ note "50 ~ ~ 50 ~ ~ 48 ~"

# sound "simplefm"

# sustain 0.5

# gain 0.8

# fmamt 2

off does the same thing as superimpose, but it also shifts the copy further in time by a
specified number of cycles. The number doesn’t have to be positive: Tidal, unlike most
other software, allows you to send things back in time! The number can also be zero, and
it is easy to see how off 0 is just the same as superimpose.

What if we wanted to superimpose multiple copies and offset them sligthly? Turns out,
there is a function for that:
Example 16

d1

$ stutWith 3 (1/8) (|+ note 7)

$ note "50 ~ ~ 50 ~ ~ 48 ~"

# sound "simplefm"

# sustain 0.5

# gain 0.8

# fmamt 2

stutWith creates n-1 copies of the original pattern, offsets them by a specified cycle
count, and applies a function to them. If you have trouble wrapping your head around it,
play with it for a moment.

Through the power of function composition, you can use stutWith to build rather
complex patterns, like this:
Example 17

d1

$ fast (3/2)

$ stutWith 5 (1/8) ( id

. (|+ note 7)

. (|* sustain (3/4))

. (|* fmamt (9/8)) )

$ note "50 ~ ~ 50 ~ ~ 48 ~"

# sound "simplefm"

# sustain 0.5

# gain 0.8

# fmamt 2

Here, we are stacking perfect fifths, with higher notes becoming progressively sharper in
timbre and shorter in duration. Doing this with stack would be a nightmare, while this
way is very readable and elegant. Everything having a dedicated line makes it easy to
apply any change to the whole process.

These three functions have a curious relationship: superimpose is just off 0, and as you
may have noticed, off is just stutWith 2. As a consequence, superimpose is just
stutWith 2 0. Simple functions being special cases of more powerful functions is
something that happens often in Tidal (sometimes by design, sometimes not), and it’s a
good idea to pay attention to it when it happens.

So in these cases, how do you decide which one to use? It depends. The simplest function
is the one that will take the least space on the screen and be the easiest to read and
understand quickly, and those are definitely benefits, for both you and your audience.
However, even if you are not using all the power of a more complex function right now,
having it in your code means that you can start using that power at any time, easily and
quickly, which can be especially important in a live setting where you want your code to be
flexible. We never know what the future holds, so in case of doubt, I suggest that you use
the more complex function to keep your options open.

Note that if you are often using a specific case of a very powerful function, it might be
useful to define that case as its own, more specific, function. For example, if you know that
you only want to use stutWith to create copies of a pattern at 0 delay with higher pitch,
you can evaluate something like let superLayer copies pitch = stutWith copies
0 (|+ note pitch). This gains you some extra clarity:

Example 18

-- a function for people who really, really like supersaws

let superLayer copies pitch = stutWith copies 0 (|+ note pitch)

d1

$ fast (3/2)

$ superLayer 4 7

$ note "50 ~ ~ 50 ~ ~ 48 ~"

# sound "simplefm"

# sustain 0.5

# gain 0.8

# fmamt 2

Functions of this kind are among the easiest to write yourself, and they’re a good place to
start if you want to start building a library with your own functions. We will be looking at
how to do this in a later part, but for now a let statement will suffice.

Patterning functions
You probably already know that the parameters of most functions are patternable. This
means that you can replace an argument of any type with a pattern of the same type: for
example, fast 4 can become fast "<2 4>", or even fast (range 2 4 $ slow 2 $
sine).

This feature wasn’t always there, and its advent made Tidal a lot more powerful than it was
before. One important consequence is that the “core” pattern, the one that causes events
to be generated deep down before functions are applied to it, doesn’t have to be your
main focus of interest. Let me explain what this means.

When you start learning Tidal, you are taught that the mini-notation is a language that
enables you to write rhytmic patterns. It is very powerful and you can do complex things
with it! Then, you learn how to sprinkle functions on top of your rhythm, to modify it
somehow. However, as your functions gain the power to become rhythmically complex
themselves, they can put in just as much work as the base pattern, since they can exploit
the power of the mini-notation in the same way! While it is intuitive to think of your sound
as your main rhythmic motif that you are applying functions to, sometimes you will prefer
a very dull base pattern, while the functions that you are applying to it are very intricate in
their temporal development:
Example 19

d1

$ fast "<[8 4 8 6] [8!2 [16 [32 64]] 12]>"

$ sound "bd drum"

Here, the base pattern is kept intentionally very simple, because we want to focus on the
way its speed varies over time. If you tried doing this with a complicated base pattern, you
would risk losing track of what’s happening at a higher, “meta” level.

Which part of your code you should be making more complex, whether the base pattern
or some patternable function or some other patternable function, depends a lot on what
you want your focus to be: do you want to keep adding new samples over time? Do you
want to be working on a more meta-rhytmic level? Etc.

The pattern that is used as an argument for fast is a bona fide pattern, and functions can
be applied to it normally. The only difference is that it may not be a pattern of events (a
ControlPattern, in technical jargon). Before I explain, here are two examples:
Example 20

d1

$ fast ( id

$ stack [ id

$ "<[8 4 8 6] [8!2 [16 [32 64]] 12]>"

, id

$ "<4 4>" ])

$ sound "bd drum"

d1

$ fast ( id

$ stutWith 3 0 (|/ 2)

$ "<[8 4 8 6] [8!2 [16 [32 64]] 12]>")

$ sound "bd drum"

Confusing? Definitely, but still worth looking into. In the first example, we are using stack
to add another version of the pattern; this one has a fixed rhythm, so it provides a more
stable baseline while the first one does weirder things.

To understand the second example, we need to stop for a minute and talk (in a very
simplified way) about types in Haskell. As in most programming languages, all values in
Haskell have a type: 3 is an integer, (3/2) is a rational number, “ada” is a string, etc. All
functions can be applied to some specific types of values, but not to others. A pattern is a
kind of “container” type: every pattern contains element of another specific type. This
means that a pattern can be a pattern of integers, of rational numbers, or of other things.
Most of the time, you are patterning samples or notes, and in those cases, you are usually
dealing with pattern of a specific type, called ControlPattern. However, as you can
probably guess by looking at it, here the pattern "<[8 4 8 6] [8!2 [16 [32 64]]
12]>" is a pattern of numbers (of rational numbers more specifically).

Now, in the second example, we are using stutWith to create copies of the pattern, but
dividing the values by 2 each time we make a copy. The result is equivalent to a stack of
<[8 4 8 6]..., <[4 2 4 3]..., and <[2 1 2 (3/2).... This is something you couldn’t
do when applying stutWith to a base pattern, because it makes no sense to “divide” a bd
or a sn by 2! However, fast takes a pattern of rational numbers, so division is an
appropriate function to apply.

Arpeggios
arpeggiate and its sibling arp are interesting functions. They were originally designed to
be used with chords, but they power goes much beyond that. First of all, let’s look at the
most basic, intended use.

This is a simple arpeggio:


Example 21

d1

$ arpeggiate

$ note ("[50, 53, 57, 62]")

# sound "simplefm"

# sustain 0.5

# gain 0.8

# fmamt 2

The base pattern is a chord that is played all at once. But arpeggiate spreads it out,
playing one note at a time! If you want to control the order of the notes, you can use arp:

Example 22

d1

$ arp "<up converge down diverge>"

$ note ("[50, 53, 57, 62, 65, 69, 74]")

# sound "simplefm"

# sustain 0.5

# gain 0.8

# fmamt 2

The options you can use for arp are listed in the documentation.

arpeggiate doesn’t strictly work with chords, though. It spreads out events when there
are multiple events happening at exactly the same time, and it does so by taking the
timespan between the moment in which the events would occur and the moment when
the next event should occur, and spreading them evenly in this timespan. Some interesting
things can happen:
Example 23

d1

$ arpeggiate

$ stack [ id

$ sound "bd*8"

, id

$ sound "sn*8"]

From looking at the stack, it’s obvious that the two patterns should be in perfect sync.
However, when adding arpeggiate, the times where the two events overlap are spread
out, and they get desynced.

Conclusion
We have looked at a bunch of different, disconnected things: now putting them together
is your job! I hope you will find at least some of them helpful :)

There are many things I would still like to talk about, enough to get us at least to part 4 (a
very incomplete list: how to make your own function library, spaceOut, inside, kindohm’s
custom mapp function, elastic tempi, microtonality, plyWith, fix, contrast), but I’m
closing part 1 here, and will continue when I have time and spoons.

If you have any kind of feedback for this part, or would like to suggest content for future
parts, you can send me an email.

Thanks for getting this far and happy music making!


Home

You might also like