lathoub / Arduino-USBMIDI

Allows a microcontroller, with native USB capabilities, to appear as a MIDI device over USB to a connected computer
MIT License
148 stars 11 forks source link

Example MIDI DIN2USB does not work with Leonardo #22

Open steinundfloete opened 1 year ago

steinundfloete commented 1 year ago

I did test example MIDI_DIN2USB from USB-MIDI library v1.12 with Arduino Pro Micro (Leonardo)

Sending control change B0,07,7f from PC to Arduino USB MIDI. logging of the (modified) sketch printed out the correct bytes were received from Arduino USB, but they were not forwarded to my MIDI device.

For testing, i was just connecting MIDI DIN out -> MIDI DIN in on my Arduino board. (The way then would be PC -> Arduino USB -> Arduino DIN out -> Arduino DIN in -> Arduino USB -> PC)

I sended again from PC -> USB 3 times nothing was received from serial MIDI. When sending the same control change to USB the 4th time, it got fancy: Suddenly data was received from Serial MIDI but not the original data, (see logging below) It was forwarded to USB and on the PC but it received b0,00,00 like hell It did not stop to send it again and again, I had to unplug the usb cable to stop it.

All best Uli Schmidt

here the sketch and logging:

#define VERBOSE

#include <USB-MIDI.h>
USING_NAMESPACE_MIDI;

typedef USBMIDI_NAMESPACE::usbMidiTransport __umt;
typedef MIDI_NAMESPACE::MidiInterface<__umt> __ss;
__umt usbMIDI(0);  // cableNr
__ss MIDICoreUSB((__umt&)usbMIDI);

typedef Message<MIDI_NAMESPACE::DefaultSettings::SysExMaxSize> MidiMessage;

MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDICoreSerial);

void setup() {
#ifdef VERBOSE
  Serial.begin(115200);
#endif

  MIDICoreUSB.setHandleMessage(onUsbMessage);
  MIDICoreSerial.setHandleMessage(onSerialMessage);

  MIDICoreUSB.begin(MIDI_CHANNEL_OMNI);
  MIDICoreSerial.begin(MIDI_CHANNEL_OMNI);

  //  MIDICoreUSB.turnThruOff();
  //  MIDICoreSerial.turnThruOff();

}

void loop() {
  MIDICoreUSB.read();
  MIDICoreSerial.read();
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void onUsbMessage(const MidiMessage& message) {
  MIDICoreSerial.send(message);
#ifdef VERBOSE
  printMsg("usb ", message);
#endif
}

void onSerialMessage(const MidiMessage& message) {
  MIDICoreUSB.send(message);

#ifdef VERBOSE
  printMsg("ser ", message);
#endif
}

#ifdef VERBOSE
void printMsg(const char* from, const MidiMessage& message) {
  Serial.print(from);
  Serial.print(message.type, HEX);

  switch (message.type & 0xf0) {
    case 0xf0:  // sysex
      Serial.print(" SysEx size=");
      Serial.println(message.getSysExSize());
      return;
    case 0xc0:  // ProgramChange - 1 byte messages
    case 0xd0:  // AfterTouchChannel
      Serial.print(" ");
      Serial.print(message.data1, HEX);
      break;
    case 0x80:  // NoteOff - 2 byte messages
    case 0x90:  // NoteOn
    case 0xa0:  // AfterTouchPoly
    case 0xb0:  // ControlChange
    case 0xe0:  // PitchBend
      Serial.print(" ");
      Serial.print(message.data1, HEX);
      Serial.print(" ");
      Serial.print(message.data2, HEX);
      break;
    default:
      break;
  }
  Serial.print(" len=");
  Serial.print(message.length);
  Serial.print(" valid=");
  Serial.print(message.valid);
  Serial.print(" channel=");
  Serial.println(message.channel, HEX);

}
#endif

01:18:10.615 -> usb B0 7 7F
01:18:12.436 -> usb B0 7 7F
01:18:14.015 -> usb B0 7 7F
01:18:14.015 -> ser B0 B0 B0
01:18:14.015 -> ser B0 30 30
01:18:14.015 -> ser B0 30 30
01:18:14.015 -> ser B0 30 30
01:18:14.015 -> ser B0 30 30
01:18:14.015 -> ser B0 30 30
01:18:14.015 -> ser B0 30 30
01:18:14.015 -> ser B0 30 30
......................... goes on forever!
lathoub commented 1 year ago

Did you look at this?

(I'm not going to download the sketch zip (not a best practice on GitHub), please paste your code here using the MarkDown code syntax).

steinundfloete commented 1 year ago

I was looking at this before... the solution is not clear yet... have to read further :) I was doing 2 additional tests

If I get this all to work, I can test it on the RP2040 (which I got last week). If you're interested, I'll share my experiences ;)

steinundfloete commented 1 year ago

code is now pasted on the prev message

lathoub commented 1 year ago

Does it work without the modified SysEx? (SysEx is always tricky)

steinundfloete commented 1 year ago

Well SysEx would be the next step... but first notes + controllers should work

steinundfloete commented 1 year ago

Test success... I set the message.length to the real message length now. Notes are played now -> I was creating a new message instance and copied all fields (SysEx not yet) but manually set the length field. Works. If I copy the length from the original message (=0), it doesn't work

steinundfloete commented 1 year ago

Sending original SysEx message from USB to DIN is not received on device. But there the length field is correct. F0,3E,00,7F,01,00,F7

type=F0 data1=7 data2=0 valid=true channel=0 length=7 getSysExSize()=7 sSysExMaxSize=256

steinundfloete commented 1 year ago

That could be a problem... from MIDI.hpp

           // sysexArray does not contain the start and end tags
            mTransport.write(MidiType::SystemExclusiveStart);
            for (size_t i = 0; i < inMessage.getSysExSize(); i++)
                mTransport.write(inMessage.sysexArray[i]);

            mTransport.write(MidiType::SystemExclusiveEnd);

I'll check if the sysex array contains F0 + F7 If so, it can't work

steinundfloete commented 1 year ago

It does. Will test without

steinundfloete commented 1 year ago

Ok, my conclusion for SysEx (via setHandleMessage(...)) is the following: Arduino receives SysEx:

Then it works perfect.

steinundfloete commented 1 year ago

Oh no. No it's getting strange again I have a Waldorf Microwave here + Editor The Editor requests a program by sending F0 3E 0 0 2 0 F7 Waldorf replies with a sound dump (187 bytes) F0 3E 0 0 42 10 38 40 2 0 1 15 43 1 44 0 10 0 48 2 0 1 15 39 0 33 0 0 4 26 1 4A 40 5B 0 C 40 0 40 1 1E 8 11 7F 40 69 0 C 68 0 40 1 0 30 50 0 7F 5C 68 40 0 15 40 0 40 40 0 4E 40 7F 0 C 40 0 40 0 40 2 2F 38 47 6 25 6 40 9 40 6 35 0 0 4 1B 10 46 0 40 7 1B 6 2B 9 40 8 40 0 0 37 2A 3 1C 32 46 7B 5B 11 1E 0 0 0 0 0 6 40 9 40 3 0 0 21 0 40 3 16 40 16 1 A 0 0 8 0 40 4 0 0 40 0 7F 0 20 1 0 43 68 72 69 73 74 27 20 42 65 6C 6C 73 20 20 20 36 0 11 40 4B 6C 0 0 0 20 7F 0 0 4A 68 55 24 F7

Which is fine until being received from PC via USB. Suddenly we have an unexpected 0 after F0 in the message f0 00 3e 00 00 42 and so on

steinundfloete commented 1 year ago

Tested with smaller sysex (GlobalParameterDump) Request by F0 3E 00 00 0A 00 F7 Response (received on Arduino Serial MIDI in): F0 3E 00 00 4A 7F 7F 40 01 00 00 00 00 01 01 01 01 01 01 01 01 01 01 49 F7 From Arduino sending to usb (without f0+f7) 3E 00 00 4A 7F 7F 40 01 00 00 00 00 01 01 01 01 01 01 01 01 01 01 49 received on PC F0 00 3E 00 00 4A 7F 7F 40 01 00 00 00 00 01 01 01 01 01 01 01 01 01 01 49 F7

steinundfloete commented 1 year ago

Seems it doesn't happen when sending to serial MIDI, otherwise the Synth wouldn't reply So this is a problem of the USB Midi

steinundfloete commented 1 year ago

Any idea?

lathoub commented 1 year ago

Have you tried sending SysEx through USB, hardcoded, without the Serial USB in the code. So send the SysEx every second like in the example code. (and put Serial.print in the USB write code).

Most of the write code is here: https://github.com/lathoub/Arduino-USBMIDI/blob/ab62611b9ef50a32875910d4af74eea260bbdcde/src/USB-MIDI.h#L103-L117

Add some Serial.print and see what is being send

steinundfloete commented 1 year ago

Yes, this works. It looks like I did some mistake on copying the bytes. But did you recognize the other things I mentioned?

lathoub commented 1 year ago

But did you recognize the other things I mentioned?

A bit, the begin- and end sysEx brings back the programming memories.

Yes, this works. It looks like I did some mistake on copying the bytes.

So, all good?

steinundfloete commented 1 year ago

Without modifying the incoming message it will not work. That is what I experienced here

steinundfloete commented 1 year ago

Shortmessages: I have to set the message.length to the real message length then it works. The received message contains a length of 0. This doesn't work

steinundfloete commented 1 year ago

SysEx Messages: The received message struct, length + coded length (data1+2) always contain F0+F7 forwarding the SysEx Message to USB / Serial: You have to