Optimize memory usage of the translation tables, using sorted arrays and binary search. Still runs reasonably fast, and memory usage is much lower know (in the KB range).
parent
9d6cc38171
commit
ade9aa3db8
184
midizap.c
184
midizap.c
|
@ -151,26 +151,112 @@ send_midi(uint8_t portno, int status, int data, int step, int incr, int index, i
|
|||
queue_midi(&seq, msg, portno);
|
||||
}
|
||||
|
||||
static int stroke_data_cmp(const void *a, const void *b)
|
||||
{
|
||||
const stroke_data *ad = (const stroke_data*)a;
|
||||
const stroke_data *bd = (const stroke_data*)b;
|
||||
if (ad->chan == bd->chan)
|
||||
return ad->data - bd->data;
|
||||
else
|
||||
return ad->chan - bd->chan;
|
||||
}
|
||||
|
||||
static stroke *find_stroke_data(stroke_data *sd,
|
||||
int chan, int data, int index,
|
||||
int *step, int *incr,
|
||||
uint16_t n)
|
||||
{
|
||||
if (n < 16) {
|
||||
// Linear search is presumably faster for small arrays, and we also avoid
|
||||
// function calls for doing the comparisons here. Not sure where it breaks
|
||||
// even with glibc's bsearch(), though (TODO: measure).
|
||||
uint16_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (sd[i].chan == chan && sd[i].data == data) {
|
||||
if (step) *step = sd[i].step[index];
|
||||
if (incr) *incr = sd[i].is_incr;
|
||||
return sd[i].s[index];
|
||||
} else if (sd[i].chan > chan ||
|
||||
(sd[i].chan == chan && sd[i].data > data))
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
// binary search from libc
|
||||
stroke_data *ret, key;
|
||||
key.chan = chan; key.data = data;
|
||||
ret = bsearch(&key, sd, n, sizeof(stroke_data), stroke_data_cmp);
|
||||
if (ret) {
|
||||
if (step) *step = ret->step[index];
|
||||
if (incr) *incr = ret->is_incr;
|
||||
return ret->s[index];
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static stroke *find_note(translation *tr, int shift,
|
||||
int chan, int data, int index)
|
||||
{
|
||||
return find_stroke_data(tr->note[shift], chan, data, index, 0, 0,
|
||||
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,
|
||||
tr->n_pc[shift]);
|
||||
}
|
||||
|
||||
static stroke *find_cc(translation *tr, int shift,
|
||||
int chan, int data, int index)
|
||||
{
|
||||
return find_stroke_data(tr->cc[shift], chan, data, index, 0, 0,
|
||||
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,
|
||||
tr->n_ccs[shift]);
|
||||
}
|
||||
|
||||
static stroke *find_pb(translation *tr, int shift,
|
||||
int chan, int index)
|
||||
{
|
||||
return find_stroke_data(tr->pb[shift], chan, 0, index, 0, 0,
|
||||
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,
|
||||
tr->n_pbs[shift]);
|
||||
}
|
||||
|
||||
stroke *
|
||||
fetch_stroke(translation *tr, uint8_t portno, int status, int chan, int data,
|
||||
int index, int dir)
|
||||
int index, int dir, int *step, int *incr)
|
||||
{
|
||||
if (tr && tr->portno == portno) {
|
||||
switch (status) {
|
||||
case 0x90:
|
||||
return tr->note[shift][chan][data][index];
|
||||
return find_note(tr, shift, chan, data, index);
|
||||
case 0xc0:
|
||||
return tr->pc[shift][chan][data][index];
|
||||
return find_pc(tr, shift, chan, data, index);
|
||||
case 0xb0:
|
||||
if (dir)
|
||||
return tr->ccs[shift][chan][data][dir>0];
|
||||
return find_ccs(tr, shift, chan, data, dir>0, step, incr);
|
||||
else
|
||||
return tr->cc[shift][chan][data][index];
|
||||
return find_cc(tr, shift, chan, data, index);
|
||||
case 0xe0:
|
||||
if (dir)
|
||||
return tr->pbs[shift][chan][dir>0];
|
||||
return find_pbs(tr, shift, chan, dir>0, step);
|
||||
else
|
||||
return tr->pb[shift][chan][index];
|
||||
return find_pb(tr, shift, chan, index);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -221,10 +307,11 @@ static char *debug_key(translation *tr, char *name,
|
|||
data / 12 + midi_octave, chan+1);
|
||||
break;
|
||||
case 0xb0: {
|
||||
int step = tr->cc_step[shift][chan][data][dir>0];
|
||||
int step = 1, is_incr = 0;
|
||||
if (tr) (void)find_ccs(tr, shift, chan, data, dir>0, &step, &is_incr);
|
||||
if (!dir)
|
||||
suffix = "";
|
||||
else if (tr->is_incr[shift][chan][data])
|
||||
else if (is_incr)
|
||||
suffix = (dir<0)?"<":">";
|
||||
else
|
||||
suffix = (dir<0)?"-":"+";
|
||||
|
@ -238,7 +325,8 @@ static char *debug_key(translation *tr, char *name,
|
|||
sprintf(name, "%sPC%d-%d", prefix, data, chan+1);
|
||||
break;
|
||||
case 0xe0: {
|
||||
int step = tr->pb_step[shift][chan][dir>0];
|
||||
int step = 1;
|
||||
if (tr) (void)find_pbs(tr, shift, chan, dir>0, &step);
|
||||
if (!dir)
|
||||
suffix = "";
|
||||
else
|
||||
|
@ -255,7 +343,7 @@ static char *debug_key(translation *tr, char *name,
|
|||
return name;
|
||||
}
|
||||
|
||||
static void debug_input(translation *tr, int portno,
|
||||
static void debug_input(int portno,
|
||||
int status, int chan, int data, int data2)
|
||||
{
|
||||
char name[100];
|
||||
|
@ -264,10 +352,10 @@ static void debug_input(translation *tr, int portno,
|
|||
data2 = ((data2 << 7) | data) - 8192;
|
||||
if (status == 0xc0)
|
||||
printf("[%d] %s\n", portno,
|
||||
debug_key(tr, name, status, chan, data, 0));
|
||||
debug_key(0, name, status, chan, data, 0));
|
||||
else
|
||||
printf("[%d] %s value = %d\n", portno,
|
||||
debug_key(tr, name, status, chan, data, 0), data2);
|
||||
debug_key(0, name, status, chan, data, 0), data2);
|
||||
}
|
||||
|
||||
// Some machinery to handle the debugging of section matches. This is
|
||||
|
@ -300,21 +388,23 @@ void
|
|||
send_strokes(translation *tr, uint8_t portno, int status, int chan, int data,
|
||||
int index, int dir)
|
||||
{
|
||||
int nkeys = 0;
|
||||
stroke *s = fetch_stroke(tr, portno, status, chan, data, index, dir);
|
||||
int nkeys = 0, step = 0, is_incr = 0;
|
||||
stroke *s = fetch_stroke(tr, portno, status, chan, data, index, dir,
|
||||
&step, &is_incr);
|
||||
// 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));
|
||||
(!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir, 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);
|
||||
s = fetch_stroke(tr, portno, status, chan, data, index, dir,
|
||||
&step, &is_incr);
|
||||
chk = chk || s ||
|
||||
(!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir));
|
||||
(!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir, 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;
|
||||
|
@ -323,9 +413,10 @@ send_strokes(translation *tr, uint8_t portno, int status, int chan, int data,
|
|||
if (!s) {
|
||||
// fall back to the 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);
|
||||
chk = chk || s ||
|
||||
(!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir));
|
||||
(!dir && fetch_stroke(tr, portno, status, chan, data, !index, dir, 0, 0));
|
||||
}
|
||||
|
||||
if (debug_regex) {
|
||||
|
@ -486,34 +577,39 @@ static uint8_t inpbdown[2][16];
|
|||
int
|
||||
check_incr(translation *tr, uint8_t portno, int chan, int data)
|
||||
{
|
||||
int is_incr;
|
||||
if (tr && tr->portno == portno &&
|
||||
(tr->ccs[shift][chan][data][0] || tr->ccs[shift][chan][data][1]))
|
||||
return tr->is_incr[shift][chan][data];
|
||||
(find_ccs(tr, shift, chan, data, 0, 0, &is_incr) ||
|
||||
find_ccs(tr, shift, chan, data, 1, 0, &is_incr)))
|
||||
return is_incr;
|
||||
tr = default_midi_translation[portno];
|
||||
if (tr && tr->portno == portno &&
|
||||
(tr->ccs[shift][chan][data][0] || tr->ccs[shift][chan][data][1]))
|
||||
return tr->is_incr[shift][chan][data];
|
||||
(find_ccs(tr, shift, chan, data, 0, 0, &is_incr) ||
|
||||
find_ccs(tr, shift, chan, data, 1, 0, &is_incr)))
|
||||
return is_incr;
|
||||
tr = default_translation;
|
||||
if (tr && tr->portno == portno &&
|
||||
(tr->ccs[shift][chan][data][0] || tr->ccs[shift][chan][data][1]))
|
||||
return tr->is_incr[shift][chan][data];
|
||||
(find_ccs(tr, shift, chan, data, 0, 0, &is_incr) ||
|
||||
find_ccs(tr, shift, chan, data, 1, 0, &is_incr)))
|
||||
return is_incr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
get_cc_step(translation *tr, uint8_t portno, int chan, int data, int dir)
|
||||
{
|
||||
int step;
|
||||
if (tr && tr->portno == portno &&
|
||||
tr->ccs[shift][chan][data][dir>0])
|
||||
return tr->cc_step[shift][chan][data][dir>0];
|
||||
find_ccs(tr, shift, chan, data, dir>0, &step, 0))
|
||||
return step;
|
||||
tr = default_midi_translation[portno];
|
||||
if (tr && tr->portno == portno &&
|
||||
tr->ccs[shift][chan][data][dir>0])
|
||||
return tr->cc_step[shift][chan][data][dir>0];
|
||||
find_ccs(tr, shift, chan, data, dir>0, &step, 0))
|
||||
return step;
|
||||
tr = default_translation;
|
||||
if (tr && tr->portno == portno &&
|
||||
tr->ccs[shift][chan][data][dir>0])
|
||||
return tr->cc_step[shift][chan][data][dir>0];
|
||||
find_ccs(tr, shift, chan, data, dir>0, &step, 0))
|
||||
return step;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -521,15 +617,18 @@ int
|
|||
check_pbs(translation *tr, uint8_t portno, int chan)
|
||||
{
|
||||
if (tr && tr->portno == portno &&
|
||||
(tr->pbs[shift][chan][0] || tr->pbs[shift][chan][1]))
|
||||
(find_pbs(tr, shift, chan, 0, 0) ||
|
||||
find_pbs(tr, shift, chan, 1, 0)))
|
||||
return 1;
|
||||
tr = default_midi_translation[portno];
|
||||
if (tr && tr->portno == portno &&
|
||||
(tr->pbs[shift][chan][0] || tr->pbs[shift][chan][1]))
|
||||
(find_pbs(tr, shift, chan, 0, 0) ||
|
||||
find_pbs(tr, shift, chan, 1, 0)))
|
||||
return 1;
|
||||
tr = default_translation;
|
||||
if (tr && tr->portno == portno &&
|
||||
(tr->pbs[shift][chan][0] || tr->pbs[shift][chan][1]))
|
||||
(find_pbs(tr, shift, chan, 0, 0) ||
|
||||
find_pbs(tr, shift, chan, 1, 0)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -537,17 +636,18 @@ check_pbs(translation *tr, uint8_t portno, int chan)
|
|||
int
|
||||
get_pb_step(translation *tr, uint8_t portno, int chan, int dir)
|
||||
{
|
||||
int step;
|
||||
if (tr && tr->portno == portno &&
|
||||
tr->pbs[shift][chan][dir>0])
|
||||
return tr->pb_step[shift][chan][dir>0];
|
||||
find_pbs(tr, shift, chan, dir>0, &step))
|
||||
return step;
|
||||
tr = default_midi_translation[portno];
|
||||
if (tr && tr->portno == portno &&
|
||||
tr->pbs[shift][chan][dir>0])
|
||||
return tr->pb_step[shift][chan][dir>0];
|
||||
find_pbs(tr, shift, chan, dir>0, &step))
|
||||
return step;
|
||||
tr = default_translation;
|
||||
if (tr && tr->portno == portno &&
|
||||
tr->pbs[shift][chan][dir>0])
|
||||
return tr->pb_step[shift][chan][dir>0];
|
||||
find_pbs(tr, shift, chan, dir>0, &step))
|
||||
return step;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -563,7 +663,7 @@ handle_event(uint8_t *msg, uint8_t portno)
|
|||
msg[0] = status | chan;
|
||||
msg[2] = 0;
|
||||
}
|
||||
if (debug_midi) debug_input(tr, portno, status, chan, msg[1], msg[2]);
|
||||
if (debug_midi) debug_input(portno, status, chan, msg[1], msg[2]);
|
||||
switch (status) {
|
||||
case 0xc0:
|
||||
start_debug();
|
||||
|
|
34
midizap.h
34
midizap.h
|
@ -64,25 +64,33 @@ typedef struct _stroke {
|
|||
#define NUM_KEYS 128
|
||||
#define NUM_CHAN 16
|
||||
|
||||
typedef struct _stroke_data {
|
||||
// key (MIDI channel and, for note/CC/PB, data byte)
|
||||
uint8_t chan, data;
|
||||
// stroke data, indexed by press/release or up/down index
|
||||
stroke *s[2];
|
||||
// step size (CC and PB only)
|
||||
int step[2];
|
||||
// incr flag (CC only)
|
||||
uint8_t is_incr;
|
||||
} stroke_data;
|
||||
|
||||
typedef struct _translation {
|
||||
struct _translation *next;
|
||||
char *name;
|
||||
int is_default;
|
||||
regex_t regex;
|
||||
uint8_t portno;
|
||||
// XXXFIXME: This way of storing the translation tables is easy to
|
||||
// construct, but wastes quite a lot of memory. We should rather use some
|
||||
// kind of dictionary here.
|
||||
uint8_t is_incr[2][NUM_CHAN][NUM_KEYS];
|
||||
stroke *pc[2][NUM_CHAN][NUM_KEYS][2];
|
||||
stroke *note[2][NUM_CHAN][NUM_KEYS][2];
|
||||
stroke *cc[2][NUM_CHAN][NUM_KEYS][2];
|
||||
stroke *ccs[2][NUM_CHAN][NUM_KEYS][2];
|
||||
stroke *pb[2][NUM_CHAN][2];
|
||||
stroke *pbs[2][NUM_CHAN][2];
|
||||
// step size for control changes and pitch bend (1 by default)
|
||||
int cc_step[2][NUM_CHAN][NUM_KEYS][2];
|
||||
int pb_step[2][NUM_CHAN][2];
|
||||
// these are indexed by shift status
|
||||
stroke_data *note[2];
|
||||
stroke_data *pc[2];
|
||||
stroke_data *cc[2];
|
||||
stroke_data *ccs[2];
|
||||
stroke_data *pb[2];
|
||||
stroke_data *pbs[2];
|
||||
// actual and allocated sizes (can be at most 16*128)
|
||||
uint16_t n_note[2], n_pc[2], n_cc[2], n_ccs[2], n_pb[2], n_pbs[2];
|
||||
uint16_t a_note[2], a_pc[2], a_cc[2], a_ccs[2], a_pb[2], a_pbs[2];
|
||||
} translation;
|
||||
|
||||
extern void reload_callback(void);
|
||||
|
|
204
readconfig.c
204
readconfig.c
|
@ -371,10 +371,129 @@ free_strokes(stroke *s)
|
|||
}
|
||||
}
|
||||
|
||||
static int stroke_data_cmp(const void *a, const void *b)
|
||||
{
|
||||
const stroke_data *ad = (const stroke_data*)a;
|
||||
const stroke_data *bd = (const stroke_data*)b;
|
||||
if (ad->chan == bd->chan)
|
||||
return ad->data - bd->data;
|
||||
else
|
||||
return ad->chan - bd->chan;
|
||||
}
|
||||
|
||||
static void finish_stroke_data(stroke_data **sd,
|
||||
uint16_t *n, uint16_t *a)
|
||||
{
|
||||
if (*a && *a > *n) {
|
||||
// realloc to needed size
|
||||
*sd = realloc(*sd, (*n)*sizeof(stroke_data));
|
||||
*a = *n;
|
||||
}
|
||||
// sort by chan/data for faster access
|
||||
qsort(*sd, *n, sizeof(stroke_data), stroke_data_cmp);
|
||||
}
|
||||
|
||||
static void free_stroke_data(stroke_data *sd, uint16_t n)
|
||||
{
|
||||
uint16_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
free_strokes(sd[i].s[0]);
|
||||
free_strokes(sd[i].s[1]);
|
||||
}
|
||||
free(sd);
|
||||
}
|
||||
|
||||
static stroke **find_stroke_data(stroke_data **sd,
|
||||
int chan, int data, int index,
|
||||
int step, int incr,
|
||||
uint16_t *n, uint16_t *a)
|
||||
{
|
||||
uint16_t i;
|
||||
for (i = 0; i < *n; i++) {
|
||||
if ((*sd)[i].chan == chan && (*sd)[i].data == data) {
|
||||
// existing entry
|
||||
(*sd)[i].step[index] = step;
|
||||
(*sd)[i].is_incr = incr;
|
||||
return &(*sd)[i].s[index];
|
||||
}
|
||||
}
|
||||
// add a new entry
|
||||
if (*n >= *a) {
|
||||
// make some room
|
||||
*a = (*a)?2*(*a):8;
|
||||
*sd = realloc(*sd, (*a)*sizeof(stroke_data));
|
||||
}
|
||||
memset(&(*sd)[*n], 0, sizeof(stroke_data));
|
||||
(*sd)[*n].chan = chan;
|
||||
(*sd)[*n].data = data;
|
||||
(*sd)[*n].step[index] = step;
|
||||
(*sd)[*n].is_incr = incr;
|
||||
return &(*sd)[(*n)++].s[index];
|
||||
}
|
||||
|
||||
static stroke **find_note(translation *tr, int shift,
|
||||
int chan, int data, int index)
|
||||
{
|
||||
return find_stroke_data(&tr->note[shift], chan, data, index, 0, 0,
|
||||
&tr->n_note[shift], &tr->a_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,
|
||||
&tr->n_pc[shift], &tr->a_pc[shift]);
|
||||
}
|
||||
|
||||
static stroke **find_cc(translation *tr, int shift,
|
||||
int chan, int data, int index)
|
||||
{
|
||||
return find_stroke_data(&tr->cc[shift], chan, data, index, 0, 0,
|
||||
&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,
|
||||
&tr->n_ccs[shift], &tr->a_ccs[shift]);
|
||||
}
|
||||
|
||||
static stroke **find_pb(translation *tr, int shift,
|
||||
int chan, int index)
|
||||
{
|
||||
return find_stroke_data(&tr->pb[shift], chan, 0, index, 0, 0,
|
||||
&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,
|
||||
&tr->n_pbs[shift], &tr->a_pbs[shift]);
|
||||
}
|
||||
|
||||
void
|
||||
finish_translation_section(translation *tr)
|
||||
{
|
||||
int k;
|
||||
|
||||
if (tr) {
|
||||
for (k=0; k<2; k++) {
|
||||
finish_stroke_data(&tr->pc[k], &tr->n_pc[k], &tr->a_pc[k]);
|
||||
finish_stroke_data(&tr->note[k], &tr->n_note[k], &tr->a_note[k]);
|
||||
finish_stroke_data(&tr->cc[k], &tr->n_cc[k], &tr->a_cc[k]);
|
||||
finish_stroke_data(&tr->ccs[k], &tr->n_ccs[k], &tr->a_ccs[k]);
|
||||
finish_stroke_data(&tr->pb[k], &tr->n_pb[k], &tr->a_pb[k]);
|
||||
finish_stroke_data(&tr->pbs[k], &tr->n_pbs[k], &tr->a_pbs[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
free_translation_section(translation *tr)
|
||||
{
|
||||
int i, j, k;
|
||||
int k;
|
||||
|
||||
if (tr != NULL) {
|
||||
free(tr->name);
|
||||
|
@ -382,22 +501,12 @@ free_translation_section(translation *tr)
|
|||
regfree(&tr->regex);
|
||||
}
|
||||
for (k=0; k<2; k++) {
|
||||
for (i=0; i<NUM_CHAN; i++) {
|
||||
for (j=0; j<NUM_KEYS; j++) {
|
||||
free_strokes(tr->pc[k][i][j][0]);
|
||||
free_strokes(tr->pc[k][i][j][1]);
|
||||
free_strokes(tr->note[k][i][j][0]);
|
||||
free_strokes(tr->note[k][i][j][1]);
|
||||
free_strokes(tr->cc[k][i][j][0]);
|
||||
free_strokes(tr->cc[k][i][j][1]);
|
||||
free_strokes(tr->ccs[k][i][j][0]);
|
||||
free_strokes(tr->ccs[k][i][j][1]);
|
||||
}
|
||||
free_strokes(tr->pb[k][i][0]);
|
||||
free_strokes(tr->pb[k][i][1]);
|
||||
free_strokes(tr->pbs[k][i][0]);
|
||||
free_strokes(tr->pbs[k][i][1]);
|
||||
}
|
||||
free_stroke_data(tr->pc[k], tr->n_pc[k]);
|
||||
free_stroke_data(tr->note[k], tr->n_note[k]);
|
||||
free_stroke_data(tr->cc[k], tr->n_cc[k]);
|
||||
free_stroke_data(tr->ccs[k], tr->n_ccs[k]);
|
||||
free_stroke_data(tr->pb[k], tr->n_pb[k]);
|
||||
free_stroke_data(tr->pbs[k], tr->n_pbs[k]);
|
||||
}
|
||||
free(tr);
|
||||
}
|
||||
|
@ -934,11 +1043,11 @@ start_translation(translation *tr, char *which_key)
|
|||
switch (status & 0xf0) {
|
||||
case 0x90:
|
||||
// note on/off
|
||||
first_stroke = &(tr->note[k][chan][data][0]);
|
||||
release_first_stroke = &(tr->note[k][chan][data][1]);
|
||||
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 = &(tr->note[0][chan][data][0]);
|
||||
alt_release_stroke = &(tr->note[0][chan][data][1]);
|
||||
alt_press_stroke = find_note(tr, 0, chan, data, 0);
|
||||
alt_release_stroke = find_note(tr, 0, chan, data, 1);
|
||||
}
|
||||
is_keystroke = 1;
|
||||
break;
|
||||
|
@ -948,32 +1057,34 @@ start_translation(translation *tr, char *which_key)
|
|||
// this message has no off state. Thus, when we receive a pc, it's
|
||||
// supposed to be treated as a "press" sequence immediately followed by
|
||||
// the corresponding "release" sequence.
|
||||
first_stroke = &(tr->pc[k][chan][data][0]);
|
||||
release_first_stroke = &(tr->pc[k][chan][data][1]);
|
||||
first_stroke = find_pc(tr, k, chan, data, 0);
|
||||
release_first_stroke = find_pc(tr, k, chan, data, 1);
|
||||
if (is_anyshift) {
|
||||
alt_press_stroke = &(tr->pc[0][chan][data][0]);
|
||||
alt_release_stroke = &(tr->pc[0][chan][data][1]);
|
||||
alt_press_stroke = find_pc(tr, 0, chan, data, 0);
|
||||
alt_release_stroke = find_pc(tr, 0, chan, data, 1);
|
||||
}
|
||||
is_keystroke = 1;
|
||||
break;
|
||||
case 0xb0:
|
||||
if (!incr) {
|
||||
// cc on/off
|
||||
first_stroke = &(tr->cc[k][chan][data][0]);
|
||||
release_first_stroke = &(tr->cc[k][chan][data][1]);
|
||||
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 = &(tr->cc[0][chan][data][0]);
|
||||
alt_release_stroke = &(tr->cc[0][chan][data][1]);
|
||||
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)
|
||||
tr->is_incr[k][chan][data] = incr>1;
|
||||
first_stroke = &(tr->ccs[k][chan][data][dir>0]);
|
||||
if (is_anyshift) {
|
||||
alt_press_stroke = &(tr->ccs[0][chan][data][0]);
|
||||
if (step <= 0) {
|
||||
fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key);
|
||||
return 1;
|
||||
}
|
||||
first_stroke = find_ccs(tr, k, chan, data, dir>0, step, incr>1);
|
||||
if (is_anyshift) {
|
||||
alt_press_stroke = find_ccs(tr, 0, chan, data, dir>0, step, incr>1);
|
||||
}
|
||||
tr->cc_step[k][chan][data][dir>0] = step;
|
||||
if (!dir) {
|
||||
// This is a bidirectional translation (=, ~). We first fill in the
|
||||
// "down" part (pointed to by first_stroke). When finishing off the
|
||||
|
@ -983,22 +1094,21 @@ start_translation(translation *tr, char *which_key)
|
|||
// translation, here to remember the "up" part of the translation,
|
||||
// so that we can fill in that part later.
|
||||
is_bidirectional = 1;
|
||||
release_first_stroke = &(tr->ccs[k][chan][data][1]);
|
||||
release_first_stroke = find_ccs(tr, k, chan, data, 1, step, incr>1);
|
||||
if (is_anyshift) {
|
||||
alt_release_stroke = &(tr->ccs[0][chan][data][1]);
|
||||
alt_release_stroke = find_ccs(tr, 0, chan, data, 1, step, incr>1);
|
||||
}
|
||||
tr->cc_step[k][chan][data][1] = step;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xe0:
|
||||
if (!incr) {
|
||||
// pb on/off
|
||||
first_stroke = &(tr->pb[k][chan][0]);
|
||||
release_first_stroke = &(tr->pb[k][chan][1]);
|
||||
first_stroke = find_pb(tr, k, chan, 0);
|
||||
release_first_stroke = find_pb(tr, k, chan, 1);
|
||||
if (is_anyshift) {
|
||||
alt_press_stroke = &(tr->pb[0][chan][0]);
|
||||
alt_release_stroke = &(tr->pb[0][chan][1]);
|
||||
alt_press_stroke = find_pb(tr, 0, chan, 0);
|
||||
alt_release_stroke = find_pb(tr, 0, chan, 1);
|
||||
}
|
||||
is_keystroke = 1;
|
||||
} else {
|
||||
|
@ -1007,18 +1117,16 @@ start_translation(translation *tr, char *which_key)
|
|||
fprintf(stderr, "zero or negative step size not permitted here: [%s]%s\n", current_translation, which_key);
|
||||
return 1;
|
||||
}
|
||||
first_stroke = &(tr->pbs[k][chan][dir>0]);
|
||||
first_stroke = find_pbs(tr, k, chan, dir>0, step);
|
||||
if (is_anyshift) {
|
||||
alt_press_stroke = &(tr->pbs[0][chan][0]);
|
||||
alt_press_stroke = find_pbs(tr, 0, chan, dir>0, step);
|
||||
}
|
||||
tr->pb_step[k][chan][dir>0] = step;
|
||||
if (!dir) {
|
||||
is_bidirectional = 1;
|
||||
release_first_stroke = &(tr->pbs[k][chan][1]);
|
||||
release_first_stroke = find_pbs(tr, k, chan, 1, step);
|
||||
if (is_anyshift) {
|
||||
alt_release_stroke = &(tr->pbs[0][chan][1]);
|
||||
alt_release_stroke = find_pbs(tr, 0, chan, 1, step);
|
||||
}
|
||||
tr->pb_step[k][chan][1] = step;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1324,6 +1432,7 @@ read_config_file(void)
|
|||
}
|
||||
s[1] = '\0';
|
||||
}
|
||||
finish_translation_section(tr);
|
||||
tr = new_translation_section(name, regex);
|
||||
continue;
|
||||
}
|
||||
|
@ -1432,6 +1541,7 @@ read_config_file(void)
|
|||
}
|
||||
finish_translation();
|
||||
}
|
||||
finish_translation_section(tr);
|
||||
|
||||
fclose(f);
|
||||
return 1;
|
||||
|
|
Loading…
Reference in New Issue