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.
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.
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.
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.
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
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.
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.
int gest_addmetaphrase(gest_d *g, int sz);
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.
int gest_randtarget(gest_d *g);
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.
int gest_randbehavior(gest_d *g);
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.
int gest_randnode(gest_d *g);
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.
int gest_randphrase(gest_d *g);
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
.
int gest_setscalar(gest_d *g, gest_scalar *s, SKFLT val);
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
.
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.
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
.
int gest_mark(gest_d *g);
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.
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.
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.
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
.
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.
int gest_skewexp(gest_d *g, int dir);
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.
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.
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.
int gest_ramp(gest_d *g);
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.
int gest_invramp(gest_d *g);
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