Can I refer to patterns inside a pattern in Tidal to combine them?

Hi, I'm new to Tidal but I've used some Haskell in the past. I'm going through the workshop and the video tutorials, and had a question about combining my patterns. Maybe it's not how Tidal is supposed to work, but I wanted to make some sort of mixing of previously defined patterns. For example: say I have patterns d1, d2, d3, d4. I want to mix and play some of those patterns simultaneously in a more complex orchestration without having to copy and paste them multiple times. Maybe like

time --->
d1 ~~ ~~ d1 d1
d2 ~~ d2 ~~ d2
~~ d3 d3 ~~ ~~
~~ d4 ~~ ~~ d4

So from what I understand from Concatenation | Tidal Cycles perhaps I'd write it as

d5 $ cat "[d1, d2], [d3, d4], [d2, d3], [d1], [d1, d2, d4]"

This would let me make named patterns and then kinda like combine them into a longer thing that I can then "visualize" better in the code.

Does this make sense?

here is one way to look at it: you have a pattern of patterns, so you need a function join :: Pattern (Pattern a) -> Pattern a, see slides of my talk at https://www.imn.htwk-leipzig.de/LFUNK2026/

This function is seemingly avoided (but hidden in the implementation) if you use inhabit on a pattern of names-for-patterns, https://uzu.lurk.org/t/motivating-examples-for-squeeze-join/6213/2

1 Like

Hi, and welcome to Tidal!

If you picked d1, d2, d3, d4 just as arbitrary names, that’s fine, but be careful: in Tidal, d1…d12 are not patterns, they’re output channels (connections to SuperDirt). d1 $ s "bd sn" means “play this pattern on channel 1”. That’s why you can’t use d1 as a value inside another pattern, and why cat "[d1, d2], ..." won’t work (also, cat takes a list of patterns, not a mini-notation string).

If you meant them as names for your building blocks, define them as normal Haskell variables with other names:

let a = s "bd*4"
    b = s "~ sn"
    c = s "hh*8"
    d = n "0 3 5 7" # s "superpiano"

For the kind of “score” you’re describing, there’s a function made for exactly this: ur (short for “pattern of patterns”). It takes the length in cycles of the whole piece, a mini-notation string that arranges names over time, and a list pairing each name with a pattern:

d1 $ ur 5 "[a,b] [c,d] [b,c] a [a,b,d]"
  [ ("a", a)
  , ("b", b)
  , ("c", c)
  , ("d", d)
  ]
  []

Here:

  • 5 is the total length in cycles, so each of the 5 steps lasts one cycle.
  • [a,b] plays patterns at the same time, like the columns in your diagram.
  • ~ gives you a silence, so a ~ ~ a a works for your sparse rows.
  • The last empty list [] is for named transformations (functions applied to patterns), which is handy when you want variations of the same material.

Your table reads column by column as "[a,b] [c,d] [b,c] a [a,b,d]", which is exactly what’s above.

If you’d rather keep each row as its own channel, plain cat with silence also works:

d1 $ cat [a, silence, silence, a, a]
d2 $ cat [b, silence, b, silence, b]

but for composing a longer structure from named blocks, ur is usually the nicest fit. You can check its page in the docs under “Composition”.

Hope this helps, and have fun!

1 Like

Thanks! That's right what I looking for. The possibilities seems endless when exploiting functional programming techniques, I have to make the effort to not be overwhelmed hehe

The example from the Composition docs is so spot on :slight_smile: