Tidal patterns vs SuperCollider patterns

Apologies if this does not exactly fall into the category - feel free to move the question around.


I have been exploring the family of P objects in SuperCollider (eg. Pseq, Pbind, Pstut) and the ideas underlying patterns - eg. their stateless behaviour, why using patterns instead of routines etc.
Some questions have come to me, such as:

  • what is the main difference between a pattern in Tidal and one in SuperCollider, if it exists?
  • what are pros/cons of designing a pattern in either Tidal or SuperCollider?
  • etc.

I don't think there is a specific answer for this, nevertheless, I would love to share some opinions.
Cheers.

2 Likes

I'd love to hear an answer to this too! I haven't used supercollider patterns myself, it'd be interesting to see an example of how they can be used to control superdirt directly.

1 Like

I'm curious about this as well.

I'm not a big expert on using SC patterns, but unlike Tidal Patterns they're explicitly lists - there's a "next" function to obtain the next value, and they do not themselves have any notion of timing or type. How a SC pattern differs from a vanilla SC list is mostly in that they are evaluated "on demand" and can be infinite.

In practice, using a bunch of SC patterns inside a Pbind to control a SynthDef can wind up being rather similar to what Tidal can do. But the notations are quite different and there are still differences in how you can or can't merge together things with different timing.

I think this can be an example:

(
p = Pbind(
	\type, \dirt,
	\dirt, ~dirt,
	\gain, Pseq([Pseq([0.9, 0.5], inf), 0.3], inf), 
	\sound, Pseq(["bd", "sd"], inf),
    \dur, Pseq([0.25, 0.75], inf)
).play;
)

p.stop;

In Tidal, you can do it using something like this (I hope!):

d1 $ fast 2 $ s "bd sd@3" # gain "<0.9 0.5> 0.3"

(I added the fast 2 to kind of match the speed).

What I can see here is the following:

  • you have a clear separation between the sound (as note played) and its duration, whereas mininotation brings them together;
  • some patterns pairs (the \key, value that represents the parameter for an action) can be mapped to the functions in Tidal, eg. `gain;
  • it is more verbose;
  • patterns do not repeat infinitely by default;
  • you can nest patterns in patterns, as in Tidal;
  • I feel like the timing is kind of more "fluid" in the example in SuperCollider (of course you are missing all the architecture about cycle, fractions of the whole etc.)

Agreed. I think what I would like to get is some (musical) situations where Tidal patterns are far superior to SC ones and vice versa.
I've been kind of trying to find the example that breaks either paradigm :upside_down_face:

Can you give me an example, please?

One thing is that the Tidal syntax is more concise and more elegant. I find it easier to read a Tidal pattern compared to a Pbind. I would love to see something like the Tidal syntax as an alternative syntax for Pbinds directly in SuperCollider. Take a look at this example taken from the documentation:

d1 $ slow 2 $ 
  n (off 0.25 (+12) $ off 0.125 (+7) $ slow 2 "c(3,8) a(3,8,2) f(3,8) e(3,8,4)") 
  # sound "superpiano"

Writing the same pattern using the default SuperCollider pattern syntax would be a non-trivial task. The next one goes further into offsetting patterns and it is still manageable/readable:

d1
  $ slow 2
  $ stack [
  note "c(3,8) a(3,8,2) f(3,8) e(3,8,4)",
  off (slow 2 $ segment 24 $ sine) (+0) $ note "<c7(7,8) c6(7,8) c5(7,8)>",
  off "<0.5 0.25 0.5 0.75>" (+7) $ "c(3,8) a(3,8,2) f(3,8) e(3,8,4)" |+ note 12]
  # s "superpiano"

It might not answer directly to your question, but I hope that it shows that playing with time/repetition/structure is somewhat more easier on the Tidal side. Of course, with enough dedication, you could surely obtain the same pattern using SCLang.

I seems that one difference is in how they deal with evolutions over time and longer time frames. Tidal seems to be designed on the user to evolve patterns over time in terms of performance, whereas it seems easier in SC to define envelopes and modifiers that operate at various time levels to control the sound evolution over a longer period of time. So in other words, improvised vs designed (or more broadly stage vs studio)… I’m not sure if this makes sense, and I know that there are many things that break this rule, but generally that’s my understanding/feeling.

But somebody please correct me!

1 Like

I was thinking of a Tidal example like:

"0 1 2" |+| "3 4"

where the structure comes from both Patterns. While I wouldn't be surprised if there's some way to get this kind of behavior in SC, it doesn't seem at all simple.

3 Likes

I see what you mean, and I agree - if you take a peek at my recent posts, I've been trying to study patterns in terms of interferences following Schillinger's theory of rhythm and it is handy when done in Tidal.

On the other hand, something that in Tidal I find slightly difficult to handle is when you want patterns to have lengths that are not multiples of a cycle:

"{1 2 3 4 5}%4"

One more example of phasing patterns of one event each:

d1 $ stack [ 
    "{t f!7}%8" $ s "bd"
    , struct "{t f!8}%8" $ s "sd"
    ,struct "{t f!9}%8" $ s "hh"
]

because I am not really thinking in terms of cycles but more in pulses (or beat or tactus, whatever you want to call it).

Yes, I think it does make sense.

Unless you specify that a stream must be infinite, the pattern will be repeated only a finite amount of times.
Moreover, there is a distinction between pattern as the blueprint and stream as the sequence of events, whereas it is my understanding that in Tidal a pattern is a function that automatically translates into time.

My feeling is that SC allows for more fine-coarse settings of your blueprint, with all pros and cons within.


One addendum here: my curiosity comes from the fact that recently I happen to have a lot of synthesiser parameters that I want to modulate. There are several ways to do so:

  • inside the synth using modulation functions
  • using Tidal with cc MIDI messages
  • using SC with patterns and CC

What I can experience is that rhythmic sequences work best, but if you try to modulate parameters such as filter cutoff, resonance waveform shape etc. listening to the same recurring drawing becomes...boring. If you think, it is also not the way you would do on a physical device - all in all, we have two hands.

Certainly, you can schedule short sequences in Tidal using seqP and friends, but it becomes much complicated. Therefore, I am asking myself whether I shall take the "parameter modulation" topic outside Tidal.

2 Likes

There are many. I can name just two:

Afaik, you can nest patterns in both, but in SC you can nest different kinds of patterns while in Tidal you nest sequences and chain functions to modify the whole thing, with a few exceptions that minitidal allows (like random). Please correct me if I'm wrong. I'd love to learn how to do that in Tidal.

In SC you can also reference other parameters in a Pbind. So you can use the current value of a parameter to modify another one, like so:
Pbind(\dur, Pseq([1,2,4],inf), \degree, 0 - Pkey(\dur))
which would play low notes longer.

You can also use parameters of a Pbind in other Pbinds, but it's a bit picky.

This is so very well put. I would add that there are two types of SC patterns, data patterns and event patterns. Pbind is of the latter, and is used to play synthdefs with data patterns like Pseq, or just values.

And, of course, there's the uniqueness of Tidal's use of time in cycles as opposed to Pbind's clock beats.

There's an example in SuperDirt's repo that does just that :).

There have been many attempts. Ixilang is a legacy language that was pretty cool and easy to use; I've heard Thor Magnusson is thinking to update it (works only on very old SC versions). There's also chucklib which is pretty cool. Not exactly tidalcyclish, but very interesting indeed. PLbindef from miSCellanous_lib that allows function composition which helps a lot syntax-wise.

2 Likes

I've tried them all to see how it felt playing with them. Some of them are really cool, such as IXI Lang that you just mentioned. There was once a hidden IXI kind of interpreter for Sonic Pi too. It must still be usable but it hasn't been developed/extended since it appeared a year or two ago. If you haven't seen it before, check out the IXI integration for the Rezonality live-coding environment. Still under development, but very promising. It's basically an IDE embedding multiple pattern languages and libraries + custom audio/video engine.

All these SC-side pattern libraries rely on heavy modifications of the interpreter using SC preProcessor. It's amazing to see such flexibility but it also appears to be super hard to customize/develop such a system by relying on interpreter hacks.

Right. PLbindef, though is not using the preProcessor, just some complex remapping of things. I wrote a small extension from it to simplify my life while live coding. I've been using it in all my performaces for a while and works well, but it's (my extension) still under heavy development and very unstable.

There's another Quark explicitly inspired by TidalCycles: Bacalao by @totalgee . He's constantly adding new things, and is worth a check, although he developed it as a playground more than a stable library. In this case it also uses the preProcessor but in a way that you can also use normal SC code with it.

Wow!! This is really impressive!

1 Like

So cool! I wanted to do something like this for a long time but I wasn't skilled enough to make it happen. Thanks for the link!

Anyway.. let's get back to the main topic!

1 Like

Generally speaking (please correct if this is wrong):

In both cases, patterns can be nested.

tidal patterns:

  • input: range of time
  • returns: a list of events

supercollider patterns:

  • input: nothing
  • returns: a coroutine (stream)

in turn, supercollider (event or value) streams:

  • input: a value or an event
  • output: a modified copy of that value or event

So you can't fast forward a stream in sc, but you can jump to any time in tidal.
In sc, each stream has independent state, in tidal this is not the case. You can thread new streams to all the streams generated from a pattern on the fly.
Nested tidal patterns can restructure each other more radically, in sc there might be a little more what a stream can do on an event-to-event basis.

Generally, tidal patterns start from loops and opens them further and further. Supercollider patterns are infinite streams of states, so everything that requires loops (e.g. reversing a pattern) is non-trivial, while concatenations are easy.

In short, tidal is more from whole to part, sc is more from part to whole. Both are not restrictions of the language, but just how things usually are done.

5 Likes

Just bumped into this old thread that I find very interesting. I just wanted to add that I find this "whole to part / part to whole" differentiation not at all trivial. It points to very different concepts of how time is structured. In SuperCollider, events are treated somewhat additive: they add up in time, one after another, with certain durations. While in TidalCycles time is treaded as a block that is (potentially) infinitely divisible. This leads to quite different compositional strategies and therefore to quite different result, even if some things could be equally well achieved in both languages.

That being said, I think SuperCollider (whose patterns have always been its greatest strength, in my opinion) could be quite enriched by directly incorporating the Tidal mini notation into its language to make it possible to work with both time/event paradigms. It's exciting to see there have been attempts in that direction. Some of them have been described and discussed over at the SC forum: