Subset euclidean rhythms with a euclidean function?

In the same way you can inv a euclidean rhythm and produce a second rhythm, i'm trying to split time into four interlocking parts using two euclidean functions. The inv part i've got down, but i don't know how to subset a euclidean rhythm with another euclidean function.

Is there a way in Tidal to take a subset of a euclidean rhythm with another euclidean function? That is, a way to euclid a euclid?

example:
euclid 3 5 of euclid 5 8

struct t(5,8) is like euclid 5 8 which is t f t t f t t f.

struct t(3,5) or euclid 3 5 is t f t f t

Applying the second to the first, (keeping only 3 out the 5 Trues, by alternating according to "euclid 3 5") would give
t f f t f f t f. I'm dropping 2 Trues according to the order in euclid 3 5.

:thinking:

Since what I'm talking about would only make sense for when the parameters set to 5 in my example are matching, there are really on 3 parameters for this operation.
For euclid 3 5 of euclid 5 8, the syntax might be something like this euclidNested 3 5 8

euclidNested would be like first doing euclid 5 8 then applying euclid 3 5 to only the true values, resulting in t f F t f F t f, where the capital 'F's are the 't's that were converted (eliminated) by euclid 3 5.

I see the first euclidean rhythm as choosing the division of time and selecting an approximately evenly distributed subset. From that subset, the outer eucliidean rhythm selects a smaller subset (sub-subset) that is approximately evenly distributed.

Does this make any sense? If so is there already a way to do this?

1 Like

i cannot believe you mentioned this, i literally found the answer to this the other day while searching through some obscure functions

you need the distrib function

https://blog.tidalcycles.org/#:~:text=Yet%20another%20function%20distrib

although it works weeeeeird af (when using complex patterns, keep it one note and it'll work as expected, which seems to be your use case). i sent a message in the discord saying "this is unexplainable"

Example

--ok this is just like euclid
d1 $ s $ distrib ["5","8"] "bd"

--ok sure, it distributes 4 notes between the 5,8 euclid
d1 $ s $ distrib ["4","5","8"] "bd"

--wait...
d1 $ s $ distrib ["5","8"] "bd*8"

--that sounded like
d1 $ mask "t(5,8)" $ s "bd*8"
--ok, it sort of acts like a mask then

--mhmhm what if i use a more complex pattern
d1 $ s $ distrib ["5","8"] "bd*8 sd"

--wait! that doesn't sound like
d1 $ mask "t(5,8)" $ s "bd*8 sd"

--well, sure, maybe it doesn't mask. it takes each element as contiguous, so if a sound has already been started it'll still play it...

--wait no what is this
d1 $ s $ distrib ["5","8"] "bd*8 sd*3"
1 Like

Hey, is "distrib" in the documentation?

@geikha aamaazing!! thank you, it seems like it is exactly what i was thinking. funny how we were both trying to do this. quantum entanglement is clearly the only explanation. :laughing:

And you can pattern distrib too!

1 Like

Oh I like it. If you pattern the second number, you get the different variations of euclidean rhythms, but if you keep the distribution at 6, then it just feels like a nice syncopation.

d1 $ s $ distrib ["6", "<12 14 15>","16"] "bd*8 sd"

d2 $ s "hh*16"

3 Likes

no, i was going to document it but as explained it has a very weird behavior sometimes which I couldn't explain at all

From the commit message, we learn that distrib is "for meta-bjorklund stuff", i.e. meta level euclidean rythms.

I think it would be good to document that it exists but write that it's challenging to completely grasp all interactions. Perhaps @yaxu can enlighten us about the design some day, or we will learn from experimentation / find an improved design.

Hi all,

Heh yes it seems distrib is a bit unpredictable - it's taking structure from both the boolean euclidean pattern that comes from the numbers and the pattern that it's working on, so you get a weird mash up. Changing a <*> to a <* in the implementation is enough to get a better behaved version that only takes the structure from the boolean pattern. It'll be fixed in the next release, or you can try it now by running:

import Sound.Tidal.Bjorklund

import Prelude hiding ((<*), (*>))

_distrib :: [Int] -> Pattern a -> Pattern a
_distrib xs p = boolsToPat (foldr distrib' (replicate (last xs) True) (reverse $ layers xs)) p
  where
    distrib' :: [Bool] -> [Bool] -> [Bool]
    distrib' [] _ = []
    distrib' (_:a) [] = False : distrib' a []
    distrib' (True:a) (x:b) = x : distrib' a b
    distrib' (False:a) b = False : distrib' a b
    layers = map bjorklund . (zip<*>tail)
    boolsToPat a b' = flip const <$> filterValues (== True) (fastFromList a) <* b'

distrib :: [Pattern Int] -> Pattern a -> Pattern a
distrib ps p = do p' <- sequence ps
                  _distrib p' p
2 Likes