I'm playing around with some ideas, and one thing I'd like to try is to use the cycle number to get the nth element of an infinite list (then use that return value to build a pattern). I've been digging through the source code looking at functions that seem to depend on cycle number, but mostly just scratching my head. This is partly because my Haskell knowledge is patchy at best as is my knowledge of Pattern anatomy.
One of the two things I've been looking at is
sig which gets used in the "analog" patterns such as
perlin2. I can kind of get this to work, as in, I can use it as a pattern itself:
d1 $ s "superpiano" # n (sig fromRational)
which goes up one semitone for each cycle that passes. But I don't know how I can 'extract' Int values from this such that I could use them as input to a function like
f = (!!) myInfiniteList
The other place where Tidal clearly uses cycle number is in the functions like
whenmod. These depend internally on the function
when whose first argument is an
(Int -> Bool) (Core.hs, line 417). The Int in that argument, is presumably the cycle number. In the function body, the
(Int -> Bool) predicate takes as its argument
floor $ start $ arc st
st is a
State - but then I hit a wall since I don't know where it is coming from, so I am unable to use it in my code. I suppose my understanding of how
States, etc fit together is kind of shoddy.
I would be hugely grateful if someone could help clarify what is going on in these two scenarios and/or provide another way to get the cycle number as an Int!
A tidal pattern is a function of time, rather than a sequence like a lazy infinite list. The most recent explanation of that is in here https://github.com/yaxu/nime20/blob/master/pattern.pdf
It world be possible to make a pattern that does this lookup of a list, and I can make an example later. But then if you queried a pattern for events at cycle 100000, it would have to calculate the whole list up to that point.
So it would be good to hear about your overall aim with this and see whether the structure can be expressed as a function of time rather than a list.
Thanks the the reply (and for the link). I suppose I am in danger of losing the forest for the trees. . . It's just that the trees are also really interesting.
The original problem I was trying to solve was coming up with a general way of using iterative functions (e.g., cellular automata, dynamic systems) to generate material in Tidal.
The simple example that I was playing with was using the logistic map function to generate melodies. If I start with an iterative function like this (where the x value feeds forward):
logisticMap r x = r * (1 - x) * x
I can use
iterate on this to get an infinite list:
let logisticList = iterate (logisticMap 3.6) 0.5 :: [Integer]
Then maybe use
fmap (floor . (*8)) to get values I could use with Tidal's
I was thinking that I could make this into a function of time, by indexing the list with (!!). In general with this appoach, if I'm trying to access the 100th element in the list, I will have already accessed the 99th. I understand that if I were to arbitrarily index the 99th element in my list, it will have to work its way through the prior 98 steps to get that value. But if I use
sprint: on that infinite list after doing this, that 99th value seems to have been somehow 'memoized' (my understanding here is pretty hazy). I'm assuming/hoping that it wouldn't need to repeat the those 99 calculation again, although I guess it would have to 'walk' its way through the list each time.
What I have been doing until now is explicitly crunching out the values for a large, but not infinite, list. Then mapping those values to Patterns, then
cating those Patterns together. It kind of works, but it feels like cheating - I'd like to see if this can be done without precalculating.
Yes memoisation might help, I read that it doesn't always work well with Tidal's FRP-style approach.. and once you start manipulating time, you'd end up jumping around the list a lot.
Anyway, you were really close. I've used floor rather than fromRational although they might well do the same thing. You just need to
fmap to do the lookup for all the values inside the pattern. I've used the
<$> operator which is an alias for fmap:
let mylist = [0, 2 ..]
pat = segment 1 $ (mylist !!) <$> sig floor
I also added 'segment 1', so you end up with discrete events (sig is generally for continuously varying functions of time).
I'll make an 'innards' category for this kind of discussion later on..
Thanks! I feel like I've been banging my head against this for ages. So many things I want to try out now . . .
And an 'innards' category sounds like a fantastic idea!
Wow this is great! Here's a silly looping example
let mylist = [1,2,6,3,50,14,31,34,2,6]
let l = pure (length mylist)
let pat = segment 1 $ (mylist !!) <$> (mod (sig floor) (l))
d1 $ s "superpiano" # n pat
I've written an L-System generator and some Cellular Automata in GLOSS a while ago and will see if it's possible to update the visuals each cycle. Will post the results if anyone's interested
Edit: Chris Stryczynski has succesfully integrated Tidal and Gloss
I'd love to see what you put together. Please post the results when you have some!