[the following is a bit technical ... in short, there is a problem in my code (time shift is useless), and there's a problem in randrun
implementation (ignores Arc endpoint), and I propose an alternative. I can make a PR if someone confirms that the idea works, and would like to use it.]
- time-shifting: this only makes sense for the continuous pattern (
rand
), not fot the discretized one (randrun
is discrete). E.g., two different sequences, events (for both) at each fourth:
segment 4 (0.1 ~> irand 10)
-- [(0>⅒)-¼|9,0-(⅒>¼)|5,(¼>½)|7,(½>¾)|5,(¾>1)|0]
segment 4 (0.2 ~> irand 10)
-- [(0>⅕)-¼|8,0-(⅕>¼)|4,(¼>½)|1,(½>¾)|8,(¾>1)|6]
something quite different:
0.1 ~> (segment 4 $ irand 10)
-- [-117/20-(0>⅒)|3,(⅒>7/20)|3,(7/20>⅗)|6,(⅗>17/20)|1,(17/20>1)-1⅒|3]
0.2 ~> (segment 4 $ irand 10)
-- [-119/20-(0>⅕)|3,(⅕>9/20)|3,(9/20>7/10)|6,(7/10>19/20)|1,(19/20>1)-1⅕|3]
- non-randomness for
randrun
at time zero: I think the reason is
randrun n' =
splitQueries $ Pattern (\(State a@(Arc s _) _) -> events a $ sam s)
.....................................^^^^^^^^
uses just s
(start of arc) and ignores the arc's end.
NB - Each time I see (in Tidal sources) an implementation that works on queries directly, I wonder - is it really necessary to break the abstraction barrier? I am dreaming of a world where data Pattern a
is opaque (constructor is not exported), and the module that contains data Pattern a = ...
is as small as possible)
- I tried to find a "more abstract" implementation. Maybe this:
rands :: Fractional a => Int -> Pattern [a]
rands k = Pattern $ \(State a@(Arc s e) _)
-> [Event (Context []) Nothing a (map realToFrac $ (timeToRands ((e + s)/2) k :: [Double]))]
randrun' :: Int -> Pattern Int
randrun' n = segment 1 (rands n) >>= \ rs ->
let go [] [] = []
go (r:rs) xs =
let i = floor (r * fromIntegral (length xs))
(pre, p:ost) = splitAt i xs
in p : go rs (pre <> ost)
in fastcat $ map pure $ go rs [0 .. n-1]
perhaps rands
can be built in some better way (I just copied rand
and replaced timeToRand
with timeToRands
).
- If we want a different "random" realization (for events at the same time), then time-shifting does not help, see above. To be able to do this, we can
randrun'' :: Int -> Pattern (Pattern Int)
randrun'' n = flip fmap (rands n) $ \ rs ->
let go [] [] = []
go (r:rs) xs =
let i = floor (r * fromIntegral (length xs))
(pre, p:ost) = splitAt i xs
in p : go rs (pre <> ost)
in fastcat $ map pure $ go rs [0 .. n-1]
note on the result type: the outer pattern is continuous (it refers to rand
), and the inner pattern is discrete. In the application, we can then
unwrap $ segment 1 $ 0.4 ~> randrun'' 12
and by changing the shift, we get different values while keeping the timing.