How does cat behave with patterns that are longer than one cycle?

I have this snippet

d5 $ (cat [
    slow 3 $ note "d'min a4'min'i g4'maj"
    , note "bf3'maj'i f3'maj'ii c4'maj'i"
    ]) # s "midi" # midichan "0" # legato 0.7

and I would expect as concatenation

  • the first 3 chords, one per cycle
  • the last 3 chords in one cycle
  • grand total: 4 cycles

But, Tidal gives me back a new pattern that is made of 6 cycles, where the second pattern in the list gets interleaved ie.

d'min                              -- first chord in first pattern
+ (bf3'maj'i f3'maj'ii c4'maj'i)   -- second pattern
+ a4'min'i                         -- second chord in first pattern
+ (bf3'maj'i f3'maj'ii c4'maj'i)   -- second pattern
+ g4'maj                           -- third chord in first pattern
+ (bf3'maj'i f3'maj'ii c4'maj'i)   -- second pattern

How is that? Does cat concatenate a list of patterns only if the patterns are all one-cycle long?
And how I can achieve the expected result, shall I move to seqPLoop?

Yes, cat basically concatenates if patterns are one-cycle. Or said in a different way - it takes one cycle of the first pattern, one cycle of the second pattern, one cycle of the third... until it gets to the end of the list, then starts with the second cycle of the first pattern and so on. In general, patterns don't know how "long" they are (they may never repeat!) so in your example there's no way for cat to know to repeat the first pattern three times.

So yes, seqPLoop might work for you, since you can tell it explicitly how long you want to run each pattern. Or you could use the mininotation:

d1 $ note "<d'min a4'min'i g4'maj [bf3'maj'i f3'maj'ii c4'maj'i]>" ...

Wouldn't append also work?

append works the same way as cat, it's defined like this: append a b = cat [a,b]

1 Like

Thanks @bgold, you're making my days recently!

I am interested in knowing a bit more about what you wrote above if you can elaborate?

This gets into the guts a bit, but deep down a Pattern is really just(1) a function where the input is a timespan (called an "Arc" in Tidal) and the output is a list of Events that occur during that timespan. There's no info on whether it repeats or not, or how "long" the pattern is. In fact, patterns like rand should basically never repeat, but even with a pattern like ("[0.25 0.5]/3" ~>) $ iter 4 $ s "{bd sn [cp cp]}%5" ... how long until it repeats? I have no idea, and it'd be a bit of a math puzzle to figure out. Fortunately, I don't need to, and neither does Tidal - it just asks for events during timespans.

There is one slightly special length of time, which is just the "unit" we choose to use when we count - a cycle. So functions like rev and cat can be (and are) defined to work with patterns one cycle at a time. But if you have some other timespan in mind you're going to need to specify it one way or another, by writing it out explicitly in the mininotation or specifying it as an argument to something like seqPLoop.

This is related to a kind of mantra I have to repeat to myself often: Patterns Are Not Lists. It's easy to think of them as being like lists, but that can be deceptive - lists have a length, a clear way to index their elements, an obvious well-ordering, etc. None of those are true for Patterns.

(1) OK, nowadays Patterns have a bit of extra stuff attached to them but this is effectively true 99% of the time.