~pbatch/gest

9673cd5d04b75d9e02994c225e53a41fdb0efca6 — Paul Batchelor 2 months ago 13ced32
added bezier behavior
3 files changed, 123 insertions(+), 4 deletions(-)

M gest.org
M l_gest.c
M test.lil
M gest.org => gest.org +95 -3
@@ 617,7 617,7 @@ void gest_loopit(gest_d *g)
* Behavior Commands
Behaviors are the means by which one target gets to thep
next target.
** Linear behavior
** Linear
Linear: converts the last target to use linear behavior.

#+NAME: funcdefs


@@ 637,7 637,7 @@ void gest_behavior_linear(gest_d *g)
    g->curtarget->tick = linear;
}
#+END_SRC
** Step behavior
** Step
Step: converts the last target to be a step (no line, just
the value).



@@ 721,7 721,7 @@ void gest_behavior_smallgliss(gest_d *g)
}
#+END_SRC

** Exponential behavior
** Exponential
Exponential: converts the last target to use exponential
behavior with slope =slope=.



@@ 756,6 756,98 @@ void gest_behavior_exponential(gest_d *g, SKFLT slope)
    *s = slope;
}
#+END_SRC
** Bezier
Applies a quadratic Bezier line segment between to two
targets. Bezier takes in two control values that are
control targets.

#+NAME: funcdefs
#+BEGIN_SRC c
void gest_behavior_bezier(gest_d *g, SKFLT cx, SKFLT cy);
#+END_SRC

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.

#+NAME: funcs
#+BEGIN_SRC c
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 x, SKFLT y, SKFLT a, void *ud)
{

    struct bezier_data *bd;
    bd = ud;
    a = bezier_curve(a, bd->cx, bd->cy);
    return (1 - a)*x + a*y;
}

void gest_behavior_bezier(gest_d *g, SKFLT cx, SKFLT cy)
{
    struct bezier_data *bd;
    g->curtarget->tick = bezier;
    g->curtarget->ud = gest_alloc(g, sizeof(struct bezier_data));
    bd = (struct bezier_data *)g->curtarget->ud;
    bd->cx = cx;
    bd->cy = cy;
}
#+END_SRC
* Temporal Weight Commands
** mass
=gest_mass= the global mass to an absolute value.

M l_gest.c => l_gest.c +26 -1
@@ 321,7 321,7 @@ static lil_value_t l_gest_exponential(lil_t lil,
    SKFLT val;

    core = lil_get_data(lil);
    SKLIL_ARITY_CHECK(lil, "gest_target", argc, 1);
    SKLIL_ARITY_CHECK(lil, "gest_exponential", argc, 1);
    rc = sk_core_generic_pop(core, (void **)&g);
    SKLIL_ERROR_CHECK(lil, rc, "couldn't get gest data.");



@@ 333,6 333,30 @@ static lil_value_t l_gest_exponential(lil_t lil,
    return NULL;
}

static lil_value_t l_gest_bezier(lil_t lil,
                                 size_t argc,
                                 lil_value_t *argv)
{
    sk_core *core;
    gest_d *g;
    int rc;
    SKFLT cx;
    SKFLT cy;

    core = lil_get_data(lil);
    SKLIL_ARITY_CHECK(lil, "gest_bezier", argc, 2);
    rc = sk_core_generic_pop(core, (void **)&g);
    SKLIL_ERROR_CHECK(lil, rc, "couldn't get gest data.");

    cx = lil_to_double(argv[0]);
    cy = lil_to_double(argv[1]);

    gest_behavior_bezier(g, cx, cy);

    sk_core_generic_push(core, g);
    return NULL;
}


void sklil_load_gest(lil_t lil)
{


@@ 353,4 377,5 @@ void sklil_load_gest(lil_t lil)
    lil_register(lil, "gest_gliss", l_gest_gliss);
    lil_register(lil, "gest_smallgliss", l_gest_smallgliss);
    lil_register(lil, "gest_exponential", l_gest_exponential);
    lil_register(lil, "gest_bezier", l_gest_bezier);
}

M test.lil => test.lil +2 -0
@@ 42,8 42,10 @@ func modindex {} {
    gest_begin 3 3
    gest_monoramp 2
    gest_target 0
    gest_bezier 0.4 1

    gest_target 2
    gest_exponential 3
    gest_end
    gest_loopit
    gest_finish