-
-
Save DBraun/6b73b9b69300775f4eb68d2c5551d944 to your computer and use it in GitHub Desktop.
ADSR bias faust demo
This file contains 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
import("stdfaust.lib"); | |
adsr_bias_env = environment | |
{ | |
// In the functions below, we use the equation `y=bias_curve(b,x)`. | |
// `b`: bias between 0 and 1. Bias of 0.5 results in `y=x`. Bias above 0.5 pulls y upward. | |
// `x`: input between 0 and 1 that needs to be remapped/biased into `y` | |
// `y`: `x` after it has been biased. Note that `(y==0 iff x==0) AND (y==1 iff x==1)`. | |
bias_curve(b,x) = (x / ((((1.0/b) - 2.0)*(1.0 - x))+1.0)); | |
// d/dx of bias_curve(b,x) | |
bias_curve_d_dx(b, x) = 0-(-1+b)*b/((1-x+b*(-1+2*x))^2); | |
// Solve for x in y=bias_curve(b,x) | |
bias_curve_inverse(b,y) = (b-1)*y / (2*b*y-b-y); | |
// We don't allow the bias to be too close to 0 or 1 because it leads to slopes too | |
// close to positive or negative infinity. | |
bias_clip = aa.clip(.03, .97); | |
adsr_bias(att, dec, sus, rel, final, bias_att, bias_dec, bias_rel, legato, gate) = envelope | |
with { | |
ugate = gate>0; | |
fb(_state, _y) = nextState, nextY | |
with { | |
// Legato control | |
onset = ba.impulsify(ugate); | |
state = select2(onset, _state, 0), _state : select2(legato); | |
y = select2(onset, _y, final), _y : select2(legato); | |
// State 0: release | |
// State 1: attack | |
// State 2: decay | |
y_at_release = y : ba.latch(ugate==0); | |
// Slope is a y-distance divided by a number of samples | |
att_slope = (1-final) / max(1,(att*ma.SR)); | |
dec_slope = (sus-1) / max(1,(dec*ma.SR)); | |
rel_slope = (final-y_at_release) / max(1,(rel*ma.SR)); | |
// Get bias based on the state, then clip for safety. | |
b = bias_rel, bias_att, bias_dec : select3(state) : bias_clip; | |
// We will remap from an input domain to [0..1] based on the current state. | |
from1 = ba.if(state==2, sus, final); | |
from2 = ba.if(state==0, y_at_release, 1); | |
// Prevent divide-by-zero in it.remap | |
pct = it.remap(from1, from2, 0, 1, y), 0.5 : select2(from1==from2) : bias_curve_inverse(b); | |
slope = rel_slope, att_slope, dec_slope : select3(state) : _*bias_curve_d_dx(b, pct); | |
nextY = y + slope : aa.clip(from1, 1); | |
nextState = select2(ugate, | |
0, | |
select3(state, | |
1, | |
select2(y < 1.0, 2, 1), | |
2 | |
) | |
); | |
}; | |
envelope = fb ~ (_,_) : !, _; | |
}; | |
ahdsr_bias(att, hol, dec, sus, rel, final, bias_att, bias_dec, bias_rel, legato, gate) = envelope | |
with { | |
ugate = gate>0; | |
fb(_state, _y) = nextState, nextY | |
with { | |
// Legato control | |
onset = ba.impulsify(ugate); | |
state = select2(onset, _state, 0), _state : select2(legato); | |
// two conditions in which we want to hard-reset the `y` to `final` | |
// instead of using the previous `_y`. | |
y = ba.if((onset & (legato<0.5)) | (ba.time==0), final, _y); | |
// State 0: release | |
// State 1: attack | |
// State 2: hold | |
// State 3: decay | |
y_at_release = ba.if(ba.time==0,1,y) : ba.latch(gate==0); | |
// Slope is a y-distance divided by a number of samples | |
att_slope = (1-final) / max(1,(att*ma.SR)); | |
hold_slope = ba.if(gate, att_slope, rel_slope); | |
dec_slope = (sus-1) / max(1,(dec*ma.SR)); | |
rel_slope = (final-y_at_release) / max(1,(rel*ma.SR)); | |
// Get bias based on the state, then clip for safety. | |
// Note that for the hold state, we choose a bias of 0.5 (the middle value). | |
b = bias_rel, bias_att, .5, bias_dec : ba.selectn(4, state) : bias_clip; | |
from1 = ba.if(state==3, sus, final); | |
from2 = ba.if(state==0, y_at_release, 1); | |
// Prevent divide-by-zero in it.remap | |
pct = it.remap(from1, from2, 0, 1, y), 0.5 : select2(from1==from2) : bias_curve_inverse(b); | |
slope = rel_slope, att_slope, hold_slope, dec_slope : ba.selectn(4, state) : _*bias_curve_d_dx(b, pct); | |
hold_time = ma.SR * hol; | |
hold_timer = ugate : +~(*(ugate * (state != 1))); | |
nextY = y + slope : aa.clip(from1, 1); | |
nextState = select2(ugate, | |
0, | |
ba.selectn(4, state, | |
1, | |
select2(y < 1.0, 2, 1), | |
select2(hold_timer < hold_time, 3, 2), | |
3 | |
) | |
); | |
}; | |
envelope = fb ~ (_,_) : !, _; | |
}; | |
}; | |
//------------------------`(en.)adsrf_bias`------------------------------ | |
// ADSR (Attack, Decay, Sustain, Release, Final) envelope generator with | |
// control over bias on each segment, and toggle for legato. | |
// | |
// #### Usage | |
// | |
// ``` | |
// adsrf_bias(at,dt,sl,rt,final,b_att,b_dec,b_rel,legato,t) : _ | |
// ``` | |
// | |
// Where: | |
// | |
// * `at`: attack time (sec) | |
// * `dt`: decay time (sec) | |
// * `sl`: sustain level (between 0..1) | |
// * `rt`: release time (sec) | |
// * `final`: final level (between 0..1) but less than or equal to `sl` | |
// * `b_att`: bias during attack (between 0..1) where 0.5 is no bias. | |
// * `b_dec`: bias during decay (between 0..1) where 0.5 is no bias. | |
// * `b_rel`: bias during release (between 0..1) where 0.5 is no bias. | |
// * `legato`: toggle for legato. If disabled, envelopes "re-trigger" from zero. | |
// * `t`: trigger signal (attack is triggered when `t>0`, release is triggered | |
// when `t=0`) | |
//------------------------------------------------------------------------------- | |
declare adsrf_bias author "Andrew John March and David Braun"; | |
declare adsrf_bias licence "STK-4.3"; | |
adsrf_bias(att, dec, sus, rel, final, bias_att, bias_dec, bias_rel, legato, gate) = adsr_bias_env.adsr_bias(att, dec, sus, rel, final, bias_att, bias_dec, bias_rel, legato, gate); | |
//------------------------`(en.)adsr_bias`------------------------------ | |
// ADSR (Attack, Decay, Sustain, Release) envelope generator with | |
// control over bias on each segment, and toggle for legato. | |
// | |
// #### Usage | |
// | |
// ``` | |
// adsr_bias(at,dt,sl,rt,b_att,b_dec,b_rel,legato,t) : _ | |
// ``` | |
// | |
// Where: | |
// | |
// * `at`: attack time (sec) | |
// * `dt`: decay time (sec) | |
// * `sl`: sustain level (between 0..1) | |
// * `rt`: release time (sec) | |
// * `b_att`: bias during attack (between 0..1) where 0.5 is no bias. | |
// * `b_dec`: bias during decay (between 0..1) where 0.5 is no bias. | |
// * `b_rel`: bias during release (between 0..1) where 0.5 is no bias. | |
// * `legato`: toggle for legato. If disabled, envelopes "re-trigger" from zero. | |
// * `t`: trigger signal (attack is triggered when `t>0`, release is triggered | |
// when `t=0`) | |
//------------------------------------------------------------------------------- | |
declare adsr_bias author "Andrew John March and David Braun"; | |
declare adsr_bias licence "STK-4.3"; | |
adsr_bias( att, dec, sus, rel, bias_att, bias_dec, bias_rel, legato, gate) = adsr_bias_env.adsr_bias(att, dec, sus, rel, 0, bias_att, bias_dec, bias_rel, legato, gate); | |
//------------------------`(en.)ahdsrf_bias`--------------------------- | |
// AHDSR (Attack, Hold, Decay, Sustain, Release, Final) envelope generator | |
// with control over bias on each segment, and toggle for legato. | |
// | |
// #### Usage | |
// | |
// ``` | |
// ahdsrf_bias(at,ht,dt,sl,rt,final,b_att,b_dec,b_rel,legato,t) : _ | |
// ``` | |
// | |
// Where: | |
// | |
// * `at`: attack time (sec) | |
// * `ht`: hold time (sec) | |
// * `dt`: decay time (sec) | |
// * `sl`: sustain level (between 0..1) | |
// * `rt`: release time (sec) | |
// * `final`: final level (between 0..1) but less than or equal to `sl` | |
// * `b_att`: bias during attack (between 0..1) where 0.5 is no bias. | |
// * `b_dec`: bias during decay (between 0..1) where 0.5 is no bias. | |
// * `b_rel`: bias during release (between 0..1) where 0.5 is no bias. | |
// * `legato`: toggle for legato. If disabled, envelopes "re-trigger" from zero. | |
// * `t`: trigger signal (attack is triggered when `t>0`, release is triggered | |
// when `t=0`) | |
//--------------------------------------------------------------------- | |
declare ahdsrf_bias author "Andrew John March and David Braun"; | |
declare ahdsrf_bias licence "STK-4.3"; | |
ahdsrf_bias(att, hol, dec, sus, rel, final, bias_att, bias_dec, bias_rel, legato, gate) = adsr_bias_env.ahdsr_bias(att, hol, dec, sus, rel, final, bias_att, bias_dec, bias_rel, legato, gate); | |
//------------------------`(en.)ahdsr_bias`--------------------------- | |
// AHDSR (Attack, Hold, Decay, Sustain, Release) envelope generator | |
// with control over bias on each segment, and toggle for legato. | |
// | |
// #### Usage | |
// | |
// ``` | |
// ahdsr_bias(at,ht,dt,sl,rt,final,b_att,b_dec,b_rel,legato,t) : _ | |
// ``` | |
// | |
// Where: | |
// | |
// * `at`: attack time (sec) | |
// * `ht`: hold time (sec) | |
// * `dt`: decay time (sec) | |
// * `sl`: sustain level (between 0..1) | |
// * `rt`: release time (sec) | |
// * `final`: final level (between 0..1) but less than or equal to `sl` | |
// * `b_att`: bias during attack (between 0..1) where 0.5 is no bias. | |
// * `b_dec`: bias during decay (between 0..1) where 0.5 is no bias. | |
// * `b_rel`: bias during release (between 0..1) where 0.5 is no bias. | |
// * `legato`: toggle for legato. If disabled, envelopes "re-trigger" from zero. | |
// * `t`: trigger signal (attack is triggered when `t>0`, release is triggered | |
// when `t=0`) | |
//--------------------------------------------------------------------- | |
declare ahdsr_bias author "Andrew John March and David Braun"; | |
declare ahdsr_bias licence "STK-4.3"; | |
ahdsr_bias( att, hol, dec, sus, rel, bias_att, bias_dec, bias_rel, legato, gate) = adsr_bias_env.ahdsr_bias(att, hol, dec, sus, rel, 0, bias_att, bias_dec, bias_rel, legato, gate); | |
// process = adsrf_bias( | |
// hslider("[0]attack", 1.0, .0, 1., .001), | |
// hslider("[1]decay", .5, .0, 1., .001), | |
// hslider("[2]sustain", .5, .0, 1., .001), | |
// hslider("[3]release", .2, .0, 1., .001), | |
// hslider("[4]final", .2, .0, 1., .001), | |
// k, k, k, | |
// checkbox("[6]Legato"), | |
// button("Gate") | |
// ) | |
// with { | |
// k = hslider("[5]k", .001, .0, 1., .001); | |
// }; | |
// process = adsr_bias( | |
// hslider("[0]attack", 1.0, .0, 1., .001), | |
// hslider("[1]decay", .5, .0, 1., .001), | |
// hslider("[2]sustain", .5, .0, 1., .001), | |
// hslider("[3]release", .2, .0, 1., .001), | |
// // hslider("[4]final", .2, .0, 1., .001), | |
// k, k, k, | |
// checkbox("[6]Legato"), | |
// button("Gate") | |
// ) | |
// with { | |
// k = hslider("[5]k", .001, .0, 1., .001); | |
// }; | |
process = ahdsrf_bias( | |
hslider("[0]attack", 1.0, .0, 1., .001), | |
hslider("[1]hold", 1.0, .0, 1., .001), | |
hslider("[2]decay", .5, .0, 1., .001), | |
hslider("[3]sustain", .5, .0, 1., .001), | |
hslider("[4]release", .2, .0, 1., .001), | |
hslider("[5]final", .2, .0, 1., .001), | |
k, k, k, | |
checkbox("[7]Legato"), | |
button("gate") | |
) | |
with { | |
k = hslider("[6]k", .5, .0, 1., .001); | |
}; | |
// process = ahdsr_bias( | |
// hslider("[0]attack", 1.0, .0, 1., .001), | |
// hslider("[1]hold", 1.0, .0, 1., .001), | |
// hslider("[2]decay", .5, .0, 1., .001), | |
// hslider("[3]sustain", .5, .0, 1., .001), | |
// hslider("[4]release", .2, .0, 1., .001), | |
// // hslider("[5]final", .2, .0, 1., .001), | |
// k, k, k, | |
// checkbox("[7]Legato"), | |
// button("gate") | |
// ) | |
// with { | |
// k = hslider("[6]k", .001, .0, 1., .001); | |
// }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment