All of lore.kernel.org
 help / color / mirror / Atom feed
* rawmidi driver dropping some sysex commands
@ 2021-12-10  4:31 Kolten Pearson
  2021-12-17 19:45 ` John Keeping
  0 siblings, 1 reply; 2+ messages in thread
From: Kolten Pearson @ 2021-12-10  4:31 UTC (permalink / raw)
  To: alsa-devel

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!

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: rawmidi driver dropping some sysex commands
  2021-12-10  4:31 rawmidi driver dropping some sysex commands Kolten Pearson
@ 2021-12-17 19:45 ` John Keeping
  0 siblings, 0 replies; 2+ messages in thread
From: John Keeping @ 2021-12-17 19:45 UTC (permalink / raw)
  To: Kolten Pearson; +Cc: alsa-devel

On Thu, Dec 09, 2021 at 09:31:12PM -0700, Kolten Pearson wrote:
> 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);

You're opening in non-blocking mode here, which may affect the behaviour
later...

>     int count = snd_rawmidi_write(midi_output, raw_command,
> sizeof(raw_command));
>     assert(count == sizeof(raw_command) && "bad write");

Are you definitely compiling with these asserts enabled?  Have you
considered:

	if (count != sizeof(raw_command))
		warnx("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?

How is the Arturia device connected?  Is it USB?

I wonder if it is the device that is dropping the data.  Normally USB
MIDI devices will NAK transfers if they are unable to process data but
maybe that is not happening here.

You may be able to use usbmon and Wireshark to capture the USB traffic
to the device and confirm whether the data is being sent over the bus or
if it is being lost in the rawmidi layer somehow.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-12-17 19:46 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-12-10  4:31 rawmidi driver dropping some sysex commands Kolten Pearson
2021-12-17 19:45 ` John Keeping

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.