Add synthetic macro events, change detection, and some refactoring bugfixes.

master
Albert Graef 2018-09-15 23:52:56 +02:00
parent f3efca83a3
commit a81a0f87da
3 changed files with 125 additions and 49 deletions

View File

@ -99,15 +99,14 @@ void
handle_event(uint8_t *msg, uint8_t portno, int depth, int recursive);
void
send_midi(uint8_t portno, int status, int data,
int step, int n_steps, int *steps,
int incr, int index, int dir,
send_midi(uint8_t portno, stroke *s, int index, int dir,
int mod, int mod_step, int mod_n_steps, int *mod_steps,
int val, int swap,
int recursive, int depth,
uint8_t ret_msg[3])
int val, int depth, uint8_t ret_msg[3])
{
if (!jack_num_outputs) return; // MIDI output not enabled
int status = s->status, data = s->data, swap = s->swap,
recursive = s->recursive;
int step = s->step, n_steps = s->n_steps, *steps = s->steps;
if (!recursive && !jack_num_outputs) return; // MIDI output not enabled
uint8_t msg[3];
int chan = status & 0x0f;
msg[0] = status;
@ -135,6 +134,10 @@ send_midi(uint8_t portno, int status, int data,
int v = datavals(r, step, steps, n_steps);
if (d > 127 || d < 0) return;
if (v > 127 || v < 0) return;
if (s->change) {
if (s->change > 1 && s->d == d && s->v == v) return; // unchanged value
s->d = d; s->v = v; s->change = 2; // >1 => initialized
}
msg[1] = d;
msg[2] = v;
} else if (!index) {
@ -145,7 +148,7 @@ send_midi(uint8_t portno, int status, int data,
break;
case 0xb0:
if (dir) {
if (incr) {
if (s->incr) {
// incremental controller, simply spit out a relative sign bit value
if (!step) step = 1;
dir *= step;
@ -169,11 +172,16 @@ send_midi(uint8_t portno, int status, int data,
msg[2] = ccvalue[portno][chan][data];
}
} else if (mod) {
int m = (data>=128)*128;
int q = swap?val%mod:val/mod, r = swap?val/mod:val%mod;
int d = msg[1] + datavals(q, mod_step, mod_steps, mod_n_steps);
int v = datavals(r, step, steps, n_steps);
if (d > 127 || d < 0) return;
if (d-m > 127 || d-m < 0) return;
if (v > 127 || v < 0) return;
if (s->change) {
if (s->change > 1 && s->d == d && s->v == v) return; // unchanged value
s->d = d; s->v = v; s->change = 2; // >1 => initialized
}
msg[1] = d;
msg[2] = v;
} else if (!index) {
@ -204,6 +212,10 @@ send_midi(uint8_t portno, int status, int data,
int v = datavals(r, step, steps, n_steps);
if (d > 127 || d < 0) return;
if (v > 127 || v < 0) return;
if (s->change) {
if (s->change > 1 && s->d == d && s->v == v) return; // unchanged value
s->d = d; s->v = v; s->change = 2; // >1 => initialized
}
msg[1] = d;
msg[2] = v;
} else if (!index) {
@ -231,6 +243,10 @@ send_midi(uint8_t portno, int status, int data,
} else if (mod) {
int v = datavals(swap?val/mod:val%mod, step, steps, n_steps);
if (v > 127 || v < 0) return;
if (s->change) {
if (s->change > 1 && s->v == v) return; // unchanged value
s->v = v; s->change = 2; // >1 => initialized
}
msg[1] = v;
} else if (!index) {
msg[1] = dataval(step, 0, 127);
@ -258,6 +274,10 @@ send_midi(uint8_t portno, int status, int data,
} else if (mod) {
int v = datavals(swap?val/mod:val%mod, step, steps, n_steps);
if (v > 16383 || v < 0) return;
if (s->change) {
if (s->change > 1 && s->v == v) return; // unchanged value
s->v = v; s->change = 2; // >1 => initialized
}
pbval = v;
} else if (!index) {
pbval = 8192+dataval(step, -8192, 8191);
@ -276,6 +296,10 @@ send_midi(uint8_t portno, int status, int data,
if (mod) {
int d = msg[1] + datavals(swap?val%mod:val/mod, mod_step, mod_steps, mod_n_steps);
if (d > 127 || d < 0) return;
if (s->change) {
if (s->change > 1 && s->d == d) return; // unchanged value
s->d = d; s->change = 2; // >1 => initialized
}
msg[1] = d;
}
// just send the message
@ -284,10 +308,17 @@ send_midi(uint8_t portno, int status, int data,
return;
}
if (ret_msg) memcpy(ret_msg, msg, 3);
if (!recursive)
queue_midi(&seq, msg, portno);
else
if (recursive) {
// As these values may be mutated, we need to save and restore them, in
// case a macro calls itself recursively.
uint8_t change = s->change;
int d = s->d, v = s->v;
s->change = change>0;
handle_event(msg, portno, depth+1, recursive);
s->change = change;
s->d = d; s->v = v;
} else
queue_midi(&seq, msg, portno);
}
static int stroke_data_cmp(const void *a, const void *b)
@ -615,21 +646,24 @@ static char *debug_key(translation *tr, char *name,
suffix = (dir<0)?"-":"+";
else
suffix = "";
// check for pseudo CC messages denoting a macro
char *tok = data>=128?"M":"CC";
data %= 128;
if (dir && step != 1)
sprintf(name, "%sCC%d[%d]-%d%s", prefix, data, step, chan+1, suffix);
sprintf(name, "%s%s%d[%d]-%d%s", prefix, tok, data, step, chan+1, suffix);
else if (!dir && mod)
if (step != 1)
sprintf(name, "%sCC%d[%d][%d]-%d%s", prefix, data, mod, step, chan+1, suffix);
sprintf(name, "%s%s%d[%d][%d]-%d%s", prefix, tok, data, mod, step, chan+1, suffix);
else if (n_steps) {
sprintf(name, "%sCC%d[%d]{", prefix, data, mod);
sprintf(name, "%s%s%d[%d]{", prefix, tok, data, mod);
int l = strlen(name);
for (int i = 0; i < n_steps; i++, (l = strlen(name)))
sprintf(name+l, "%s%d", i?",":"", steps[i]);
sprintf(name+l, "}-%d%s", chan+1, suffix);
} else
sprintf(name, "%sCC%d[%d]-%d%s", prefix, data, mod, chan+1, suffix);
sprintf(name, "%s%s%d[%d]-%d%s", prefix, tok, data, mod, chan+1, suffix);
else
sprintf(name, "%sCC%d-%d%s", prefix, data, chan+1, suffix);
sprintf(name, "%s%s%d-%d%s", prefix, tok, data, chan+1, suffix);
break;
}
case 0xc0:
@ -841,22 +875,18 @@ send_strokes(translation *tr, uint8_t portno, int status, int chan,
if (!s->recursive && jack_num_outputs > 1) {
if (s->feedback == 1)
// direct feedback, simply flip the port number
send_midi(!portno,
s->status, s->data, s->step, s->n_steps, s->steps,
s->incr, index, dir, mod,
step, n_steps, steps, data2, s->swap, 0, depth, 0);
send_midi(!portno, s, index, dir, mod,
step, n_steps, steps, data2, depth, 0);
else if (portno == 0 && !mod && !dir)
// shift feedback, this only works with key translations right
// now, and portno *must* be zero
send_midi(1, s->status, s->data, s->step, s->n_steps, s->steps,
s->incr, !shift, 0, 0,
step, n_steps, steps, data2, s->swap, 0, depth,
send_midi(1, s, !shift, 0, 0,
step, n_steps, steps, data2, depth,
shift?shift_fb[shift-1]:0);
}
} else {
send_midi(portno, s->status, s->data, s->step, s->n_steps, s->steps,
s->incr, index, dir, mod,
step, n_steps, steps, data2, s->swap, s->recursive, depth, 0);
send_midi(portno, s, index, dir, mod,
step, n_steps, steps, data2, depth, 0);
}
}
s = s->next;

View File

@ -62,6 +62,11 @@ typedef struct _stroke {
// the swap bit indicates that 1st and 2nd data byte are to be swapped in
// mod translations
uint8_t swap;
// the change bit indicates that the message should only be output if its
// value has changed since the last time
uint8_t change;
// cached values for the change bit
int d, v;
// the recursive bit indicates a MIDI message which is to be translated
// recursively
uint8_t recursive;
@ -83,7 +88,7 @@ typedef struct _stroke_data {
// incr flag (CC only)
uint8_t is_incr;
// modulus
uint8_t mod;
uint16_t mod;
// anyshift flag (default rule)
uint8_t anyshift;
} stroke_data;

View File

@ -678,7 +678,10 @@ print_stroke(stroke *s, int mod, int step, int n_steps, int *steps, int val)
} else {
int status = s->status & 0xf0;
int channel = (s->status & 0x0f) + 1;
char *suffix = s->swap?"'":s->incr?"~":"";
char suffix[3] = "";
if (s->incr) strcpy(suffix, "~");
if (s->swap) strcat(suffix, "'");
if (s->change) strcat(suffix, "?");
if (s->recursive) printf("$");
if (s->feedback) printf(s->feedback==2?"^":"!");
switch (status) {
@ -722,22 +725,27 @@ print_stroke(stroke *s, int mod, int step, int n_steps, int *steps, int val)
printf("KP:%s%d-%d%s ", note_name(s->data),
note_octave(s->data), channel, suffix);
break;
case 0xb0:
case 0xb0: {
// check for pseudo CC messages denoting a macro
int data = s->data;
char *tok = data>=128?"M":"CC";
data %= 128;
if (mod) {
int q = s->swap?val%mod:val/mod, r = s->swap?val/mod:val%mod;
int d = s->data + datavals(q, step, steps, n_steps);
int d = data + datavals(q, step, steps, n_steps);
int v = datavals(r, s->step, s->steps, s->n_steps);
printf("CC%d[%d]-%d%s ", d, v, channel, suffix);
printf("%s%d[%d]-%d%s ", tok, d, v, channel, suffix);
} else if (s->steps) {
printf("CC%d{", s->data);
printf("%s%d{", tok, data);
for (int i = 0; i < s->n_steps; i++)
printf("%s%d", i?",":"", s->steps[i]);
printf("}-%d%s ", channel, suffix);
} else if (s->step)
printf("CC%d[%d]-%d%s ", s->data, s->step, channel, suffix);
printf("%s%d[%d]-%d%s ", tok, data, s->step, channel, suffix);
else
printf("CC%d-%d%s ", s->data, channel, suffix);
printf("%s%d-%d%s ", tok, data, channel, suffix);
break;
}
case 0xc0:
if (mod) {
int v = datavals(s->swap?val%mod:val/mod, s->step, s->steps, s->n_steps);
@ -861,7 +869,7 @@ append_nop(void)
void
append_midi(int status, int data, int step, int n_steps, int *steps,
int swap, int incr, int recursive, int feedback)
int swap, int change, int incr, int recursive, int feedback)
{
stroke *s = (stroke *)allocate(sizeof(stroke));
@ -869,6 +877,7 @@ append_midi(int status, int data, int step, int n_steps, int *steps,
s->status = status;
s->data = data;
s->swap = swap;
s->change = change;
s->step = step;
s->n_steps = n_steps;
s->steps = stepsdup(n_steps, steps);
@ -1020,7 +1029,7 @@ static int note_number(char c, char b, int k)
}
}
#define MAXSTEPS 8193
#define MAXSTEPS 16384
static char *parse_steps(char *tok, char *p,
int *step, int *n_steps, int **steps)
@ -1100,9 +1109,9 @@ static char *parse_steps(char *tok, char *p,
}
int
parse_midi(char *tok, char *s, int lhs, int mode,
parse_midi(char *tok, char *s, int lhs, int mode, int recursive,
int *status, int *data, int *step, int *n_steps, int **steps,
int *incr, int *dir, int *mod, int *swap)
int *incr, int *dir, int *mod, int *swap, int *change)
{
char *p = tok, *t;
int n, m = -1, k = midi_channel;
@ -1192,12 +1201,27 @@ parse_midi(char *tok, char *s, int lhs, int mode,
return 0;
}
}
*incr = *dir = *swap = 0;
*incr = *dir = *swap = *change = 0;
if (*p == '\'') {
// swap flag (only on rhs in mod translations)
if (lhs || mode < 2) return 0;
*swap = 1;
p++;
if (*p == '?') {
// change flag
*change = 1;
p++;
}
} else if (*p == '?') {
// change flag (only on rhs in mod translations)
if (lhs || mode < 2) return 0;
*change = 1;
p++;
if (*p == '\'') {
// swap flag
*swap = 1;
p++;
}
} else if (*p && strchr("+-=<>~", *p)) {
// incremental flag (messages with data only, not "ch" or "pc")
if (strcmp(s, "ch") == 0) return 0;
@ -1229,7 +1253,7 @@ parse_midi(char *tok, char *s, int lhs, int mode,
if (strcmp(s, "ch") == 0) {
if (lhs) return 0; // not permitted on lhs
if (*step || *n_steps) return 0; // not permitted
if (*swap || steps2 || n_steps2) return 0; // not permitted
if (*swap || *change || steps2 || n_steps2) return 0; // not permitted
// we return a bogus status of 0 here, along with the MIDI channel
// in the data byte; also check that the MIDI channel is in the
// proper range
@ -1280,6 +1304,22 @@ parse_midi(char *tok, char *s, int lhs, int mode,
if (lhs && *incr && *step < 0) return 0; // not permitted
if (lhs && !*step) *step = 1; // default
return 1;
} else if (strcmp(s, "m") == 0) {
// macro, encoded as a pseudo cc message which cannot actually occur on
// input; this is only permitted in macro calls or on the lhs of a mod
// translation
if (m < 0 || m > 127) return 0;
*status = 0xb0 | k; *data = m+128;
// step size on lhs indicates modulus if non-incremental
if (lhs && *step && !*incr) {
*mod = *step; *step = step2;
*n_steps = n_steps2; *steps = steps2;
if (*mod < 0) *mod = 128;
} else if (lhs || !recursive)
return 0; // not permitted
if (lhs && *incr && *step < 0) return 0; // not permitted
if (lhs && !*step) *step = 1; // default
return 1;
} else if (strcmp(s, "kp") == 0) {
// key pressure
if (m < 0 || m > 127) return 0;
@ -1345,7 +1385,7 @@ static void dup_stroke_data(stroke_data **sd, uint16_t *n, uint16_t *a,
} else {
append_midi(s->status, s->data,
s->step, s->n_steps, s->steps,
s->swap, s->incr, s->recursive, s->feedback);
s->swap, s->change, s->incr, s->recursive, s->feedback);
}
s = s->next;
}
@ -1358,7 +1398,8 @@ static void dup_stroke_data(stroke_data **sd, uint16_t *n, uint16_t *a,
int
start_translation(translation *tr, char *which_key)
{
int status, data, step, n_steps, *steps, incr, dir, mod, swap, anyshift;
int status, data, step, n_steps, *steps, incr, dir, mod, swap, change,
anyshift;
char buf[100];
//printf("start_translation(%s)\n", which_key);
@ -1386,7 +1427,7 @@ start_translation(translation *tr, char *which_key)
} else {
anyshift = 1;
}
if (parse_midi(which_key+offs, buf, 1, 0, &status, &data, &step, &n_steps, &steps, &incr, &dir, &mod, &swap)) {
if (parse_midi(which_key+offs, buf, 1, 0, 0, &status, &data, &step, &n_steps, &steps, &incr, &dir, &mod, &swap, &change)) {
int chan = status & 0x0f;
mode = incr?0:mod?2:1;
switch (status & 0xf0) {
@ -1615,7 +1656,7 @@ add_release(int all_keys)
if (!s->keysym && !s->shift && s->dirty) {
append_midi(s->status, s->data,
s->step, s->n_steps, s->steps,
s->swap, s->incr, s->recursive, s->feedback);
s->swap, s->change, s->incr, s->recursive, s->feedback);
s->dirty = 0;
}
s = s->next;
@ -1640,7 +1681,7 @@ add_release(int all_keys)
} else {
append_midi(s->status, s->data,
s->step, s->n_steps, s->steps,
s->swap, s->incr, s->recursive, s->feedback);
s->swap, s->change, s->incr, s->recursive, s->feedback);
}
s = s->next;
}
@ -1678,14 +1719,14 @@ add_string(char *str)
void
add_midi(char *tok)
{
int status, data, step, n_steps, *steps, incr, dir = 0, mod = 0, swap = 0;
int status, data, step, n_steps, *steps, incr, dir = 0, mod = 0, swap = 0, change = 0;
int recursive = *tok == '$', fb = *tok == '!', fb2 = *tok == '^';
char buf[100];
if (fb2 && mode != 1) {
fprintf(stderr, "shift feedback only allowed in key translations: %s\n", tok);
return;
}
if (parse_midi(tok+recursive+fb+fb2, buf, 0, mode, &status, &data, &step, &n_steps, &steps, &incr, &dir, &mod, &swap)) {
if (parse_midi(tok+recursive+fb+fb2, buf, 0, mode, recursive, &status, &data, &step, &n_steps, &steps, &incr, &dir, &mod, &swap, &change)) {
if (status == 0) {
// 'ch' token; this doesn't actually generate any output, it just sets
// the default MIDI channel
@ -1694,7 +1735,7 @@ add_midi(char *tok)
fprintf(stderr, "invalid macro call: %s\n", tok);
} else {
append_midi(status, data, step, n_steps, steps,
swap, incr!=0, recursive, fb2?2:fb);
swap, change, incr!=0, recursive, fb2?2:fb);
}
} else {
// inspect the token that was actually recognized (if any) to give some