TidalCycles (or just ‘Tidal’ for short) is free/open source software for making patterns, mainly musical ones. I made it while a research student, and have been working on it for many years since, with the help of contributors. One thing I’ve always been struck by is how even though Tidal is an extremely logical (to be exact, pure functional) system, it is something that I’ve only understood through the process of making it. Even now, over ten years into development, I notice something that simplifies understanding of what Tidal is and how it works (or should work).
For example, a core feature of Tidal is how easily two patterns can be combined, often creating an interesting ‘interference pattern’. For example taking one pattern:
and a second one:
they can be easily added together like this:
I hope the above is clear without too much explanation – each piece of code is shown with a diagram showing the resulting structure.
Notice that the structure resulting from the combination (by addition) of the two patterns is made up of intersections between matching events from the two source patterns. There are four intersections, so first we have
1 + 4 = 5, then
2 + 4 = 6,
2 + 5 = 7 and
3 + 5 + 8.
|+| is used to take simple intersections, but there are two other ways to add patterns together. In particular, he
|+ operator preserves structure from the pattern on the left, and
+| preserves structure from the pattern on the right. Here are the results:
You can see in the above that the intersections are still the same, but Tidal keeps note of the whole events that the intersections are part of, illustrated with a dashed border. Note that the vertical position of the events in the above diagrams are not significant, beyond showing that the event wholes overlap and so events are shown ‘stacked up’. In the first example, these wholes come from the pattern on the left, and in the second example from the right. This becomes really crucial when it comes to triggering (e.g. musical) events from the patterns, because if an event is missing its first part, it doesn’t cause a sound to be triggered. Such events are still useful for combining with other events, but do not actually contain an ‘onset’ by themselves.
If you want to try this out and have Tidal installed, here’s ‘real world’ examples that actually make sound:
d1 $ note ("1 2 3" |+| "4 5") # sound "superpiano"
d1 $ note ("1 2 3" |+ "4 5") # sound "superpiano"
d1 $ note ("1 2 3" +| "4 5") # sound "superpiano"
You’d hear that the above
|+| example results in four triggers, the
|+ example results in three triggers, and the
+| example results in two triggers. (Note that you could use
+ instead of
|+| in the above, they do exactly the same thing).
This behaviour is core to Tidal, and has arisen from a few insights. Once was while practicing on the train on the way to a performance, I noticed that if I swapped around the order of patterns that were being combined, the behaviour changed – I’d implemented this without understanding its usefulness at all. This is so nice – you write code by following it to its logical conclusion, and only then can start to use it and begin to understand and make use of that logic.
Another insight came another Tidal contributor – David Ogborn, who a year or so ago suggested that structure could come from both sides. This seemed ridiculous as until then ‘structure comes from the left’ had actually become a Tidal mantra, but it is always good to take ridiculous ideas seriously and with some thought this idea lead to a major clarifying rewrite of Tidal’s innards.
The most recent insight came earlier this week – the realisation that it is not really structure that comes from the left or right – the intersections in the above example are always the same! These intersections are the salient event parts, and it is the event wholes that are preserved from one or the other side, telling us whether the resulting events have had their starts lopped off or not, and therefore whether they should trigger anything. This feels like such a fundamental structural insight to gain this late in Tidal’s development, and clears up a confusion that I’ve had for years without knowing it. It took a couple of hours to ‘fix’ the underlying representation. This was a representational simplification rather than any kind of extra feature, but I feel sure many useful features will come out of it.
In conclusion, I just wanted to get across that even working in the logical domain of pure functional computer programming, to take things forward you have to step into the dark, without really knowing where you are going, and work beyond your perceptual capabilities by thinking with tools and languages.