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

"within" not functioning as it should #313

Closed
TylerMclaughlin opened this issue Jul 1, 2018 · 7 comments
Closed

"within" not functioning as it should #313

TylerMclaughlin opened this issue Jul 1, 2018 · 7 comments

Comments

@TylerMclaughlin
Copy link
Collaborator

TylerMclaughlin commented Jul 1, 2018

When I type d1 $ within (0, 0.2) (fast 2) $ sound "bd hh cp sd",
I expect the equivalent of d1 $ sound "[bd bd] hh cp sd" but instead I hear d1 $ sound "[bd hh] hh cp sd".

Via the reference for the within function:

d1 $ within (0, 0.5) (fast 2) $ sound "bd*2 sn lt mt hh hh hh hh"

When I copy this code and run it, it is different than the reference audio sample, instead applying fast 2 to the hi-hats.

@TylerMclaughlin TylerMclaughlin changed the title within command not functioning as it should "within" not functioning as it should Jul 1, 2018
@bgold-cosmos
Copy link
Contributor

The behavior is what I'd expect, the reference audio sounds wrong to me!

within (0, 0.2) (fast 2) to me means "use fast 2 for the first two tenths of a cycle, then use the original pattern for the rest". fast 2 $ s "bd hh cp sd" is "bd hh cp sd bd hh cp sd", so you get the first two beats of that before reverting to the original.

I don't know why the reference audio sounds weird.

@TylerMclaughlin
Copy link
Collaborator Author

TylerMclaughlin commented Jul 2, 2018

Hi @bgold-cosmos!

Thanks to your reply I realize now that there are two ways of thinking about how this could work because there are two ways to chain up within and fast that sound different.

The way you're thinking about it (strategy A) is that first the original cycle is cloned (duplicated). Then fast is applied to that cloned cycle yielding "bd hh cp sd bd hh cp sd". Then the arc corresponding to the [0, 0.2] interval in the new, faster cycle is swapped for the [0,0.2] interval arc in the original slower cycle. This is what tidal is doing currently but not what the reference audio does.

Strategy A in pseudo code:
Clone cycle -> Apply function to cloned cycle -> Select interval in cloned cycle -> swap intervals

The way I was thinking about it (strategy B) is that first the arc of notes in just the [0,0.2] interval in the original cycle are selected, producing (conceptually) a masked version "bd ~ ~ ~" . Then fast is applied to the the non-rest part, producing [bd bd] ~ ~ ~. Then that part is swapped with the original notes in the [0,0.2] interval.

Strategy B in pseudo code:
Select interval in cycle -> clone interval -> apply function to cloned interval -> swap intervals

New to Haskell AND new to tidal btw so please forgive me if I'm making a fool out of myself.

@TylerMclaughlin
Copy link
Collaborator Author

I'm trying to understand how within (0, 0.2) (fast 2) works at the functional level.
In both the reference and source code, it is defined to take an Arc first and then apply a function:
within :: Arc -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

This would seem to be more in line with strategy B, right? Because it selects the arc before it applies the function.

Sorry for the verbosity. Looking forward to hearing what you think!

@bgold-cosmos
Copy link
Contributor

bgold-cosmos commented Jul 2, 2018

The order of the arguments doesn't really matter to Haskell. If you look at the source, within really is doing strategy A pretty directly - when the time is inside the boundaries it plays the pattern with the function applied, otherwise it plays the original pattern.

If you want something like strategy B, that's possible, but I think a little more complicated, because when you "clone" the interval to apply the function you need to tell it to use the interval as a cycle boundary. You can do something like this (sorry for the lack of formatting)

within' (s,e) f p = stack [ 
    playWhen (\t -> cyclePos t >= s && cyclePos t < e) $ compress (s,e) $ f $ zoom (s,e) $ p, 
    playWhen (\t -> not $ cyclePos t >= s && cyclePos t < e) $ p 
]

So the new within' will work something like strategy B. But to get the second bd exactly on the 8th step, you would need to specify that the 1/4 cycle is what fast 2 should double

within' (0,0.25) (fast 2) $ s "bd hh cp sd"

@TylerMclaughlin
Copy link
Collaborator Author

nice! got your new function to work. haha you made that look easy.

I see the old version of within was modified over a year ago and the old version was probably used to make the reference audio. The use of sliceArc instead of playWhen probably lead to a bug that motivated the change.
By adding compress and zoom, what you just proposed is like a hybrid of the old version and the new version which uses playWhen. :)

Would you like me to add your within' (within prime) in a pull request following the quick guide to contributing a change to tidal ?

@bgold-cosmos
Copy link
Contributor

Go ahead!

@yaxu
Copy link
Member

yaxu commented Jul 9, 2019

I'm assuming this is done, please reopen if not!

@yaxu yaxu closed this as completed Jul 9, 2019
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

No branches or pull requests

3 participants