Add support for recursive translations (experimental).
parent
0d5a542146
commit
5241d9a0c9
136
midizap.c
136
midizap.c
|
@ -92,11 +92,15 @@ static int datavals(int val, int step, int *steps, int n_steps)
|
|||
return val;
|
||||
}
|
||||
|
||||
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,
|
||||
int mod, int mod_step, int mod_n_steps, int *mod_steps, int val)
|
||||
int mod, int mod_step, int mod_n_steps, int *mod_steps, int val,
|
||||
int recursive, int depth)
|
||||
{
|
||||
if (!jack_num_outputs) return; // MIDI output not enabled
|
||||
uint8_t msg[3];
|
||||
|
@ -271,7 +275,10 @@ send_midi(uint8_t portno, int status, int data,
|
|||
default:
|
||||
return;
|
||||
}
|
||||
queue_midi(&seq, msg, portno);
|
||||
if (!recursive)
|
||||
queue_midi(&seq, msg, portno);
|
||||
else
|
||||
handle_event(msg, portno, depth+1, recursive);
|
||||
}
|
||||
|
||||
static int stroke_data_cmp(const void *a, const void *b)
|
||||
|
@ -705,9 +712,12 @@ static void end_debug()
|
|||
debug_state = 0;
|
||||
}
|
||||
|
||||
// maximum recursion depth
|
||||
#define MAX_DEPTH 10
|
||||
|
||||
void
|
||||
send_strokes(translation *tr, uint8_t portno, int status, int chan,
|
||||
int data, int data2, int index, int dir)
|
||||
int data, int data2, int index, int dir, int depth)
|
||||
{
|
||||
int nkeys = 0, step = 0, n_steps = 0, *steps = 0, is_incr = 0, mod = 0;
|
||||
stroke *s = fetch_stroke(tr, portno, status, chan, data, index, dir,
|
||||
|
@ -769,9 +779,18 @@ send_strokes(translation *tr, uint8_t portno, int status, int chan,
|
|||
// toggle shift status
|
||||
shift = !shift;
|
||||
} 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);
|
||||
if (s->recursive && depth >= MAX_DEPTH) {
|
||||
char name[100];
|
||||
if (tr && tr->name)
|
||||
fprintf(stderr, "Error: [%s]$%s: recursion too deep\n",
|
||||
tr->name, debug_key(tr, name, status, chan, data, dir));
|
||||
else
|
||||
fprintf(stderr, "Error: $%s: recursion too deep\n",
|
||||
debug_key(tr, name, status, chan, data, dir));
|
||||
} 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->recursive, depth);
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
|
@ -1204,8 +1223,20 @@ get_pb_mod(translation *tr, uint8_t portno, int chan)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
check_recursive(int status, int chan, int data, int recursive)
|
||||
{
|
||||
// only mod translations can be used in recursive calls
|
||||
if (recursive) {
|
||||
char name[100];
|
||||
fprintf(stderr, "Warning: $%s: undefined\n",
|
||||
debug_key(0, name, status, chan, data, 0));
|
||||
}
|
||||
return recursive;
|
||||
}
|
||||
|
||||
void
|
||||
handle_event(uint8_t *msg, uint8_t portno)
|
||||
handle_event(uint8_t *msg, uint8_t portno, int depth, int recursive)
|
||||
{
|
||||
translation *tr = get_focused_window_translation();
|
||||
|
||||
|
@ -1221,22 +1252,27 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
switch (status) {
|
||||
case 0xc0:
|
||||
start_debug();
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, 0);
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 1, 0);
|
||||
if (check_recursive(status, chan, msg[1], recursive)) break;
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, 0, depth);
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 1, 0, depth);
|
||||
end_debug();
|
||||
break;
|
||||
case 0xb0:
|
||||
start_debug();
|
||||
if (get_cc_mod(tr, portno, chan, msg[1]))
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0);
|
||||
else if (msg[2]) {
|
||||
if (get_cc_mod(tr, portno, chan, msg[1])) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0, depth);
|
||||
end_debug();
|
||||
break;
|
||||
}
|
||||
if (check_recursive(status, chan, msg[1], recursive)) break;
|
||||
if (msg[2]) {
|
||||
if (!keydown_tracker || !inccdown[portno][chan][msg[1]]) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0);
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0, depth);
|
||||
inccdown[portno][chan][msg[1]] = 1;
|
||||
}
|
||||
} else {
|
||||
if (!keydown_tracker || inccdown[portno][chan][msg[1]]) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 1, 0);
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 1, 0, depth);
|
||||
inccdown[portno][chan][msg[1]] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1258,7 +1294,7 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
if (step) {
|
||||
int d = msg[2]/step;
|
||||
while (d) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, 1);
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, 1, depth);
|
||||
d--;
|
||||
}
|
||||
}
|
||||
|
@ -1267,7 +1303,7 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
if (step) {
|
||||
int d = (msg[2]-64)/step;
|
||||
while (d) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, -1);
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, -1, depth);
|
||||
d--;
|
||||
}
|
||||
}
|
||||
|
@ -1281,7 +1317,7 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
int d = abs(inccvalue[portno][chan][msg[1]] - msg[2]);
|
||||
if (d > step) d = step;
|
||||
if (d < step) break;
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, dir);
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, dir, depth);
|
||||
inccvalue[portno][chan][msg[1]] += dir*d;
|
||||
}
|
||||
}
|
||||
|
@ -1290,16 +1326,20 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
break;
|
||||
case 0x90:
|
||||
start_debug();
|
||||
if (get_note_mod(tr, portno, chan, msg[1]))
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0);
|
||||
else if (msg[2]) {
|
||||
if (get_note_mod(tr, portno, chan, msg[1])) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0, depth);
|
||||
end_debug();
|
||||
break;
|
||||
}
|
||||
if (check_recursive(status, chan, msg[1], recursive)) break;
|
||||
if (msg[2]) {
|
||||
if (!keydown_tracker || !innotedown[portno][chan][msg[1]]) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0);
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0, depth);
|
||||
innotedown[portno][chan][msg[1]] = 1;
|
||||
}
|
||||
} else {
|
||||
if (!keydown_tracker || innotedown[portno][chan][msg[1]]) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 1, 0);
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 1, 0, depth);
|
||||
innotedown[portno][chan][msg[1]] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1313,7 +1353,7 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
int d = abs(innotevalue[portno][chan][msg[1]] - msg[2]);
|
||||
if (d > step) d = step;
|
||||
if (d < step) break;
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, dir);
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, dir, depth);
|
||||
innotevalue[portno][chan][msg[1]] += dir*d;
|
||||
}
|
||||
}
|
||||
|
@ -1322,16 +1362,20 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
break;
|
||||
case 0xa0:
|
||||
start_debug();
|
||||
if (get_kp_mod(tr, portno, chan, msg[1]))
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0);
|
||||
else if (msg[2]) {
|
||||
if (get_kp_mod(tr, portno, chan, msg[1])) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0, depth);
|
||||
end_debug();
|
||||
break;
|
||||
}
|
||||
if (check_recursive(status, chan, msg[1], recursive)) break;
|
||||
if (msg[2]) {
|
||||
if (!keydown_tracker || !inkpdown[portno][chan][msg[1]]) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0);
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0, depth);
|
||||
inkpdown[portno][chan][msg[1]] = 1;
|
||||
}
|
||||
} else {
|
||||
if (!keydown_tracker || inkpdown[portno][chan][msg[1]]) {
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 1, 0);
|
||||
send_strokes(tr, portno, status, chan, msg[1], msg[2], 1, 0, depth);
|
||||
inkpdown[portno][chan][msg[1]] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1345,7 +1389,7 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
int d = abs(inkpvalue[portno][chan][msg[1]] - msg[2]);
|
||||
if (d > step) d = step;
|
||||
if (d < step) break;
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, dir);
|
||||
send_strokes(tr, portno, status, chan, msg[1], 0, 0, dir, depth);
|
||||
inkpvalue[portno][chan][msg[1]] += dir*d;
|
||||
}
|
||||
}
|
||||
|
@ -1354,16 +1398,20 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
break;
|
||||
case 0xd0:
|
||||
start_debug();
|
||||
if (get_cp_mod(tr, portno, chan))
|
||||
send_strokes(tr, portno, status, chan, 0, msg[1], 0, 0);
|
||||
else if (msg[1]) {
|
||||
if (get_cp_mod(tr, portno, chan)) {
|
||||
send_strokes(tr, portno, status, chan, 0, msg[1], 0, 0, depth);
|
||||
end_debug();
|
||||
break;
|
||||
}
|
||||
if (check_recursive(status, chan, msg[1], recursive)) break;
|
||||
if (msg[1]) {
|
||||
if (!keydown_tracker || !incpdown[portno][chan]) {
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 0, 0);
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 0, 0, depth);
|
||||
incpdown[portno][chan] = 1;
|
||||
}
|
||||
} else {
|
||||
if (!keydown_tracker || incpdown[portno][chan]) {
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 1, 0);
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 1, 0, depth);
|
||||
incpdown[portno][chan] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1377,7 +1425,7 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
int d = abs(incpvalue[portno][chan] - msg[1]);
|
||||
if (d > step) d = step;
|
||||
if (d < step) break;
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 0, dir);
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 0, dir, depth);
|
||||
incpvalue[portno][chan] += dir*d;
|
||||
}
|
||||
}
|
||||
|
@ -1388,16 +1436,20 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
int bend = ((msg[2] << 7) | msg[1]) - 8192;
|
||||
start_debug();
|
||||
//fprintf(stderr, "pb %d\n", bend);
|
||||
if (get_pb_mod(tr, portno, chan))
|
||||
send_strokes(tr, portno, status, chan, 0, bend, 0, 0);
|
||||
else if (bend) {
|
||||
if (get_pb_mod(tr, portno, chan)) {
|
||||
send_strokes(tr, portno, status, chan, 0, bend, 0, 0, depth);
|
||||
end_debug();
|
||||
break;
|
||||
}
|
||||
if (check_recursive(status, chan, msg[1], recursive)) break;
|
||||
if (bend) {
|
||||
if (!keydown_tracker || !inpbdown[portno][chan]) {
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 0, 0);
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 0, 0, depth);
|
||||
inpbdown[portno][chan] = 1;
|
||||
}
|
||||
} else {
|
||||
if (!keydown_tracker || inpbdown[portno][chan]) {
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 1, 0);
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 1, 0, depth);
|
||||
inpbdown[portno][chan] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1410,7 +1462,7 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
int d = abs(inpbvalue[portno][chan] - 8192 - bend);
|
||||
if (d > step) d = step;
|
||||
if (d < step) break;
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 0, dir);
|
||||
send_strokes(tr, portno, status, chan, 0, 0, 0, dir, depth);
|
||||
inpbvalue[portno][chan] += dir*d;
|
||||
}
|
||||
}
|
||||
|
@ -1626,7 +1678,7 @@ main(int argc, char **argv)
|
|||
exit(0);
|
||||
}
|
||||
while (pop_midi(&seq, msg, &portno)) {
|
||||
handle_event(msg, portno);
|
||||
handle_event(msg, portno, 0, 0);
|
||||
time_t t = time(0);
|
||||
if (t > t0) {
|
||||
// Check whether to reload the config file every sec.
|
||||
|
|
|
@ -59,6 +59,9 @@ typedef struct _stroke {
|
|||
// the incremental bit indicates an incremental control change (typically
|
||||
// used with endless rotary encoders) to be represented as a sign bit value
|
||||
uint8_t incr;
|
||||
// the recursive bit indicates a MIDI message which is to be translated
|
||||
// recursively
|
||||
uint8_t recursive;
|
||||
// the dirty bit indicates a MIDI event for which a release event still
|
||||
// needs to be generated in key events
|
||||
uint8_t dirty;
|
||||
|
|
20
readconfig.c
20
readconfig.c
|
@ -629,6 +629,7 @@ 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;
|
||||
if (s->recursive) printf("$");
|
||||
switch (status) {
|
||||
case 0x90:
|
||||
if (mod) {
|
||||
|
@ -792,7 +793,8 @@ append_shift(void)
|
|||
}
|
||||
|
||||
void
|
||||
append_midi(int status, int data, int step, int n_steps, int *steps, int incr)
|
||||
append_midi(int status, int data, int step, int n_steps, int *steps, int incr,
|
||||
int recursive)
|
||||
{
|
||||
stroke *s = (stroke *)allocate(sizeof(stroke));
|
||||
|
||||
|
@ -806,6 +808,7 @@ append_midi(int status, int data, int step, int n_steps, int *steps, int incr)
|
|||
s->n_steps = n_steps;
|
||||
s->steps = stepsdup(n_steps, steps);
|
||||
s->incr = incr;
|
||||
s->recursive = recursive;
|
||||
// if this is a keystroke event, for all messages but program change (which
|
||||
// has no "on" and "off" states), mark the event as "dirty" so that the
|
||||
// corresponding "off" event gets added later to the "release" strokes
|
||||
|
@ -1494,7 +1497,7 @@ add_release(int all_keys)
|
|||
stroke *s = *press_first_stroke;
|
||||
while (s) {
|
||||
if (!s->keysym && !s->shift && s->dirty) {
|
||||
append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr);
|
||||
append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr, s->recursive);
|
||||
s->dirty = 0;
|
||||
}
|
||||
s = s->next;
|
||||
|
@ -1516,7 +1519,7 @@ add_release(int all_keys)
|
|||
} else if (s->shift) {
|
||||
append_shift();
|
||||
} else {
|
||||
append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr);
|
||||
append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr, s->recursive);
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
|
@ -1531,7 +1534,7 @@ add_release(int all_keys)
|
|||
} else if (s->shift) {
|
||||
append_shift();
|
||||
} else {
|
||||
append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr);
|
||||
append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr, s->recursive);
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
|
@ -1544,7 +1547,7 @@ add_release(int all_keys)
|
|||
} else if (s->shift) {
|
||||
append_shift();
|
||||
} else {
|
||||
append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr);
|
||||
append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr, s->recursive);
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
|
@ -1584,15 +1587,18 @@ void
|
|||
add_midi(char *tok)
|
||||
{
|
||||
int status, data, step, n_steps, *steps, incr, dir = 0, mod = 0;
|
||||
int recursive = *tok == '$';
|
||||
char buf[100];
|
||||
if (parse_midi(tok, buf, 0, mode, &status, &data, &step, &n_steps, &steps, &incr, &dir, &mod)) {
|
||||
if (parse_midi(tok+recursive, buf, 0, mode, &status, &data, &step, &n_steps, &steps, &incr, &dir, &mod)) {
|
||||
if (status == 0) {
|
||||
// 'ch' token; this doesn't actually generate any output, it just sets
|
||||
// the default MIDI channel
|
||||
midi_channel = data;
|
||||
if (recursive)
|
||||
fprintf(stderr, "recursion not permitted: %s\n", tok);
|
||||
} else {
|
||||
if ((status & 0xf0) != 0xe0 || step != 0)
|
||||
append_midi(status, data, step, n_steps, steps, incr!=0);
|
||||
append_midi(status, data, step, n_steps, steps, incr!=0, recursive);
|
||||
else
|
||||
fprintf(stderr, "zero step size not permitted: %s\n", tok);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue