Euclid legato without silence

This problem is primarily noticeable with MIDI notes, but it can be observed with samples too:

d1 $ note "c5(3,8)" # s "midi"

Alternate sample version:

d1 $ s "bev(3,8)" # legato 1

In the above patterns, each note's duration is only 1/8 of a cycle:

|x x x |

Where there is white space in the text, there is no sound.

Intead, with Euclid patterns, is it possible to have the note's event time fully occupy the time until the next note? For lack of a better string representation, something like this instead:

|x__x__x_|

Where the "_" character means that the sound still continues to play.

I've tried working around this by specifying larger values for legato (e.g. legato 2 or legato 3), but the Euclid patterns can vary and shift, and sometimes the legato value still isn't long enough, or it's too long and overlaps with the following note.

Ideas?

4 Likes

It's an interesting math problem!
I haven't found a suitable solution for 8 yet, but for a (4, 7) euclidean rhythm, this works:

d1 $ sound "gabor(4, 7)"
  # legato 1
  |+| (legato "1(3, 7)")

I think we'd need to find a way to express the spaces between the events as an euclidean pattern or a combination of euclidean patterns, and then reinject this formula into the code above.

Or you could use cut but it's significantly less fun than to solve the mathematical problem underneath.

Well the events of the gaps are described by euclidInv and euclidFull gives you an easy way to operate on both on and off events of a euclidean rhythm. But I don't know if that gets you closer to what you want.

1 Like

Yes this works for me just fine with samples, but most of my Tidal coding is with MIDI these days, so it would be great to find a mathematical solution!

OK, can't resist. Maths (-by-example) time!

  • euclid(7,16) is |x x x x x x x |
  • so the intervals are 3 2 2 3 2 2 2,
  • subtract 2, get 1 0 0 1 0 0 0
  • this is (structurally) euclid(2,7)

This is the Euclidean algorithm at work: gcd (7,16) = gcd (16 mod 7, 7) = gcd(2,7). Hence, the name of the pattern.

Of course the above is not a proof. But 7 and 16 are "random enough" for the idea to work in the general case.

1 Like

Note that my Haskell is not very good, but I had a go a making a function that will turn binary strings like 1 0 0 1 0 1 0 into legato ready strings...

import Data.List.Split

binSpace x = unwords $ tail $ fmap (show) $ fmap (+1) $ map length $ splitOn "1" $ filter (/=' ') $ x

example:

binSpace "1 0 0 1 0 1 0"
"3 2 2"
binSpace "1 1 0 1 1 0 1 1 1 0 0 0"
"1 2 1 2 1 1 4"

Dunno how to get this into Tidal...

This function seems to work ok:

import           Sound.Tidal.Bjorklund (bjorklund)

euclidGapless :: Int -> Int -> Pattern Bool
euclidGapless n x = timeCat $ map (\d -> (toRational d,pure True)) $ iois 0 $ bjorklund (n,x)
  where iois :: Int -> [Bool] -> [Int]
        iois 0 [] = []
        iois i [] = (i:[])
        iois 0 (True:xs) = iois 1 xs
        iois i (True:xs) = i:(iois 1 xs)
        iois i (False:xs) = iois (i+1) xs

3 Likes

Thanks everyone, I'll try and give this a spin later today!

I couldn't think of a good mininotation shorthand for euclidGapless, except maybe double parens:

d1 $ note "c5((3,8))" # s "midi"
5 Likes

I started to type a reply, but then realized it was getting too long, and too wrong.

So I did some more research, and wrote https://gitlab.imn.htwk-leipzig.de/waldmann/computer-mu/-/tree/master/euclid

3 Likes

can this be a thing? i would love this!!

1 Like

I think that makes sense.

Discussion continues on the issue here: https://github.com/tidalcycles/Tidal/issues/760