Week 4, lesson 3 - random marathon part 2: randcat, stripe, degrade, sometimes, someCycles, randslice + more

Continuing on from part one of the random marathon..

  • 0:08 - randcat - picking patterns from a list
  • 3:51 - wrandcat - picking patterns from a list, with different probabilities/weightings
  • 6:35 - stripe - patterns of random lengths, fitting together into a particular number of cycles
  • 9:26 - degrade - randomly drop events 50% of the time
  • 10:12 - degradeBy - randomly drop events with a given probability
  • 11:21 - sometimes - apply a function, sometimes
  • 12:10 - sometimesBy - apply a function, with a given probability
  • 13:38 - sometimes shorthands - rarely, almostAlways, often, almostNever etc
  • 14:16 - someCycles - apply a function, to some cycles
  • 16:13 - randslice - play random slices from a sample
-- randcat

-- randcat is a variant of cat, which we haven't actually looked at
-- yet, so lets start with that..
d1 $ sound (cat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])

-- So you can hear that cat 'concatenates' patterns - it plays them
-- one after the other, in order.

-- randcat on the other hand, plays them in random order:
d1 $ sound (randcat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])

-- You can give it as many patterns to choose from as you like:
d1 $ sound (randcat ["kick snare:4 [~ kick] snare:5",
                     "kick snare:4 . hc(5,8)",
                     "snare:3(9,16)"
                    ]
           )

-- You can use it to randomise control patterns other than sound,
-- e.g. the vowel effect:
d1 $ vowel (randcat ["a e*2 i o", "e o u", "o*8"])
   # sound ("kick snare:4 clap:4")


-- wrandcat is to randcat, what wchoose is to choose. That is,
-- You can give the choices relative probabilities:
d1 $ sound (wrandcat [("bd sn:4(3,8)", 1),
                      ("arpy clap", 0.5),
                      ("cpu(5,8)", 0.25)
                     ]
           )

-- stripe is a weird one. Lets start with a rhythm with the
-- cpu2 samples:
d1 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
  # squiz 2

-- 'fast 2' would squeeze that into two cycles:
d1 $ fast 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
  # squiz 2

-- stripe is similar, but the cycles are random durations,
-- although still fit the cycle:
d1 $ stripe 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
  # squiz 2

-- It sounds random, but against a straight clap, you can hear
-- every other repetition still perfectly aligns with the cycle:
d2 $ sound "clap:4"

-- degrade - remember the ? mininotation modifier in the previous
-- video? It drops events at random:
d1 $ sound "bd*8?"

-- Degrade is a function that does the same:
d1 $ degrade $ sound "bd*8"

-- Just like this:
d1 $ sound "bd*8?0.6"

-- You can specify a probability, by using 'degradeBy'. E.g.,
-- to give each event a 60% chance of being 'lost':
d1 $ degradeBy 0.6 $ sound "bd*8"

-- 'sometimes' applies a function to a pattern, but only sometimes.
-- lets hurry this rhythm, but only sometimes:
d1 $ sometimes (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

-- Here's the original, which sounds pretty boring in comparison:
d1 $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

-- You can use it to apply effects as well.
d1 $ sometimes (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

-- There's also a 'sometimesBy' variant, for specifying a
-- probability:
d1 $ sometimesBy 0.3 (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

-- There's some aliases for different probabilities:

{-
sometimes = sometimesBy 0.5
often = sometimesBy 0.75
rarely = sometimesBy 0.25
almostNever = sometimesBy 0.1
almostAlways = sometimesBy 0.9
-}

-- So you can do this:
d1 $ rarely (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

-- somecycles is similar to sometimes, but works on whole
-- cycles at a time, rather than individual events:
d1 $ somecycles (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"
  # speed 1.5

-- Again, there's a 'somecyclesBy' variant for being specific
-- about that probability. To apply the squiz, 90% of the time:
d1 $ somecyclesBy 0.9 (# squiz 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"
  # speed 1.5

-- randslice is a bit like 'slice' that we met a couple of lessons
-- ago:
d1 $ slice 4 "0 1 2 3" $ sound "break:8"

-- Instead of taking a pattern of slices though, it picks slices at
-- random. So to play a random quarter of this break:
d1 $ randslice 4 $ sound "break:8"

-- We can use 'loopAt' to fit them to a cycle, just like we saw before
-- with 'chop' and 'striate':
d1 $ loopAt 1 $ randslice 4 $ sound "break:8*4"

-- We could also do the same sort of thing by giving 'slice' or 'splice'
-- a random pattern:
d1 $ splice 4 (segment 4 $ irand 4) $ sound "break:8"
9 Likes

fantastic, thank you

Awesome. I got so excited by the randomisation of splice that I totally forgot about the other stuff. Looking forward to playing with randcat.

I think someone said in another thread that they will need to go back over all the videos to consolidate. I definitely feel the same!

d1 $ stack [
    loopAt ((irand 8)+1) $ slice 8 (segment 8 $ irand 8) $ s "foley:2"
      # legato 1
      # pan perlin,
    sometimes (hurry 2) $ loopAt ((irand 3)+1) $ splice 8 (segment 4 $ irand 8) $ s "break:31"
      # legato 1
      # krush 2
      # gain 0.5
]

d2 $ sometimes (slow (irand 3)) $ n (segment "[3|5|4|8]" $ (irand 7 - (irand 32)))
  # s "superpiano"
  # gain 0.4
  # lpf (slow 4 (range 5000 200 $ sine))
  # lpq 0.9
  # sustain 1.2
3 Likes

Thanks @yaxu, the stripe function answered a question I didn't know I had -
I enjoy listening to a british group called gogo penguin (analog instruments), but the drummer frequently does a stripe 2-like adjustment to his beat, and I could never quite work out how to explain what he was doing... now I can :smiley:

@ 2:34

4 Likes

Who needs Venetian Snares when you have random slices :slight_smile:

d1 $ splice 8 (segment 8 $ irand 8)$ s "break:4"

d2 $ s "<cpu cpu*2 cpu(3,8) cpu*4>"

edit:
Obviously to be proper Venetian Snares it should be in 7/8

d1 $ splice 8 (segment 7 $ irand 8)$ s "break:4"

d2 $ s "<cpu cpu(2,7) cpu(3,7) cpu(4,7)>"

5 Likes

super nice example ! you made me wanna try with those breaks...
@vin i also feel like starting all over... and taking many notes! on paper! fun times to come ^^
@yaxu thanks for all this randomness, it's really helpful in order to go face to face with subtleties of the syntax. For instance the fact that
$ sometimesBy 0.6 (hurry 1.5)
isn't written like
$ sometimesBy 0.6 (#speed 1.5)
... I had totally missed.
It's not so clear although I managed getting it to work. It takes time to get used to but it feels nicer each week!

d1 $ jux rev $ rarely (# squiz 4) $ sometimes (#distort 0.2) $ almostNever (#coarse 100)  $ almostAlways (#triode 2)  
    $ slice 8 (segment 8 $ irand 4) $ s "break:1"
    #room (randcat ["0.1 0.8 0.5 0.3"])
    #size (wrandcat [("0.4",0.8), ("0.6",0.1), ("0.9",0.2)])
    #gain (randcat ["1 0.8 0.85 0.9"])
    #vowel (wrandcat [("e",0.6), ("a",0.3), ("o",0.6)])
2 Likes

Hey @yaxu, am I right in understanding that the # sign in relation to @gnozo's post here has to do with the patterning? I want to make sure I understand properly. So the sometimes is providing the pattern that # is applied to? Thus taking the structure from the left? Whereas hurry applies a modifier TO the pattern and thus changes the pattern? Or something like that?

1 Like

This surely reminds me of things which I've heard in the videos! From what you say and trying to understand, I guess that nesting functions and patterns involves adding # for patterns and no $ for... functions? I hope all this will be clear one day ^^

Yes hurry and speed are related in English but are different kinds of functions in Tidal.

speed takes a pattern of numbers and turns it into a pattern of 'controls' that can be sent to superdirt as part of a sound trigger. speed is the same type of function to squiz, pan, n. It's similar to sound and vowel - they take a pattern of words rather than numbers, but still return a pattern of controls. # and friends is then for combining these patterns of controls together in to a new one. So speed "1 2 3" is a pattern of controls, so is sound "clap", and so is speed "3 4 5" # sound "clap", because the # has combined them together.

We tend to call # (and also +, -, /, * etc) an 'operator', but really it is also a function.. It takes two control patterns and creates a new one. As an operator, it just behaves a bit differently - its two inputs are either side of it, rather than to the right. So in 3 + 5, + is a function that takes two numbers (3 and 5 in this case) and outputs a new one (8 in this case). Likewise in speed "3 4 5" # sound "clap", the # operator takes speed "3 4 5" and sound "clap" as input, and outputs a new control pattern as output, that is the two inputs combined together into a control pattern that has both speed and sound values.

hurry is a different type of function entirely. Rather than combining two control patterns, it only takes one as input. It also has another input - how much to 'hurry' the control pattern by. So hurry 2 (sound "bd sn") gives you a control pattern as well.

Now although hurry and speed are different types of function, the strange thing is that (# speed 2) and (hurry 2) are the same types! (in computer science they say they have the same types).

Why's that? Well look at what's missing from both of them - a control pattern. That's the remaining 'input' to the function. (tbc after a meeting..)

3 Likes

Thanks a lot for walking us through the topic! It's very interesting, I'd be glad to hear more here or in the next threads. Reading it now made me think about control voltage and gate signals - I was looking at the different ways Moog and Buchla treat these concepts recently, it's fascinating. Could we say that what we are discussing here is the equivalent of a patching system in Tidal? Understanding the mechanics is essential in order to manipulate the possible patterning techniques at hand!

Yes it is a bit like patching - you're connecting functions up, which data kind of flows through later. Under the hood it's quite a different approach to how dataflow systems normally work (e.g. puredata and max are dataflow languages), but the end result does feel similar I think. You can see that in this strange visual interface I once made for tidal:

5 Likes

It's very interesting from a learning perspective to see the relation between a visual patching system and the syntax -and as in pure date, it holds something entertaining. Also, it's intriguing to see Tidal displayed like a toolbox. How we use the language live can also be questioned differently here, in terms of how improvised decision making influences the end result from the audience's perspective.

1 Like