Tidal
Tidal copied to clipboard
Arc UI
With @tonyday567's recent changes (#415), the way arcs are specified has changed. So e.g
d1 $ within (0,0.25) (fast 2) $ s "bd*8"
is now:
d1 $ within (Arc 0 0.25) (fast 2) $ s "bd*8"
I think I preferred the former, the latter is a bit too much to type. It'd be easy to restore the previous interface, by for example renaming the current within
to _within
, then making within (a,b) = _within (Arc a b)
.. But this is an opportunity to rethink the interface for specifying arcs, while we're making breaking changes for 1.0.0. Some possibilities:
Separate parameters (curried), which could be patterned
within :: Pattern Time -> Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
d1 $ within 0 0.25 (fast 2) $ s "bd*8"
d1 $ within "0" "<0.25 0.5>" (fast 2) $ s "bd*8"
Single pattern of arcs, with parser support
within :: Pattern Arc -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
d1 $ within "(0,0.25)" (fast 2) $ s "bd*8"
d1 $ within "(0,<0.25 0.5>)" (fast 2) $ s "bd*8"
Any thoughts? I think I'm leaning towards the latter..
I like the general idea of using Arc
internally but changing the interface of within
. Are there any other "user" functions that take an Arc as an argument?
For the latter case, how would the parser work? Keep Euclidean stuff the way it is but interpret an outermost set of parens as denoting an Arc pattern?
To answer my first question, zoom
, compress
(and related), and revArc
are about the only functions that I suspect most users would run into that take Arcs
Euclidean would work fine as-is I think, as it only comes into play when it follows a value (with no space between). A bit confusing to have two meanings for parens, but the parser would cope
Yes within is the only one I use directly during a performance, I see the others as internal ones really.. but if arcs were easier to specify, maybe they'd be more useful.
I marked revArc add to document in error I think, looks like internal function
One common operator for a range is (...) so 0.25 ... 0.5
but here, with a lot of operators and parsing language it feels a bit verbose. I like the look of <0.25 0.5>
but that must be pattern parsing right? because you can't set up haskell like that. within 0.25 0.5
seems fine.
I fixed the examples above (they were missing the transformation function) and added types to make clearer what is going on
"(0,<0.25 0.5>)"
is of type Pattern Arc
, and is using ghci's OverloadedStrings extension to call parseBP_E
to parse the string. We'd just need to add a function to parse the tuple into an arc as part of Arc
's Parseable
instance.
The <>
bit is already in the parser, and just means 'cycle through the subsequence, taking one value per cycle.
I'm unclear on the best way forward for this, so will for now just return to the previous interface of within (s,e)
I guess an argument for the curried form would be that it might make it easier to do different things - outside of the pattern parser - to the beginning and ending of the arc. The example at the top of this thread shows them being patterned separately via the parser but not via other definitions. Here's an attempt at an example (perhaps contrived, I can't say I've every actually wanted to do this but you never know?): d1 $ within (fast 3 sine) (fast 5 sine) (fast 4) $ s "drum*8" # n (irand 12)
The problem is that start and stop can't really be treated independently like this. We could easily support the case where e < s by swapping them. But still, I'm not sure if that's a useful way of dealing with timespans.
Perhaps it would make more sense to instead of (or as an additional alternative to) start and stop, use start and duration? Then within (slow 4 $ segment 4 saw) 0.25
would do the same as chunk 4
.
Or maybe even centrepoint rather than start..
Actually I did originally consider defining arcs in terms of start
and duration
, but start
and stop
felt easier to work with in the end.
I think you could have all three interpretations supported by different definitions, regardless of what the implementation of arc is. I can imagine interesting uses for all of them.
Related to #397
in trying to get some extended uses of zoom
and within
and potentially transcend the static/non-patternable arc, could one solution possibly be something along the lines of this?
arcFunction = duration startPoint offset
where duration defines the "width" of the arc (patternable, fractional...1/10th of a cycle, etc.), the startPoint defines what position of the cycle to begin the arc (patternable, fractional...1/2 is midpoint, etc.), and the offset defines any shifting that you want to happen over time (default would be 0 offset but you could nest a range and move slide the offset around over time).
example:
d1 $ zoom "<0.1 0.25>" "<0 0.5 0.75>" (range 0 1 $ slow 16 sine) $ myPattern