/* * x1k2-midi-osc.c * * (c) 2023 Thomas White * * X1K2-midi-osc is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * X1K2-midi-osc is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with X1K2-midi-osc. If not, see . * */ #include #include #include #include #include #include struct faderpot { int id; int cc_val; int physical_value; int physical_value_known; int enabled; int pickup_value; int has_button_and_led; int button; int led_green; int led_orange; int led_red; const char *type; }; struct encoder { int id; int cc_val; int enabled; int fine_button; int fine_active; int has_led; int led_green; int led_orange; int led_red; }; struct button { const char *name; int note; int led_green; int led_orange; int led_red; }; struct button buttons[18]; struct encoder encoders[6]; struct faderpot faders[4]; struct faderpot potentiometers[12]; int n_buttons = 18; int n_encoders = 6; int n_faders = 4; int n_potentiometers = 12; static void init_fader(struct faderpot *fad, int id, int cc_val) { fad->id = id; fad->cc_val = cc_val; fad->physical_value = 0; fad->physical_value_known = 0; fad->pickup_value = 0; fad->has_button_and_led = 0; fad->enabled = 0; fad->type = "faders"; } static void init_potentiometer(struct faderpot *fad, int id, int cc_val, int button) { fad->id = id; fad->cc_val = cc_val; fad->physical_value = 0; fad->physical_value_known = 0; fad->pickup_value = 0; fad->has_button_and_led = 1; fad->button = button; fad->led_red = button; fad->led_orange = button+36; fad->led_green = button+72; fad->enabled = 0; fad->type = "potentiometers"; } 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); 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); } static void init_encoder_noled(struct encoder *enc, int id, int cc_val, int fine_button) { enc->id = id; enc->cc_val = cc_val; enc->fine_button = fine_button; enc->fine_active = 0; enc->has_led = 0; } static void init_encoder(struct encoder *enc, int id, int cc_val, int fine_button) { enc->id = id; enc->cc_val = cc_val; enc->fine_button = fine_button; enc->fine_active = 0; enc->has_led = 1; enc->led_red = fine_button; enc->led_orange = fine_button+36; enc->led_green = fine_button+72; } static void add_encoder_methods(struct encoder *enc, lo_server osc_server) { 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 init_button_full(struct button *but, const char *name, int note, int r, int o, int g) { but->name = name; but->note = note; but->led_red = r; but->led_orange = o; but->led_green = g; } static void init_button(struct button *but, const char *name, int note) { init_button_full(but, name, note, note, note+36, note+72); } static void add_button_methods(struct button *but, lo_server osc_server) { 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 show_help(const char *s) { 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"); } static void error_callback(int num, const char *msg, const char *path) { fprintf(stderr, "liblo error %i (%s) for path %s\n", num, msg, path); } 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); } struct led_callback_data { int red; int orange; int green; snd_rawmidi_t *midi_out; }; static int led_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *vp) { struct led_callback_data *cb = vp; if ( strcmp("red", &argv[0]->s) == 0 ) { send_note_on(cb->midi_out, cb->red); } else if ( strcmp("orange", &argv[0]->s) == 0 ) { send_note_on(cb->midi_out, cb->orange); } else if ( strcmp("green", &argv[0]->s) == 0 ) { send_note_on(cb->midi_out, cb->green); } else if ( strcmp("off", &argv[0]->s) == 0 ) { /* Usually, turning off any one of the colours turns off the * LED, regardless of the current colour. However, the bottom * 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); } send_note_off(cb->midi_out, cb->red); } else { fprintf(stderr, "Unrecognised LED mode '%s'\n", &argv[0]->s); } return 1; } static int pot_set_pickup_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *vp) { return 1; } static void handle_note_off(int note, int vel, lo_address osc_send_addr) { int i; for ( i=0; i 0 ); memmove(midi_buf, midi_buf+total_proc, 4096-total_proc); midi_buf_pos -= total_proc; } } } } while ( 1 ); snd_rawmidi_drain(midi_in); snd_rawmidi_close(midi_in); snd_rawmidi_drain(midi_out); snd_rawmidi_close(midi_out); return 0; }