tidalcycles / strudel

Web-based environment for live coding algorithmic patterns, incorporating a faithful port of TidalCycles to JavaScript
https://strudel.cc/
GNU Affero General Public License v3.0
586 stars 105 forks source link

pickOut(), pickRestart(), pickReset() #950

Closed eefano closed 4 months ago

eefano commented 4 months ago

added pickr() and pickrmod() , see https://github.com/tidalcycles/strudel/issues/948

also fixed typos in inhabit() and inhabitmod()

yaxu commented 4 months ago

The use of collect and restart here is cunning but I think will limit patterning possibilities. It'd be simpler and more flexible to use a trigZeroJoin. I think this might well involve changes to register to support, which currently has an innerJoin. Maybe this just needs a pick but with a trigZeroJoin

I'd say use of reset (trig) should be privileged over restart (trigZero), as the former is more 'patterny', although we can offer both as an option.

Maybe a nice solution would be to define pick as an operator, then all the different join variants would be automatically created, with aliases added if necessarily. Actually .reset is an alias for .keepif.trig. So pickReset could be an alias for .pick.trig then.

eefano commented 4 months ago

With my implementation of pickr() i can do something like that: "<[0,2] 1@2>".pickr(["a", "<b c>", "d"]).note()

And the result is equivalent to this looped indefinitely: "[a,d] b c"

When you use pick() , you have this loop instead: "[a,d] c b [a,d] b c"

Now, assuming your API suggestions are implemented, can you please show me a strudel example that makes my use case work correctly?

yaxu commented 4 months ago

Hmm unfortunately defining pick as an operator doesn't really work as operators are defined to work on pairs of values, not patterns.

yaxu commented 4 months ago

Now, assuming your API suggestions are implemented, can you please show me a strudel example that makes my use case work correctly?

Howabout this?

https://strudel.cc/?leVkB6geMrE_

These are the same as inhabit but with different joins (_pick is pasted in because it's not exported from signal.mjs)

Maybe it's clear from this how reset is more patterny..

eefano commented 4 months ago

Your approach is cleaner, for sure! But pickReset still doesn't work as I'd like. The equivalent output is: "[a,d] c b [a,d] b c"

pickRestart works as intended.

I'm keeping both in the PR.

eefano commented 4 months ago

I have added also pickOuter() , applying an outer join can achieve something useful like that:

"<0 1>/9".pickRestart(
  ["<rd*3 , <[[bd ~ bd] [~ ~ bd]]!3@2 [bd ~ bd] [~ bd bd]!2> , <[~ sd]!3@2 ~ sd!2> , cr/9>"
  ,"<rd*2 , <[[bd ~ bd] [bd ~ ~]]!3@2 [bd ~ bd] [~ bd bd]!2> , <[sd sd]!3@2 ~ sd!2> , cr/9>" 
  ]).pickOuter({
             rd:s('rd').gain(0.1).pan(0.4),
             bd:s('bd').gain(0.5),
             sd:s('sd').gain(0.5),
             cr:s('cr').gain(0.1).pan(0.6)}).bank("Linn9000").velocity(0.5)
felixroos commented 4 months ago

these functions look very useful! maybe it makes sense to add pickSqueeze / pickmodSqueeze as synonyms for inhabit / inhabitmod to make the naming more consistent?

I also wonder if it would make sense to change the syntax from pickX to pick.x, e.g.:

"a b".pick.trig({...})
// instead of
"a b".pickReset({...})

this would follow the same convention as operators e.g.

"0 1".add.trig("0 1 2 3")

overview:

now then
pick pick, pick.in
pickOuter pick.out
pickRestart pick.trigzero
pickReset pick.trig
inhabit inhabit, pick.squeeze

I've omitted all the mod variants, because they are the same

not sure if it makes sense to add all operators, probably not

eefano commented 4 months ago

Pragmatically speaking, can this PR be merged as is by now ? I can work on a structured patch in the future.

daslyfe commented 4 months ago

these functions look very useful! maybe it makes sense to add pickSqueeze / pickmodSqueeze as synonyms for inhabit / inhabitmod to make the naming more consistent?

I also wonder if it would make sense to change the syntax from pickX to pick.x, e.g.:

"a b".pick.trig({...})
// instead of
"a b".pickReset({...})

this would follow the same convention as operators e.g.

"0 1".add.trig("0 1 2 3")

overview:

now then pick pick, pick.in pickOuter pick.out pickRestart pick.trigzero pickReset pick.trig inhabit inhabit, pick.squeeze I've omitted all the mod variants, because they are the same

not sure if it makes sense to add all operators, probably not

I like this approach it seems a lot more flexible

yaxu commented 4 months ago

Maybe we should standardise on the friendlier reset and restart rather than trig and trigZero?

Yes pick.x would be nice, as would moving towards supporting this in general, across all patterning function parameters. Tricky for functions with higher arity though..

eefano commented 4 months ago

I tried to introduce the mux operator but tests don't pass, so i reverted. At the moment I'm not knowledgeable enough to provide a better solution. I hope you'll integrate pickOuter, pickReset, pickRestart soon. A better solution can be thought out in the future.

felixroos commented 4 months ago

Maybe we should standardise on the friendlier reset and restart rather than trig and trigZero?

Yes pick.x would be nice, as would moving towards supporting this in general, across all patterning function parameters. Tricky for functions with higher arity though..

now tracking this here: https://github.com/tidalcycles/strudel/issues/970

felixroos commented 4 months ago

I've renamed pickOuter to pickOut for consistency with the alignment operators. I'd merge this now, but maybe we'll get the dot notation with https://github.com/tidalcycles/strudel/issues/970

felixroos commented 4 months ago

For now I'd consider these functions experimental, as they might get renamed later

felixroos commented 4 months ago

and thanks @eefano :)

eefano commented 4 months ago

thank you Felix, this is very useful!