Serial MIDI to USB and USB to MIDI Serial Howto?

Hi everyone, first post. I'm new to arduino programming, and I just got an arduino DUE.

I really want/need a USB midi interface, and, instead of buying a simple midi to usb cable to control mi synths and mi DAW using an old midi keyboard, I thought "Hey, and arduino must be a lot better option".

It turns out it is not that simple, and I'm very frustrated. I tested some midi out examples (not using USB) and it works just fine.

I think understand how to create and program a midi controller, and I know about electronics. The code for supposed to be fairly easy using some libraries, right? Isn't it allready available? AM I totally mistaken?

Please help! I've allready read like a thousand articles on how to create a midi controller, and no one mentions this, not on a DUE at least.

:sob: :sob: :sob:

Look at the standard MIDI library it has just been updated in the last few weeks.

It will allow you to use various transport systems, use a serial port for the input and transfer it to to USB-MIDI output. There are examples that come with the library that show you how to have more than one interface.

The Control Surface library allows you to easily create MIDI controllers, and has flexible MIDI routing options.

For example: MIDI_Pipes-Routing.ino

The following code bridges the USB and Serial MIDI interfaces: all data that's received on the Serial interface is sent to the USB interface, and all data that's received on the USB interface is sent to the Serial interface.

#include <Control_Surface.h>

// Instantiate two MIDI interfaces
USBMIDI_Interface midiusb;
HardwareSerialMIDI_Interface midiser = Serial1;

// Bidirectional pipe that routes MIDI traffic
BidirectionalMIDI_Pipe pipe;

void setup() {
  midiusb | pipe | midiser; // bridge the USB and Serial MIDI interfaces
  midiusb.setAsDefault();   // Select the interface that will be used by Control Surface
  Control_Surface.begin();
}
 
void loop() {
  // Routes all MIDI traffic and updates MIDI control elements
  Control_Surface.loop();
}

Pieter

Hey, thank you Pieter and Mike !! Glad to hear from you. But anyway, I see a lot of errors when compiling many library examples.

This is the output I get when trying the Control_Surface example @PieterP just posted, using latest Arduino IDE and latest Control-surface-master library downloaded from Github:

es\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

     MIDIAddress;

                ^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

     MIDIAddress;

                ^

In file included from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Inputs\MIDIInputElement.hpp:6:0,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Inputs\MIDIInputElementChannelPressure.hpp:3,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Inputs\MIDIInputElementChannelPressure.cpp:1:

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:57:80: warning: 'deprecated' attribute directive ignored [-Wattributes]

 using MIDICNChannel [[deprecated("Use MIDIChannelCN instead")]] = MIDIChannelCN;

                                                                                ^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

     MIDIAddress;

                ^

In file included from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/MIDI_Inputs/MIDIInputElement.hpp:6:0,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Inputs\MIDIInputElementCC.hpp:4,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Inputs\MIDIInputElementCC.cpp:1:

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:57:80: warning: 'deprecated' attribute directive ignored [-Wattributes]

 using MIDICNChannel [[deprecated("Use MIDIChannelCN instead")]] = MIDIChannelCN;

                                                                                ^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

     MIDIAddress;

                ^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

     MIDIAddress;

                ^

In file included from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/MIDI_Inputs/MIDIInputElement.hpp:6:0,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/MIDI_Inputs/MIDIInputElementSysEx.hpp:3,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Inputs\MCU\LCD.hpp:5,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Inputs\MCU\LCD.cpp:1:

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:57:80: warning: 'deprecated' attribute directive ignored [-Wattributes]

 using MIDICNChannel [[deprecated("Use MIDIChannelCN instead")]] = MIDIChannelCN;

                                                                                ^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

     MIDIAddress;

                ^

In file included from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\MIDI_Interface.hpp:6:0,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\MIDI_Interface.cpp:1:

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:57:80: warning: 'deprecated' attribute directive ignored [-Wattributes]

 using MIDICNChannel [[deprecated("Use MIDIChannelCN instead")]] = MIDIChannelCN;

                                                                                ^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

     MIDIAddress;

                ^

In file included from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\MIDI_Interface.hpp:6:0,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\SerialMIDI_Interface.hpp:3,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\DebugMIDI_Interface.hpp:3,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\DebugMIDI_Interface.cpp:1:

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:57:80: warning: 'deprecated' attribute directive ignored [-Wattributes]

 using MIDICNChannel [[deprecated("Use MIDIChannelCN instead")]] = MIDIChannelCN;

                                                                                ^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

     MIDIAddress;

                ^

In file included from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/MIDI_Interfaces/MIDI_Interface.hpp:6:0,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Control_Surface/Control_Surface_Class.hpp:10,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Senders\RelativeCCSender.hpp:3,

                 from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Senders\RelativeCCSender.cpp:1:

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:57:80: warning: 'deprecated' attribute directive ignored [-Wattributes]

 using MIDICNChannel [[deprecated("Use MIDIChannelCN instead")]] = MIDIChannelCN;

                                                                                ^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

     MIDIAddress;

                ^

In file included from C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.cpp:17:0:

C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.cpp: In member function 'virtual int MIDI_::getInterface(uint8_t*)':

C:\Users\felipe\AppData\Local\Arduino15\packages\arduino\hardware\sam\1.6.12\cores\arduino/USB/USBCore.h:93:56: warning: narrowing conversion of '(int)((MIDI_*)this)->MIDI_::<anonymous>.PluggableUSBModule::pluggedEndpoint' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

 #define USB_ENDPOINT_OUT(addr)                 ((addr) | 0x00)

                                                        ^

C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.h:187:10: note: in definition of macro 'D_MIDI_JACK_EP'

  { 9, 5, _addr,_attr,_packetSize, 0, 0, 0}

          ^

C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.cpp:53:18: note: in expansion of macro 'USB_ENDPOINT_OUT'

   D_MIDI_JACK_EP(USB_ENDPOINT_OUT(MIDI_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,MIDI_BUFFER_SIZE),

                  ^

C:\Users\felipe\AppData\Local\Arduino15\packages\arduino\hardware\sam\1.6.12\cores\arduino/USB/USBCore.h:94:56: warning: narrowing conversion of '(int)((((MIDI_*)this)->MIDI_::<anonymous>.PluggableUSBModule::pluggedEndpoint + 1u) | 128u)' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

 #define USB_ENDPOINT_IN(addr)                  ((addr) | 0x80)

                                                        ^

C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.h:187:10: note: in definition of macro 'D_MIDI_JACK_EP'

  { 9, 5, _addr,_attr,_packetSize, 0, 0, 0}

          ^

C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.cpp:55:18: note: in expansion of macro 'USB_ENDPOINT_IN'

   D_MIDI_JACK_EP(USB_ENDPOINT_IN(MIDI_ENDPOINT_IN),USB_ENDPOINT_TYPE_BULK,MIDI_BUFFER_SIZE),

                  ^

I'm probably doing something wrong, but what? Thanks again for your help guys, I really appreciate it!

Without the code the compiler error is hard or almost impossible to find.
So can we have all your code please.

el_fela:
Hey, thank you Pieter and Mike !! Glad to hear from you. But anyway, I see a lot of errors when compiling many library examples.

This is the output I get when trying the Control_Surface example @PieterP just posted, using latest Arduino IDE and latest Control-surface-master library downloaded from Github:

es\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

MIDIAddress;

^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

MIDIAddress;

^

In file included from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\MIDI_Interface.hpp:6:0,

from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\MIDI_Interface.cpp:1:

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:57:80: warning: 'deprecated' attribute directive ignored [-Wattributes]

using MIDICNChannel [[deprecated("Use MIDIChannelCN instead")]] = MIDIChannelCN;

^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

MIDIAddress;

^

In file included from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\MIDI_Interface.hpp:6:0,

from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\SerialMIDI_Interface.hpp:3,

from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\DebugMIDI_Interface.hpp:3,

from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Interfaces\DebugMIDI_Interface.cpp:1:

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:57:80: warning: 'deprecated' attribute directive ignored [-Wattributes]

using MIDICNChannel [[deprecated("Use MIDIChannelCN instead")]] = MIDIChannelCN;

^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

MIDIAddress;

^

In file included from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/MIDI_Interfaces/MIDI_Interface.hpp:6:0,

from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Control_Surface/Control_Surface_Class.hpp:10,

from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Senders\RelativeCCSender.hpp:3,

from C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src\MIDI_Senders\RelativeCCSender.cpp:1:

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:57:80: warning: 'deprecated' attribute directive ignored [-Wattributes]

using MIDICNChannel [[deprecated("Use MIDIChannelCN instead")]] = MIDIChannelCN;

^

C:\Users\felipe\Documents\Arduino\libraries\Control-Surface-master\src/Def/MIDIAddress.hpp:276:16: warning: 'deprecated' attribute directive ignored [-Wattributes]

MIDIAddress;

^

In file included from C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.cpp:17:0:

C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.cpp: In member function 'virtual int MIDI_::getInterface(uint8_t*)':

C:\Users\felipe\AppData\Local\Arduino15\packages\arduino\hardware\sam\1.6.12\cores\arduino/USB/USBCore.h:93:56: warning: narrowing conversion of '(int)((MIDI_*)this)->MIDI_::.PluggableUSBModule::pluggedEndpoint' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

#define USB_ENDPOINT_OUT(addr)                ((addr) | 0x00)

^

C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.h:187:10: note: in definition of macro 'D_MIDI_JACK_EP'

{ 9, 5, _addr,_attr,_packetSize, 0, 0, 0}

^

C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.cpp:53:18: note: in expansion of macro 'USB_ENDPOINT_OUT'

D_MIDI_JACK_EP(USB_ENDPOINT_OUT(MIDI_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,MIDI_BUFFER_SIZE),

^

C:\Users\felipe\AppData\Local\Arduino15\packages\arduino\hardware\sam\1.6.12\cores\arduino/USB/USBCore.h:94:56: warning: narrowing conversion of '(int)((((MIDI_*)this)->MIDI_::.PluggableUSBModule::pluggedEndpoint + 1u) | 128u)' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

#define USB_ENDPOINT_IN(addr)                  ((addr) | 0x80)

^

C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.h:187:10: note: in definition of macro 'D_MIDI_JACK_EP'

{ 9, 5, _addr,_attr,_packetSize, 0, 0, 0}

^

C:\Users\felipe\Documents\Arduino\libraries\MIDIUSB\src\MIDIUSB.cpp:55:18: note: in expansion of macro 'USB_ENDPOINT_IN'

D_MIDI_JACK_EP(USB_ENDPOINT_IN(MIDI_ENDPOINT_IN),USB_ENDPOINT_TYPE_BULK,MIDI_BUFFER_SIZE),

^




I'm probably doing something wrong, but what? Thanks again for your help guys, I really appreciate it!

Those all look like warnings to me. The code I posted compiles fine for me for the Arduino SAM Core version 1.6.12 and Arduino IDE version 1.8.9.

The warning: 'deprecated' attribute directive ignored [-Wattributes] warnings are caused by the ancient compiler that's used by the Due toolchain, it doesn't understand the "deprecated" attribute yet. It's not an error, the compiler simply ignores it.

The other warnings in the MIDIUSB library are narrowing conversions that shouldn't be there, but are pretty harmless nonetheless.

If the code fails to compile, you'll have to post the full output and code, because I can't find any errors in the part of the output you posted.

Hey,thanks again for answering! I thought it was some obvious thing.

I made it work using this code:

/**
 * MIDI routing using MIDI_Pipe%s.
 * 
 * Bridges the USB MIDI interface to a Serial MIDI interface, and loops back
 * anything it receives on the USB interface.
 * 
 * You can also use the MIDI pipes to route the input and output of Control 
 * Surface itself, not just the input and output of MIDI interfaces. This is
 * demonstrated in the @ref Dual-MIDI-Interface.ino example.
 * 
 * @boards  AVR USB, Due, Nano 33, Teensy 3.x, ESP32
 */

#include <Control_Surface.h>

USBMIDI_Interface midiusb;
HardwareSerialMIDI_Interface midiser = Serial1;

MIDI_PipeFactory<3> pipes;

void setup() {
  midiusb >> pipes >> midiser; // all incoming midi from USB is sent to serial
  midiusb << pipes << midiser; // all incoming midi from Serial is sent to USB
  midiusb >> pipes >> midiusb; // all incoming midi from USB is looped back

  midiusb.begin();
  midiser.begin();
}

void loop() {
  midiusb.update();
  midiser.update();
}

Anyway I'm soo happy now that something worked!!! 8) 8) 8)

The code that when compiled creates that output is the example project called Dual-MIDI-Interface, without modifications:

/** 
 * This example demonstrates how to group together two or more MIDI interfaces,
 * so you can send the MIDI output over both MIDI USB and 5-pin DIN MIDI, for 
 * example. MIDI input is received from all interfaces as well.
 * 
 * Also have a look at the @ref MIDI_Pipes-Routing.ino example, the
 * @ref MIDI_Routing module and the @ref MIDI_Pipe documentation for more 
 * information about MIDI routing.  
 * Control Surface can be used as both a MIDI sink and a MIDI source.
 * 
 * When you call `Control_Surface.begin()`, it automatically connects itself to 
 * the default MIDI interface (@ref MIDI_Interface::getDefault()).  
 * If you want to route everything manually, you have to connect it before 
 * calling `Control_Surface.begin()`, or you have to disconnect the default 
 * pipes before connecting your own, using 
 * @ref Control_Surface_::disconnectMIDI_Interfaces().
 *
 * @boards  AVR USB, Nano Every, Due, Teensy 3.x
 * 
 * Connections
 * -----------
 * 
 * - A0: wiper of a potentiometer
 * 
 * Connect the left terminal of the potentiometer to ground, and the right one
 * to V<sub>CC</sub>.
 * 
 * Behavior
 * --------
 * 
 * - When you turn the potentiometer, you should receive MIDI Control Change
 *   events on both the Serial MIDI interface and the USB MIDI interface.
 * - When a MIDI Note event for middle C is received on either MIDI interface,
 *   the state of the built-in LED will change accordingly.
 * 
 * Mapping
 * -------
 * 
 * - None
 * 
 * Written by PieterP, 2019-08-22  
 * https://github.com/tttapa/Control-Surface
 */
#include <Control_Surface.h>

// Create two MIDI interfaces
USBMIDI_Interface usbmidi;
HardwareSerialMIDI_Interface serialmidi = {Serial1, MIDI_BAUD};

// Create a MIDI pipe factory to connect the MIDI interfaces to Control Surface
BidirectionalMIDI_PipeFactory<2> pipes;

// Add some MIDI elements to show that the MIDI interfaces actually work
CCPotentiometer pot = {A0, MIDI_CC::General_Purpose_Controller_1};
NoteValueLED led = {LED_BUILTIN, 0x3C};

void setup() {
  // Manually connect the MIDI interfaces to Control Surface
  Control_Surface | pipes | usbmidi;
  Control_Surface | pipes | serialmidi;
  // Initialize Control Surface _after_ connecting the interfaces
  Control_Surface.begin();
}

void loop() {
  Control_Surface.loop();
}

/*
 * The vertical pipe operator (|) is used to make a bidirectional connection 
 * between a MIDI sink or source and a MIDI pipe.
 * You can also use unidirectional pipes. These can be connected using the 
 * stream operators (<< and >>).
 * 
 * For example:
 * 
 *     MIDI_PipeFactory<2> pipes;
 *     ...
 *       Control_Surface >> pipes >> usbmidi;    // Output to usbmidi
 *       Control_Surface << pipes << serialmidi; // Input from serialmidi
 */

ARDUINO: 1.8.12

BOARD INFO:
BN: Arduino Due (Native USB Port)
VID: 0x2341
PID: 0x003e

This information might be helpful for other people :slight_smile:

el_fela:
Could this be a bug? Should I report this?

Could what be a bug?

My mistake, the code that worked using the web ide was this one:

/**
 * MIDI routing using MIDI_Pipe%s.
 * 
 * Bridges the USB MIDI interface to a Serial MIDI interface, and loops back
 * anything it receives on the USB interface.
 * 
 * You can also use the MIDI pipes to route the input and output of Control 
 * Surface itself, not just the input and output of MIDI interfaces. This is
 * demonstrated in the @ref Dual-MIDI-Interface.ino example.
 * 
 * @boards  AVR USB, Due, Nano 33, Teensy 3.x, ESP32
 */

#include <Control_Surface.h>

USBMIDI_Interface midiusb;
HardwareSerialMIDI_Interface midiser = Serial1;

MIDI_PipeFactory<3> pipes;

void setup() {
  midiusb >> pipes >> midiser; // all incoming midi from USB is sent to serial
  midiusb << pipes << midiser; // all incoming midi from Serial is sent to USB
  midiusb >> pipes >> midiusb; // all incoming midi from USB is looped back

  midiusb.begin();
  midiser.begin();
}

void loop() {
  midiusb.update();
  midiser.update();
}

I'll edit my previous post