tttapa / MIDI_controller

This is a library for creating a MIDI controller using an Arduino or Teensy board.
GNU General Public License v3.0
402 stars 70 forks source link

FeatureReq - Send SysEx message on button press #51

Open mungewell opened 6 years ago

mungewell commented 6 years ago

A little request; to be able to send a SysEx command when a button is pressed.

I imagine that this would be a new definition (say 'DigitalSysEx()') and take a string of hex digits which would be sent each time the button was pressed.

This is respect to creating a start/stop device for the Akai MPC, as seen here: https://www.youtube.com/watch?v=2PngH1TE_dA

Required SysEx are described here: https://www.dropbox.com/s/71crq2qvd378zbg/MPC%20and%20MC6%20Editor%20Notes.pdf?dl=0

Thanks, Simon.

mungewell commented 6 years ago

I had a go at implementing: https://github.com/mungewell/MIDI_controller/tree/20180627_DigitalSE

it compiles, but I don't have an Arduino to test it on (they're on order).

tttapa commented 6 years ago

I plan on restructuring the Digital and Analog classes to make them less dependent on the send implementation. Once that's done, adding SysEx support should be easy.

mungewell commented 6 years ago

After circling around for quite a while with a very puzzled look, I finally realized that the board (Arduino UNO) I am using is actually using the serial port (rather than USB) and got something coming out of the port.

Then the 2nd realization struck - arduino_midi doesn't support SysEx: https://github.com/ddiakopoulos/hiduino/issues/20

Well some progress was made.... and a few bugs were squashed.

Might work for other boards.

mungewell commented 6 years ago

I should add the Uno is borrowed, whilst I wait for my Pro Micros to arrive. The Micros appear to have inbuilt USB, so I'm still hopeful it will work.

mungewell commented 6 years ago

Note to self: https://github.com/PaulStoffregen/cores/blob/master/usb_midi/usb_api.cpp#L33

tttapa commented 6 years ago

I see that you use separate bytes to pass to the constructor. You could pass the SysEx as an array: either as a pointer to the first element of the array (C-style):

void sendSysEx(uint8_t *data, size_t length) {
  for (size_t i = 0; i < length; i++) {
    Serial.println(data[i]);
  }
}

Alternatively, you can use a reference to an array (C++-style):

template <size_t N>
void sendSysEx(uint8_t (&data)[N]) {
  for (const uint8_t &data_byte : data) {
    Serial.println(data_byte);
  }
}

I use this approach at multiple points in the library already, for example here: https://github.com/tttapa/Control-Surface/blob/1293f468d0cbacf1039d41bf5584ca8b17bc8f76/src/ExtendedInputOutput/AnalogMultiplex.h#L12
One thing to keep in mind is that if you initialize it using a brace-enclosed initializer list, the lifetime of the array is the lifetime of the function. If the function in question is a constructor, you can't just save the array reference, you have to copy it.

mungewell commented 6 years ago

Found this other implementation of the UNO MIDI firmware: https://github.com/TheKikGen/USBMidiKliK

It's passing the SysEx stream, but for some reason I am having missing bytes....

mungewell commented 6 years ago

Still having difficulties with that alternative, seems that sending 5 bytes is broken but 6 bytes work...

Found another alternative (via pedalino which uses your code): https://github.com/alf45tar/Pedalino https://github.com/kuwatay/mocolufa

On the topic of creating instance with bytes or array, I figured that bytes might be easier for a not-to technical person. Happy either way.... when creating banks of buttons does it matter?