That is exactly what I was looking for, thank you!
Moved to Innards as it's a bit involved..
I'd generalise the type so it works with any number, as in Tidal notes aren't integers but floats.
inversion :: Num a => Int -> [a] -> [a] inversion _  =  inversion n xs = drop n xs ++ [ x + 12 | x <- take n xs ]
Then I'd get it to with with lists of Tidal events rather than values:
eventInversion :: Num a => Int -> [Event a] -> [Event a] eventInversion _  =  eventInversion n xs = drop n xs ++ (fmap (fmap (+12)) $ take n xs )
I used fmap to work in the values inside events, and for brevity used fmap on the list too instead of the list comprehension.
Then I made this function that allows you to group any co-occuring events and work on them together:
withFriends :: ([Event a] -> [Event b]) -> Pattern a -> Pattern b withFriends f pat = withEvents munge pat where munge es = concatMap (f) (groupBy (\a b -> whole a == whole b) $ sortOn whole es)
Then bring it together:
invert :: Num b => Int -> Pattern b -> Pattern b invert = withFriends . eventInversion
d1 $ n (invert 2 "c'maj e'min'4") $ sound "superpiano"
It's complicated because tidal patterns are functions from time to events, so you have to make a function that intercepts values on the way out of the pattern, grouping together ones happening at the same time.
Here's a less attractive version of
inversion that works with negative inversions:
inversion :: Num a => Int -> [Event a] -> [Event a] inversion _  =  inversion n xs = map (\i -> fmap (+ (fromIntegral $ (i `div` l)*12)) (xs !! (i `mod` l))) $ take l [n ..] where l = length xs
Thanks for the explanation @yaxu, there are quite many things that I am not able to understand.
I will try to summarise them, feel free to skip if you think we are going down the rabbit hole and perhaps it is better to wait.
fmap is used here because
Event is a
Functor therefore we can't really apply standard functions such as
So here I understand that when we
stack something as in the case of chords, Tidal creates an
Event for every single note in the stack and these
Events happen to play in the same
Part, i.e. they are scheduled to be simultaneous?
(Plus I got a bit lost inside the function TBH.)
Yep! The fmap is there to do something to the value inside the event.
Yes, so if you played two chords at the same time, this function would treat them as a single chord.
At this point tidal isn't creating any events, but composing a function for creating events.
Yes there's a lot going on here..
I can see couple of things in there though:
- you are using
withEvents, which (if I am correct) should apply a function to the input pattern
- the function that you want to apply is
- sorts a list of
Events from lowest to highest (I assume with respect of time) based on
whole(no real idea about it)
- groups the resulting list given some predicate (and
wholeis here again)
- applies the function coming all the way from
withEventsand concatenate the result
- sorts a list of
but where is
I think this relates to what I was saying somewhere else in the club about the struggle to making things work.
What I experience is that I sometimes (hopefully) learn something new in Haskell, e.g. list comprehension. A lot of ideas come on how to tweak this list into that - but then I try to write something and it almost never works because either the function input is not what it should be or the output is not what Tidal wants.
Oops that should be -
invert = withFriends . eventInversion
A lot of haskell documentation focuses on working with lazy lists, which isn't often useful with tidal. Generally they're awesome but I'd say that lists are a kind of code smell with tidal.
Definitely interested in knowing more about your point of view.
It's just that Tidal paradigm is about functions of time, not data structures like lists.. About defining behaviour and not procedures.
you're welcome @loopology!
I've been trying really hard to get deeper into the innards and every time I see this kind of discussion I jump in straight away.
@yaxu I apologise in advance because I'll probably be asking many more times in the next weeks about Tidal paradigm as it is not clear yet to me
@mattia.paterna, please tag me when you do, as I'm on the same track, even if behind you