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
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)
# 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;
}
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
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
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;
switch (status & 0xf0) {
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);
} else {
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];
}
} 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) {
msg[2] = dataval(step, 0, 127);
} 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;
}
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) {
msg[2] = dataval(step, 0, 127);
} 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;
}
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) {
msg[1] = dataval(step, 0, 127);
} 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;
}
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) {
pbval = 8192+dataval(step, -8192, 8191);
} else {
@ -219,7 +265,8 @@ static int stroke_data_cmp(const void *a, const void *b)
static stroke *find_stroke_data(stroke_data *sd,
int chan, int data, int index,
int *step, int *incr,
int *step, int *n_steps, int **steps,
int *incr, int *mod,
uint16_t n)
{
if (n < 16) {
@ -230,7 +277,10 @@ static stroke *find_stroke_data(stroke_data *sd,
for (i = 0; i < n; i++) {
if (sd[i].chan == chan && sd[i].data == data) {
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 (mod) *mod = sd[i].mod;
return sd[i].s[index];
} else if (sd[i].chan > chan ||
(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);
if (ret) {
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 (mod) *mod = ret->mod;
return ret->s[index];
} else
return NULL;
@ -252,105 +305,117 @@ static stroke *find_stroke_data(stroke_data *sd,
}
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]);
}
static stroke *find_pc(translation *tr, int shift,
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]);
}
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]);
}
static stroke *find_ccs(translation *tr, int shift,
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]);
}
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]);
}
static stroke *find_kps(translation *tr, int shift,
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]);
}
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]);
}
static stroke *find_cps(translation *tr, int shift,
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]);
}
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]);
}
static stroke *find_pbs(translation *tr, int shift,
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]);
}
stroke *
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) {
switch (status) {
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:
return find_pc(tr, shift, chan, data, index);
case 0xb0:
if (dir)
return find_ccs(tr, shift, chan, data, dir>0, step, incr);
else
return find_cc(tr, shift, chan, data, index);
return find_cc(tr, shift, chan, data, index, mod, step, n_steps, steps);
case 0xa0:
if (dir)
return find_kps(tr, shift, chan, data, dir>0, step);
else
return find_kp(tr, shift, chan, data, index);
return find_kp(tr, shift, chan, data, index, mod, step, n_steps, steps);
case 0xd0:
if (dir)
return find_cps(tr, shift, chan, dir>0, step);
else
return find_cp(tr, shift, chan, index);
return find_cp(tr, shift, chan, index, mod, step, n_steps, steps);
case 0xe0:
if (dir)
return find_pbs(tr, shift, chan, dir>0, step);
else
return find_pb(tr, shift, chan, index);
return find_pb(tr, shift, chan, index, mod, step, n_steps, steps);
default:
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,
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 = "";
strcpy(name, "??");
switch (status) {
case 0x90:
sprintf(name, "%s%s%d-%d", prefix, note_names[data % 12],
data / 12 + midi_octave, chan+1);
case 0x90: {
int mod = 0, step, n_steps, *steps;
(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;
}
case 0xa0: {
int step = 1;
if (tr) (void)find_kps(tr, shift, chan, data, dir>0, &step);
int step = 0, n_steps = 0, *steps = 0, mod = 0;
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)
suffix = "";
else
suffix = (dir<0)?"-":"+";
if (dir && step != 1)
sprintf(name, "%sKP:%s%d[%d]-%d%s", prefix, note_names[data % 12],
data / 12 + midi_octave, step, chan+1, suffix);
sprintf(name, "%sKP:%s%d[%d]-%d%s", prefix, note_name(data),
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
sprintf(name, "%sKP:%s%d-%d%s", prefix, note_names[data % 12],
data / 12 + midi_octave, chan+1, suffix);
sprintf(name, "%sKP:%s%d-%d%s", prefix, note_name(data),
note_octave(data), chan+1, suffix);
break;
}
case 0xb0: {
int step = 1, is_incr = 0;
if (tr) (void)find_ccs(tr, shift, chan, data, dir>0, &step, &is_incr);
int step = 0, n_steps = 0, *steps = 0, mod = 0, is_incr = 0;
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)
suffix = "";
else if (is_incr)
@ -426,6 +551,17 @@ static char *debug_key(translation *tr, char *name,
suffix = (dir<0)?"-":"+";
if (dir && step != 1)
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
sprintf(name, "%sCC%d-%d%s", prefix, data, chan+1, suffix);
break;
@ -434,14 +570,31 @@ static char *debug_key(translation *tr, char *name,
sprintf(name, "%sPC%d-%d", prefix, data, chan+1);
break;
case 0xd0: {
int step = 1;
if (tr) (void)find_cps(tr, shift, chan, dir>0, &step);
int step = 0, n_steps = 0, *steps = 0, mod = 0;
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)
suffix = "";
else
suffix = (dir<0)?"-":"+";
if (dir && step != 1)
if (dir && step != 1)
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
sprintf(name, "%sCP-%d%s", prefix, chan+1, suffix);
break;
@ -509,26 +662,26 @@ static void end_debug()
}
void
send_strokes(translation *tr, uint8_t portno, int status, int chan, int data,
int index, int dir)
send_strokes(translation *tr, uint8_t portno, int status, int chan,
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,
&step, &is_incr);
&step, &n_steps, &steps, &is_incr, &mod);
// If there's no press/release translation, check whether we have got at
// least the corresponding release/press translation, in order to prevent
// spurious error messages if either the press or release translation just
// happens to be empty.
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) {
// fall back to default MIDI translation
tr = default_midi_translation[portno];
s = fetch_stroke(tr, portno, status, chan, data, index, dir,
&step, &is_incr);
&step, &n_steps, &steps, &is_incr, &mod);
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
// the [MIDI2] section (or the section is missing altogether).
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
tr = default_translation;
s = fetch_stroke(tr, portno, status, chan, data, index, dir,
&step, &is_incr);
&step, &n_steps, &steps, &is_incr, &mod);
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) {
@ -561,7 +714,8 @@ send_strokes(translation *tr, uint8_t portno, int status, int chan, int data,
if (s && debug_keys) {
char name[100];
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) {
if (s->keysym) {
@ -571,7 +725,9 @@ send_strokes(translation *tr, uint8_t portno, int status, int chan, int data,
// toggle shift status
shift = !shift;
} 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;
}
@ -702,6 +858,24 @@ static uint8_t inpbdown[2][16];
static uint8_t inkpdown[2][16][128];
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
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;
}
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
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;
}
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
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;
}
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
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;
}
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
handle_event(uint8_t *msg, uint8_t portno)
{
@ -892,20 +1138,22 @@ handle_event(uint8_t *msg, uint8_t portno)
switch (status) {
case 0xc0:
start_debug();
send_strokes(tr, portno, status, chan, msg[1], 0, 0);
send_strokes(tr, portno, status, chan, msg[1], 1, 0);
send_strokes(tr, portno, status, chan, msg[1], 0, 0, 0);
send_strokes(tr, portno, status, chan, msg[1], 0, 1, 0);
end_debug();
break;
case 0x90:
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]]) {
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;
}
} else {
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;
}
}
@ -913,14 +1161,16 @@ handle_event(uint8_t *msg, uint8_t portno)
break;
case 0xb0:
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]]) {
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;
}
} else {
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;
}
}
@ -942,7 +1192,7 @@ handle_event(uint8_t *msg, uint8_t portno)
if (step) {
int d = msg[2]/step;
while (d) {
send_strokes(tr, portno, status, chan, msg[1], 0, 1);
send_strokes(tr, portno, status, chan, msg[1], 0, 0, 1);
d--;
}
}
@ -951,7 +1201,7 @@ handle_event(uint8_t *msg, uint8_t portno)
if (step) {
int d = (msg[2]-64)/step;
while (d) {
send_strokes(tr, portno, status, chan, msg[1], 0, -1);
send_strokes(tr, portno, status, chan, msg[1], 0, 0, -1);
d--;
}
}
@ -965,7 +1215,7 @@ handle_event(uint8_t *msg, uint8_t portno)
int d = abs(inccvalue[portno][chan][msg[1]] - msg[2]);
if (d > step) d = step;
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;
}
}
@ -974,14 +1224,16 @@ handle_event(uint8_t *msg, uint8_t portno)
break;
case 0xa0:
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]]) {
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;
}
} else {
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;
}
}
@ -995,7 +1247,7 @@ handle_event(uint8_t *msg, uint8_t portno)
int d = abs(inkpvalue[portno][chan][msg[1]] - msg[2]);
if (d > step) d = step;
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;
}
}
@ -1004,14 +1256,16 @@ handle_event(uint8_t *msg, uint8_t portno)
break;
case 0xd0:
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]) {
send_strokes(tr, portno, status, chan, 0, 0, 0);
send_strokes(tr, portno, status, chan, 0, 0, 0, 0);
incpdown[portno][chan] = 1;
}
} else {
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;
}
}
@ -1025,7 +1279,7 @@ handle_event(uint8_t *msg, uint8_t portno)
int d = abs(incpvalue[portno][chan] - msg[1]);
if (d > step) d = step;
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;
}
}
@ -1036,14 +1290,16 @@ handle_event(uint8_t *msg, uint8_t portno)
int bend = ((msg[2] << 7) | msg[1]) - 8192;
start_debug();
//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]) {
send_strokes(tr, portno, status, chan, 0, 0, 0);
send_strokes(tr, portno, status, chan, 0, 0, 0, 0);
inpbdown[portno][chan] = 1;
}
} else {
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;
}
}
@ -1056,7 +1312,7 @@ handle_event(uint8_t *msg, uint8_t portno)
int d = abs(inpbvalue[portno][chan] - 8192 - bend);
if (d > step) d = step;
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;
}
}
@ -1146,11 +1402,13 @@ static char *absolute_path(char *name)
#define CONF_FREQ 1
#define MAX_COUNT (1000000/CONF_FREQ/POLL_INTERVAL)
#include <time.h>
int
main(int argc, char **argv)
{
uint8_t msg[3];
int opt, count = 0;
int opt;
// Start recording the command line to be passed to Jack session management.
add_command(argv[0]);
@ -1260,6 +1518,7 @@ main(int argc, char **argv)
int do_flush = debug_regex || debug_strokes || debug_keys || debug_midi ||
debug_jack;
signal(SIGINT, quitter);
time_t t0 = time(0);
while (!quit) {
uint8_t portno;
if (jack_quit) {
@ -1270,16 +1529,19 @@ main(int argc, char **argv)
}
while (pop_midi(&seq, 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);
if (++count >= MAX_COUNT) {
// Check whether to reload the config file if we haven't seen any MIDI
// input in a while. Note that if the file *is* reloaded, then we also
// need to reset last_focused_window here, so that the translations of
// the focused window are recomputed the next time we handle an event.
time_t t = time(0);
if (t > t0) {
// Check again when polling.
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
// be buffered when midizap is running inside a QjackCtl session).

View File

@ -54,6 +54,8 @@ typedef struct _stroke {
// keysym == shift == 0 => MIDI event
int status, data; // status and, if applicable, first data byte
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
// used with endless rotary encoders) to be represented as a sign bit value
uint8_t incr;
@ -67,10 +69,12 @@ typedef struct _stroke_data {
uint8_t chan, data;
// stroke data, indexed by press/release or up/down index
stroke *s[2];
// step size (CP, KP, CC and PB only)
int step[2];
// step size
int step[2], n_steps[2], *steps[2];
// incr flag (CC only)
uint8_t is_incr;
// modulus
uint8_t mod;
} stroke_data;
typedef struct _translation {
@ -100,7 +104,9 @@ typedef struct _translation {
extern void reload_callback(void);
extern int read_config_file(void);
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 int debug_regex, debug_strokes, debug_keys, debug_midi;
extern int default_debug_regex, default_debug_strokes, default_debug_keys,

View File

@ -201,6 +201,7 @@ free_strokes(stroke *s)
stroke *next;
while (s != NULL) {
next = s->next;
if (s->steps) free(s->steps);
free(s);
s = next;
}
@ -234,13 +235,27 @@ static void free_stroke_data(stroke_data *sd, uint16_t n)
for (i = 0; i < n; i++) {
free_strokes(sd[i].s[0]);
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);
}
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,
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 i;
@ -248,7 +263,10 @@ static stroke **find_stroke_data(stroke_data **sd,
if ((*sd)[i].chan == chan && (*sd)[i].data == data) {
// existing entry
(*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].mod = mod;
return &(*sd)[i].s[index];
}
}
@ -262,77 +280,91 @@ static stroke **find_stroke_data(stroke_data **sd,
(*sd)[*n].chan = chan;
(*sd)[*n].data = data;
(*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].mod = mod;
return &(*sd)[(*n)++].s[index];
}
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]);
}
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]);
}
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]);
}
static stroke **find_ccs(translation *tr, int shift,
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]);
}
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]);
}
static stroke **find_kps(translation *tr, int shift,
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]);
}
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]);
}
static stroke **find_cps(translation *tr, int shift,
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]);
}
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]);
}
static stroke **find_pbs(translation *tr, int shift,
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]);
}
@ -495,10 +527,39 @@ KeySym_to_string(KeySym ks)
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
print_stroke(stroke *s)
print_stroke(stroke *s, int mod, int step, int n_steps, int *steps, int val)
{
char *str;
@ -517,23 +578,54 @@ print_stroke(stroke *s)
int channel = (s->status & 0x0f) + 1;
switch (status) {
case 0x90:
if (s->step)
printf("%s%d[%d]-%d ", note_names[s->data % 12],
s->data / 12 + midi_octave, s->step, channel);
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("%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
printf("%s%d-%d ", note_names[s->data % 12],
s->data / 12 + midi_octave, channel);
printf("%s%d-%d ", note_name(s->data),
note_octave(s->data), channel);
break;
case 0xa0:
if (s->step)
printf("KP:%s%d[%d]-%d ", note_names[s->data % 12],
s->data / 12 + midi_octave, s->step, channel);
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("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
printf("KP:%s%d-%d ", note_names[s->data % 12],
s->data / 12 + midi_octave, channel);
printf("KP:%s%d-%d ", note_name(s->data),
note_octave(s->data), channel);
break;
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?"~":"");
else
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);
break;
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);
else
printf("CP-%d ", channel);
break;
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);
else
printf("PB-%d ", channel);
@ -561,14 +669,15 @@ print_stroke(stroke *s)
}
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)
printf("%s[%s]: ", name, up_or_down);
else
printf("%s: ", name);
while (s) {
print_stroke(s);
print_stroke(s, mod, step, n_steps, steps, val);
s = s->next;
}
printf("\n");
@ -630,7 +739,7 @@ append_shift(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));
@ -641,6 +750,8 @@ append_midi(int status, int data, int step, int incr)
s->status = status;
s->data = data;
s->step = step;
s->n_steps = n_steps;
s->steps = stepsdup(n_steps, steps);
s->incr = incr;
// 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
@ -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
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;
int n, m = -1, k = midi_channel, l;
int n, m = -1, k = midi_channel;
s[0] = 0;
while (*p && !isdigit(*p) && !strchr("+-=<>~[:", *p)) p++;
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;
}
}
// step size
// step size / modulus
*mod = 0;
int step2 = 0, n_steps2 = 0, *steps2 = 0;
if (*p == '[') {
if (sscanf(++p, "%d%n", &l, &n) == 1) {
if (!l || (lhs && l<0)) return 0; // must be nonzero / positive on lhs
p += n;
if ((p = parse_steps(tok, p, step, n_steps, steps))) {
if (*n_steps) {
// 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;
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 {
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
// the rhs this indicates the default value
*step = 0;
*n_steps = 0;
*steps = 0;
}
// suffix with MIDI channel (not permitted with 'ch')
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
if (*p != '~')
return 0;
else if (!mode)
else if (mode)
fprintf(stderr, "warning: incremental flag ignored in key mode: %s\n", tok);
*incr = 2; *dir = 0;
}
@ -886,6 +1050,8 @@ parse_midi(char *tok, char *s, int lhs, int mode,
if (strcmp(s, "ch") == 0) {
if (lhs) return 0; // not permitted on lhs
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
// in the data byte; also check that the MIDI channel is in the
// proper range
@ -895,23 +1061,28 @@ parse_midi(char *tok, char *s, int lhs, int mode,
} else if (strcmp(s, "pb") == 0) {
// pitch bend, no data byte
*status = 0xe0 | k; *data = 0;
// negative step size is always permitted on rhs here, even in key mode
// step size only permitted on lhs if incremental
if (lhs && *step && !*incr) return 0;
// step size on lhs indicates modulus if non-incremental
if (lhs && *step && !*incr) {
*mod = *step; *step = step2;
*n_steps = n_steps2; *steps = steps2;
}
if (lhs && !*step) *step = 1; // default
return 1;
} else if (strcmp(s, "cp") == 0) {
// channel pressure, no data byte
*status = 0xd0 | k; *data = 0;
// negative step size not permitted on rhs in key mode
if (!lhs && *step < 0 && !mode) return 0;
// step size only permitted on lhs if incremental
if (lhs && *step && !*incr) return 0;
// step size on lhs indicates modulus if non-incremental
if (lhs && *step && !*incr) {
*mod = *step; *step = step2;
*n_steps = n_steps2; *steps = steps2;
}
if (lhs && !*step) *step = 1; // default
return 1;
} else if (strcmp(s, "pc") == 0) {
// program change
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;
*status = 0xc0 | k; *data = m;
return 1;
@ -919,27 +1090,31 @@ parse_midi(char *tok, char *s, int lhs, int mode,
// control change
if (m < 0 || m > 127) return 0;
*status = 0xb0 | k; *data = m;
// negative step size not permitted on rhs in key mode
if (!lhs && *step < 0 && !mode) return 0;
// step size only permitted on lhs if incremental
if (lhs && *step && !*incr) return 0;
// step size on lhs indicates modulus if non-incremental
if (lhs && *step && !*incr) {
*mod = *step; *step = step2;
*n_steps = n_steps2; *steps = steps2;
}
if (lhs && !*step) *step = 1; // default
return 1;
} else if (strcmp(s, "kp") == 0) {
// key pressure
if (m < 0 || m > 127) return 0;
*status = 0xa0 | k; *data = m;
// negative step size not permitted on rhs in key mode
if (!lhs && *step < 0 && !mode) return 0;
// step size only permitted on lhs if incremental
if (lhs && *step && !*incr) return 0;
// step size on lhs indicates modulus if non-incremental
if (lhs && *step && !*incr) {
*mod = *step; *step = step2;
*n_steps = n_steps2; *steps = steps2;
}
if (lhs && !*step) *step = 1; // default
return 1;
} else {
// negative step size not permitted on rhs
if (!lhs && *step < 0) return 0;
// step size not permitted on lhs
if (lhs && *step) return 0;
// step size on lhs indicates modulus
if (lhs && *step) {
*mod = *step; *step = step2;
*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
// octave number; first character is the note name (must be a..g);
// 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
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];
//printf("start_translation(%s)\n", which_key);
@ -970,19 +1145,29 @@ start_translation(translation *tr, char *which_key)
modifier_count = 0;
midi_channel = 0;
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;
mode = !!incr;
mode = incr?0:mod?2:1;
switch (status & 0xf0) {
case 0x90:
// note on/off
first_stroke = find_note(tr, k, chan, data, 0);
release_first_stroke = find_note(tr, k, chan, data, 1);
if (is_anyshift) {
alt_press_stroke = find_note(tr, 0, chan, data, 0);
alt_release_stroke = find_note(tr, 0, chan, data, 1);
if (mod) {
// note mod
first_stroke = find_note(tr, k, chan, data, 0, mod,
step, n_steps, steps);
if (is_anyshift) {
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;
case 0xc0:
// 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;
break;
case 0xb0:
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 {
if (incr) {
// cc (step up, down)
if (step <= 0) {
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);
}
}
} 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;
case 0xa0:
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 {
if (incr) {
// kp (step up, down)
if (step <= 0) {
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);
}
}
} 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;
case 0xd0:
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 {
if (incr) {
// cp (step up, down)
if (step <= 0) {
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);
}
}
} 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;
case 0xe0:
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 {
if (incr) {
// pb (step up, down)
if (step <= 0) {
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);
}
}
} 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;
default:
@ -1187,7 +1404,7 @@ add_release(int all_keys)
stroke *s = *press_first_stroke;
while (s) {
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 = s->next;
@ -1209,7 +1426,7 @@ add_release(int all_keys)
} else if (s->shift) {
append_shift();
} 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;
}
@ -1224,7 +1441,7 @@ add_release(int all_keys)
} else if (s->shift) {
append_shift();
} 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;
}
@ -1237,7 +1454,7 @@ add_release(int all_keys)
} else if (s->shift) {
append_shift();
} 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;
}
@ -1276,16 +1493,16 @@ add_string(char *str)
void
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];
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) {
// 'ch' token; this doesn't actually generate any output, it just sets
// the default MIDI channel
midi_channel = data;
} else {
if ((status & 0xf0) != 0xe0 || step != 0)
append_midi(status, data, step, incr!=0);
append_midi(status, data, step, n_steps, steps, incr!=0);
else
fprintf(stderr, "zero step size not permitted: %s\n", tok);
}
@ -1309,10 +1526,10 @@ finish_translation(void)
add_release(1);
if (debug_strokes) {
if (is_keystroke) {
print_stroke_sequence(key_name, "D", *press_first_stroke);
print_stroke_sequence(key_name, "U", *release_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, 0, 0, 0, 0, 0);
} else {
print_stroke_sequence(key_name, "", *first_stroke);
print_stroke_sequence(key_name, "", *first_stroke, 0, 0, 0, 0, 0);
}
printf("\n");
}