How can I generate a random Boolean pattern to control a trance gate in TidalCycles?

Continuing the discussion from How to implement a tranceGate control pattern in TidalCycles?:

Here is a more concise version of trancegate, based directly on the original implementation by @Yaxu:

let trancegate i r = trigZeroJoin . fmap (\b -> ampbus i $ if b then slow r (when (<1) (const $ segment 8 isaw) $ pure 1) else 0.7)
in do
  d1 $ note "-14" # sound "supersaw" # trancegate 1 0.05 ("1011010110011101") # gain 0.8
  d2 $ s "kick:6*4"

Is it possible to create a helper function, for example randBits, that takes a number n and outputs a Boolean pattern of length n which can be directly used as the third argument of trancegate? The idea is to randomly determine which slices the gate closes on, so that I can write something like:

let trancegate i r = trigZeroJoin . fmap (\b -> ampbus i $ if b then slow r (when (<1) (const $ segment 8 isaw) $ pure 1) else 0.7)
in do
  d1 $ note "-14" # sound "supersaw" # trancegate 1 0.05 (randBits 16) # gain 0.8
  d2 $ s "kick:6*4"

Any suggestions or examples for implementing randBits in TidalCycles would be greatly appreciated.

randBits n = segment n ((/= 0) <$> irand 2)

How about the above?

1 Like

Thanks so much for this, @yaxu! That’s incredibly concise and elegant. I love how randBits gives a perpetually unpredictable gating pattern. Perfect for what I wanted. Really appreciate the quick solution:

let trancegate i r = trigZeroJoin . fmap (\b -> ampbus i $ if b then slow r (when (<1) (const $ segment 8 isaw) $ pure 1) else 0.7)
    randBits n = segment n ((/= 0) <$> irand 2)
in do
  d1 $ note "-14" # sound "supersaw" # trancegate 1 0.05 (randBits 16) # gain 0.8
  d2 $ s "kick:6*4"

I found that I sometimes need a random pattern to be generated once and have it repeat every cycle. I made a binary convertor such that:

let trancegate i r = trigZeroJoin . fmap (\b -> ampbus i $ if b then slow r (when (<1) (const $ segment 8 isaw) $ pure 1) else 0.7)
in do
  d1 $ note "-14" # sound "supersaw" # trancegate 1 0.05 ("1011010110011101") # gain 0.8
  d2 $ s "kick:6*4"

is the same as:

let trancegate i r = trigZeroJoin . fmap (\b -> ampbus i $ if b then slow r (when (<1) (const $ segment 8 isaw) $ pure 1) else 0.7)
    bin n=fastcat$map pure$reverse$let f x|x==0=[]|1>0=(x`mod`2==1):f(x`div`2)in if n==0 then[False]else f n
in do
  d1 $ note "-14" # sound "supersaw" # trancegate 1 0.05 (bin 46493) # gain 0.8
  d2 $ s "kick:6*4"

Of course, for 8-bit numbers we can usebinary:

let trancegate i r = trigZeroJoin . fmap (\b -> ampbus i $ if b then slow r (when (<1) (const $ segment 8 isaw) $ pure 1) else 0.7)
in do
  d1 $ note "-14" # sound "supersaw" # trancegate 1 0.05 (binary $ pure 241) # gain 0.8
  d2 $ s "kick:6*4"

After playing with the code all day and trying bit scrambling, I ended up using seed-based hashing to generate fixed-length deterministic pseudo-random bits:

let trancegate i r = trigZeroJoin . fmap (\b -> ampbus i $ if b then slow r (when (<1) (const $ segment 8 isaw) $ pure 1) else 0.7)
    rngBin s l = fastcat $ map pure $ take l $ f ((1103515245*s+12345) `mod` 2^64)
      where f 0 = repeat False; f x = (x `mod` 2==1):f(x`div`2)
in do
  d1 $ note "-14" # sound "supersaw" # trancegate 1 0.06 (rngBin 14 16) # gain 0.8
  d2 $ s "kick:6*4"

I’m just starting out with TidalCycles, and this makes experimenting with patterns so much more approachable. Thank you!

2 Likes

Have a look at the timeLoop function for this as well - @polymorphic.engine put me onto it in this blog post:

1 Like

hey @yaxu, I was curious what I would need to do to alter this so that it could be passed into the second argument of binaryN: ex d1 $ struct (binaryN 16 (randBits 16)) $ "s “bd”. it worked fine for the trancegate example but not for the binaryN experiment.