I have been working on reverse engineering the sysex commands to control an Arturia MiniLab mkII controller, and have run into an issue where the rawmidi driver is dropping some of the commands. Here is a snippet of my code that illustrates the problem --- snd_rawmidi_t* midi_input; snd_rawmidi_t* midi_output;
void midi_init() { int ret = snd_rawmidi_open(&midi_input, &midi_output, "hw:3,0,0", SND_RAWMIDI_NONBLOCK); assert (ret == 0 && "could not open midi device");
uint8_t pad_list[] = { MA_PAD_1, MPC_NO_COLOR, MA_PAD_2, MPC_RED, MA_PAD_3, MPC_GREEN, MA_PAD_4, MPC_YELLOW, MA_PAD_5, MPC_BLUE, MA_PAD_6, MPC_CYAN, MA_PAD_7, MPC_MAGENTA, MA_PAD_8, MPC_WHITE,
MA_PAD_9, MPC_NO_COLOR, MA_PAD_10, MPC_RED, MA_PAD_11, MPC_GREEN, MA_PAD_12, MPC_YELLOW, MA_PAD_13, MPC_BLUE, MA_PAD_14, MPC_CYAN, MA_PAD_15, MPC_MAGENTA, MA_PAD_16, MPC_WHITE, };
for (int i = 0; i < 16; i++) { midi_set(MC_ON_OFF, pad_list[2*i], 0x08); //sets the pad to be a control instead of a note midi_set(MC_MIN_RANGE, pad_list[2*i], 0); midi_set(MC_MAX_RANGE, pad_list[2*i], 1); midi_set(MC_MODE_SET, pad_list[2*i], 1); //set it to gate, 0 is toggle midi_set(MC_PAD_COLOR, pad_list[2*i], pad_list[2*i+1]); }
midi_set(MC_GLOBAL_SET, MA_PAD_BACKLIGHTS, 0x0f); //updates the pad backlights
uint8_t knob_list[] = { MA_KNOB_1, MA_KNOB_2, MA_KNOB_3, MA_KNOB_4, MA_KNOB_5, MA_KNOB_6, MA_KNOB_7, MA_KNOB_8, MA_KNOB_9, MA_KNOB_10, MA_KNOB_11, MA_KNOB_12, MA_KNOB_13, MA_KNOB_14, MA_KNOB_15, MA_KNOB_16 };
for (int i = 0; i < 16; i++) { midi_set(MC_MODE_SET, knob_list[i], 0x02); //sets it to relative mode where 0-3 is right turn, 7f-7d is left turn midi_set(MC_CC_SET, knob_list[i], i); }
}
void midi_set(enum midi_set_command command, enum midi_set_address address, uint8_t data) {
uint8_t raw_command[] = {0xf0, 0x00, 0x20, 0x6b, 0x7f, 0x42, 0x02, 0x00, command, address, data, 0xf7};
int count = snd_rawmidi_write(midi_output, raw_command, sizeof(raw_command)); assert(count == sizeof(raw_command) && "bad write"); //SDL_Delay(1); int ret = snd_rawmidi_drain(midi_output); assert(ret == 0 && "could not drain"); } --- When this code is run, the minilab will only respond to a nondeterministic number of calls to the midi_set function and ignore the rest. However if the SDL_Delay(1) line is uncommented, it will work correctly every time (This function call causes the process to sleep for at least 1 millisecond).
I feel like the call to snd_rawmidi_drain should make the SDL_Delay call unnecessary, but that is not the case. Is there something I am not understanding about how the api works? Thanks for any help!