Use of `slow` (or `fast`)


I've been analysing various code examples and try to wrap my head around it. Here is one example which kind of made me think about the use of slow (resp. fast) (source):

d1 $ slow 0.1 $ s "armora*2" # n 6
  # release 0.5
  # cutoff (slow 0.1 $ range 20 9999 $ rand)
  # resonance rand
  # speed (range 0 3 $ rand)
  # pan "0 0.25 0.5 0.75 1"

I am especially interested in the bit where a random value is fed into the cutoff parameter. If I print out the example with slow:

putStrLn . show $ slow 0.1 $ range 20 9999 $ rand

it shows:


(10 generated events)

Without slow or slow set to 1 there is just one:


(I know that if you give slow a value below 1 it actually behaves like fast and therefore you could replace slow 0.1 with fast 10 which probably makes more sense.)

If I listen to the example it seems that slow at this point kind of helps distribute the cutoff values over the complete range from 20 to 9999. Otherwise (e. g. slow set to 1) cutoff will only get very high values, which will result in a very different sound.

Can someone explain what is going on? It does not seem to be very complicated but I just can't put all the pieces together.

Another question which I bumped into while researching the above example:

drawLineSz 120 $ fast (choose [1,3]) $ "a b" -- will result in:

[21 cycles]

drawLineSz 120 $ fast (choose [1,3.25]) $ "a b" -- will result in:
[12 cycles]


What exactly is happening in the 2nd example (using a float in the list) and: does the hyphen mean that these are events spread over more than one cycle and originating in an earlier cycle? (I hope I could make myself clear...)

This example:

putStrLn $ show $ slow 0.1 $ _range 20 9999 $ rand

gives just one 'event':


So it's range that causing that event to get fragmented into parts, one per cycle. The difference is that the first two parameters to range are patterns, and both 20 and 9999 are treated as events that happen once per cycle. So with all the plumbing going on behind the scenes combining these different patterns, some fragmentation happens.

It's the same with that parameter to slow (vs _slow), but you don't notice, because the show function only gets one cycle.

This fragmentation doesn't matter in practice - the ~'s indicate that these are not discrete events but continuous values, so don't really have a beginning and ending, so no additional event triggers are caused. All the parts have the same value, because the random number is chosen based on the midpoint of the timespan that is being 'sampled', which in the case of show will be the first cycle. If you manipulate time (e.g. changing the first parameter to slow) or combine with discrete events, you'll end up with different pseudo-random values being picked.

You'd probably want to 'segment' the choose pattern so that you only pick one value per cycle like this:

drawLineSz 120 $ fast (segment 1 $ choose [1,3]) $ "a b" -- will result in:

I think the drawLineSz does this for you but if you tried to play it then you'd probably hear something much wilder as random values would be picked at a faster rate than once per cycle.. could be wrong on that though!

Also to be picky, 3.25 in this context isn't treated as a floating point number but a rational.

The hyphen is just a continuation of the previous event, in this case a cycle is shown as 13 steps so each character is 1/13th, so b- is an event with value 'b' happening over 2/13ths of a cycle. However drawLineSz doesn't represent whether an event is a fragment of a larger event.. In this case the lone 'b's or 'a's will be half-events but that's not clear just by looking at it.


Alex, thanks again for taking the time to answer so patiently.

Let me be honest: I still don't get the full picture (maybe not even half of it). I will read and think about what you wrote and try to come up with some more questions. For me this is a somehow asymptotical process. Gradually things become clearer and questions become more precise.

Here are some (very basic) questions to continue the asymtotical process and to keep the ball rolling:

  • I don't know _slow or _range. What did I miss?
  • Did you choose to write slow 10 on purpose? ( I am quite sure you did but my first example is about slow 0.1 so let me just make sure this is no missunderstanding.) If yes, why?
  • There is a sonic difference (a difference you can hear) in the mentioned example. So # cutoff (slow 0.1 $ range 20 9999 $ rand) sounds different from # cutoff (slow 1 $ range 20 9999 $ rand) or # cutoff (slow 3 $ range 20 9999 $ rand). I am very interested to understand the inner logic of what's going on but for the moment I could live with just a vage idea where the difference comes from and - more importantly - how I can make musical use of the mechanics.

Last but not least: I was hoping drawLine and the putStrLn I found being used by someone in the forum to could help me to visualize what is going on sonically. As far as I see this is the case sometimes but not always. Is there another way (besides listening :wink: ) you'd recommend to analyse examples like the one above?

Questions are good! This helps me think things through too.

Sorry that should have been slow 0.1, have edited it.

_slow is the underlying implementation for slowing down a pattern by a given factor. slow is a wrapper for _slow that does some magic so that the first parameter is itself a pattern. _slow isn't generally used directly. It's the same story with _range, _fast, and a lot of other functions with 'patterned' parameters.

Because that first parameter is a pattern, when you're doing something like slow 4 $ sound "bd sd" you're combining two patterns, the sound "bd sd" pattern, with the 4 pattern, which is shorthand for pure 4 (which is equivalent to "4" in mininotation), i.e. the number 4 that repeats once per cycle. So you might see the influence of both patterns in the outcome. In your example the 0.1 cuts the continuous rand pattern into parts.

I meant the fragmentation doesn't matter in practice - the fact that a continuous pattern seems to be broken into multiple events. In practice they join up into the same continuous values. Fundamentally, you can't print out a continuously varying pattern, because it represents an infinite number of possible values. Tidal manages to print something out by treating them at discrete events, but they are not.

When you speed up or slow down rand you are expanding and contracting a continuously varying pattern which contains an infinite number of random values. When you do that you end up sampling different values from it, from a different part of the timeline.

1 Like

I think this is what I kind of assumed. It is confusing in the beginning because you might expect to manipulate time with fast and slow but in this case this is only an interim result, because you are acutally manipulating the set of values rand will select from (hope this correctly rephrases what you already eplained above and does not expose new missunderstandings :wink: ).

Still digesting the theory and at the same time checking out some musical implications.

This is a crazy duo:

  $ segment "<8 16 4>"
  $ struct "t(<7 9>,<8 16>)"
  $ (off 0.25 (# gain (range 0.25 1 rand)) . (# pan (range 0 0.75 rand)))
  $ n (scale "major" $ floor <$> (fast "<2 4 6 8 10>" (range 0 7 sine)) + "c5")
  # sound "superhammond"
  # gain 1
  # room 0.5 # size 0.5

  $ segment "<4 16 8>"
  $ struct "t(<5 9>,<16 8>)"
  $ (off 0.75 (# gain (range 0.25 1 rand)) . (# pan (range 0.25 1 rand)))
  $ n (scale "major" $ floor <$> (fast "<9 7 5 3 1>" (range 0 7 sine)) + "f5")
  # sound "superhammond"
  # gain 1
  # room 0.5 # size 0.5