From 2d57ab93a1550226d33619ef4ec1c3684cc2372a Mon Sep 17 00:00:00 2001 From: Thomas White Date: Thu, 15 Jun 2023 21:07:07 +0200 Subject: Implement high-level interface --- x1k2-midi-osc.c | 412 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 284 insertions(+), 128 deletions(-) diff --git a/x1k2-midi-osc.c b/x1k2-midi-osc.c index e5809ab..535654b 100644 --- a/x1k2-midi-osc.c +++ b/x1k2-midi-osc.c @@ -35,6 +35,7 @@ struct faderpot int physical_value; int physical_value_known; int enabled; + int congruent; int pickup_value; int has_button_and_led; int button; @@ -49,7 +50,6 @@ struct encoder { int id; int cc_val; - int enabled; int fine_button; int fine_active; int has_led; @@ -78,6 +78,38 @@ int n_encoders = 6; int n_faders = 4; int n_potentiometers = 12; +snd_rawmidi_t *midi_out; + + +static void send_note_on(snd_rawmidi_t *midi_out, int note) +{ + unsigned char sbuf[3]; + ssize_t r; + sbuf[0] = 0x9e; + sbuf[1] = note; + sbuf[2] = 127; + r = snd_rawmidi_write(midi_out, sbuf, 3); + if ( r != 3 ) { + printf("snd_rawmidi_write said %li\n", r); + } + usleep(1000); +} + + +static void send_note_off(snd_rawmidi_t *midi_out, int note) +{ + unsigned char sbuf[3]; + ssize_t r; + sbuf[0] = 0x8e; + sbuf[1] = note; + sbuf[2] = 0; + r = snd_rawmidi_write(midi_out, sbuf, 3); + if ( r != 3 ) { + printf("snd_rawmidi_write said %li\n", r); + } + usleep(1000); +} + static void init_fader(struct faderpot *fad, int id, int cc_val) { @@ -87,7 +119,7 @@ static void init_fader(struct faderpot *fad, int id, int cc_val) fad->physical_value_known = 0; fad->pickup_value = 0; fad->has_button_and_led = 0; - fad->enabled = 0; + fad->enabled = 1; fad->type = "faders"; } @@ -100,6 +132,7 @@ static void init_potentiometer(struct faderpot *fad, int id, int cc_val, fad->physical_value = 0; fad->physical_value_known = 0; fad->pickup_value = 0; + fad->congruent = 0; fad->has_button_and_led = 1; fad->button = button; fad->led_red = button; @@ -110,18 +143,128 @@ static void init_potentiometer(struct faderpot *fad, int id, int cc_val, } +static void faderpot_note_on(struct faderpot *fad) +{ + /* Ignored for now */ +} + + +static void faderpot_note_off(struct faderpot *fad) +{ + /* Ignored for now */ +} + + +static int in_range(int a, int val1, int val2) +{ + return ((a>=val1) && (a<=val2)) || ((a>=val2) && (a<=val1)); +} + + +static void pot_set_led(struct faderpot *fad) +{ + if ( fad->has_button_and_led ) { + if ( fad->enabled ) { + if ( fad->congruent ) { + send_note_on(midi_out, fad->led_green); + } else { + send_note_on(midi_out, fad->led_orange); + } + } else { + send_note_off(midi_out, fad->led_green); + } + } +} + + +static void faderpot_cc(struct faderpot *fad, int val, lo_address osc_send_addr) +{ + if ( !fad->congruent ) { + int inr = in_range(fad->pickup_value, fad->physical_value, val); + if ( fad->physical_value_known && inr ) { + fad->congruent = 1; + } + } + + if ( fad->enabled ) { + + pot_set_led(fad); + + if ( fad->congruent ) { + char tmp[64]; + snprintf(tmp, 64, "/x1k2/%s/%i/value-change", fad->type, fad->id); + lo_send(osc_send_addr, tmp, "i", val); + printf("sending %s = %i\n", tmp, val); + } + + } + + fad->physical_value = val; + fad->physical_value_known = 1; +} + + +static int pot_set_pickup_handler(const char *path, const char *types, + lo_arg **argv, int argc, + lo_message msg, void *vp) +{ + struct faderpot *fad = vp; + + fad->pickup_value = argv[0]->i; + + if ( fad->physical_value_known + && (fad->pickup_value == fad->physical_value) ) + { + fad->congruent = 1; + } else { + fad->congruent = 0; + } + + pot_set_led(fad); + + return 1; +} + + +static int pot_enable_handler(const char *path, const char *types, + lo_arg **argv, int argc, + lo_message msg, void *vp) +{ + struct faderpot *fad = vp; + fad->enabled = 1; + pot_set_led(fad); + return 1; +} + + +static int pot_disable_handler(const char *path, const char *types, + lo_arg **argv, int argc, + lo_message msg, void *vp) +{ + struct faderpot *fad = vp; + + fad->enabled = 0; + + if ( fad->has_button_and_led ) { + send_note_off(midi_out, fad->led_green); + } + + return 1; +} + + static void add_faderpot_methods(struct faderpot *fad, lo_server osc_server) { char tmp[256]; - snprintf(tmp, 255, "/x1k2/%s/%i/set-pickup-value", fad->type, fad->id); + snprintf(tmp, 255, "/x1k2/%s/%i/set-pickup", fad->type, fad->id); lo_server_add_method(osc_server, tmp, "i", pot_set_pickup_handler, fad); snprintf(tmp, 255, "/x1k2/%s/%i/enable", fad->type, fad->id); lo_server_add_method(osc_server, tmp, "", pot_enable_handler, fad); snprintf(tmp, 255, "/x1k2/%s/%i/disable", fad->type, fad->id); - lo_server_add_method(osc_server, tmp, "", pot_enable_handler, fad); + lo_server_add_method(osc_server, tmp, "", pot_disable_handler, fad); } @@ -150,105 +293,108 @@ static void init_encoder(struct encoder *enc, int id, int cc_val, } -static void add_encoder_methods(struct encoder *enc, lo_server osc_server) +static int enc_set_led_handler(const char *path, const char *types, + lo_arg **argv, int argc, + lo_message msg, void *vp) { - char tmp[256]; - snprintf(tmp, 255, "/x1k2/encoders/%i/set-led", enc->id); - lo_server_add_method(osc_server, tmp, "s", enc_set_led_handler, enc); -} + struct encoder *enc = vp; + if ( strcmp("red", &argv[0]->s) == 0 ) { + send_note_on(midi_out, enc->led_red); + } else if ( strcmp("orange", &argv[0]->s) == 0 ) { + send_note_on(midi_out, enc->led_orange); + } else if ( strcmp("green", &argv[0]->s) == 0 ) { + send_note_on(midi_out, enc->led_green); + } else if ( strcmp("off", &argv[0]->s) == 0 ) { + send_note_off(midi_out, enc->led_red); + } else { + fprintf(stderr, "Unrecognised LED mode '%s'\n", &argv[0]->s); + } + return 1; +} -static void init_button_full(struct button *but, const char *name, int note, - int r, int o, int g) +static void encoder_note_on(struct encoder *enc) { - but->name = name; - but->note = note; - but->led_red = r; - but->led_orange = o; - but->led_green = g; + enc->fine_active = 1; } -static void init_button(struct button *but, const char *name, int note) +static void encoder_note_off(struct encoder *enc) { - init_button_full(but, name, note, note, note+36, note+72); + enc->fine_active = 0; } -static void add_button_methods(struct button *but, lo_server osc_server) +static void encoder_cc(struct encoder *enc, int val, lo_address osc_send_addr) { char tmp[256]; - snprintf(tmp, 255, "/x1k2/buttons/%s/set-led", but->name); - lo_server_add_method(osc_server, tmp, "s", button_set_led_handler, but); + const char *v; + + if ( val == 1 ) { + v = "inc"; + } else if ( val == 127 ) { + v = "dec"; + } else { + fprintf(stderr, "Invalid encoder value %i\n", val); + return; + } + + snprintf(tmp, 255, "/x1k2/encoders/%i/%s%s", + enc->id, v, enc->fine_active ? "-fine" : ""); + lo_send(osc_send_addr, tmp, ""); } -static void show_help(const char *s) +static void add_encoder_methods(struct encoder *enc, lo_server osc_server) { - printf("Syntax: %s [-h] [-d /dev/snd/midiXXXX]\n\n", s); - printf("MIDI to OSC interface for A&H Xone:K2\n" - "\n" - " -h, --help Display this help message.\n" - " -d, --device MIDI device name.\n"); + char tmp[256]; + snprintf(tmp, 255, "/x1k2/encoders/%i/set-led", enc->id); + lo_server_add_method(osc_server, tmp, "s", enc_set_led_handler, enc); } -static void error_callback(int num, const char *msg, const char *path) +static void init_button_full(struct button *but, const char *name, int note, + int r, int o, int g) { - fprintf(stderr, "liblo error %i (%s) for path %s\n", num, msg, path); + but->name = name; + but->note = note; + but->led_red = r; + but->led_orange = o; + but->led_green = g; } -static void send_note_on(snd_rawmidi_t *midi_out, int note) +static void init_button(struct button *but, const char *name, int note) { - unsigned char sbuf[3]; - ssize_t r; - sbuf[0] = 0x9e; - sbuf[1] = note; - sbuf[2] = 127; - r = snd_rawmidi_write(midi_out, sbuf, 3); - if ( r != 3 ) { - printf("snd_rawmidi_write said %li\n", r); - } - usleep(1000); + init_button_full(but, name, note, note, note+36, note+72); } -static void send_note_off(snd_rawmidi_t *midi_out, int note) +static void button_note_off(struct button *but, lo_address osc_send_addr) { - unsigned char sbuf[3]; - ssize_t r; - sbuf[0] = 0x8e; - sbuf[1] = note; - sbuf[2] = 0; - r = snd_rawmidi_write(midi_out, sbuf, 3); - if ( r != 3 ) { - printf("snd_rawmidi_write said %li\n", r); - } - usleep(1000); } -struct led_callback_data +static void button_note_on(struct button *but, lo_address osc_send_addr) { - int red; - int orange; - int green; - snd_rawmidi_t *midi_out; -}; + char tmp[256]; + snprintf(tmp, 255, "/x1k2/buttons/%s/press", but->name); + lo_send(osc_send_addr, tmp, ""); +} -static int led_handler(const char *path, const char *types, lo_arg **argv, - int argc, lo_message msg, void *vp) +static int button_set_led_handler(const char *path, const char *types, + lo_arg **argv, int argc, + lo_message msg, void *vp) { - struct led_callback_data *cb = vp; + struct button *but = vp; if ( strcmp("red", &argv[0]->s) == 0 ) { - send_note_on(cb->midi_out, cb->red); + send_note_on(midi_out, but->led_red); } else if ( strcmp("orange", &argv[0]->s) == 0 ) { - send_note_on(cb->midi_out, cb->orange); + send_note_on(midi_out, but->led_orange); } else if ( strcmp("green", &argv[0]->s) == 0 ) { - send_note_on(cb->midi_out, cb->green); + send_note_on(midi_out, but->led_green); } else if ( strcmp("off", &argv[0]->s) == 0 ) { /* Usually, turning off any one of the colours turns off the @@ -256,10 +402,10 @@ static int led_handler(const char *path, const char *types, lo_arg **argv, * left button's LED is weird, I think because it's * also the "layer" button. It can only be switched off * from the same colour. So, we force it to be red. */ - if ( cb->red == 12 ) { - send_note_on(cb->midi_out, cb->red); + if ( but->led_red == 12 ) { + send_note_on(midi_out, but->led_red); } - send_note_off(cb->midi_out, cb->red); + send_note_off(midi_out, but->led_red); } else { fprintf(stderr, "Unrecognised LED mode '%s'\n", &argv[0]->s); } @@ -268,103 +414,114 @@ static int led_handler(const char *path, const char *types, lo_arg **argv, } -static int pot_set_pickup_handler(const char *path, const char *types, lo_arg **argv, - int argc, lo_message msg, void *vp) +static void add_button_methods(struct button *but, lo_server osc_server) { - return 1; + char tmp[256]; + snprintf(tmp, 255, "/x1k2/buttons/%s/set-led", but->name); + lo_server_add_method(osc_server, tmp, "s", button_set_led_handler, but); } -static void handle_note_off(int note, int vel, lo_address osc_send_addr) +static void show_help(const char *s) { - int i; + printf("Syntax: %s [-h] [-d /dev/snd/midiXXXX]\n\n", s); + printf("MIDI to OSC interface for A&H Xone:K2\n" + "\n" + " -h, --help Display this help message.\n" + " -d, --device MIDI device name.\n"); +} - for ( i=0; i