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
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);

View File

@ -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);

View File

@ -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]);