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
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 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