Last active
June 24, 2021 18:54
-
-
Save trentgill/19109bca849f5fcf39f2124228087bdd to your computer and use it in GitHub Desktop.
working through some issues in asl2's mutable / iterating type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- feels different if you separate the ASL structure from the data | |
function modulator(height, risetime, falltime) | |
return loop{ to( height, risetime ) | |
, to( 0, falltime) | |
} | |
end | |
function init() | |
starting_rise = 1 | |
output[1]( modulator( dyn{height = 10} | |
, (mutable(starting_rise)-0.1) % dyn{new_rise=starting_rise} | |
, dyn{fall_time = 0.2})) | |
end | |
output[1].dyn.height = 4 -- change to 4V tall | |
output[1].dyn.new_rise = 2 -- rise time resets to 2 seconds (not 1) | |
------------------------------------------------ | |
-- proposed version with mutate as a verb | |
-- mdyn is just a dyn with mutation precedence | |
function init() | |
starting_rise = 1 | |
output[1]( modulator( dyn{height = 10} | |
, mutate( (mdyn(starting_rise)-0.1) % dyn{new_rise=starting_rise}) | |
, dyn{fall_time = 0.2})) | |
end | |
------------------------------------------------ | |
-- it's weird that mdyn is modified by the function that calls it | |
-- too much magic & thus hard to follow | |
-- | |
-- more natural would be if mutate were a function that takes a dyn argument | |
-- original snippet | |
mutate( (mdyn(starting_rise)-0.1) % dyn{new_rise=starting_rise}) + 0.01 -- addition is just to demonstrate scope | |
-- consider 'on_step' as an alternate to 'mutate' | |
dyn(1):on_step( function(self) return (self-0.1) % reset_rise end ) + 0.01 | |
-- which we can format: | |
dyn(1):on_step( function(self) | |
return (self-0.1) % reset_rise end | |
) + 0.01 | |
-- or name the function | |
function dec(self) | |
return (self-0.1) % reset_rise | |
end | |
dyn(1):on_step(dec) + 0.01 | |
-- this is tough because we no longer have access to the 'reset_rise' variable | |
-------------------------------------------------------- | |
-- let's look at the function style, in-lined, in the full context | |
function init() | |
starting_rise = 1 | |
output[1]( modulator( dyn{height = 10} | |
, dyn(starting_rise):on_step( function(self) | |
return (self-0.1) % dyn{new_rise=starting_rise} end | |
) + 0.01 | |
, dyn{fall_time = 0.2})) | |
end | |
---------------------------------------------------------------------------------------------------- | |
-- or we could take this same idea but use the 'dec' function but paramterize it | |
function modulator(height, risetime, falltime) | |
return loop{ to( height, risetime ) | |
, to( 0, falltime) | |
} | |
end | |
-- returns a function as we're describing an action that will happen in the future | |
function dec(self, step, reset) | |
return function(self) (self - step) % reset end | |
end | |
function init() | |
starting_rise = 1 | |
output[1]( | |
modulator( dyn{height = 10} | |
, dyn(starting_rise):on_step( dec(0.1, dyn{reset_rise=starting_rise}) ) + 0.01 | |
, dyn{fall_time = 0.2})) | |
end | |
-- alternate form without method call, and just paramaterized on_step | |
function init() | |
starting_rise = 1 | |
output[1]( | |
modulator( dyn{height = 10} | |
, on_step( dyn(starting_rise), dec(0.1, dyn{reset_rise=starting_rise}) ) + 0.01 | |
, dyn{fall_time = 0.2})) | |
end | |
------------------------------- | |
-- return to the mutate as verb option | |
function init() | |
starting_rise = 1 | |
output[1]( | |
modulator( dyn{height = 10} | |
, mutate( (mdyn(starting_rise)-0.1) % dyn{new_rise=starting_rise}) | |
, dyn{fall_time = 0.2} | |
)) | |
end | |
---- another form where dyn_iter produces an ASL number with an associated iteration behaviour | |
-- a super-charged *dyn* that is modified on each access | |
output[1]( | |
modulator( dyn{height = 10} | |
, dyn_iter( starting_rise -- initial value (can also be a table for named arg: {rise=starting_rise}) | |
, function(i) -- this function gets called on each access. arg 'i' is the dynamic variable to modify | |
return (i-0.1) % dyn{new_rise=starting_rise} end | |
) + 0.01 -- dyn_iter produces a number we can perform arithmetic on (like dyn) | |
, dyn{fall_time = 0.2}) | |
) | |
-- the above is nice in that codifies the mutation as an iteration (a concept known to crow scripters) | |
-- the *problem* is that it looks like a normal function, BUT IT'S NOT | |
-- *the function is only allowed to perform arithmetic as it must be compiled into a pure C function* | |
-- i worry that this caveat makes this whole approach counter-intuitive. | |
-- it *looks* like a function, and acts like one in many ones, but not in *all* the ways | |
-------------------------- | |
-- new thoughts post discussion with brian | |
-- 1. 2nd arg to dyn is a mutation-description-table | |
output[1]( | |
modulator( dyn{height = 10} | |
, dyn( {rise=starting_rise} | |
, {inc=-0.1, range={0, dyn{new_rise=starting_rise}}} | |
) | |
, dyn{fall_time = 0.2}) | |
) | |
-- 2. dyn can be method-chained to per-step-modifiers, and range-limiters | |
output[1]( | |
modulator( dyn{height = 10} | |
, dyn{rise=starting_rise}:step(-0.1):wrap(0, dyn{new_rise=starting_rise}) | |
, dyn{fall_time = 0.2}) | |
) | |
-- can also break up the method chains for readability | |
output[1]( | |
modulator( dyn{height = 10} | |
, dyn{rise=starting_rise} | |
:step(-0.1) | |
:wrap(0, dyn{new_rise=starting_rise}) | |
, dyn{fall_time = 0.2}) | |
) | |
-- per-step modifiers | |
:step(increment) -- increments the dyn value per step | |
:mul(multiplier) -- scales the dyn value per step | |
-- range limits applied *after* per-step modifiers | |
:wrap(min, max) -- sawtooth modulation | |
:clamp(min, max) -- one-shot attacks (eg pitch enveloping) | |
:bounce(min, max) -- triangle modulation | |
-- i like this second idea because it aligns with the approach from sequins & public | |
-- naming requires some thought obviously, but this illustrates an approach |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment