Ply and chords

Given this:

    chords = [
            "e'maj",
            "b'maj",
            "fs'min",
            "ds'dim"
         ]
    inst1 = midichan 0 # s "midi"
    in
    do
    d1
    $ stack
    [
       every 3 (ply 4) $ 
       up (cat chords) # legato "4" # octave "4"
    ]
    # inst1

I was expecting that ply would cause the whole chord to be played 4 times. Instead it is arpeggiated 4 times. A pleasant surprise, but not what I was expecting. Can anyone explain this to me?

I think it simply comes from how it's implemented:

ply :: Pattern Int -> Pattern a -> Pattern a
ply = tParam _ply

_ply :: Int -> Pattern a -> Pattern a
_ply n p = arpeggiate $ stack (replicate n p)

Basically, the arpeggiate is here to have the elements in stack spread out instead of played all at once, which has the side effect of also spreading the elements of the chord, since a chord really only is a list of notes played at the same time.
I'm unsure how one would go about doing what you were going for to begin with. It would involve distinguishing the multiple notes arising from the chords from the ones arising from the replicate, which I don't see an obvious way of doing.

Ah...

Thanks very much th4!

By the way, I really enjoyed your last live stream. I've been experimenting with techniques learned by watching you, and it is what prompted my question.

I'm still struggling with syntax and I am always forgetting to type :t (function). Please forgive my ignorance, but ow does one display the second lines in your explanations?

Thanks for your kind words! I knew that I had seen this kind of code before :smiley:

The second lines are not obtainable by a command that I know of. You can either navigate to https://github.com/tidalcycles/Tidal/ and type the name of the function in the search bar and then do your best to locate the place in the source code where it's defined, or you can use Hoogle to find your function (make sure to pick the one that is actually part of Tidal, sometimes there are homonyms), and then get to the source code like this. Both solutions are mostly equivalent, it's a matter of taste which one you prefer.

Fantastic! Now I know that up is an alias of note. I was confused about the documentation for speed, which lists up as a convenience parameter... So much to learn.

Thanks again!

Best wishes.

Yes that implementation of ply isn't right, it's a bug that it doesn't do as you expect @mcoblio. There is an issue here with a suggested alternative implementation that you could try out: https://github.com/tidalcycles/Tidal/issues/591

I'll try to look at this for the next release

Ok I just stayed up a bit too late looking into this.. I was working on a fix that was getting very long and complicated, when suddenly this very short and simple solution came to me:

ply :: Pattern Time -> Pattern a -> Pattern a
ply = tParam _ply
 where _ply n pat = squeezeJoin $ (_fast n . pure) <$> pat

In these moments I realise that Haskell is a pretty neat language..

edit Note that this new version accepts fractional ply factors.. going to have to sleep now but ply 1.5 would likely be cool..

6 Likes

Wow Alex! I didn't even think it was a bug. I usually suspect my lack of understanding in such cases. Thanks for digging into it. I am continually amazed at the responsiveness, patience, and helpfulness of everyone in the tidalcycles community.

Best wishes,
Daniel

No problem! I'm so happy with this solution and it's giving me new ideas for how to deal with syncopation etc.

squeezeJoin $ (_fast n . pure) <$> pat can be translated to english quite neatly:

For every value in a pattern (<$>), turn that value into its own pattern, triggering once per cycle (pure) and repeat it the given number of times (_fast n). Then you have close to what you want, but it's a pattern of patterns of values, and not a pattern of values. So you want to take one cycle from each pattern inside the pattern, and squeeze that into the timespan that the original value had (squeezeJoin). A lot nicer than expressing it in terms of duplicating events, manipulating time arcs etc..

3 Likes

Oh, wow, yeah see I ended up stepping away from this when I tried to look at it last spring because the solution kept being so complicated.

But this? This is cool.

1 Like

Yep! and leads to this definition of syncopation which I love:

3 Likes