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?
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.
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 applyingeuclid 3 5
to only the true values, resulting int 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?
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
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"
--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"
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"
Hey, is "distrib" in the documentation?
@ritchse 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.
And you can pattern
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"
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.
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 Prelude hiding ((<*), (*>))
_distrib :: [Int] -> Pattern a -> Pattern a
_distrib xs p = boolsToPat (foldr distrib' (replicate (last xs) True) (reverse $ layers xs)) p
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