Special mod translations in key mode (experimental).

master
Albert Graef 2018-08-25 07:55:15 +02:00
parent 40cd0abe66
commit 46d15aa3d2
4 changed files with 710 additions and 206 deletions

View File

@ -173,6 +173,25 @@ A#5 D#7
B5 E7 B5 E7
C6 F7 C6 F7
# meter feedback
# The Mackie protocol packs all 8 channel meters into a single channel
# pressure message which we need to transform into the corresponding
# note messages for the LEDs. Note that we only use the upper 5x8 part
# of the grid here, in order not to clobber the 3 rows at the bottom
# with the rec/solo/mute buttons. This means that the meters, which
# actually have 8 different values, have to be squashed into 5 LEDs per
# channel.
?CP[16] C2[0,1] G#2[0,0,0,1] E3[0,0,0,0,0,5] C4[0,0,0,0,0,0,0,5] G#4[0,0,0,0,0,0,0,0,3]
# Here's an alternative decoding, which creates horizontal meters
# covering the full range, with the first channel on top. Note,
# however, that this ranges across the entire 8x8 grid and will thus
# clobber the rec/solo/mute controls!
#?CP[16][-8] G#4[0,1] A4[0,0,1] A#4[0,0,0,1] B4[0,0,0,0,1] C5[0,0,0,0,0,5] C#5[0,0,0,0,0,0,5] D5[0,0,0,0,0,0,0,5] D#5[0,0,0,0,0,0,0,0,3]
# no feedback for faders (faders aren't motorized) # no feedback for faders (faders aren't motorized)
# NOTE: Feedback for rec/solo/mute/select also needs to be recognized in shift # NOTE: Feedback for rec/solo/mute/select also needs to be recognized in shift

424
midizap.c
View File

@ -77,8 +77,25 @@ static int dataval(int val, int min, int max)
return val; return val;
} }
static int datavals(int val, int step, int *steps, int n_steps)
{
if (val < 0)
return -datavals(-val, step, steps, n_steps);
else if (val < n_steps)
return steps[val];
else if (n_steps)
return steps[n_steps-1];
else if (step)
return step*val;
else
return val;
}
void void
send_midi(uint8_t portno, int status, int data, int step, int incr, int index, int dir) 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)
{ {
if (!jack_num_outputs) return; // MIDI output not enabled if (!jack_num_outputs) return; // MIDI output not enabled
uint8_t msg[3]; uint8_t msg[3];
@ -87,7 +104,14 @@ send_midi(uint8_t portno, int status, int data, int step, int incr, int index, i
msg[1] = data; msg[1] = data;
switch (status & 0xf0) { switch (status & 0xf0) {
case 0x90: case 0x90:
if (!index) { if (mod) {
int d = msg[1] + datavals(val/mod, mod_step, mod_steps, mod_n_steps);
int v = datavals(val%mod, step, steps, n_steps);
if (d > 127 || d < 0) return;
if (v > 127 || v < 0) return;
msg[1] = d;
msg[2] = v;
} else if (!index) {
msg[2] = dataval(step, 0, 127); msg[2] = dataval(step, 0, 127);
} else { } else {
msg[2] = 0; msg[2] = 0;
@ -118,6 +142,13 @@ send_midi(uint8_t portno, int status, int data, int step, int incr, int index, i
} }
msg[2] = ccvalue[chan][data]; msg[2] = ccvalue[chan][data];
} }
} else if (mod) {
int d = msg[1] + datavals(val/mod, mod_step, mod_steps, mod_n_steps);
int v = datavals(val%mod, step, steps, n_steps);
if (d > 127 || d < 0) return;
if (v > 127 || v < 0) return;
msg[1] = d;
msg[2] = v;
} else if (!index) { } else if (!index) {
msg[2] = dataval(step, 0, 127); msg[2] = dataval(step, 0, 127);
} else { } else {
@ -140,6 +171,13 @@ send_midi(uint8_t portno, int status, int data, int step, int incr, int index, i
if (kpvalue[chan][data] < 0) kpvalue[chan][data] = 0; if (kpvalue[chan][data] < 0) kpvalue[chan][data] = 0;
} }
msg[2] = kpvalue[chan][data]; msg[2] = kpvalue[chan][data];
} else if (mod) {
int d = msg[1] + datavals(val/mod, mod_step, mod_steps, mod_n_steps);
int v = datavals(val%mod, step, steps, n_steps);
if (d > 127 || d < 0) return;
if (v > 127 || v < 0) return;
msg[1] = d;
msg[2] = v;
} else if (!index) { } else if (!index) {
msg[2] = dataval(step, 0, 127); msg[2] = dataval(step, 0, 127);
} else { } else {
@ -162,6 +200,10 @@ send_midi(uint8_t portno, int status, int data, int step, int incr, int index, i
if (cpvalue[chan] < 0) cpvalue[chan] = 0; if (cpvalue[chan] < 0) cpvalue[chan] = 0;
} }
msg[1] = cpvalue[chan]; msg[1] = cpvalue[chan];
} else if (mod) {
int v = datavals(val%mod, step, steps, n_steps);
if (v > 127 || v < 0) return;
msg[1] = v;
} else if (!index) { } else if (!index) {
msg[1] = dataval(step, 0, 127); msg[1] = dataval(step, 0, 127);
} else { } else {
@ -185,6 +227,10 @@ send_midi(uint8_t portno, int status, int data, int step, int incr, int index, i
if (pbvalue[chan] < 0) pbvalue[chan] = 0; if (pbvalue[chan] < 0) pbvalue[chan] = 0;
} }
pbval = pbvalue[chan]; pbval = pbvalue[chan];
} else if (mod) {
int v = datavals(val%mod, step, steps, n_steps);
if (v > 8191 || v < -8192) return;
pbval = 8192+v;
} else if (!index) { } else if (!index) {
pbval = 8192+dataval(step, -8192, 8191); pbval = 8192+dataval(step, -8192, 8191);
} else { } else {
@ -219,7 +265,8 @@ static int stroke_data_cmp(const void *a, const void *b)
static stroke *find_stroke_data(stroke_data *sd, static stroke *find_stroke_data(stroke_data *sd,
int chan, int data, int index, int chan, int data, int index,
int *step, int *incr, int *step, int *n_steps, int **steps,
int *incr, int *mod,
uint16_t n) uint16_t n)
{ {
if (n < 16) { if (n < 16) {
@ -230,7 +277,10 @@ static stroke *find_stroke_data(stroke_data *sd,
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (sd[i].chan == chan && sd[i].data == data) { if (sd[i].chan == chan && sd[i].data == data) {
if (step) *step = sd[i].step[index]; if (step) *step = sd[i].step[index];
if (n_steps) *n_steps = sd[i].n_steps[index];
if (steps) *steps = sd[i].steps[index];
if (incr) *incr = sd[i].is_incr; if (incr) *incr = sd[i].is_incr;
if (mod) *mod = sd[i].mod;
return sd[i].s[index]; return sd[i].s[index];
} else if (sd[i].chan > chan || } else if (sd[i].chan > chan ||
(sd[i].chan == chan && sd[i].data > data)) (sd[i].chan == chan && sd[i].data > data))
@ -244,7 +294,10 @@ static stroke *find_stroke_data(stroke_data *sd,
ret = bsearch(&key, sd, n, sizeof(stroke_data), stroke_data_cmp); ret = bsearch(&key, sd, n, sizeof(stroke_data), stroke_data_cmp);
if (ret) { if (ret) {
if (step) *step = ret->step[index]; if (step) *step = ret->step[index];
if (n_steps) *n_steps = ret->n_steps[index];
if (steps) *steps = ret->steps[index];
if (incr) *incr = ret->is_incr; if (incr) *incr = ret->is_incr;
if (mod) *mod = ret->mod;
return ret->s[index]; return ret->s[index];
} else } else
return NULL; return NULL;
@ -252,105 +305,117 @@ static stroke *find_stroke_data(stroke_data *sd,
} }
static stroke *find_note(translation *tr, int shift, static stroke *find_note(translation *tr, int shift,
int chan, int data, int index) int chan, int data, int index, int *mod,
int *step, int *n_steps, int **steps)
{ {
return find_stroke_data(tr->note[shift], chan, data, index, 0, 0, return find_stroke_data(tr->note[shift], chan, data, index,
step, n_steps, steps, 0, mod,
tr->n_note[shift]); tr->n_note[shift]);
} }
static stroke *find_pc(translation *tr, int shift, static stroke *find_pc(translation *tr, int shift,
int chan, int data, int index) int chan, int data, int index)
{ {
return find_stroke_data(tr->pc[shift], chan, data, index, 0, 0, return find_stroke_data(tr->pc[shift], chan, data, index, 0, 0, 0, 0, 0,
tr->n_pc[shift]); tr->n_pc[shift]);
} }
static stroke *find_cc(translation *tr, int shift, static stroke *find_cc(translation *tr, int shift,
int chan, int data, int index) int chan, int data, int index, int *mod,
int *step, int *n_steps, int **steps)
{ {
return find_stroke_data(tr->cc[shift], chan, data, index, 0, 0, return find_stroke_data(tr->cc[shift], chan, data, index,
step, n_steps, steps, 0, mod,
tr->n_cc[shift]); tr->n_cc[shift]);
} }
static stroke *find_ccs(translation *tr, int shift, static stroke *find_ccs(translation *tr, int shift,
int chan, int data, int index, int *step, int *incr) int chan, int data, int index, int *step, int *incr)
{ {
return find_stroke_data(tr->ccs[shift], chan, data, index, step, incr, return find_stroke_data(tr->ccs[shift], chan, data, index, step, 0, 0,
incr, 0,
tr->n_ccs[shift]); tr->n_ccs[shift]);
} }
static stroke *find_kp(translation *tr, int shift, static stroke *find_kp(translation *tr, int shift,
int chan, int data, int index) int chan, int data, int index, int *mod,
int *step, int *n_steps, int **steps)
{ {
return find_stroke_data(tr->kp[shift], chan, data, index, 0, 0, return find_stroke_data(tr->kp[shift], chan, data, index,
step, n_steps, steps, 0, mod,
tr->n_kp[shift]); tr->n_kp[shift]);
} }
static stroke *find_kps(translation *tr, int shift, static stroke *find_kps(translation *tr, int shift,
int chan, int data, int index, int *step) int chan, int data, int index, int *step)
{ {
return find_stroke_data(tr->kps[shift], chan, data, index, step, 0, return find_stroke_data(tr->kps[shift], chan, data, index, step, 0, 0, 0, 0,
tr->n_kps[shift]); tr->n_kps[shift]);
} }
static stroke *find_cp(translation *tr, int shift, static stroke *find_cp(translation *tr, int shift,
int chan, int index) int chan, int index, int *mod,
int *step, int *n_steps, int **steps)
{ {
return find_stroke_data(tr->cp[shift], chan, 0, index, 0, 0, return find_stroke_data(tr->cp[shift], chan, 0, index,
step, n_steps, steps, 0, mod,
tr->n_cp[shift]); tr->n_cp[shift]);
} }
static stroke *find_cps(translation *tr, int shift, static stroke *find_cps(translation *tr, int shift,
int chan, int index, int *step) int chan, int index, int *step)
{ {
return find_stroke_data(tr->cps[shift], chan, 0, index, step, 0, return find_stroke_data(tr->cps[shift], chan, 0, index, step, 0, 0, 0, 0,
tr->n_cps[shift]); tr->n_cps[shift]);
} }
static stroke *find_pb(translation *tr, int shift, static stroke *find_pb(translation *tr, int shift,
int chan, int index) int chan, int index, int *mod,
int *step, int *n_steps, int **steps)
{ {
return find_stroke_data(tr->pb[shift], chan, 0, index, 0, 0, return find_stroke_data(tr->pb[shift], chan, 0, index,
step, n_steps, steps, 0, mod,
tr->n_pb[shift]); tr->n_pb[shift]);
} }
static stroke *find_pbs(translation *tr, int shift, static stroke *find_pbs(translation *tr, int shift,
int chan, int index, int *step) int chan, int index, int *step)
{ {
return find_stroke_data(tr->pbs[shift], chan, 0, index, step, 0, return find_stroke_data(tr->pbs[shift], chan, 0, index, step, 0, 0, 0, 0,
tr->n_pbs[shift]); tr->n_pbs[shift]);
} }
stroke * stroke *
fetch_stroke(translation *tr, uint8_t portno, int status, int chan, int data, fetch_stroke(translation *tr, uint8_t portno, int status, int chan, int data,
int index, int dir, int *step, int *incr) int index, int dir, int *step, int *n_steps, int **steps,
int *incr, int *mod)
{ {
if (tr && tr->portno == portno) { if (tr && tr->portno == portno) {
switch (status) { switch (status) {
case 0x90: case 0x90:
return find_note(tr, shift, chan, data, index); return find_note(tr, shift, chan, data, index, mod, step, n_steps, steps);
case 0xc0: case 0xc0:
return find_pc(tr, shift, chan, data, index); return find_pc(tr, shift, chan, data, index);
case 0xb0: case 0xb0:
if (dir) if (dir)
return find_ccs(tr, shift, chan, data, dir>0, step, incr); return find_ccs(tr, shift, chan, data, dir>0, step, incr);
else else
return find_cc(tr, shift, chan, data, index); return find_cc(tr, shift, chan, data, index, mod, step, n_steps, steps);
case 0xa0: case 0xa0:
if (dir) if (dir)
return find_kps(tr, shift, chan, data, dir>0, step); return find_kps(tr, shift, chan, data, dir>0, step);
else else
return find_kp(tr, shift, chan, data, index); return find_kp(tr, shift, chan, data, index, mod, step, n_steps, steps);
case 0xd0: case 0xd0:
if (dir) if (dir)
return find_cps(tr, shift, chan, dir>0, step); return find_cps(tr, shift, chan, dir>0, step);
else else
return find_cp(tr, shift, chan, index); return find_cp(tr, shift, chan, index, mod, step, n_steps, steps);
case 0xe0: case 0xe0:
if (dir) if (dir)
return find_pbs(tr, shift, chan, dir>0, step); return find_pbs(tr, shift, chan, dir>0, step);
else else
return find_pb(tr, shift, chan, index); return find_pb(tr, shift, chan, index, mod, step, n_steps, steps);
default: default:
return NULL; return NULL;
} }
@ -389,35 +454,95 @@ static void debug_section(translation *tr)
} }
} }
static char *note_name(int n)
{
static char *note_names[] = { "C", "C#", "D", "Eb", "E", "F", "F#", "G", "G#", "A", "Bb", "B" };
if (n < 0 && n%12)
return note_names[12+n%12];
else
return note_names[n%12];
}
static int note_octave(int n)
{
if (n < 0 && n%12)
return n/12-1 + midi_octave;
else
return n/12 + midi_octave;
}
static char *debug_key(translation *tr, char *name, static char *debug_key(translation *tr, char *name,
int status, int chan, int data, int dir) int status, int chan, int data, int dir)
{ {
static char *note_names[] = { "C", "C#", "D", "Eb", "E", "F", "F#", "G", "G#", "A", "Bb", "B" };
char *prefix = shift?"^":"", *suffix = ""; char *prefix = shift?"^":"", *suffix = "";
strcpy(name, "??"); strcpy(name, "??");
switch (status) { switch (status) {
case 0x90: case 0x90: {
sprintf(name, "%s%s%d-%d", prefix, note_names[data % 12], int mod = 0, step, n_steps, *steps;
data / 12 + midi_octave, chan+1); (void)find_note(tr, shift, chan, data, 0, &mod, &step, &n_steps, &steps);
if (mod)
if (step != 1)
sprintf(name, "%s%s%d[%d][%d]-%d", prefix, note_name(data),
note_octave(data), mod, step, chan+1);
else if (n_steps) {
sprintf(name, "%s%s%d[%d][", prefix, note_name(data),
note_octave(data), mod);
int l = strlen(name);
for (int i = 0; i < n_steps; i++, (l = strlen(name)))
sprintf(name+l, "%s%d", i?",":"", steps[i]);
sprintf(name+l, "]-%d", chan);
} else
sprintf(name, "%s%s%d[%d]-%d", prefix, note_name(data),
note_octave(data), mod, chan+1);
else
sprintf(name, "%s%s%d-%d", prefix, note_name(data),
note_octave(data), chan+1);
break; break;
}
case 0xa0: { case 0xa0: {
int step = 1; int step = 0, n_steps = 0, *steps = 0, mod = 0;
if (tr) (void)find_kps(tr, shift, chan, data, dir>0, &step); if (tr) {
if (dir) {
step = 1;
(void)find_kps(tr, shift, chan, data, dir>0, &step);
} else
(void)find_kp(tr, shift, chan, data, 0, &mod, &step, &n_steps, &steps);
}
if (!dir) if (!dir)
suffix = ""; suffix = "";
else else
suffix = (dir<0)?"-":"+"; suffix = (dir<0)?"-":"+";
if (dir && step != 1) if (dir && step != 1)
sprintf(name, "%sKP:%s%d[%d]-%d%s", prefix, note_names[data % 12], sprintf(name, "%sKP:%s%d[%d]-%d%s", prefix, note_name(data),
data / 12 + midi_octave, step, chan+1, suffix); note_octave(data), step, chan+1, suffix);
else if (!dir && mod)
if (step != 1)
sprintf(name, "%sKP:%s%d[%d][%d]-%d", prefix, note_name(data),
note_octave(data), mod, step, chan+1);
else if (n_steps) {
sprintf(name, "%sKP:%s%d[%d][", prefix, note_name(data),
note_octave(data), mod);
int l = strlen(name);
for (int i = 0; i < n_steps; i++, (l = strlen(name)))
sprintf(name+l, "%s%d", i?",":"", steps[i]);
sprintf(name+l, "]-%d", chan);
} else
sprintf(name, "%sKP:%s%d[%d]-%d", prefix, note_name(data),
note_octave(data), mod, chan+1);
else else
sprintf(name, "%sKP:%s%d-%d%s", prefix, note_names[data % 12], sprintf(name, "%sKP:%s%d-%d%s", prefix, note_name(data),
data / 12 + midi_octave, chan+1, suffix); note_octave(data), chan+1, suffix);
break; break;
} }
case 0xb0: { case 0xb0: {
int step = 1, is_incr = 0; int step = 0, n_steps = 0, *steps = 0, mod = 0, is_incr = 0;
if (tr) (void)find_ccs(tr, shift, chan, data, dir>0, &step, &is_incr); if (tr) {
if (dir) {
step = 1;
(void)find_ccs(tr, shift, chan, data, dir>0, &step, &is_incr);
} else
(void)find_cc(tr, shift, chan, data, 0, &mod, &step, &n_steps, &steps);
}
if (!dir) if (!dir)
suffix = ""; suffix = "";
else if (is_incr) else if (is_incr)
@ -426,6 +551,17 @@ static char *debug_key(translation *tr, char *name,
suffix = (dir<0)?"-":"+"; suffix = (dir<0)?"-":"+";
if (dir && step != 1) if (dir && step != 1)
sprintf(name, "%sCC%d[%d]-%d%s", prefix, data, step, chan+1, suffix); sprintf(name, "%sCC%d[%d]-%d%s", prefix, data, step, chan+1, suffix);
else if (!dir && mod)
if (step != 1)
sprintf(name, "%sCC%d[%d][%d]-%d", prefix, data, mod, step, chan+1);
else if (n_steps) {
sprintf(name, "%sCC%d[%d][", prefix, data, mod);
int l = strlen(name);
for (int i = 0; i < n_steps; i++, (l = strlen(name)))
sprintf(name+l, "%s%d", i?",":"", steps[i]);
sprintf(name+l, "]-%d", chan);
} else
sprintf(name, "%sCC%d[%d]-%d", prefix, data, mod, chan+1);
else else
sprintf(name, "%sCC%d-%d%s", prefix, data, chan+1, suffix); sprintf(name, "%sCC%d-%d%s", prefix, data, chan+1, suffix);
break; break;
@ -434,14 +570,31 @@ static char *debug_key(translation *tr, char *name,
sprintf(name, "%sPC%d-%d", prefix, data, chan+1); sprintf(name, "%sPC%d-%d", prefix, data, chan+1);
break; break;
case 0xd0: { case 0xd0: {
int step = 1; int step = 0, n_steps = 0, *steps = 0, mod = 0;
if (tr) (void)find_cps(tr, shift, chan, dir>0, &step); if (tr) {
if (dir) {
step = 1;
(void)find_cps(tr, shift, chan, dir>0, &step);
} else
(void)find_cp(tr, shift, chan, 0, &mod, &step, &n_steps, &steps);
}
if (!dir) if (!dir)
suffix = ""; suffix = "";
else else
suffix = (dir<0)?"-":"+"; suffix = (dir<0)?"-":"+";
if (dir && step != 1) if (dir && step != 1)
sprintf(name, "%sCP[%d]-%d%s", prefix, step, chan+1, suffix); sprintf(name, "%sCP[%d]-%d%s", prefix, step, chan+1, suffix);
else if (!dir && mod)
if (step != 1)
sprintf(name, "%sCP[%d][%d]-%d", prefix, mod, step, chan+1);
else if (n_steps) {
sprintf(name, "%sCP[%d][", prefix, mod);
int l = strlen(name);
for (int i = 0; i < n_steps; i++, (l = strlen(name)))
sprintf(name+l, "%s%d", i?",":"", steps[i]);
sprintf(name+l, "]-%d", chan);
} else
sprintf(name, "%sCP[%d]-%d", prefix, mod, chan+1);
else else
sprintf(name, "%sCP-%d%s", prefix, chan+1, suffix); sprintf(name, "%sCP-%d%s", prefix, chan+1, suffix);
break; break;
@ -509,26 +662,26 @@ static void end_debug()
} }
void void
send_strokes(translation *tr, uint8_t portno, int status, int chan, int data, send_strokes(translation *tr, uint8_t portno, int status, int chan,
int index, int dir) int data, int data2, int index, int dir)
{ {
int nkeys = 0, step = 0, is_incr = 0; 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, stroke *s = fetch_stroke(tr, portno, status, chan, data, index, dir,
&step, &is_incr); &step, &n_steps, &steps, &is_incr, &mod);
// If there's no press/release translation, check whether we have got at // If there's no press/release translation, check whether we have got at
// least the corresponding release/press translation, in order to prevent // least the corresponding release/press translation, in order to prevent
// spurious error messages if either the press or release translation just // spurious error messages if either the press or release translation just
// happens to be empty. // happens to be empty.
int chk = s || int chk = s ||
(!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir, 0, 0)); (!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir, 0, 0, 0, 0, 0));
if (!s && jack_num_outputs) { if (!s && jack_num_outputs) {
// fall back to default MIDI translation // fall back to default MIDI translation
tr = default_midi_translation[portno]; tr = default_midi_translation[portno];
s = fetch_stroke(tr, portno, status, chan, data, index, dir, s = fetch_stroke(tr, portno, status, chan, data, index, dir,
&step, &is_incr); &step, &n_steps, &steps, &is_incr, &mod);
chk = chk || s || chk = chk || s ||
(!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir, 0, 0)); (!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir, 0, 0, 0, 0, 0));
// Ignore all MIDI input on the second port if no translation was found in // Ignore all MIDI input on the second port if no translation was found in
// the [MIDI2] section (or the section is missing altogether). // the [MIDI2] section (or the section is missing altogether).
if (portno && !s) return; if (portno && !s) return;
@ -538,9 +691,9 @@ send_strokes(translation *tr, uint8_t portno, int status, int chan, int data,
// fall back to the default translation // fall back to the default translation
tr = default_translation; tr = default_translation;
s = fetch_stroke(tr, portno, status, chan, data, index, dir, s = fetch_stroke(tr, portno, status, chan, data, index, dir,
&step, &is_incr); &step, &n_steps, &steps, &is_incr, &mod);
chk = chk || s || chk = chk || s ||
(!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir, 0, 0)); (!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir, 0, 0, 0, 0, 0));
} }
if (debug_regex) { if (debug_regex) {
@ -561,7 +714,8 @@ send_strokes(translation *tr, uint8_t portno, int status, int chan, int data,
if (s && debug_keys) { if (s && debug_keys) {
char name[100]; char name[100];
print_stroke_sequence(debug_key(tr, name, status, chan, data, dir), print_stroke_sequence(debug_key(tr, name, status, chan, data, dir),
dir?"":index?"U":"D", s); (dir||mod)?"":index?"U":"D", s,
mod, step, n_steps, steps, data2);
} }
while (s) { while (s) {
if (s->keysym) { if (s->keysym) {
@ -571,7 +725,9 @@ send_strokes(translation *tr, uint8_t portno, int status, int chan, int data,
// toggle shift status // toggle shift status
shift = !shift; shift = !shift;
} else { } else {
send_midi(portno, s->status, s->data, s->step, s->incr, index, dir); 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 = s->next; s = s->next;
} }
@ -702,6 +858,24 @@ static uint8_t inpbdown[2][16];
static uint8_t inkpdown[2][16][128]; static uint8_t inkpdown[2][16][128];
static uint8_t incpdown[2][16]; static uint8_t incpdown[2][16];
int
get_note_mod(translation *tr, uint8_t portno, int chan, int data)
{
int mod;
if (tr && tr->portno == portno &&
find_note(tr, shift, chan, data, 0, &mod, 0, 0, 0))
return mod;
tr = default_midi_translation[portno];
if (tr && tr->portno == portno &&
find_note(tr, shift, chan, data, 0, &mod, 0, 0, 0))
return mod;
tr = default_translation;
if (tr && tr->portno == portno &&
find_note(tr, shift, chan, data, 0, &mod, 0, 0, 0))
return mod;
return 0;
}
int int
check_incr(translation *tr, uint8_t portno, int chan, int data) check_incr(translation *tr, uint8_t portno, int chan, int data)
{ {
@ -761,6 +935,24 @@ get_cc_step(translation *tr, uint8_t portno, int chan, int data, int dir)
return 1; return 1;
} }
int
get_cc_mod(translation *tr, uint8_t portno, int chan, int data)
{
int mod;
if (tr && tr->portno == portno &&
find_cc(tr, shift, chan, data, 0, &mod, 0, 0, 0))
return mod;
tr = default_midi_translation[portno];
if (tr && tr->portno == portno &&
find_cc(tr, shift, chan, data, 0, &mod, 0, 0, 0))
return mod;
tr = default_translation;
if (tr && tr->portno == portno &&
find_cc(tr, shift, chan, data, 0, &mod, 0, 0, 0))
return mod;
return 0;
}
int int
check_kps(translation *tr, uint8_t portno, int chan, int data) check_kps(translation *tr, uint8_t portno, int chan, int data)
{ {
@ -799,6 +991,24 @@ get_kp_step(translation *tr, uint8_t portno, int chan, int data, int dir)
return 1; return 1;
} }
int
get_kp_mod(translation *tr, uint8_t portno, int chan, int data)
{
int mod;
if (tr && tr->portno == portno &&
find_kp(tr, shift, chan, data, 0, &mod, 0, 0, 0))
return mod;
tr = default_midi_translation[portno];
if (tr && tr->portno == portno &&
find_kp(tr, shift, chan, data, 0, &mod, 0, 0, 0))
return mod;
tr = default_translation;
if (tr && tr->portno == portno &&
find_kp(tr, shift, chan, data, 0, &mod, 0, 0, 0))
return mod;
return 0;
}
int int
check_cps(translation *tr, uint8_t portno, int chan) check_cps(translation *tr, uint8_t portno, int chan)
{ {
@ -837,6 +1047,24 @@ get_cp_step(translation *tr, uint8_t portno, int chan, int dir)
return 1; return 1;
} }
int
get_cp_mod(translation *tr, uint8_t portno, int chan)
{
int mod;
if (tr && tr->portno == portno &&
find_cp(tr, shift, chan, 0, &mod, 0, 0, 0))
return mod;
tr = default_midi_translation[portno];
if (tr && tr->portno == portno &&
find_cp(tr, shift, chan, 0, &mod, 0, 0, 0))
return mod;
tr = default_translation;
if (tr && tr->portno == portno &&
find_cp(tr, shift, chan, 0, &mod, 0, 0, 0))
return mod;
return 0;
}
int int
check_pbs(translation *tr, uint8_t portno, int chan) check_pbs(translation *tr, uint8_t portno, int chan)
{ {
@ -875,6 +1103,24 @@ get_pb_step(translation *tr, uint8_t portno, int chan, int dir)
return 1; return 1;
} }
int
get_pb_mod(translation *tr, uint8_t portno, int chan)
{
int mod;
if (tr && tr->portno == portno &&
find_pb(tr, shift, chan, 0, &mod, 0, 0, 0))
return mod;
tr = default_midi_translation[portno];
if (tr && tr->portno == portno &&
find_pb(tr, shift, chan, 0, &mod, 0, 0, 0))
return mod;
tr = default_translation;
if (tr && tr->portno == portno &&
find_pb(tr, shift, chan, 0, &mod, 0, 0, 0))
return mod;
return 0;
}
void void
handle_event(uint8_t *msg, uint8_t portno) handle_event(uint8_t *msg, uint8_t portno)
{ {
@ -892,20 +1138,22 @@ handle_event(uint8_t *msg, uint8_t portno)
switch (status) { switch (status) {
case 0xc0: case 0xc0:
start_debug(); start_debug();
send_strokes(tr, portno, status, chan, msg[1], 0, 0); send_strokes(tr, portno, status, chan, msg[1], 0, 0, 0);
send_strokes(tr, portno, status, chan, msg[1], 1, 0); send_strokes(tr, portno, status, chan, msg[1], 0, 1, 0);
end_debug(); end_debug();
break; break;
case 0x90: case 0x90:
start_debug(); start_debug();
if (msg[2]) { 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 (!keydown_tracker || !notedown[portno][chan][msg[1]]) { if (!keydown_tracker || !notedown[portno][chan][msg[1]]) {
send_strokes(tr, portno, status, chan, msg[1], 0, 0); send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0);
notedown[portno][chan][msg[1]] = 1; notedown[portno][chan][msg[1]] = 1;
} }
} else { } else {
if (!keydown_tracker || notedown[portno][chan][msg[1]]) { if (!keydown_tracker || notedown[portno][chan][msg[1]]) {
send_strokes(tr, portno, status, chan, msg[1], 1, 0); send_strokes(tr, portno, status, chan, msg[1], msg[2], 1, 0);
notedown[portno][chan][msg[1]] = 0; notedown[portno][chan][msg[1]] = 0;
} }
} }
@ -913,14 +1161,16 @@ handle_event(uint8_t *msg, uint8_t portno)
break; break;
case 0xb0: case 0xb0:
start_debug(); start_debug();
if (msg[2]) { 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 (!keydown_tracker || !inccdown[portno][chan][msg[1]]) { if (!keydown_tracker || !inccdown[portno][chan][msg[1]]) {
send_strokes(tr, portno, status, chan, msg[1], 0, 0); send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0);
inccdown[portno][chan][msg[1]] = 1; inccdown[portno][chan][msg[1]] = 1;
} }
} else { } else {
if (!keydown_tracker || inccdown[portno][chan][msg[1]]) { if (!keydown_tracker || inccdown[portno][chan][msg[1]]) {
send_strokes(tr, portno, status, chan, msg[1], 1, 0); send_strokes(tr, portno, status, chan, msg[1], msg[2], 1, 0);
inccdown[portno][chan][msg[1]] = 0; inccdown[portno][chan][msg[1]] = 0;
} }
} }
@ -942,7 +1192,7 @@ handle_event(uint8_t *msg, uint8_t portno)
if (step) { if (step) {
int d = msg[2]/step; int d = msg[2]/step;
while (d) { while (d) {
send_strokes(tr, portno, status, chan, msg[1], 0, 1); send_strokes(tr, portno, status, chan, msg[1], 0, 0, 1);
d--; d--;
} }
} }
@ -951,7 +1201,7 @@ handle_event(uint8_t *msg, uint8_t portno)
if (step) { if (step) {
int d = (msg[2]-64)/step; int d = (msg[2]-64)/step;
while (d) { while (d) {
send_strokes(tr, portno, status, chan, msg[1], 0, -1); send_strokes(tr, portno, status, chan, msg[1], 0, 0, -1);
d--; d--;
} }
} }
@ -965,7 +1215,7 @@ handle_event(uint8_t *msg, uint8_t portno)
int d = abs(inccvalue[portno][chan][msg[1]] - msg[2]); int d = abs(inccvalue[portno][chan][msg[1]] - msg[2]);
if (d > step) d = step; if (d > step) d = step;
if (d < step) break; if (d < step) break;
send_strokes(tr, portno, status, chan, msg[1], 0, dir); send_strokes(tr, portno, status, chan, msg[1], 0, 0, dir);
inccvalue[portno][chan][msg[1]] += dir*d; inccvalue[portno][chan][msg[1]] += dir*d;
} }
} }
@ -974,14 +1224,16 @@ handle_event(uint8_t *msg, uint8_t portno)
break; break;
case 0xa0: case 0xa0:
start_debug(); start_debug();
if (msg[2]) { 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 (!keydown_tracker || !inkpdown[portno][chan][msg[1]]) { if (!keydown_tracker || !inkpdown[portno][chan][msg[1]]) {
send_strokes(tr, portno, status, chan, msg[1], 0, 0); send_strokes(tr, portno, status, chan, msg[1], msg[2], 0, 0);
inkpdown[portno][chan][msg[1]] = 1; inkpdown[portno][chan][msg[1]] = 1;
} }
} else { } else {
if (!keydown_tracker || inkpdown[portno][chan][msg[1]]) { if (!keydown_tracker || inkpdown[portno][chan][msg[1]]) {
send_strokes(tr, portno, status, chan, msg[1], 1, 0); send_strokes(tr, portno, status, chan, msg[1], msg[2], 1, 0);
inkpdown[portno][chan][msg[1]] = 0; inkpdown[portno][chan][msg[1]] = 0;
} }
} }
@ -995,7 +1247,7 @@ handle_event(uint8_t *msg, uint8_t portno)
int d = abs(inkpvalue[portno][chan][msg[1]] - msg[2]); int d = abs(inkpvalue[portno][chan][msg[1]] - msg[2]);
if (d > step) d = step; if (d > step) d = step;
if (d < step) break; if (d < step) break;
send_strokes(tr, portno, status, chan, msg[1], 0, dir); send_strokes(tr, portno, status, chan, msg[1], 0, 0, dir);
inkpvalue[portno][chan][msg[1]] += dir*d; inkpvalue[portno][chan][msg[1]] += dir*d;
} }
} }
@ -1004,14 +1256,16 @@ handle_event(uint8_t *msg, uint8_t portno)
break; break;
case 0xd0: case 0xd0:
start_debug(); start_debug();
if (msg[1]) { if (get_cp_mod(tr, portno, chan))
send_strokes(tr, portno, status, chan, 0, msg[1], 0, 0);
else if (msg[1]) {
if (!keydown_tracker || !incpdown[portno][chan]) { if (!keydown_tracker || !incpdown[portno][chan]) {
send_strokes(tr, portno, status, chan, 0, 0, 0); send_strokes(tr, portno, status, chan, 0, 0, 0, 0);
incpdown[portno][chan] = 1; incpdown[portno][chan] = 1;
} }
} else { } else {
if (!keydown_tracker || incpdown[portno][chan]) { if (!keydown_tracker || incpdown[portno][chan]) {
send_strokes(tr, portno, status, chan, 0, 1, 0); send_strokes(tr, portno, status, chan, 0, 0, 1, 0);
incpdown[portno][chan] = 0; incpdown[portno][chan] = 0;
} }
} }
@ -1025,7 +1279,7 @@ handle_event(uint8_t *msg, uint8_t portno)
int d = abs(incpvalue[portno][chan] - msg[1]); int d = abs(incpvalue[portno][chan] - msg[1]);
if (d > step) d = step; if (d > step) d = step;
if (d < step) break; if (d < step) break;
send_strokes(tr, portno, status, chan, 0, 0, dir); send_strokes(tr, portno, status, chan, 0, 0, 0, dir);
incpvalue[portno][chan] += dir*d; incpvalue[portno][chan] += dir*d;
} }
} }
@ -1036,14 +1290,16 @@ handle_event(uint8_t *msg, uint8_t portno)
int bend = ((msg[2] << 7) | msg[1]) - 8192; int bend = ((msg[2] << 7) | msg[1]) - 8192;
start_debug(); start_debug();
//fprintf(stderr, "pb %d\n", bend); //fprintf(stderr, "pb %d\n", bend);
if (bend) { if (get_pb_mod(tr, portno, chan))
send_strokes(tr, portno, status, chan, 0, bend, 0, 0);
else if (bend) {
if (!keydown_tracker || !inpbdown[portno][chan]) { if (!keydown_tracker || !inpbdown[portno][chan]) {
send_strokes(tr, portno, status, chan, 0, 0, 0); send_strokes(tr, portno, status, chan, 0, 0, 0, 0);
inpbdown[portno][chan] = 1; inpbdown[portno][chan] = 1;
} }
} else { } else {
if (!keydown_tracker || inpbdown[portno][chan]) { if (!keydown_tracker || inpbdown[portno][chan]) {
send_strokes(tr, portno, status, chan, 0, 1, 0); send_strokes(tr, portno, status, chan, 0, 0, 1, 0);
inpbdown[portno][chan] = 0; inpbdown[portno][chan] = 0;
} }
} }
@ -1056,7 +1312,7 @@ handle_event(uint8_t *msg, uint8_t portno)
int d = abs(inpbvalue[portno][chan] - 8192 - bend); int d = abs(inpbvalue[portno][chan] - 8192 - bend);
if (d > step) d = step; if (d > step) d = step;
if (d < step) break; if (d < step) break;
send_strokes(tr, portno, status, chan, 0, 0, dir); send_strokes(tr, portno, status, chan, 0, 0, 0, dir);
inpbvalue[portno][chan] += dir*d; inpbvalue[portno][chan] += dir*d;
} }
} }
@ -1146,11 +1402,13 @@ static char *absolute_path(char *name)
#define CONF_FREQ 1 #define CONF_FREQ 1
#define MAX_COUNT (1000000/CONF_FREQ/POLL_INTERVAL) #define MAX_COUNT (1000000/CONF_FREQ/POLL_INTERVAL)
#include <time.h>
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
uint8_t msg[3]; uint8_t msg[3];
int opt, count = 0; int opt;
// Start recording the command line to be passed to Jack session management. // Start recording the command line to be passed to Jack session management.
add_command(argv[0]); add_command(argv[0]);
@ -1260,6 +1518,7 @@ main(int argc, char **argv)
int do_flush = debug_regex || debug_strokes || debug_keys || debug_midi || int do_flush = debug_regex || debug_strokes || debug_keys || debug_midi ||
debug_jack; debug_jack;
signal(SIGINT, quitter); signal(SIGINT, quitter);
time_t t0 = time(0);
while (!quit) { while (!quit) {
uint8_t portno; uint8_t portno;
if (jack_quit) { if (jack_quit) {
@ -1270,16 +1529,19 @@ main(int argc, char **argv)
} }
while (pop_midi(&seq, msg, &portno)) { while (pop_midi(&seq, msg, &portno)) {
handle_event(msg, portno); handle_event(msg, portno);
count = 0; time_t t = time(0);
if (t > t0) {
// Check whether to reload the config file every sec.
if (read_config_file()) last_focused_window = 0;
t0 = t;
}
} }
usleep(POLL_INTERVAL); usleep(POLL_INTERVAL);
if (++count >= MAX_COUNT) { time_t t = time(0);
// Check whether to reload the config file if we haven't seen any MIDI if (t > t0) {
// input in a while. Note that if the file *is* reloaded, then we also // Check again when polling.
// need to reset last_focused_window here, so that the translations of
// the focused window are recomputed the next time we handle an event.
if (read_config_file()) last_focused_window = 0; if (read_config_file()) last_focused_window = 0;
count = 0; t0 = t;
} }
// Make sure that debugging output gets flushed every once in a while (may // Make sure that debugging output gets flushed every once in a while (may
// be buffered when midizap is running inside a QjackCtl session). // be buffered when midizap is running inside a QjackCtl session).

View File

@ -54,6 +54,8 @@ typedef struct _stroke {
// keysym == shift == 0 => MIDI event // keysym == shift == 0 => MIDI event
int status, data; // status and, if applicable, first data byte int status, data; // status and, if applicable, first data byte
int step; // step size (1, 127 or 8191 by default, depending on status) int step; // step size (1, 127 or 8191 by default, depending on status)
// discrete steps (for special "modulus" translations only)
int n_steps, *steps;
// the incremental bit indicates an incremental control change (typically // the incremental bit indicates an incremental control change (typically
// used with endless rotary encoders) to be represented as a sign bit value // used with endless rotary encoders) to be represented as a sign bit value
uint8_t incr; uint8_t incr;
@ -67,10 +69,12 @@ typedef struct _stroke_data {
uint8_t chan, data; uint8_t chan, data;
// stroke data, indexed by press/release or up/down index // stroke data, indexed by press/release or up/down index
stroke *s[2]; stroke *s[2];
// step size (CP, KP, CC and PB only) // step size
int step[2]; int step[2], n_steps[2], *steps[2];
// incr flag (CC only) // incr flag (CC only)
uint8_t is_incr; uint8_t is_incr;
// modulus
uint8_t mod;
} stroke_data; } stroke_data;
typedef struct _translation { typedef struct _translation {
@ -100,7 +104,9 @@ typedef struct _translation {
extern void reload_callback(void); extern void reload_callback(void);
extern int read_config_file(void); extern int read_config_file(void);
extern translation *get_translation(char *win_title, char *win_class); extern translation *get_translation(char *win_title, char *win_class);
extern void print_stroke_sequence(char *name, char *up_or_down, stroke *s); extern void print_stroke_sequence(char *name, char *up_or_down, stroke *s,
int mod, int step, int n_steps, int *steps,
int val);
extern translation *default_translation, *default_midi_translation[2]; extern translation *default_translation, *default_midi_translation[2];
extern int debug_regex, debug_strokes, debug_keys, debug_midi; extern int debug_regex, debug_strokes, debug_keys, debug_midi;
extern int default_debug_regex, default_debug_strokes, default_debug_keys, extern int default_debug_regex, default_debug_strokes, default_debug_keys,

View File

@ -201,6 +201,7 @@ free_strokes(stroke *s)
stroke *next; stroke *next;
while (s != NULL) { while (s != NULL) {
next = s->next; next = s->next;
if (s->steps) free(s->steps);
free(s); free(s);
s = next; s = next;
} }
@ -234,13 +235,27 @@ static void free_stroke_data(stroke_data *sd, uint16_t n)
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
free_strokes(sd[i].s[0]); free_strokes(sd[i].s[0]);
free_strokes(sd[i].s[1]); free_strokes(sd[i].s[1]);
if (sd[i].steps[0]) free(sd[i].steps[0]);
if (sd[i].steps[1]) free(sd[i].steps[1]);
} }
free(sd); free(sd);
} }
static int *stepsdup(int n_steps, int *steps)
{
if (n_steps) {
int *ret = malloc(n_steps*sizeof(int));
memcpy(ret, steps, n_steps*sizeof(int));
return ret;
} else
return 0;
}
static stroke **find_stroke_data(stroke_data **sd, static stroke **find_stroke_data(stroke_data **sd,
int chan, int data, int index, int chan, int data, int index,
int step, int incr, int step, int n_steps, int *steps,
int incr, int mod,
uint16_t *n, uint16_t *a) uint16_t *n, uint16_t *a)
{ {
uint16_t i; uint16_t i;
@ -248,7 +263,10 @@ static stroke **find_stroke_data(stroke_data **sd,
if ((*sd)[i].chan == chan && (*sd)[i].data == data) { if ((*sd)[i].chan == chan && (*sd)[i].data == data) {
// existing entry // existing entry
(*sd)[i].step[index] = step; (*sd)[i].step[index] = step;
(*sd)[i].n_steps[index] = n_steps;
(*sd)[i].steps[index] = stepsdup(n_steps, steps);
(*sd)[i].is_incr = incr; (*sd)[i].is_incr = incr;
(*sd)[i].mod = mod;
return &(*sd)[i].s[index]; return &(*sd)[i].s[index];
} }
} }
@ -262,77 +280,91 @@ static stroke **find_stroke_data(stroke_data **sd,
(*sd)[*n].chan = chan; (*sd)[*n].chan = chan;
(*sd)[*n].data = data; (*sd)[*n].data = data;
(*sd)[*n].step[index] = step; (*sd)[*n].step[index] = step;
(*sd)[*n].n_steps[index] = n_steps;
(*sd)[*n].steps[index] = stepsdup(n_steps, steps);
(*sd)[*n].is_incr = incr; (*sd)[*n].is_incr = incr;
(*sd)[*n].mod = mod;
return &(*sd)[(*n)++].s[index]; return &(*sd)[(*n)++].s[index];
} }
static stroke **find_note(translation *tr, int shift, static stroke **find_note(translation *tr, int shift,
int chan, int data, int index) int chan, int data, int index, int mod,
int step, int n_steps, int *steps)
{ {
return find_stroke_data(&tr->note[shift], chan, data, index, 0, 0, return find_stroke_data(&tr->note[shift], chan, data, index,
step, n_steps, steps, 0, mod,
&tr->n_note[shift], &tr->a_note[shift]); &tr->n_note[shift], &tr->a_note[shift]);
} }
static stroke **find_pc(translation *tr, int shift, static stroke **find_pc(translation *tr, int shift,
int chan, int data, int index) int chan, int data, int index)
{ {
return find_stroke_data(&tr->pc[shift], chan, data, index, 0, 0, return find_stroke_data(&tr->pc[shift], chan, data, index, 0, 0, 0, 0, 0,
&tr->n_pc[shift], &tr->a_pc[shift]); &tr->n_pc[shift], &tr->a_pc[shift]);
} }
static stroke **find_cc(translation *tr, int shift, static stroke **find_cc(translation *tr, int shift,
int chan, int data, int index) int chan, int data, int index, int mod,
int step, int n_steps, int *steps)
{ {
return find_stroke_data(&tr->cc[shift], chan, data, index, 0, 0, return find_stroke_data(&tr->cc[shift], chan, data, index,
step, n_steps, steps, 0, mod,
&tr->n_cc[shift], &tr->a_cc[shift]); &tr->n_cc[shift], &tr->a_cc[shift]);
} }
static stroke **find_ccs(translation *tr, int shift, static stroke **find_ccs(translation *tr, int shift,
int chan, int data, int index, int step, int incr) int chan, int data, int index, int step, int incr)
{ {
return find_stroke_data(&tr->ccs[shift], chan, data, index, step, incr, return find_stroke_data(&tr->ccs[shift], chan, data, index, step, 0, 0,
incr, 0,
&tr->n_ccs[shift], &tr->a_ccs[shift]); &tr->n_ccs[shift], &tr->a_ccs[shift]);
} }
static stroke **find_kp(translation *tr, int shift, static stroke **find_kp(translation *tr, int shift,
int chan, int data, int index) int chan, int data, int index, int mod,
int step, int n_steps, int *steps)
{ {
return find_stroke_data(&tr->kp[shift], chan, data, index, 0, 0, return find_stroke_data(&tr->kp[shift], chan, data, index,
step, n_steps, steps, 0, mod,
&tr->n_kp[shift], &tr->a_kp[shift]); &tr->n_kp[shift], &tr->a_kp[shift]);
} }
static stroke **find_kps(translation *tr, int shift, static stroke **find_kps(translation *tr, int shift,
int chan, int data, int index, int step) int chan, int data, int index, int step)
{ {
return find_stroke_data(&tr->kps[shift], chan, data, index, step, 0, return find_stroke_data(&tr->kps[shift], chan, data, index, step, 0, 0, 0, 0,
&tr->n_kps[shift], &tr->a_kps[shift]); &tr->n_kps[shift], &tr->a_kps[shift]);
} }
static stroke **find_cp(translation *tr, int shift, static stroke **find_cp(translation *tr, int shift,
int chan, int index) int chan, int index, int mod,
int step, int n_steps, int *steps)
{ {
return find_stroke_data(&tr->cp[shift], chan, 0, index, 0, 0, return find_stroke_data(&tr->cp[shift], chan, 0, index,
step, n_steps, steps, 0, mod,
&tr->n_cp[shift], &tr->a_cp[shift]); &tr->n_cp[shift], &tr->a_cp[shift]);
} }
static stroke **find_cps(translation *tr, int shift, static stroke **find_cps(translation *tr, int shift,
int chan, int index, int step) int chan, int index, int step)
{ {
return find_stroke_data(&tr->cps[shift], chan, 0, index, step, 0, return find_stroke_data(&tr->cps[shift], chan, 0, index, step, 0, 0, 0, 0,
&tr->n_cps[shift], &tr->a_cps[shift]); &tr->n_cps[shift], &tr->a_cps[shift]);
} }
static stroke **find_pb(translation *tr, int shift, static stroke **find_pb(translation *tr, int shift,
int chan, int index) int chan, int index, int mod,
int step, int n_steps, int *steps)
{ {
return find_stroke_data(&tr->pb[shift], chan, 0, index, 0, 0, return find_stroke_data(&tr->pb[shift], chan, 0, index,
step, n_steps, steps, 0, mod,
&tr->n_pb[shift], &tr->a_pb[shift]); &tr->n_pb[shift], &tr->a_pb[shift]);
} }
static stroke **find_pbs(translation *tr, int shift, static stroke **find_pbs(translation *tr, int shift,
int chan, int index, int step) int chan, int index, int step)
{ {
return find_stroke_data(&tr->pbs[shift], chan, 0, index, step, 0, return find_stroke_data(&tr->pbs[shift], chan, 0, index, step, 0, 0, 0, 0,
&tr->n_pbs[shift], &tr->a_pbs[shift]); &tr->n_pbs[shift], &tr->a_pbs[shift]);
} }
@ -495,10 +527,39 @@ KeySym_to_string(KeySym ks)
return NULL; return NULL;
} }
static char *note_names[] = { "C", "C#", "D", "Eb", "E", "F", "F#", "G", "G#", "A", "Bb", "B" }; static char *note_name(int n)
{
static char *note_names[] = { "C", "C#", "D", "Eb", "E", "F", "F#", "G", "G#", "A", "Bb", "B" };
if (n < 0 && n%12)
return note_names[12+n%12];
else
return note_names[n%12];
}
static int note_octave(int n)
{
if (n < 0 && n%12)
return n/12-1 + midi_octave;
else
return n/12 + midi_octave;
}
static int datavals(int val, int step, int *steps, int n_steps)
{
if (val < 0)
return -datavals(-val, step, steps, n_steps);
else if (val < n_steps)
return steps[val];
else if (n_steps)
return steps[n_steps-1];
else if (step)
return step*val;
else
return val;
}
void void
print_stroke(stroke *s) print_stroke(stroke *s, int mod, int step, int n_steps, int *steps, int val)
{ {
char *str; char *str;
@ -517,23 +578,54 @@ print_stroke(stroke *s)
int channel = (s->status & 0x0f) + 1; int channel = (s->status & 0x0f) + 1;
switch (status) { switch (status) {
case 0x90: case 0x90:
if (s->step) if (mod) {
printf("%s%d[%d]-%d ", note_names[s->data % 12], int d = s->data + datavals(val/mod, step, steps, n_steps);
s->data / 12 + midi_octave, s->step, channel); int v = datavals(val%mod, s->step, s->steps, s->n_steps);
printf("%s%d[%d]-%d ", note_name(d),
note_octave(d), v, channel);
} else if (s->steps) {
printf("%s%d[", note_name(s->data),
note_octave(s->data));
for (int i = 0; i < s->n_steps; i++)
printf("%s%d", i?",":"", s->steps[i]);
printf("]-%d ", channel);
} else if (s->step)
printf("%s%d[%d]-%d ", note_name(s->data),
note_octave(s->data), s->step, channel);
else else
printf("%s%d-%d ", note_names[s->data % 12], printf("%s%d-%d ", note_name(s->data),
s->data / 12 + midi_octave, channel); note_octave(s->data), channel);
break; break;
case 0xa0: case 0xa0:
if (s->step) if (mod) {
printf("KP:%s%d[%d]-%d ", note_names[s->data % 12], int d = s->data + datavals(val/mod, step, steps, n_steps);
s->data / 12 + midi_octave, s->step, channel); int v = datavals(val%mod, s->step, s->steps, s->n_steps);
printf("KP:%s%d[%d]-%d ", note_name(d),
note_octave(d), v, channel);
} else if (s->steps) {
printf("KP:%s%d[", note_name(s->data),
note_octave(s->data));
for (int i = 0; i < s->n_steps; i++)
printf("%s%d", i?",":"", s->steps[i]);
printf("]-%d ", channel);
} else if (s->step)
printf("KP:%s%d[%d]-%d ", note_name(s->data),
note_octave(s->data), s->step, channel);
else else
printf("KP:%s%d-%d ", note_names[s->data % 12], printf("KP:%s%d-%d ", note_name(s->data),
s->data / 12 + midi_octave, channel); note_octave(s->data), channel);
break; break;
case 0xb0: case 0xb0:
if (s->step) if (mod) {
int d = s->data + datavals(val/mod, step, steps, n_steps);
int v = datavals(val%mod, s->step, s->steps, s->n_steps);
printf("CC%d[%d]-%d ", d, v, channel);
} else if (s->steps) {
printf("CC%d[", s->data);
for (int i = 0; i < s->n_steps; i++)
printf("%s%d", i?",":"", s->steps[i]);
printf("]-%d ", channel);
} else if (s->step)
printf("CC%d[%d]-%d%s ", s->data, s->step, channel, s->incr?"~":""); printf("CC%d[%d]-%d%s ", s->data, s->step, channel, s->incr?"~":"");
else else
printf("CC%d-%d%s ", s->data, channel, s->incr?"~":""); printf("CC%d-%d%s ", s->data, channel, s->incr?"~":"");
@ -542,13 +634,29 @@ print_stroke(stroke *s)
printf("PC%d-%d ", s->data, channel); printf("PC%d-%d ", s->data, channel);
break; break;
case 0xd0: case 0xd0:
if (s->step) if (mod) {
int v = datavals(val%mod, s->step, s->steps, s->n_steps);
printf("CP[%d]-%d ", v, channel);
} else if (s->steps) {
printf("CP[");
for (int i = 0; i < s->n_steps; i++)
printf("%s%d", i?",":"", s->steps[i]);
printf("]-%d ", channel);
} else if (s->step)
printf("CP[%d]-%d ", s->step, channel); printf("CP[%d]-%d ", s->step, channel);
else else
printf("CP-%d ", channel); printf("CP-%d ", channel);
break; break;
case 0xe0: case 0xe0:
if (s->step) if (mod) {
int v = datavals(val%mod, s->step, s->steps, s->n_steps);
printf("PB[%d]-%d ", v, channel);
} else if (s->steps) {
printf("PB[");
for (int i = 0; i < s->n_steps; i++)
printf("%s%d", i?",":"", s->steps[i]);
printf("]-%d ", channel);
} else if (s->step)
printf("PB[%d]-%d ", s->step, channel); printf("PB[%d]-%d ", s->step, channel);
else else
printf("PB-%d ", channel); printf("PB-%d ", channel);
@ -561,14 +669,15 @@ print_stroke(stroke *s)
} }
void void
print_stroke_sequence(char *name, char *up_or_down, stroke *s) print_stroke_sequence(char *name, char *up_or_down, stroke *s,
int mod, int step, int n_steps, int *steps, int val)
{ {
if (up_or_down && *up_or_down) if (up_or_down && *up_or_down)
printf("%s[%s]: ", name, up_or_down); printf("%s[%s]: ", name, up_or_down);
else else
printf("%s: ", name); printf("%s: ", name);
while (s) { while (s) {
print_stroke(s); print_stroke(s, mod, step, n_steps, steps, val);
s = s->next; s = s->next;
} }
printf("\n"); printf("\n");
@ -630,7 +739,7 @@ append_shift(void)
} }
void void
append_midi(int status, int data, int step, int incr) append_midi(int status, int data, int step, int n_steps, int *steps, int incr)
{ {
stroke *s = (stroke *)allocate(sizeof(stroke)); stroke *s = (stroke *)allocate(sizeof(stroke));
@ -641,6 +750,8 @@ append_midi(int status, int data, int step, int incr)
s->status = status; s->status = status;
s->data = data; s->data = data;
s->step = step; s->step = step;
s->n_steps = n_steps;
s->steps = stepsdup(n_steps, steps);
s->incr = incr; s->incr = incr;
// if this is a keystroke event, for all messages but program change (which // 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 // has no "on" and "off" states), mark the event as "dirty" so that the
@ -781,12 +892,47 @@ static int note_number(char c, char b, int k)
} }
} }
static char *parse_steps(char *tok, char *p,
int *step, int *n_steps, int **steps)
{
int l, n;
if (sscanf(++p, "%d%n", &l, &n) == 1) {
p += n;
if (*p == ',') {
int n_st = 1;
static int st[128];
st[0] = l;
while (*p == ',') {
if (sscanf(++p, "%d%n", &l, &n) == 1) {
p += n;
} else
return 0;
if (n_st < 128)
st[n_st++] = l;
else if (n_st == 128)
fprintf(stderr, "warning: too many steps: %s\n", tok);
}
*n_steps = n_st;
*steps = st;
*step = 0;
} else {
*n_steps = 0;
*steps = 0;
*step = l;
}
return p;
} else {
return 0;
}
}
int int
parse_midi(char *tok, char *s, int lhs, int mode, parse_midi(char *tok, char *s, int lhs, int mode,
int *status, int *data, int *step, int *incr, int *dir) int *status, int *data, int *step, int *n_steps, int **steps,
int *incr, int *dir, int *mod)
{ {
char *p = tok, *t; char *p = tok, *t;
int n, m = -1, k = midi_channel, l; int n, m = -1, k = midi_channel;
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
@ -826,14 +972,30 @@ parse_midi(char *tok, char *s, int lhs, int mode,
return 0; return 0;
} }
} }
// step size // step size / modulus
*mod = 0;
int step2 = 0, n_steps2 = 0, *steps2 = 0;
if (*p == '[') { if (*p == '[') {
if (sscanf(++p, "%d%n", &l, &n) == 1) { if ((p = parse_steps(tok, p, step, n_steps, steps))) {
if (!l || (lhs && l<0)) return 0; // must be nonzero / positive on lhs if (*n_steps) {
p += n; // only permitted on the rhs in mod translations
if (lhs || mode < 2) return 0;
} else if (!*step || (lhs && *step<0))
// must be nonzero / positive on lhs
return 0;
if (*p != ']') return 0; if (*p != ']') return 0;
p++; p++;
*step = l; if (*p == '[') {
// possible step size on lhs for mod translations (we just record it
// here, will be resolved later)
if ((p = parse_steps(tok, p, &step2, &n_steps2, &steps2))) {
if (!n_steps2 && !step2) return 0; // must be nonzero
} else {
return 0;
}
if (*p != ']') return 0;
p++;
}
} else { } else {
return 0; return 0;
} }
@ -841,6 +1003,8 @@ parse_midi(char *tok, char *s, int lhs, int mode,
// sentinel value; for the lhs, this will be filled in below; for // sentinel value; for the lhs, this will be filled in below; for
// the rhs this indicates the default value // the rhs this indicates the default value
*step = 0; *step = 0;
*n_steps = 0;
*steps = 0;
} }
// suffix with MIDI channel (not permitted with 'ch') // suffix with MIDI channel (not permitted with 'ch')
if (p[0] == '-' && isdigit(p[1])) { if (p[0] == '-' && isdigit(p[1])) {
@ -872,7 +1036,7 @@ parse_midi(char *tok, char *s, int lhs, int mode,
// an endless, sign-bit encoder // an endless, sign-bit encoder
if (*p != '~') if (*p != '~')
return 0; return 0;
else if (!mode) else if (mode)
fprintf(stderr, "warning: incremental flag ignored in key mode: %s\n", tok); fprintf(stderr, "warning: incremental flag ignored in key mode: %s\n", tok);
*incr = 2; *dir = 0; *incr = 2; *dir = 0;
} }
@ -886,6 +1050,8 @@ parse_midi(char *tok, char *s, int lhs, int mode,
if (strcmp(s, "ch") == 0) { if (strcmp(s, "ch") == 0) {
if (lhs) return 0; // not permitted on lhs if (lhs) return 0; // not permitted on lhs
if (*step) return 0; // step size not permitted if (*step) return 0; // step size not permitted
if (*n_steps) return 0; // steps not permitted
if (steps2 || n_steps2) return 0; // not permitted
// we return a bogus status of 0 here, along with the MIDI channel // we return a bogus status of 0 here, along with the MIDI channel
// in the data byte; also check that the MIDI channel is in the // in the data byte; also check that the MIDI channel is in the
// proper range // proper range
@ -895,23 +1061,28 @@ parse_midi(char *tok, char *s, int lhs, int mode,
} else if (strcmp(s, "pb") == 0) { } else if (strcmp(s, "pb") == 0) {
// pitch bend, no data byte // pitch bend, no data byte
*status = 0xe0 | k; *data = 0; *status = 0xe0 | k; *data = 0;
// negative step size is always permitted on rhs here, even in key mode // step size on lhs indicates modulus if non-incremental
// step size only permitted on lhs if incremental if (lhs && *step && !*incr) {
if (lhs && *step && !*incr) return 0; *mod = *step; *step = step2;
*n_steps = n_steps2; *steps = steps2;
}
if (lhs && !*step) *step = 1; // default if (lhs && !*step) *step = 1; // default
return 1; return 1;
} else if (strcmp(s, "cp") == 0) { } else if (strcmp(s, "cp") == 0) {
// channel pressure, no data byte // channel pressure, no data byte
*status = 0xd0 | k; *data = 0; *status = 0xd0 | k; *data = 0;
// negative step size not permitted on rhs in key mode // step size on lhs indicates modulus if non-incremental
if (!lhs && *step < 0 && !mode) return 0; if (lhs && *step && !*incr) {
// step size only permitted on lhs if incremental *mod = *step; *step = step2;
if (lhs && *step && !*incr) return 0; *n_steps = n_steps2; *steps = steps2;
}
if (lhs && !*step) *step = 1; // default if (lhs && !*step) *step = 1; // default
return 1; return 1;
} else if (strcmp(s, "pc") == 0) { } else if (strcmp(s, "pc") == 0) {
// program change // program change
if (*step) return 0; // step size not permitted if (*step) return 0; // step size not permitted
if (*n_steps) return 0; // steps not permitted
if (steps2 || n_steps2) return 0; // not permitted
if (m < 0 || m > 127) return 0; if (m < 0 || m > 127) return 0;
*status = 0xc0 | k; *data = m; *status = 0xc0 | k; *data = m;
return 1; return 1;
@ -919,27 +1090,31 @@ parse_midi(char *tok, char *s, int lhs, int mode,
// control change // control change
if (m < 0 || m > 127) return 0; if (m < 0 || m > 127) return 0;
*status = 0xb0 | k; *data = m; *status = 0xb0 | k; *data = m;
// negative step size not permitted on rhs in key mode // step size on lhs indicates modulus if non-incremental
if (!lhs && *step < 0 && !mode) return 0; if (lhs && *step && !*incr) {
// step size only permitted on lhs if incremental *mod = *step; *step = step2;
if (lhs && *step && !*incr) return 0; *n_steps = n_steps2; *steps = steps2;
}
if (lhs && !*step) *step = 1; // default if (lhs && !*step) *step = 1; // default
return 1; return 1;
} else if (strcmp(s, "kp") == 0) { } else if (strcmp(s, "kp") == 0) {
// key pressure // key pressure
if (m < 0 || m > 127) return 0; if (m < 0 || m > 127) return 0;
*status = 0xa0 | k; *data = m; *status = 0xa0 | k; *data = m;
// negative step size not permitted on rhs in key mode // step size on lhs indicates modulus if non-incremental
if (!lhs && *step < 0 && !mode) return 0; if (lhs && *step && !*incr) {
// step size only permitted on lhs if incremental *mod = *step; *step = step2;
if (lhs && *step && !*incr) return 0; *n_steps = n_steps2; *steps = steps2;
}
if (lhs && !*step) *step = 1; // default if (lhs && !*step) *step = 1; // default
return 1; return 1;
} else { } else {
// negative step size not permitted on rhs // step size on lhs indicates modulus
if (!lhs && *step < 0) return 0; if (lhs && *step) {
// step size not permitted on lhs *mod = *step; *step = step2;
if (lhs && *step) return 0; *n_steps = n_steps2; *steps = steps2;
}
if (lhs && !*step) *step = 1; // default
// we must be looking at a MIDI note here, with m denoting the // we must be looking at a MIDI note here, with m denoting the
// octave number; first character is the note name (must be a..g); // octave number; first character is the note name (must be a..g);
// optionally, the second character may denote an accidental (# or b) // optionally, the second character may denote an accidental (# or b)
@ -953,7 +1128,7 @@ parse_midi(char *tok, char *s, int lhs, int mode,
int int
start_translation(translation *tr, char *which_key) start_translation(translation *tr, char *which_key)
{ {
int k, status, data, step, incr, dir; int k, status, data, step, n_steps, *steps, incr, dir, mod;
char buf[100]; char buf[100];
//printf("start_translation(%s)\n", which_key); //printf("start_translation(%s)\n", which_key);
@ -970,19 +1145,29 @@ start_translation(translation *tr, char *which_key)
modifier_count = 0; modifier_count = 0;
midi_channel = 0; midi_channel = 0;
k = *which_key == '^' || (is_anyshift = *which_key == '?'); k = *which_key == '^' || (is_anyshift = *which_key == '?');
if (parse_midi(which_key+k, buf, 1, 0, &status, &data, &step, &incr, &dir)) { if (parse_midi(which_key+k, buf, 1, 0, &status, &data, &step, &n_steps, &steps, &incr, &dir, &mod)) {
int chan = status & 0x0f; int chan = status & 0x0f;
mode = !!incr; mode = incr?0:mod?2:1;
switch (status & 0xf0) { switch (status & 0xf0) {
case 0x90: case 0x90:
// note on/off if (mod) {
first_stroke = find_note(tr, k, chan, data, 0); // note mod
release_first_stroke = find_note(tr, k, chan, data, 1); first_stroke = find_note(tr, k, chan, data, 0, mod,
if (is_anyshift) { step, n_steps, steps);
alt_press_stroke = find_note(tr, 0, chan, data, 0); if (is_anyshift) {
alt_release_stroke = find_note(tr, 0, chan, data, 1); alt_press_stroke = find_note(tr, 0, chan, data, 0, mod,
step, n_steps, steps);
}
} else {
// note on/off
first_stroke = find_note(tr, k, chan, data, 0, 0, 0, 0, 0);
release_first_stroke = find_note(tr, k, chan, data, 1, 0, 0, 0, 0);
if (is_anyshift) {
alt_press_stroke = find_note(tr, 0, chan, data, 0, 0, 0, 0, 0);
alt_release_stroke = find_note(tr, 0, chan, data, 1, 0, 0, 0, 0);
}
is_keystroke = 1;
} }
is_keystroke = 1;
break; break;
case 0xc0: case 0xc0:
// pc: To make our live easier and for consistency with the other // pc: To make our live easier and for consistency with the other
@ -999,16 +1184,7 @@ start_translation(translation *tr, char *which_key)
is_keystroke = 1; is_keystroke = 1;
break; break;
case 0xb0: case 0xb0:
if (!incr) { if (incr) {
// cc on/off
first_stroke = find_cc(tr, k, chan, data, 0);
release_first_stroke = find_cc(tr, k, chan, data, 1);
if (is_anyshift) {
alt_press_stroke = find_cc(tr, 0, chan, data, 0);
alt_release_stroke = find_cc(tr, 0, chan, data, 1);
}
is_keystroke = 1;
} else {
// cc (step up, down) // cc (step up, down)
if (step <= 0) { if (step <= 0) {
fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key); fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key);
@ -1032,19 +1208,27 @@ start_translation(translation *tr, char *which_key)
alt_release_stroke = find_ccs(tr, 0, chan, data, 1, step, incr>1); alt_release_stroke = find_ccs(tr, 0, chan, data, 1, step, incr>1);
} }
} }
} else if (mod) {
// cc mod
first_stroke = find_cc(tr, k, chan, data, 0, mod,
step, n_steps, steps);
if (is_anyshift) {
alt_press_stroke = find_cc(tr, 0, chan, data, 0, mod,
step, n_steps, steps);
}
} else {
// cc on/off
first_stroke = find_cc(tr, k, chan, data, 0, 0, 0, 0, 0);
release_first_stroke = find_cc(tr, k, chan, data, 1, 0, 0, 0, 0);
if (is_anyshift) {
alt_press_stroke = find_cc(tr, 0, chan, data, 0, 0, 0, 0, 0);
alt_release_stroke = find_cc(tr, 0, chan, data, 1, 0, 0, 0, 0);
}
is_keystroke = 1;
} }
break; break;
case 0xa0: case 0xa0:
if (!incr) { if (incr) {
// kp on/off
first_stroke = find_kp(tr, k, chan, data, 0);
release_first_stroke = find_kp(tr, k, chan, data, 1);
if (is_anyshift) {
alt_press_stroke = find_kp(tr, 0, chan, data, 0);
alt_release_stroke = find_kp(tr, 0, chan, data, 1);
}
is_keystroke = 1;
} else {
// kp (step up, down) // kp (step up, down)
if (step <= 0) { if (step <= 0) {
fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key); fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key);
@ -1061,19 +1245,27 @@ start_translation(translation *tr, char *which_key)
alt_release_stroke = find_kps(tr, 0, chan, data, 1, step); alt_release_stroke = find_kps(tr, 0, chan, data, 1, step);
} }
} }
} else if (mod) {
// kp mod
first_stroke = find_kp(tr, k, chan, data, 0, mod,
step, n_steps, steps);
if (is_anyshift) {
alt_press_stroke = find_kp(tr, 0, chan, data, 0, mod,
step, n_steps, steps);
}
} else {
// kp on/off
first_stroke = find_kp(tr, k, chan, data, 0, 0, 0, 0, 0);
release_first_stroke = find_kp(tr, k, chan, data, 1, 0, 0, 0, 0);
if (is_anyshift) {
alt_press_stroke = find_kp(tr, 0, chan, data, 0, 0, 0, 0, 0);
alt_release_stroke = find_kp(tr, 0, chan, data, 1, 0, 0, 0, 0);
}
is_keystroke = 1;
} }
break; break;
case 0xd0: case 0xd0:
if (!incr) { if (incr) {
// cp on/off
first_stroke = find_cp(tr, k, chan, 0);
release_first_stroke = find_cp(tr, k, chan, 1);
if (is_anyshift) {
alt_press_stroke = find_cp(tr, 0, chan, 0);
alt_release_stroke = find_cp(tr, 0, chan, 1);
}
is_keystroke = 1;
} else {
// cp (step up, down) // cp (step up, down)
if (step <= 0) { if (step <= 0) {
fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key); fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key);
@ -1090,19 +1282,27 @@ start_translation(translation *tr, char *which_key)
alt_release_stroke = find_cps(tr, 0, chan, 1, step); alt_release_stroke = find_cps(tr, 0, chan, 1, step);
} }
} }
} else if (mod) {
// cp mod
first_stroke = find_cp(tr, k, chan, 0, mod,
step, n_steps, steps);
if (is_anyshift) {
alt_press_stroke = find_cp(tr, 0, chan, 0, mod,
step, n_steps, steps);
}
} else {
// cp on/off
first_stroke = find_cp(tr, k, chan, 0, 0, 0, 0, 0);
release_first_stroke = find_cp(tr, k, chan, 1, 0, 0, 0, 0);
if (is_anyshift) {
alt_press_stroke = find_cp(tr, 0, chan, 0, 0, 0, 0, 0);
alt_release_stroke = find_cp(tr, 0, chan, 1, 0, 0, 0, 0);
}
is_keystroke = 1;
} }
break; break;
case 0xe0: case 0xe0:
if (!incr) { if (incr) {
// pb on/off
first_stroke = find_pb(tr, k, chan, 0);
release_first_stroke = find_pb(tr, k, chan, 1);
if (is_anyshift) {
alt_press_stroke = find_pb(tr, 0, chan, 0);
alt_release_stroke = find_pb(tr, 0, chan, 1);
}
is_keystroke = 1;
} else {
// pb (step up, down) // pb (step up, down)
if (step <= 0) { if (step <= 0) {
fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key); fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key);
@ -1119,6 +1319,23 @@ start_translation(translation *tr, char *which_key)
alt_release_stroke = find_pbs(tr, 0, chan, 1, step); alt_release_stroke = find_pbs(tr, 0, chan, 1, step);
} }
} }
} else if (mod) {
// pb mod
first_stroke = find_pb(tr, k, chan, 0, mod,
step, n_steps, steps);
if (is_anyshift) {
alt_press_stroke = find_pb(tr, 0, chan, 0, mod,
step, n_steps, steps);
}
} else {
// pb on/off
first_stroke = find_pb(tr, k, chan, 0, 0, 0, 0, 0);
release_first_stroke = find_pb(tr, k, chan, 1, 0, 0, 0, 0);
if (is_anyshift) {
alt_press_stroke = find_pb(tr, 0, chan, 0, 0, 0, 0, 0);
alt_release_stroke = find_pb(tr, 0, chan, 1, 0, 0, 0, 0);
}
is_keystroke = 1;
} }
break; break;
default: default:
@ -1187,7 +1404,7 @@ add_release(int all_keys)
stroke *s = *press_first_stroke; stroke *s = *press_first_stroke;
while (s) { while (s) {
if (!s->keysym && !s->shift && s->dirty) { if (!s->keysym && !s->shift && s->dirty) {
append_midi(s->status, s->data, s->step, s->incr); append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr);
s->dirty = 0; s->dirty = 0;
} }
s = s->next; s = s->next;
@ -1209,7 +1426,7 @@ add_release(int all_keys)
} else if (s->shift) { } else if (s->shift) {
append_shift(); append_shift();
} else { } else {
append_midi(s->status, s->data, s->step, s->incr); append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr);
} }
s = s->next; s = s->next;
} }
@ -1224,7 +1441,7 @@ add_release(int all_keys)
} else if (s->shift) { } else if (s->shift) {
append_shift(); append_shift();
} else { } else {
append_midi(s->status, s->data, s->step, s->incr); append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr);
} }
s = s->next; s = s->next;
} }
@ -1237,7 +1454,7 @@ add_release(int all_keys)
} else if (s->shift) { } else if (s->shift) {
append_shift(); append_shift();
} else { } else {
append_midi(s->status, s->data, s->step, s->incr); append_midi(s->status, s->data, s->step, s->n_steps, s->steps, s->incr);
} }
s = s->next; s = s->next;
} }
@ -1276,16 +1493,16 @@ add_string(char *str)
void void
add_midi(char *tok) add_midi(char *tok)
{ {
int status, data, step, incr, dir = 0; int status, data, step, n_steps, *steps, incr, dir = 0, mod = 0;
char buf[100]; char buf[100];
if (parse_midi(tok, buf, 0, mode, &status, &data, &step, &incr, &dir)) { if (parse_midi(tok, buf, 0, mode, &status, &data, &step, &n_steps, &steps, &incr, &dir, &mod)) {
if (status == 0) { if (status == 0) {
// 'ch' token; this doesn't actually generate any output, it just sets // 'ch' token; this doesn't actually generate any output, it just sets
// the default MIDI channel // the default MIDI channel
midi_channel = data; midi_channel = data;
} else { } else {
if ((status & 0xf0) != 0xe0 || step != 0) if ((status & 0xf0) != 0xe0 || step != 0)
append_midi(status, data, step, incr!=0); append_midi(status, data, step, n_steps, steps, incr!=0);
else else
fprintf(stderr, "zero step size not permitted: %s\n", tok); fprintf(stderr, "zero step size not permitted: %s\n", tok);
} }
@ -1309,10 +1526,10 @@ finish_translation(void)
add_release(1); add_release(1);
if (debug_strokes) { if (debug_strokes) {
if (is_keystroke) { if (is_keystroke) {
print_stroke_sequence(key_name, "D", *press_first_stroke); print_stroke_sequence(key_name, "D", *press_first_stroke, 0, 0, 0, 0, 0);
print_stroke_sequence(key_name, "U", *release_first_stroke); print_stroke_sequence(key_name, "U", *release_first_stroke, 0, 0, 0, 0, 0);
} else { } else {
print_stroke_sequence(key_name, "", *first_stroke); print_stroke_sequence(key_name, "", *first_stroke, 0, 0, 0, 0, 0);
} }
printf("\n"); printf("\n");
} }