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
642 stars 111 forks source link

Support beat-oriented composition and transformation, via 'weighted cycles' #987

Open yaxu opened 6 months ago

yaxu commented 6 months ago

By an accident of implementation, the mininotation currently adds a __weight property to mininotation, that gives the number of 'steps' at the highest level of the sequence, e.g. a [b c] d@0.5 has a weight of 2.5.

The 'guessing-timeCat' branch explores how this could support more beat-oriented functionality. It's named that first of all because timeCat can use this weight instead of having to have it explicitly specified for every pattern.

The branch also has a beatCat function that accepts lists of lists of patterns, cycling between the elements within each sublist.

It also adds a '__pure' property to 'pure' patterns, with a view to maintaining the weight across transformations such as 'fast' when pure values are used (it's not really possible to calculate a weight when patterned factors are passed to fast, unless the weight itself is a pattern)

yaxu commented 6 months ago

With https://github.com/tidalcycles/strudel/pull/976/commits/b1b91fcae7210a9cae210def3be0b9767c8de851 , "a b c".fast("2") now has the correct weight of 6.

yaxu commented 6 months ago

Now polymeter("a b", "c d e") works.

yaxu commented 6 months ago

It would be nice if "x(3,8)" had a weight/tactus of 8. Perhaps

"x(3,8)".tactus  === 8
"[x(3,8)]".tactus  === 1
"x(3,8) x".tactus  === 2
"x(3,8)@4".tactus  === 4 // already works
"[^x(3,8)]  x".tactus  === 16
yaxu commented 6 months ago

It doesn't really make sense that x(3,8) has a higher tactus of 8 than x(3,8) x(3,8)'s 2 though.

Alternatively we could accept a breaking change and make "x(3,8) x" have a tactus of 9, with the euclid not in a subcycle, so more like ! than *. Or maybe we should have similar syntax to indicate the level with euclid. For example

"x(3,8)".tactus === 1
"x!(3,8)".tactus === 8
// which implies..
"x*(3,8)".tactus === 1

A bit messy though. :/

Another possibility:

"x(3,^8)".tactus === 8
"x(3,^8) x".tactus === 9
yaxu commented 5 months ago

Worked a lot of things out in this Tidal PR, needs back-back-porting here ! https://github.com/tidalcycles/Tidal/pull/1072

yaxu commented 5 months ago

Rather than using lcm for combining tacti, it might be better to just take the maximum by default, with the possibility to override that by marking where the tactus should come from