7. Behavior Commands
Behaviors are the means by which one target gets to thep next target.
7.1. Linear
Linear: converts the last target to use linear behavior.
void gest_behavior_linear(gest_d *g);
static SKFLT linear(gest_d *g, SKFLT a, void *ud)
{
return a;
}
void gest_behavior_linear(gest_d *g)
{
set_behavior(g, linear, NULL);
}
7.2. Step
Step: converts the last target to be a step (no line, just the value).
void gest_behavior_step(gest_d *g);
static SKFLT step(gest_d *g, SKFLT a, void *ud)
{
return 0;
}
void gest_behavior_step(gest_d *g)
{
set_behavior(g, step, NULL);
}
7.3. Gliss
Gliss
is a behavior intended
gestures that are pitches mimicking glissando.
It works by cutting the incoming ramp in half. The
first half is 0, and the second half gets
normalized to be 0-1 with a cubic slope. This
then gets interpolated between the x and y target
values.
7.3.1. Regular Gliss
void gest_behavior_gliss(gest_d *g);
static SKFLT gliss(gest_d *g, SKFLT a, void *ud)
{
if (a < 0.5) {
a = 0;
} else {
a -= 0.5;
if (a < 0) a = 0;
a *= 2;
a = a * a * a;
}
return a;
}
void gest_behavior_gliss(gest_d *g)
{
set_behavior(g, gliss, NULL);
}
7.3.2. Small Gliss
smallgliss
does this, but smaller scale. Best for
instruments that want the minimal amount of smoothing
done to preserve a step-sequenced sound.
void gest_behavior_smallgliss(gest_d *g);
static SKFLT smallgliss(gest_d *g, SKFLT a, void *ud)
{
if (a < 0.97) {
a = 0;
} else {
a -= 0.97;
if (a < 0) a = 0;
a /= 0.03;
a = a * a * a;
}
return a;
}
void gest_behavior_smallgliss(gest_d *g)
{
set_behavior(g, smallgliss, NULL);
}
7.3.3. Medium Gliss
void gest_behavior_mediumgliss(gest_d *g);
static SKFLT mediumgliss(gest_d *g, SKFLT a, void *ud)
{
if (a < 0.75) {
a = 0;
} else {
a -= 0.75;
if (a < 0) a = 0;
a /= 0.25;
a = a * a * a;
}
return a;
}
void gest_behavior_mediumgliss(gest_d *g)
{
set_behavior(g, mediumgliss, NULL);
}
7.4. Exponential
Exponential: converts the last target to use exponential
behavior with slope slope
.
void gest_behavior_exponential(gest_d *g, SKFLT slope);
void gest_behavior_step(gest_d *g);
static SKFLT exponential(gest_d *g, SKFLT a, void *ud)
{
SKFLT *s;
s = ud;
return (1.0 - exp(a * (*s))) / (1 - exp(*s));
}
void gest_behavior_exponential(gest_d *g, SKFLT slope)
{
SKFLT *s;
s = gest_alloc(g, sizeof(SKFLT));
*s = slope;
set_behavior(g, exponential, s);
}
7.5. Bezier
Applies a quadratic Bezier line segment between to two targets. Bezier takes in two control values that are control targets.
void gest_behavior_bezier(gest_d *g, SKFLT cx, SKFLT cy);
Explanation for how this works is already done in the sndkit Bezier algorithm where this is code is based, so it's worth checking that out for the mathematical derivation.
struct bezier_data {
SKFLT cx;
SKFLT cy;
};
/* https://pbat.ch/sndkit/bezier/ */
static SKFLT quadratic_equation(SKFLT a, SKFLT b, SKFLT c)
{
SKFLT det; /* determinant */
det = b*b - 4*a*c;
if (det >= 0) {
return ((-b + sqrt(det))/(2.0*a));
} else {
return 0;
}
}
static SKFLT find_t(SKFLT x0, SKFLT x1, SKFLT x2, SKFLT x)
{
SKFLT a, b, c;
a = (x0 - 2.0 * x1 + x2);
b = 2.0 * (-x0 + x1);
c = x0 - x;
if (a) {
return quadratic_equation(a, b, c);
} else {
return (x - x0) / b;
}
}
static SKFLT bezier_curve(SKFLT xpos, SKFLT cx, SKFLT cy)
{
SKFLT x[3];
SKFLT y[3];
SKFLT t;
SKFLT val;
x[0] = 0;
x[1] = cx;
x[2] = 1;
y[0] = 0;
y[1] = cy;
y[2] = 1;
t = find_t(x[0], x[1], x[2], xpos);
val = (1.0-t)*(1.0-t)*y[0] + 2.0*(1 - t)*t*y[1] + t*t*y[2];
return val;
}
static SKFLT bezier(gest_d *g, SKFLT a, void *ud)
{
struct bezier_data *bd;
bd = ud;
return bezier_curve(a, bd->cx, bd->cy);
}
void gest_behavior_bezier(gest_d *g, SKFLT cx, SKFLT cy)
{
struct bezier_data *bd;
bd = gest_alloc(g, sizeof(struct bezier_data));
bd->cx = cx;
bd->cy = cy;
set_behavior(g, bezier, bd);
}
7.6. Smoothstep
Applies a smooth step function to the behavior.
void gest_behavior_smoothstep(gest_d *g);
static SKFLT smoothstep(gest_d *g, SKFLT a, void *ud)
{
SKFLT out;
if (a <= 0) out = 0;
else if (a >= 1) out = 1;
else out = a * a * (3 - 2 * a);
return out;
}
void gest_behavior_smoothstep(gest_d *g)
{
set_behavior(g, smoothstep, NULL);
}
7.7. Biramp
Takes the linear ramp, and splits it in half at a particular position with an upwards and a downwards ramp. Intended to be used for LFO purposes.
void gest_behavior_biramp(gest_d *g, SKFLT pos);
void gest_behavior_biramp(gest_d *g, SKFLT pos);
static SKFLT biramp(gest_d *g, SKFLT a, void *ud)
{
SKFLT *pos;
SKFLT out;
pos = ud;
if (*pos == 0 || *pos == 1) return *pos;
if (a < *pos) out = a / *pos;
else out = (1 - a) / (1 - *pos);
return out;
}
void gest_behavior_biramp(gest_d *g, SKFLT pos)
{
SKFLT *ppos;
ppos = gest_alloc(g, sizeof(SKFLT));
*ppos = pos;
set_behavior(g, biramp, ppos);
}
7.8. Gate
Takes the input ramp, and produces a gate signal that is on (value of 1) for a relative percentage of the target before turning off (0).
void gest_behavior_gate(gest_d *g, SKFLT pos);
static SKFLT gatefun(gest_d *g, SKFLT a, void *ud)
{
SKFLT *pos;
SKFLT out;
pos = ud;
if (a <= *pos) out = 1.0;
else out = 0.0;
return out;
}
void gest_behavior_gate(gest_d *g, SKFLT pos)
{
SKFLT *ppos;
ppos = gest_alloc(g, sizeof(SKFLT));
*ppos = pos;
set_behavior(g, gatefun, ppos);
}
prev | home | next