Add step size option to CC messages, bugfixes.

master
Albert Graef 2018-08-10 20:43:05 +02:00
parent 53c139a1b8
commit b7afc6bd51
3 changed files with 61 additions and 28 deletions

View File

@ -69,7 +69,7 @@ send_key(KeySym key, int press)
} }
// cached controller and pitch bend values // cached controller and pitch bend values
static int8_t ccvalue[16][128]; static int16_t ccvalue[16][128];
static int16_t pbvalue[16] = static int16_t pbvalue[16] =
{8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, {8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
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 { } else {
// increment (dir==1) or decrement (dir==-1) the current value, // increment (dir==1) or decrement (dir==-1) the current value,
// clamping it to the 0..127 data byte range // clamping it to the 0..127 data byte range
if (!step) return;
dir *= step;
if (dir > 0) { if (dir > 0) {
if (ccvalue[chan][data] >= 127) return; 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 { } else {
if (ccvalue[chan][data] == 0) return; 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) { } else if (!index) {
msg[2] = 127; msg[2] = 127;
@ -198,25 +203,35 @@ send_strokes(translation *tr, int status, int chan, int data,
case 0x90: case 0x90:
sprintf(name, "%s%d-%d", note_names[data % 12], data / 12, chan+1); sprintf(name, "%s%d-%d", note_names[data % 12], data / 12, chan+1);
break; break;
case 0xb0: case 0xb0: {
int step = tr->cc_step[chan][data][dir>0];
if (!dir) if (!dir)
suffix = ""; suffix = "";
else if (tr->is_incr[chan][data]) else if (tr->is_incr[chan][data])
suffix = (dir<0)?"<":">"; suffix = (dir<0)?"<":">";
else else
suffix = (dir<0)?"-":"+"; 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; break;
}
case 0xc0: case 0xc0:
sprintf(name, "PC%d-%d", data, chan+1); sprintf(name, "PC%d-%d", data, chan+1);
break; break;
case 0xe0: case 0xe0: {
int step = tr->pb_step[chan][dir>0];
if (!dir) if (!dir)
suffix = ""; suffix = "";
else else
suffix = (dir<0)?"-":"+"; 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; break;
}
default: // this can't happen default: // this can't happen
break; break;
} }
@ -436,9 +451,15 @@ handle_event(uint8_t *msg)
} }
} else if (inccvalue[chan][msg[1]] != msg[2]) { } else if (inccvalue[chan][msg[1]] != msg[2]) {
int dir = inccvalue[chan][msg[1]] > msg[2] ? -1 : 1; int dir = inccvalue[chan][msg[1]] > msg[2] ? -1 : 1;
while (inccvalue[chan][msg[1]] != msg[2]) { int step = tr->cc_step[chan][msg[1]][dir>0];
send_strokes(tr, status, chan, msg[1], 0, dir); if (step) {
inccvalue[chan][msg[1]] += dir; 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; break;
@ -458,7 +479,7 @@ handle_event(uint8_t *msg)
} }
if (check_pbs(tr, chan) && inpbvalue[chan] - 8192 != bend) { if (check_pbs(tr, chan) && inpbvalue[chan] - 8192 != bend) {
int dir = inpbvalue[chan] - 8192 > bend ? -1 : 1; 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) { if (step) {
while (inpbvalue[chan] - 8192 != bend) { while (inpbvalue[chan] - 8192 != bend) {
int d = abs(inpbvalue[chan] - 8192 - bend); int d = abs(inpbvalue[chan] - 8192 - bend);

View File

@ -78,7 +78,9 @@ typedef struct _translation {
stroke *ccs[NUM_CHAN][NUM_KEYS][2]; stroke *ccs[NUM_CHAN][NUM_KEYS][2];
stroke *pb[NUM_CHAN][2]; stroke *pb[NUM_CHAN][2];
stroke *pbs[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; } translation;
extern int read_config_file(void); extern int read_config_file(void);

View File

@ -489,13 +489,19 @@ print_stroke(stroke *s)
printf("%s%d-%d ", note_names[s->data % 12], s->data / 12, channel); printf("%s%d-%d ", note_names[s->data % 12], s->data / 12, channel);
break; break;
case 0xb0: 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; break;
case 0xc0: case 0xc0:
printf("PC%d-%d ", s->data, channel); printf("PC%d-%d ", s->data, channel);
break; break;
case 0xe0: case 0xe0:
printf("PB-%d ", channel); if (s->step != 1)
printf("PB[%d]-%d ", s->step, channel);
else
printf("PB-%d ", channel);
break; break;
default: // this can't happen default: // this can't happen
break; break;
@ -645,21 +651,23 @@ re_press_temp_modifiers(void)
/* Parser for the MIDI message syntax. The syntax we actually parse here is: /* 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" ] note ::= ( "a" | ... | "g" ) [ "#" | "b" ]
msg ::= "ch" | "pb" [ "[" number "]" ] | "pc" | "cc" msg ::= "ch" | "pb" | "pc" | "cc"
incr ::= "-" | "+" | "=" | "<" | ">" | "~" incr ::= "-" | "+" | "=" | "<" | ">" | "~"
Numbers are always in decimal. The meaning of the first number depends on 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 the context (octave number for notes, the actual data byte for other
messages). If present, the suffix with the second number (after the dash) messages). This can optionally be followed by a number in brackets,
denotes the MIDI channel, otherwise the default MIDI channel is used. 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 Note that not all combinations are possible -- "pb" has no data byte; only
may be followed by a step size in brackets; and "ch" must *not* occur as "cc" and "pb" may be followed by a step size in brackets; and "ch" must
the first token and is followed by just a channel number. (In fact, "ch" is *not* occur as the first token and is followed by just a channel number.
no real MIDI message at all; it just sets the default MIDI channel for (In fact, "ch" is no real MIDI message at all; it just sets the default
subsequent messages in the output sequence.) MIDI channel for subsequent messages in the output sequence.)
The incr flag indicates an "incremental" controller or pitch bend value The incr flag indicates an "incremental" controller or pitch bend value
which responds to up ("+") and down ("-") changes; it is only permitted in 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; char *p = tok, *t;
int n, m = -1, k = midi_channel, l; int n, m = -1, k = midi_channel, l;
s[0] = 0; 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 if (p == tok || p-tok > 10) return 0; // no valid token
// the token by itself // the token by itself
strncpy(s, tok, p-tok); s[p-tok] = 0; 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")) { } else if (strcmp(s, "pb")) {
return 0; return 0;
} }
// step size ('pb' only) // step size ('cc' and 'pb' only)
if (*p == '[') { 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) { if (sscanf(++p, "%d%n", &l, &n) == 1) {
p += n; p += n;
if (*p != ']') return 0; if (*p != ']') return 0;
@ -726,7 +734,7 @@ parse_midi(char *tok, char *s, int lhs,
} else { } else {
return 0; return 0;
} }
} else if (strcmp(s, "pb") == 0) { } else {
*step = 1; *step = 1;
} }
if (p[0] == '-' && isdigit(p[1])) { if (p[0] == '-' && isdigit(p[1])) {
@ -845,6 +853,7 @@ start_translation(translation *tr, char *which_key)
// cc (step up, down) // cc (step up, down)
tr->is_incr[chan][data] = incr>1; tr->is_incr[chan][data] = incr>1;
first_stroke = &(tr->ccs[chan][data][dir>0]); first_stroke = &(tr->ccs[chan][data][dir>0]);
tr->cc_step[chan][data][dir>0] = step;
if (!dir) { if (!dir) {
// This is a bidirectional translation (=, ~). We first fill in the // This is a bidirectional translation (=, ~). We first fill in the
// "down" part (pointed to by first_stroke). When finishing off 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. // so that we can fill in that part later.
is_bidirectional = 1; is_bidirectional = 1;
release_first_stroke = &(tr->ccs[chan][data][1]); release_first_stroke = &(tr->ccs[chan][data][1]);
tr->cc_step[chan][data][1] = step;
} }
} }
break; break;
@ -871,7 +881,7 @@ start_translation(translation *tr, char *which_key)
return 1; return 1;
} }
first_stroke = &(tr->pbs[chan][dir>0]); first_stroke = &(tr->pbs[chan][dir>0]);
tr->step[chan][dir>0] = step; tr->pb_step[chan][dir>0] = step;
if (!dir) { if (!dir) {
is_bidirectional = 1; is_bidirectional = 1;
release_first_stroke = &(tr->pbs[chan][1]); release_first_stroke = &(tr->pbs[chan][1]);