Week 4 lesson 2 - random marathon: rand, irand, mininotation randomness, scramble, shuffle, choose + more

I broke my brain while riffing on this video. Switching the commented stuff on and off = my brain. My poor brain. Alex, this is so cool. I can't wait to get really good at understanding efficient ways to structure the code, and building fairly hefty compositions, installations, etc.

d1 $ degradeBy (slow 4(range 0.1 1.0 $ rand)) $ snowball 2 (+) (slow 4) $ shuffle (irand 5) $ n (struct "[t(5,7,3)|f(5,7,3)]" $ (irand 5) - (irand 24)) # sound "supersaw"
  -- # sustain 0.4
  -- # decay 0.8
  -- # speed (rangex 0.1 0.2 $ perlin)
  -- # room 0.3
  -- # sz 0.2
  -- # lfo 0.8
  -- # resonance 0.8
  # lpf (slow 2 (range 100 400 $ saw))
  -- # lpq 0.1
  -- # voice 0.8
  -- # lpq (slow 3 (range 0.1 0.3 $ perlin))
  # gain 0.1
  -- # binshift (slow 5 (range 0.2 0.8 $ perlin))

d2 $ repeatCycles 3 $ sometimes (fast 2) $ scramble (irand 6) $ n (struct "[t(5,7,3)|t(5,4,2)]" $ (irand 3))
    # sound (choose ["cpu", "bskick"])
    # gain 0.8
    # speed (slow 4 (range 0.02 0.4 $ sine))
    # cut 1
    -- # waveloss (slow 4 (range 20 50 $ perlin))
    -- # smear (slow 3 (range 0.2 0.8 $ perlin))
5 Likes

Also, quick question, with stuff like repeatCycles, is it possible to have that fed a random number? I tried to give it repeatCycles (irand 5) for example but it returns an error. I tried using choose as well, but that similarly didn't work as it seems the integer that xCycles is expecting is of a different data type or something?

The thoughts on randomness in this video were very interesting, thanks. I have to confess I was slighly dreading watching it, as I also have strong ideas about this area. To me, being able to ask the machine to make arbitrary decisions – agreed, let's not call them random – is fundamental to the business of algorithmic composition. I like to be able to create a high level structure and let the computer fill in the details: I see that as a fascinating way to discover 'what works' in music. James McCartney talks this somewhere, sorry I can't find the exact reference, as being able to create a class of compositions and then listen to various instances of the class.

To take an rather wonderful example from your worksheet:

d1 $ sound "bd*8? clap:4"

To me, this is asks and answers an interesting musical question, something like: 'What about… half a bar of arbitrarily syncopated kick drum hits followed by an offbeat clap? Would that work?' And yes, it does.

1 Like

Thanks @tedthetrumpet and @vin for taking on my polemic. I started out with some wariness about random number generators, then spent the rest of the video having fun using them, so take what I said with a pinch of salt!

For me the emergence of live coding was in part a reaction against "generative art", in particular the idea that by using random numbers, you can create infinite variation, and gasp at the creative system you've made which holds a mirror to the beauty of the universe. The problem is that the more you listen to infinite variation, the more it sounds the same.

I like the idea of creativity as search and discovery. You define a space of possibilities (e.g., all the possible 8 step kick-snare rhythms), and look for things in it. You can use a random number generator for picking rhythms from that space, and listen out for good ones to use.. This is the approach taken by algorithmic composers such as David Cope. But there is a slight of hand here. The value comes not from the random number generator part (which comes up with all kinds of nonsense), but the act of listening out for good ones. I.e., this isn't algorithmic composition, but simply composition lead by the ear. That's be completely fine of course, but all the posturing around chance operations, creative systems, automatic composers etc is missing the point, when the whole process still revolves around human perception.

So that's where the chip on my shoulder comes from.. But really, I do use random number generation a lot, and a point I was trying to make in the video is that using Tidal often feels a bit like hand-making a random number generator.. Really all a random number generator does is make an interference pattern, and by making your own you are finding that sweet spot between noise and mundane predictability, which is where you could say is where all the music lies!

8 Likes

Yes the first parameter is an Int, rather than a Pattern Int, so you can't put a pattern there:

repeatCycles :: Int -> Pattern a -> Pattern a

There are ways around this, e.g. using 'do' notation, and <- to take values out of patterns:

d1 $ do n <- "<2 3 4>"
        repeatCycles n $ sound "<bd(3,8) cp(3,8)>"

However this probably won't do what you expect. The above switches between different versions of the pattern every cycle, and they will be repeating at different rates, so you won't hear an orderly repetition.

(n.b., rather than taking values out of patterns, I'd say the <- there is really doing something more like taking the computation into the pattern, but this gets hard to think about.. This is the 'monadic' stuff that Haskell people waggle their eyebrows around a lot)

Anyway a version of repeatCycles' with the patternable repeat:

repeatCycles' pn pat = innerJoin $ (\n -> repeatCycles n pat) <$> pn

It's just a bit unruly..

d1 $ repeatCycles' "<2 2 3 3 3>" $ n (struct "t(5,8)" $ scale "ritusen" (irand 8)) # sound "rash"
  |+ n 24

d2 $ sound "cp"

I could put this in the next version if you think it's interesting though!

3 Likes

Hey @yaxu. Didn't you mention that this was a 'bug' with repeatCycles in the other thread over here?

Looking at the repeatCycles type:

repeatCycles :: Int -> Pattern a -> Pattern a

That first parameter is an 'int', and not a pattern of ints. Actually it's only in the last couple of years that you've been able to use patterns as parameters in this way in Tidal.. (the inner workings of this are quite something to behold, it's amazing that it works so well in general..) So this is kind of a bug in Tidal that this parameter isn't 'patternable'. I've made a note to fix it Make repeatCycles patternable · Issue #645 · tidalcycles/Tidal · GitHub

1 Like

Stumbled upon something that gives a syntax error that I would have thought would have worked:
d1 $ s "bd!8?"
This is ok:
d1 $ s "[bd!8]?"

Erp, so I did!

1 Like

hm yes.. maybe worth a bug report

Done, did the bug report.

1 Like

Thanks @yaxu, that is going to take some mental gymnastics (and trial and error) to understand the structures. Am I right in understanding that you can use haskell variables across TC more generally? In particular can you declare global variables that can be used in multiple OSC sends?

To borrow the SuperCollider global variable vernacular a bit. Sorry, this is probably for a different topic.

do
   ~globalVar1 = "some pattern"
   ~globalVar2 = "some other pattern"

d1 $ n ~globalVar1|~globalVar2 # s "bd -- mininotation pipe

d2 $ n ~globalVar1 # s "synth"

d3 $ n ~globalVar2 # s "bass"
2 Likes

Rather than do a long discussion about this (it's one of my favs), I started a new thread!

2 Likes

If I do this:

d1 $ scramble 8 $ n "0 1 2 3" # s "arpy"

is that a structure of 8 events from the scramble or a structure of 4 events from the n?

1 Like

I got the following error when trying to run:

d1 $ n "0 [0|1*3|2*8|3 4 5] 2 3" # sound "cpu"
   # speed 1.5
Error in pattern: Syntax error in sequence:
  "0 [0|1*3|2*8|3 4 5] 2 3"
       ^  
unexpected "|"
expecting float, "'", rest, "[", "{", "<", ".", "_", "," or "]"

Any ideas?

Seems like it's the " | " (straight line) in between that it's not liking?

Hi @tomh, I think you'll just have an older version of tidal installed, the | syntax is fairly new

Btw I took the liberty of editing your post to put

```

above and below the code blocks, as the forum was messing up the formatting otherwise.

2 Likes

Hey @vin would you mind explaining a bit what the "do" line does? Is this necessary for declaring variables?

1 Like

Hey @julianmrn5, in the above it is pseudocode. But in reality it encapsulates everything below it that is indented by one tab (or more) into a single execution. I’m not sure how variable scopes work in Haskell/Tidal but to my mind if in the above pseudocode the subsequent Dirt connections were indebted correctly then those variables would be local in scope. When I get in front of a computer I can paste in some actual code if that would be helpful? I can’t answer about the necessity for variables but I reckon @yaxu or @eris (I think) can give better answers around variable creation and scope!

1 Like

Ah I missed this question sorry !

You can give names to values with

a = "bd sn"

and then use them

d1 $ s a

With older versions of haskell you have to use let

let a = "bd sn"

that's still useful for naming more than one value at once:

let a = "bd sn"
    faster = fast 2
    squizit = (# squiz 4)

d1 $ squizit $ faster $ s a 
3 Likes

That is a super interesting question!

I tried the snippet myself and I'll give you my interpretation: since you are asking scramble to create 8 pieces from a 4-piece long pattern, it will fill the pattern up with some fictive steps of silence.
That is, the pattern to scramble might look something like
n "0 1 2 3 ~!4"
And that is probably why I hear silence now and then when I play it.

(although I would love @yaxu to confirm or refute)