More MIDI-related fixes and cosmetic changes.
parent
d0f27891ee
commit
e4d90cad02
72
midizap.c
72
midizap.c
|
@ -75,7 +75,7 @@ static int16_t pbvalue[16] =
|
|||
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192};
|
||||
|
||||
void
|
||||
send_midi(int status, int data, int index, int incr)
|
||||
send_midi(int status, int data, int index, int incr, int step)
|
||||
{
|
||||
if (!enable_jack_output) return; // MIDI output not enabled
|
||||
uint8_t msg[3];
|
||||
|
@ -112,13 +112,15 @@ send_midi(int status, int data, int index, int incr)
|
|||
// range (0..16383, with 8192 being the center value)
|
||||
int pbval = 0;
|
||||
if (incr) {
|
||||
if (!step) return;
|
||||
incr *= step;
|
||||
if (incr > 0) {
|
||||
if (pbvalue[chan] >= 16383) return;
|
||||
pbvalue[chan] += 1170;
|
||||
pbvalue[chan] += incr;
|
||||
if (pbvalue[chan] > 16383) pbvalue[chan] = 16383;
|
||||
} else {
|
||||
if (pbvalue[chan] == 0) return;
|
||||
pbvalue[chan] -= 1170;
|
||||
pbvalue[chan] += incr;
|
||||
if (pbvalue[chan] < 0) pbvalue[chan] = 0;
|
||||
}
|
||||
pbval = pbvalue[chan];
|
||||
|
@ -218,7 +220,7 @@ send_strokes(translation *tr, int status, int chan, int data, int index, int inc
|
|||
send_key(s->keysym, s->press);
|
||||
nkeys++;
|
||||
} else {
|
||||
send_midi(s->status, s->data, index, incr);
|
||||
send_midi(s->status, s->data, index, incr, s->step);
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
|
@ -336,6 +338,7 @@ static int16_t inpbvalue[16] =
|
|||
{8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
|
||||
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192};
|
||||
|
||||
static uint8_t notedown[16][128];
|
||||
static uint8_t inccdown[16][128];
|
||||
static uint8_t inpbdown[16];
|
||||
|
||||
|
@ -380,10 +383,17 @@ handle_event(uint8_t *msg)
|
|||
send_strokes(tr, status, chan, msg[1], 1, 0);
|
||||
break;
|
||||
case 0x90:
|
||||
if (msg[2])
|
||||
send_strokes(tr, status, chan, msg[1], 0, 0);
|
||||
else
|
||||
send_strokes(tr, status, chan, msg[1], 1, 0);
|
||||
if (msg[2]) {
|
||||
if (!notedown[chan][msg[1]]) {
|
||||
send_strokes(tr, status, chan, msg[1], 0, 0);
|
||||
notedown[chan][msg[1]] = 1;
|
||||
}
|
||||
} else {
|
||||
if (notedown[chan][msg[1]]) {
|
||||
send_strokes(tr, status, chan, msg[1], 1, 0);
|
||||
notedown[chan][msg[1]] = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xb0:
|
||||
if (msg[2]) {
|
||||
|
@ -398,12 +408,24 @@ handle_event(uint8_t *msg)
|
|||
}
|
||||
}
|
||||
if (check_incr(tr, chan, msg[1])) {
|
||||
// incremental controller a la MCU XXXTODO: maybe we should handle
|
||||
// speed of control changes here?
|
||||
// Incremental controller a la MCU. NB: This assumed a signed bit
|
||||
// representation (values above 0x40 indicate counter-clockwise
|
||||
// rotation), which seems to be what most DAWs expect nowadays.
|
||||
// But some DAWs may also have it the other way round, so that you may
|
||||
// have to swap the actions for increment and decrement. XXXTODO:
|
||||
// Maybe the encoding should be a configurable parameter?
|
||||
if (msg[2] < 64) {
|
||||
send_strokes(tr, status, chan, msg[1], 0, 1);
|
||||
int d = msg[2];
|
||||
while (d) {
|
||||
send_strokes(tr, status, chan, msg[1], 0, 1);
|
||||
d--;
|
||||
}
|
||||
} else if (msg[2] > 64) {
|
||||
send_strokes(tr, status, chan, msg[1], 0, -1);
|
||||
int d = msg[2]-64;
|
||||
while (d) {
|
||||
send_strokes(tr, status, chan, msg[1], 0, -1);
|
||||
d--;
|
||||
}
|
||||
}
|
||||
} else if (inccvalue[chan][msg[1]] != msg[2]) {
|
||||
int incr = inccvalue[chan][msg[1]] > msg[2] ? -1 : 1;
|
||||
|
@ -429,13 +451,15 @@ handle_event(uint8_t *msg)
|
|||
}
|
||||
if (check_pbs(tr, chan) && inpbvalue[chan] - 8192 != bend) {
|
||||
int incr = inpbvalue[chan] - 8192 > bend ? -1 : 1;
|
||||
while (inpbvalue[chan] - 8192 != bend) {
|
||||
int d = abs(inpbvalue[chan] - 8192 - bend);
|
||||
// scaled to ca. 7 steps in either direction, like on output
|
||||
if (d > 1170) d = 1170;
|
||||
if (d < 1170) break;
|
||||
send_strokes(tr, status, chan, 0, 0, incr);
|
||||
inpbvalue[chan] += incr*d;
|
||||
int step = tr->step[chan][incr>0];
|
||||
if (step) {
|
||||
while (inpbvalue[chan] - 8192 != bend) {
|
||||
int d = abs(inpbvalue[chan] - 8192 - bend);
|
||||
if (d > step) d = step;
|
||||
if (d < step) break;
|
||||
send_strokes(tr, status, chan, 0, 0, incr);
|
||||
inpbvalue[chan] += incr*d;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -449,10 +473,10 @@ handle_event(uint8_t *msg)
|
|||
|
||||
void help(char *progname)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-h] [-j] [-r rcfile] [-d[rsk]]\n", progname);
|
||||
fprintf(stderr, "Usage: %s [-h] [-t] [-r rcfile] [-d[rskj]]\n", progname);
|
||||
fprintf(stderr, "-h print this message\n");
|
||||
fprintf(stderr, "-j enable Jack MIDI output\n");
|
||||
fprintf(stderr, "-r config file name (default: SHUTTLE_CONFIG_FILE variable or ~/.shuttlerc)\n");
|
||||
fprintf(stderr, "-t enable MIDI output\n");
|
||||
fprintf(stderr, "-r config file name (default: MIDIZAP_CONFIG_FILE variable or ~/.midizaprc)\n");
|
||||
fprintf(stderr, "-d debug (r = regex, s = strokes, k = keys, j = jack; default: all)\n");
|
||||
}
|
||||
|
||||
|
@ -469,12 +493,12 @@ main(int argc, char **argv)
|
|||
uint8_t msg[3];
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "hjd::r:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "htd::r:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
help(argv[0]);
|
||||
exit(0);
|
||||
case 'j':
|
||||
case 't':
|
||||
enable_jack_output = 1;
|
||||
break;
|
||||
case 'd':
|
||||
|
|
|
@ -49,6 +49,7 @@ typedef struct _stroke {
|
|||
int press; // zero -> release, non-zero -> press
|
||||
// keysym == 0 => MIDI event
|
||||
int status, data; // status and, if applicable, first data byte
|
||||
int step; // step size for pitch bends (1 by default)
|
||||
// the dirty bit indicates a MIDI event for which a release event still
|
||||
// needs to be generated in key events
|
||||
int dirty;
|
||||
|
@ -70,6 +71,7 @@ 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)
|
||||
} translation;
|
||||
|
||||
extern translation *get_translation(char *win_title, char *win_class);
|
||||
|
|
60
readconfig.c
60
readconfig.c
|
@ -556,7 +556,7 @@ append_stroke(KeySym sym, int press)
|
|||
s->next = NULL;
|
||||
s->keysym = sym;
|
||||
s->press = press;
|
||||
s->status = s->data = s->dirty = 0;
|
||||
s->status = s->data = s->step = s->dirty = 0;
|
||||
if (*first_stroke) {
|
||||
last_stroke->next = s;
|
||||
} else {
|
||||
|
@ -566,7 +566,7 @@ append_stroke(KeySym sym, int press)
|
|||
}
|
||||
|
||||
void
|
||||
append_midi(int status, int data)
|
||||
append_midi(int status, int data, int step)
|
||||
{
|
||||
stroke *s = (stroke *)allocate(sizeof(stroke));
|
||||
|
||||
|
@ -575,6 +575,7 @@ append_midi(int status, int data)
|
|||
s->press = 0;
|
||||
s->status = status;
|
||||
s->data = data;
|
||||
s->step = step;
|
||||
// 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
|
||||
|
@ -660,7 +661,7 @@ re_press_temp_modifiers(void)
|
|||
|
||||
tok ::= ( note | msg ) [number] [ "-" number] [incr]
|
||||
note ::= ( "a" | ... | "g" ) [ "#" | "b" ]
|
||||
msg ::= "ch" | "pb" | "pc" | "cc"
|
||||
msg ::= "ch" | "pb" [ "[" number "]" ] | "pc" | "cc"
|
||||
incr ::= "-" | "+" | "<" | ">"
|
||||
|
||||
Numbers are always in decimal. The meaning of the first number depends on
|
||||
|
@ -668,11 +669,12 @@ re_press_temp_modifiers(void)
|
|||
messages). If present, the suffix with the second number (after the dash)
|
||||
denotes the MIDI channel, otherwise the default MIDI channel is used. Note
|
||||
that not all combinations are possible -- "pb" is *not* followed by a data
|
||||
byte, and "ch" may *not* have a channel number suffix on it. (In fact, "ch"
|
||||
is no real MIDI message at all; it just sets the default MIDI channel for
|
||||
subsequent messages.) The incr flag is only permitted in the first token of
|
||||
a translation, and only in conjunction with "pb" or "cc", whereas "ch" must
|
||||
*not* occur as the first token. */
|
||||
byte, but may be followed by a step size in brackets; and "ch" may *not*
|
||||
have a channel number suffix on it. (In fact, "ch" is no real MIDI message
|
||||
at all; it just sets the default MIDI channel for subsequent messages.) The
|
||||
incr flag is only permitted in the first token of a translation, and only
|
||||
in conjunction with "pb" or "cc", whereas "ch" must *not* occur as the
|
||||
first token. */
|
||||
|
||||
static int note_number(char c, char b, int k)
|
||||
{
|
||||
|
@ -688,12 +690,12 @@ static int note_number(char c, char b, int k)
|
|||
}
|
||||
|
||||
int
|
||||
parse_midi(char *tok, char *s, int *incr, int *status, int *data)
|
||||
parse_midi(char *tok, char *s, int *incr, int *step, int *status, int *data)
|
||||
{
|
||||
char *p = tok, *t;
|
||||
int n, m = -1, k = midi_channel;
|
||||
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;
|
||||
|
@ -706,6 +708,20 @@ parse_midi(char *tok, char *s, int *incr, int *status, int *data)
|
|||
} else if (strcmp(s, "pb")) {
|
||||
return 0;
|
||||
}
|
||||
// step size ('pb' only)
|
||||
if (*p == '[') {
|
||||
if (strcmp(s, "pb")) return 0;
|
||||
if (sscanf(++p, "%d%n", &l, &n) == 1) {
|
||||
p += n;
|
||||
if (*p != ']') return 0;
|
||||
p++;
|
||||
*step = l;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (strcmp(s, "pb") == 0) {
|
||||
*step = 1;
|
||||
}
|
||||
if (p[0] == '-' && isdigit(p[1])) {
|
||||
// suffix with MIDI channel (not permitted with 'ch')
|
||||
if (strcmp(s, "ch") == 0) return 0;
|
||||
|
@ -764,7 +780,7 @@ parse_midi(char *tok, char *s, int *incr, int *status, int *data)
|
|||
int
|
||||
start_translation(translation *tr, char *which_key)
|
||||
{
|
||||
int status, data, incr;
|
||||
int status, data, incr, step;
|
||||
char buf[100];
|
||||
|
||||
//printf("start_translation(%s)\n", which_key);
|
||||
|
@ -780,7 +796,7 @@ start_translation(translation *tr, char *which_key)
|
|||
regular_key_down = 0;
|
||||
modifier_count = 0;
|
||||
midi_channel = 0;
|
||||
if (parse_midi(which_key, buf, &incr, &status, &data)) {
|
||||
if (parse_midi(which_key, buf, &incr, &step, &status, &data)) {
|
||||
int chan = status & 0x0f;
|
||||
switch (status & 0xf0) {
|
||||
case 0x90:
|
||||
|
@ -819,13 +835,18 @@ start_translation(translation *tr, char *which_key)
|
|||
is_keystroke = 1;
|
||||
} else {
|
||||
// pb (step up, down)
|
||||
if (step <= 0) {
|
||||
fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key);
|
||||
return 1;
|
||||
}
|
||||
first_stroke = &(tr->pbs[chan][incr]);
|
||||
tr->step[chan][incr] = step;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// this can't happen
|
||||
fprintf(stderr, "bad message name: [%s]%s\n", current_translation, which_key);
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "bad message name: [%s]%s\n", current_translation, which_key);
|
||||
|
@ -884,7 +905,7 @@ add_release(int all_keys)
|
|||
stroke *s = *press_first_stroke;
|
||||
while (s) {
|
||||
if (!s->keysym && s->dirty) {
|
||||
append_midi(s->status, s->data);
|
||||
append_midi(s->status, s->data, s->step);
|
||||
s->dirty = 0;
|
||||
}
|
||||
s = s->next;
|
||||
|
@ -929,15 +950,18 @@ add_string(char *str)
|
|||
void
|
||||
add_midi(char *tok)
|
||||
{
|
||||
int status, data;
|
||||
int status, data, step = 0;
|
||||
char buf[100];
|
||||
if (parse_midi(tok, buf, NULL, &status, &data)) {
|
||||
if (parse_midi(tok, buf, NULL, &step, &status, &data)) {
|
||||
if (status == 0) {
|
||||
// 'ch' token; this doesn't actually generate any output, it just sets
|
||||
// the default MIDI channel
|
||||
midi_channel = data;
|
||||
} else {
|
||||
append_midi(status, data);
|
||||
if ((status & 0xf0) != 0xe0 || step != 0)
|
||||
append_midi(status, data, step);
|
||||
else
|
||||
fprintf(stderr, "zero step size not permitted: %s\n", tok);
|
||||
}
|
||||
} else {
|
||||
// inspect the token that was actually recognized (if any) to give some
|
||||
|
|
Loading…
Reference in New Issue