From b7afc6bd51fc54ab12b3f9121b13fa3fca1831ae Mon Sep 17 00:00:00 2001 From: Albert Graef Date: Fri, 10 Aug 2018 20:43:05 +0200 Subject: [PATCH] Add step size option to CC messages, bugfixes. --- midizap.c | 43 ++++++++++++++++++++++++++++++++----------- midizap.h | 4 +++- readconfig.c | 42 ++++++++++++++++++++++++++---------------- 3 files changed, 61 insertions(+), 28 deletions(-) diff --git a/midizap.c b/midizap.c index 1afdb9b..d078eb7 100644 --- a/midizap.c +++ b/midizap.c @@ -69,7 +69,7 @@ send_key(KeySym key, int press) } // cached controller and pitch bend values -static int8_t ccvalue[16][128]; +static int16_t ccvalue[16][128]; static int16_t pbvalue[16] = {8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192}; @@ -98,13 +98,18 @@ send_midi(int status, int data, int step, int incr, int index, int dir) } else { // increment (dir==1) or decrement (dir==-1) the current value, // clamping it to the 0..127 data byte range + if (!step) return; + dir *= step; if (dir > 0) { if (ccvalue[chan][data] >= 127) return; - msg[2] = ++ccvalue[chan][data]; + ccvalue[chan][data] += dir; + if (ccvalue[chan][data] > 127) ccvalue[chan][data] = 127; } else { if (ccvalue[chan][data] == 0) return; - msg[2] = --ccvalue[chan][data]; + ccvalue[chan][data] += dir; + if (ccvalue[chan][data] < 0) ccvalue[chan][data] = 0; } + msg[2] = ccvalue[chan][data]; } } else if (!index) { msg[2] = 127; @@ -198,25 +203,35 @@ send_strokes(translation *tr, int status, int chan, int data, case 0x90: sprintf(name, "%s%d-%d", note_names[data % 12], data / 12, chan+1); break; - case 0xb0: + case 0xb0: { + int step = tr->cc_step[chan][data][dir>0]; if (!dir) suffix = ""; else if (tr->is_incr[chan][data]) suffix = (dir<0)?"<":">"; else suffix = (dir<0)?"-":"+"; - sprintf(name, "CC%d-%d%s", data, chan+1, suffix); + if (dir && step != 1) + sprintf(name, "CC%d[%d]-%d%s", data, step, chan+1, suffix); + else + sprintf(name, "CC%d-%d%s", data, chan+1, suffix); break; + } case 0xc0: sprintf(name, "PC%d-%d", data, chan+1); break; - case 0xe0: + case 0xe0: { + int step = tr->pb_step[chan][dir>0]; if (!dir) suffix = ""; else suffix = (dir<0)?"-":"+"; - sprintf(name, "PB-%d%s", chan+1, suffix); + if (dir && step != 1) + sprintf(name, "PB[%d]-%d%s", step, chan+1, suffix); + else + sprintf(name, "PB-%d%s", chan+1, suffix); break; + } default: // this can't happen break; } @@ -436,9 +451,15 @@ handle_event(uint8_t *msg) } } else if (inccvalue[chan][msg[1]] != msg[2]) { int dir = inccvalue[chan][msg[1]] > msg[2] ? -1 : 1; - while (inccvalue[chan][msg[1]] != msg[2]) { - send_strokes(tr, status, chan, msg[1], 0, dir); - inccvalue[chan][msg[1]] += dir; + int step = tr->cc_step[chan][msg[1]][dir>0]; + if (step) { + while (inccvalue[chan][msg[1]] != msg[2]) { + int d = abs(inccvalue[chan][msg[1]] - msg[2]); + if (d > step) d = step; + if (d < step) break; + send_strokes(tr, status, chan, msg[1], 0, dir); + inccvalue[chan][msg[1]] += dir*d; + } } } break; @@ -458,7 +479,7 @@ handle_event(uint8_t *msg) } if (check_pbs(tr, chan) && inpbvalue[chan] - 8192 != bend) { int dir = inpbvalue[chan] - 8192 > bend ? -1 : 1; - int step = tr->step[chan][dir>0]; + int step = tr->pb_step[chan][dir>0]; if (step) { while (inpbvalue[chan] - 8192 != bend) { int d = abs(inpbvalue[chan] - 8192 - bend); diff --git a/midizap.h b/midizap.h index 253f531..91549aa 100644 --- a/midizap.h +++ b/midizap.h @@ -78,7 +78,9 @@ typedef struct _translation { stroke *ccs[NUM_CHAN][NUM_KEYS][2]; stroke *pb[NUM_CHAN][2]; stroke *pbs[NUM_CHAN][2]; - int step[NUM_CHAN][2]; // step size for pitch bends (1 by default) + // step size for control changes and pitch bend (1 by default) + int cc_step[NUM_CHAN][NUM_KEYS][2]; + int pb_step[NUM_CHAN][2]; } translation; extern int read_config_file(void); diff --git a/readconfig.c b/readconfig.c index dbefe94..fc82547 100644 --- a/readconfig.c +++ b/readconfig.c @@ -489,13 +489,19 @@ print_stroke(stroke *s) printf("%s%d-%d ", note_names[s->data % 12], s->data / 12, channel); break; case 0xb0: - printf("CC%d-%d%s ", s->data, channel, s->incr?"~":""); + if (s->step != 1) + printf("CC%d[%d]-%d%s ", s->data, s->step, channel, s->incr?"~":""); + else + printf("CC%d-%d%s ", s->data, channel, s->incr?"~":""); break; case 0xc0: printf("PC%d-%d ", s->data, channel); break; case 0xe0: - printf("PB-%d ", channel); + if (s->step != 1) + printf("PB[%d]-%d ", s->step, channel); + else + printf("PB-%d ", channel); break; default: // this can't happen break; @@ -645,21 +651,23 @@ re_press_temp_modifiers(void) /* Parser for the MIDI message syntax. The syntax we actually parse here is: - tok ::= ( note | msg ) [ number ] [ "-" number] [ incr ] + tok ::= ( note | msg ) [ number ] [ "[" number "]" ] [ "-" number] [ incr ] note ::= ( "a" | ... | "g" ) [ "#" | "b" ] - msg ::= "ch" | "pb" [ "[" number "]" ] | "pc" | "cc" + msg ::= "ch" | "pb" | "pc" | "cc" incr ::= "-" | "+" | "=" | "<" | ">" | "~" Numbers are always in decimal. The meaning of the first number depends on the context (octave number for notes, the actual data byte for other - messages). If present, the suffix with the second number (after the dash) - denotes the MIDI channel, otherwise the default MIDI channel is used. + messages). This can optionally be followed by a number in brackets, + denoting a step size. Also optionally, the suffix with the third number + (after the dash) denotes the MIDI channel; otherwise the default MIDI + channel is used. - Note that not all combinations are possible -- "pb" has no data byte, but - may be followed by a step size in brackets; and "ch" must *not* occur as - the first token and is followed by just a channel number. (In fact, "ch" is - no real MIDI message at all; it just sets the default MIDI channel for - subsequent messages in the output sequence.) + Note that not all combinations are possible -- "pb" has no data byte; only + "cc" and "pb" may be followed by a step size in brackets; and "ch" must + *not* occur as the first token and is followed by just a channel number. + (In fact, "ch" is no real MIDI message at all; it just sets the default + MIDI channel for subsequent messages in the output sequence.) The incr flag indicates an "incremental" controller or pitch bend value which responds to up ("+") and down ("-") changes; it is only permitted in @@ -702,7 +710,7 @@ parse_midi(char *tok, char *s, int lhs, char *p = tok, *t; int n, m = -1, k = midi_channel, l; s[0] = 0; - while (*p && !isdigit(*p) && !strchr("+-<>[", *p)) p++; + while (*p && !isdigit(*p) && !strchr("+-=<>~[", *p)) p++; if (p == tok || p-tok > 10) return 0; // no valid token // the token by itself strncpy(s, tok, p-tok); s[p-tok] = 0; @@ -715,9 +723,9 @@ parse_midi(char *tok, char *s, int lhs, } else if (strcmp(s, "pb")) { return 0; } - // step size ('pb' only) + // step size ('cc' and 'pb' only) if (*p == '[') { - if (strcmp(s, "pb")) return 0; + if (strcmp(s, "cc") && strcmp(s, "pb")) return 0; if (sscanf(++p, "%d%n", &l, &n) == 1) { p += n; if (*p != ']') return 0; @@ -726,7 +734,7 @@ parse_midi(char *tok, char *s, int lhs, } else { return 0; } - } else if (strcmp(s, "pb") == 0) { + } else { *step = 1; } if (p[0] == '-' && isdigit(p[1])) { @@ -845,6 +853,7 @@ start_translation(translation *tr, char *which_key) // cc (step up, down) tr->is_incr[chan][data] = incr>1; first_stroke = &(tr->ccs[chan][data][dir>0]); + tr->cc_step[chan][data][dir>0] = step; if (!dir) { // This is a bidirectional translation (=, ~). We first fill in the // "down" part (pointed to by first_stroke). When finishing off the @@ -855,6 +864,7 @@ start_translation(translation *tr, char *which_key) // so that we can fill in that part later. is_bidirectional = 1; release_first_stroke = &(tr->ccs[chan][data][1]); + tr->cc_step[chan][data][1] = step; } } break; @@ -871,7 +881,7 @@ start_translation(translation *tr, char *which_key) return 1; } first_stroke = &(tr->pbs[chan][dir>0]); - tr->step[chan][dir>0] = step; + tr->pb_step[chan][dir>0] = step; if (!dir) { is_bidirectional = 1; release_first_stroke = &(tr->pbs[chan][1]);