Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rolled function with variants #820

Merged
merged 12 commits into from
Feb 16, 2022

Conversation

thgrund
Copy link
Contributor

@thgrund thgrund commented Apr 7, 2021

@left_adjont @satoruki @cleary and me (mrreason aka @thgrund) created this rolled functions to give chords a harp-like effect. This was initiated in Discord here: https://discord.com/channels/779427371270275082/797978366023434240/798986145907736592

Then there was a discussion started in the TidalClub forum:
https://club.tidalcycles.org/t/share-your-creations/1281/418

rolledWith f t = withEvents aux
where aux es = concatMap (steppityIn) (groupBy (\a b -> whole a == whole b) $ sortOn whole (f es))
steppityIn xs = mapMaybe (\(n, x) -> shiftIt n (length xs) x) $ enumerate xs
shiftIt n d (Event c (Just (Arc s e)) a' v) = do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gives a 'Pattern match(es) are non-exhaustive' warning, I think this will break on continuous events (those with whole arc of Nothing). Probably adding a catchall of shiftIt _ _ ev = ev is enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I resolved this issue. This will ignore the rolled function for continuous events like

n (rolledBy "1" (irand 8) |+ "[0,8, 12]")

-- ~0>1~|n: Note {unNote = 2.0}n
-- ~0>1~|n: Note {unNote = 10.0}n
-- ~0>1~|n: Note {unNote = 14.0}n

@

And you can use `rolledBy` or `rolledBy'` to specify the length of the roll. The value in the passed pattern
is the divisor of the cycle length.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think specifying the ratio directly would be more idiomatic - e.g. 1/4 or q rather than 4 for a quarter of a cycle.

shiftIt n d (Event c (Just (Arc s e)) a' v) = do
a'' <- subArc (Arc newS e) a'
return (Event c (Just $ Arc newS e) a'' v)
where newS = s + (dur * fromIntegral n)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will result in patterns which aren't well formed, by moving events outside the original query.
Fixing this would be a little complicated I think. The query would need to be made bigger, subtracting the roll duration from the start and adding the duration to the end of the query arc. Then after the calculation done, resulting events trimmed to the original query, and removed completely if they're outside that original query.

Copy link
Contributor Author

@thgrund thgrund Jan 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @yaxu ! I'm just taking the time to try to finish this topic. My understanding is that the behavior you describe should already be implemented. For example s "superpiano" <| n (rolledBy "[1.5]" "[0,1,2]")

will result in

(0>1)|n: Note {unNote = 0.0}n, s: "superpiano"
(½>1)|n: Note {unNote = 1.0}n, s: "superpiano

So, practically, when the time arc of the pattern gets bigger (in theory), the overhanging events are truncated.

And that's what you meant, right?

Copy link
Member

@yaxu yaxu Feb 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm finding it hard to get my head around this in the time I have available..

But what I meant is something like.. Tidal calculates events in a window given by the query. This makes functions like this quite difficult, when we want to cause a new event to happen after an existing one, in at least two ways. We might query a timespan that does not contain any events, but there was one happening just before that timespan that should cause one in the window we're asking for. But we don't know about that. The other problem is that we might have an event in the window but it should cause an event outside that window. From what I could tell, both are an issue here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll merge for now and will try to make a failling test at some point

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I play with it, it seems I was misunderstanding something, it seems to work fine. Sorry for holding this up!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work - thanks Thomas and Alex

rolledWith :: ([Event a] -> [EventF (ArcF Time) a]) -> Ratio Integer -> Pattern a -> Pattern a
rolledWith f t = withEvents aux
where aux es = concatMap (steppityIn) (groupBy (\a b -> whole a == whole b) $ (f es))
steppityIn xs = mapMaybe (\(n, ev) -> (timeguard n xs ev t)) $ enumerate xs
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this zero check to make this possible:

s "superpiano" <| n (rolledBy "0" "[0,1,2,3]")

Otherwise we would receive an exception anyways.

@ndr-brt
Copy link
Contributor

ndr-brt commented Jan 11, 2022

Just a little advice, since this feature seems tricky, why not adding some tests to demonstrate the functionality?

@thgrund
Copy link
Contributor Author

thgrund commented Jan 11, 2022

@ndr-brt thanks for the advice! I added the tests.

@thgrund thgrund requested a review from yaxu January 13, 2022 11:02
rolledWith :: Ratio Integer -> Pattern a -> Pattern a
rolledWith t = withEvents aux
where aux es = concatMap (steppityIn) (groupBy (\a b -> whole a == whole b) $ ((isRev t) es))
isRev b = (\x -> if x > 0 then id else reverse ) b
Copy link
Contributor Author

@thgrund thgrund Jan 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to control the order (playing in reverse or not) within the mini notation. With this lambda it's possible to do this rolledBy "-0.5" $ n ("[0,1,2,3]"). This will result in:

(0>1)|n: Note {unNote = 3.0}n
(⅛>1)|n: Note {unNote = 2.0}n
(¼>1)|n: Note {unNote = 1.0}n
(⅜>1)|n: Note {unNote = 0.0}n

@yaxu yaxu merged commit 2434cc3 into tidalcycles:main Feb 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants