6. Meta Commands and Actions

Commands related to meta-things. Also, placing things related to actions (such as scalars) here, as there is no other place to put them, and not enough of them to make a new category.

6.1. Addmetatarget

The function gest_addmetatarget will create a new metatarget with a size of sz metatargets.

<<funcdefs>>=
int gest_addmetatarget(gest_d *g, int sz);

This function will implicitely create a new target using gest_addtarget, then configure this target to be a metatarget.

After it is created, the metatarget gets pushed onto the metatarget stack contained in the gest data.

<<funcs>>=
int gest_addmetatarget(gest_d *g, int sz)
{
    int rc;
    gest_target *t;
    gest_metatarget *mt;

    if (g->mtpos >= GEST_MTSTACK_SIZE) return 2;

    rc = gest_addtarget(g, -1);

    if (rc) return rc;

    t = g->curtarget;

    mt = metatarget_alloc(g, sz);

    t->get = get_seq;
    t->meta = mt;
    mt->parent = t;

    /* push to stack */
    g->mtstack[g->mtpos++] = mt;
    return 0;
}

6.2. Addmetabehavior

Adds a metabehavior of with sz behaviors.

<<funcdefs>>=
int gest_addmetabehavior(gest_d *g, int sz);

By default, adding a metabehavior means taking the behavior in the currently selected target and converting it into a metabehavior. A nested metabehavior will already have the root behavior converted into a metabehavior at this point. If a metabehavior has been found, it will create a metabehavior on the next available behavior in the parent metabehavior.

<<funcs>>=
int gest_addmetabehavior(gest_d *g, int sz)
{
    gest_target *t;
    gest_metabehavior *mb;
    gest_behavior *b;

    if (g->mbpos >= GEST_MBSTACK_SIZE) return 2;

    t = g->curtarget;

    b = &t->behavior;

    if (b->meta != NULL) {
        /* empty stack, shouldn't happen normally */
        if (g->mbpos <= 0) return 3;

        mb = b->meta;
        b = &mb->behaviors[mb->pos++];

        if (mb->pos >= mb->size) {
            g->mbstack[g->mbpos - 1] = NULL;
            g->mbpos--; /* don't be clever */
        }
    }

    mb = metabehavior_alloc(g, sz);

    b->get = behave_seq;
    b->meta = mb;
    mb->parent = b;

    /* push to stack */
    g->mbstack[g->mbpos++] = mb;
    return 0;
}

6.3. Addmetanode

<<funcdefs>>=
int gest_addmetanode(gest_d *g, int nbeats, int sz);

When a metanode is created, it creates the equivalent to a monoramp, then binds a metanode to it.

<<funcs>>=
int gest_addmetanode(gest_d *g, int nbeats, int sz)
{
    int rc;
    gest_node *n;
    gest_metanode *mn;

    if (g->mnpos >= GEST_MNSTACK_SIZE) return 1;

    rc = gest_monoramp(g, nbeats);

    if (rc) return rc;

    n = g->curnode;

    mn = metanode_alloc(g, n, sz);

    n->meta = mn;
    n->get = node_seq;
    mn->parent = n;

    set_curnode(g, mn->nodes[mn->pos++]);

    g->mnstack[g->mnpos++] = mn;

    return 0;
}

6.4. Addmetaphrase

The function gest_addmetaphrase will allocate a new phrase of arbitrary size and division (will be unused anyways), and then allocate a new instance of a metaphrase with sz phrases.

<<funcdefs>>=
int gest_addmetaphrase(gest_d *g, int sz);
<<funcs>>=
int gest_addmetaphrase(gest_d *g, int sz)
{
    gest_metaphrase *mp;
    gest_phrase *ph;

    if (g->phrase_top == NULL) {
        fprintf(stderr, "Sorry, metaphrases can't yet be first\n");
        return 2;
    }

    if (g->mppos >= GEST_MPSTACK_SIZE) return 1;


    gest_begin(g, 1, 1);

    ph = g->phrase_selected;

    mp = metaphrase_alloc(g, sz);

    ph->get = phrase_seq;
    ph->meta = mp;
    mp->parent = ph;

    g->mpstack[g->mppos++] = mp;

    return 0;
}

6.5. Randtarget

The function gest_randtarget configures the last metatarget to choose targets randomly.

<<funcdefs>>=
int gest_randtarget(gest_d *g);
<<funcs>>=
int gest_randtarget(gest_d *g)
{
    gest_metatarget *mt;
    if (g->mtpos <= 0) return 1;

    mt = g->mtstack[g->mtpos - 1];

    mt->parent->get = target_random;
    return 0;
}

6.6. Randbehavior

The function gest_randbehavior configures the last metabehavior to choose behaviors randomly.

<<funcdefs>>=
int gest_randbehavior(gest_d *g);
<<funcs>>=
int gest_randbehavior(gest_d *g)
{
    gest_metabehavior *mb;

    if (g->mbpos <= 0) return 1;

    mb = g->mbstack[g->mbpos - 1];

    mb->parent->get = behave_random;
    return 0;
}

6.7. Randnode

The function gest_randnode configures the last metanode to choose nodes randomly.

<<funcdefs>>=
int gest_randnode(gest_d *g);
<<funcs>>=
int gest_randnode(gest_d *g)
{
    gest_metanode *mn;

    if (g->mnpos <= 0) return 1;

    mn = g->mnstack[g->mnpos - 1];

    mn->parent->get = node_random;
    return 0;
}

6.8. Randphrase

The function gest_randphrase configures the last metaphrase to choose phrases randomly.

<<funcdefs>>=
int gest_randphrase(gest_d *g);
<<funcs>>=
int gest_randphrase(gest_d *g)
{
    gest_metaphrase *mp;

    if (g->mppos <= 0) return 1;

    mp = g->mpstack[g->mppos - 1];

    mp->parent->get = phrase_random;
    return 0;
}

6.9. Setscalar

Binds an action to the current that assings a value to an instant of a gest_scalar.

<<funcdefs>>=
int gest_setscalar(gest_d *g, gest_scalar *s, SKFLT val);
<<funcs>>=
int gest_setscalar(gest_d *g, gest_scalar *s, SKFLT val)
{
    action_scalar(g, g->curtarget, s, val);
    return 0;
}

6.10. Repeat

The command gest_repeat can be used to repeat a phrase a fixed number of times before going to the next phrase. Call this phrase after an initial phrase has been created with gest_begin.

<<funcdefs>>=
int gest_repeat(gest_d *g, int ntimes);

The repeat function works by replacing the selected phrase's next callback with a custom one, called repeater. There is also special data which gets bound to the phrase's user data slot: repeat position, and the total number of repeats, which the next callback updates as a counter. When the counter reaches the end, it resets and returns the next phrase. Otherwise, it just returns itself.

<<funcs>>=
struct repeat_data {
    int pos;
    int reps;
};

gest_phrase *repeater(gest_d *g, gest_phrase *ph)
{
    struct repeat_data *rd;

    if (ph->ud == NULL) return ph;

    rd = (struct repeat_data *)ph->ud;
    rd->pos++;

    if (rd->pos >= rd->reps) {
        rd->pos = 0;
        return ph->next;
    }

    return ph;
}

int gest_repeat(gest_d *g, int ntimes)
{
    gest_phrase *ph;
    struct repeat_data *rd;

    ph = g->phrase_selected;

    rd = gest_alloc(g, sizeof(struct repeat_data));
    rd->pos = 0;
    rd->reps = ntimes;

    ph->nextf = repeater;
    ph->ud = rd;

    return 0;
}

6.11. Mark

The command gest_mark stores the current phrase to be used for later. It is intended to be used with gest_return.

<<funcdefs>>=
int gest_mark(gest_d *g);
<<funcs>>=
int gest_mark(gest_d *g)
{
    g->saved = g->phrase_selected;
    return 0;
}

6.12. Return

The command gest_return will return to a previously marked phrase a fixed number of times before moving on.

<<funcdefs>>=
int gest_return(gest_d *g, int ntimes);

It is utilized with a special get callback, which will either return the saved phrase or the next phrase. The phrase itself is otherwise completely empty and has no duration.

<<funcs>>=
struct return_d {
    gest_phrase *ph;
    int pos;
    int ntimes;
};

static gest_phrase* goback(gest_d *g, gest_phrase *ph)
{
    struct return_d *rd;

    rd = (struct return_d *)ph->ud;

    rd->pos++;

    if (rd->pos >= rd->ntimes) {
        rd->pos = 0;
        return next_phrase(g, ph);
    }

    return rd->ph;
}

int gest_return(gest_d *g, int ntimes)
{
    gest_phrase *ph;
    struct return_d *rd;

    if (g->saved == NULL) return 1;

    gest_begin(g, 0, 0);
    gest_end(g);

    rd = gest_alloc(g, sizeof(struct return_d));
    ph = g->phrase_selected;

    rd->ph = g->saved;
    rd->pos = 0;
    rd->ntimes = ntimes;

    ph->ud = rd;
    ph->get = goback;

    return 0;
}

6.13. Skewquad

Applies quadratic temporal skewing to the currently selected phrase. The variable dir controls the direction. When dir is 0, it does an easing inwards, otherwise it goes outwards.

<<funcdefs>>=
int gest_skewquad(gest_d *g, int dir);

Quadratic skewing works by computing the difference between the current quadratic scaled position x0, and the next one x1.

<<funcs>>=
static SKFLT skewquad_in(SKFLT t, SKFLT inc)
{
    SKFLT x0, x1;

    x0 = t*t;
    t += inc;
    x1 = t*t;

    return x1 - x0;
}

static SKFLT skewquad_out(SKFLT t, SKFLT inc)
{
    SKFLT x0, x1;

    x0 = 1 - (1 - t) * (1 - t);
    t += inc;
    x1 = 1 - (1 - t) * (1 - t);

    return x1 - x0;
}

int gest_skewquad(gest_d *g, int dir)
{
    if (g->phrase_selected == NULL) return 1;

    if (dir == 0) {
        g->phrase_selected->skew = skewquad_in;
    } else {
        g->phrase_selected->skew = skewquad_out;
    }
    return 0;
}

6.14. Skewexp

Exponential skew. Similar to skewquad, only with an exponential curve. The two are very similar in behavior, except that this doesn't get as dramatically slower at the end, and is more suitable for exploring Risset rhythms.

<<funcdefs>>=
int gest_skewexp(gest_d *g, int dir);
<<funcs>>=
static SKFLT skewexp_in(SKFLT t, SKFLT inc)
{
    SKFLT x0, x1;
    SKFLT s;

    s = 1.0 / (1 - exp(1));

    x0 = (1 - exp(t)) * s;
    t += inc;
    x1 = (1 - exp(t)) * s;

    return x1 - x0;
}

static SKFLT skewexp_out(SKFLT t, SKFLT inc)
{
    SKFLT x0, x1;
    SKFLT s;

    s = 1.0 / (1 - exp(-1));

    x0 = (1 - exp(-t)) * s;
    t += inc;
    x1 = (1 - exp(-t)) * s;

    return x1 - x0;
}

int gest_skewexp(gest_d *g, int dir)
{
    if (g->phrase_selected == NULL) return 1;

    if (dir == 0) {
        g->phrase_selected->skew = skewexp_in;
    } else {
        g->phrase_selected->skew = skewexp_out;
    }
    return 0;
}

6.15. Skewshuf

Skews timing of a phrase so that it has "shuffle", or swung 16th notes. This will assume the phrase is 4 beats long.

<<funcdefs>>=
int gest_skewshuf(gest_d *g);

The algorithm for this works by taking the current signal and dividing it into 16 steps 0 through 15. Even steps will double the increment value. Odd steps will halve it.

<<funcs>>=
static SKFLT skewshuf(SKFLT t, SKFLT inc)
{
    int pos;

    if (t >= 1.0) return t;

    pos = floor(t * 16);
    pos %= 16;

    if ((pos % 2) == 0) {
       inc *= (2.0 / 3.0);
    } else {
       inc *= (4.0 / 3.0);
    }

    return inc;
}

int gest_skewshuf(gest_d *g)
{
    if (g->phrase_selected == NULL) return 1;

    g->phrase_selected->skew = skewshuf;
    return 0;
}

6.16. Ramp

Configures current target to return the value of the ramp tree rater than the interpolated targets.

<<funcdefs>>=
int gest_ramp(gest_d *g);
<<funcs>>=
static SKFLT mix_ramp(gest_d *g, SKFLT x, SKFLT y, SKFLT a)
{
    return a;
}

int gest_ramp(gest_d *g)
{
    gest_target *t;

    t = g->curtarget;

    if (t == NULL) return 1;

    gest_target_mix(t, mix_ramp);

    return 0;
}

6.17. Invramp

Configures current target to return the inverse value (1 - ramp) of the ramp.

<<funcdefs>>=
int gest_invramp(gest_d *g);
<<funcs>>=
static SKFLT mix_invramp(gest_d *g, SKFLT x, SKFLT y, SKFLT a)
{
    return 1 - a;
}

int gest_invramp(gest_d *g)
{
    gest_target *t;

    t = g->curtarget;

    if (t == NULL) return 1;

    gest_target_mix(t, mix_invramp);

    return 0;
}



prev | home | next