Limit Events Based On Delta Time?

I wonder if there's a way to limit events based upon their duration from a previous event. So 'this sound will not sound unless it is more than .5 seconds after the previous one", etc... Like some sort of flow restrictor.

I sometimes setup scenarios with modifying functions and randomness that I like, but there might be clusters of sound events that I would like to limit in density. I only want to limit the density in those clusters however, and ideally the limiting function would be based on time (or 'closeness' in terms of a cycle) rather than something like degrade which is based on randomness

I know this might be an odd one but let me know if anything comes to mind!

4 Likes

ok I have tried some things and this is what I came up with:

densityFilter:: Eq a => Double -> [Event a] -> [Event a]
densityFilter density events = foldl (fi density) events [0..length events -1]
                      where fi density es n | length es > n = filter (\e -> e == es!!n || abs ((eventPartStart e) - (eventPartStart (es!!n))) >= toRational density ) es
                                            | otherwise = es

lessDense :: Eq a => Double -> Pattern a -> Pattern a
lessDense density p = p {query = (densityFilter density) . query p}

you can call it like

d1 $ lessDense 0.01 $ s "hh*16"

The example above produces something kind of unexpected, so I'm not entierly sure what is happening here, but I think it should kind of do what you said. Just try it out a bit and tell me what you think. Maybe we can come up with something better :slight_smile:

3 Likes

Thanks for this!! Amazing.
It seems to be working! From looking at the code it seems like the parameter is based on time (and not proximity in a cycle) right?

great idea @ben! I'm bookmarking this :bookmark: Thanks for the implementation @polymorphic.engine!

3 Likes

No, it is actually based on proximity: the parameter gives a threshold of how near two events are allowed to be, if they are to near, one of them gets removed. Here is an example:

("t t t [t*4]::Pattern Bool)

In the forth beat there are four events, so each event in that beat is a 16th, so the distance between them is 1/16. So the following wont do any filtering because there are no notes that are closer than 1/16 apart.

lessDense (1/16) ("t t t [t*4]::Pattern Bool)

But if we now consider

lessDense (1/8) ("t t t [t*4]::Pattern Bool)

It will filter out the second and fourth value of the fourth beat, since they are closer to other events than 1/8.

So the best way to read lessDense x is :filter out any events that are closer than x (a bigger x value will filter more)

2 Likes

A minor addition that occured to me just now:

sometimes it might be the case that the events aren't ordered by their start time, so it's better to sort them like this:

import Data.List(sortOn)

densityFilter:: Eq a => Double -> [Event a] -> [Event a]
densityFilter density events = foldl (fi density) events [0..length events -1]
                      where fi density es n | length es > n = filter (\e -> e == es!!n || abs ((eventPartStart e) - (eventPartStart (es!!n))) >= toRational density ) es
                                            | otherwise = es

lessDense :: Eq a => Double -> Pattern a -> Pattern a
lessDense density p = p {query = (densityFilter density). sortOn whole . query p}
4 Likes

Beautiful, thank you!