Hackster is hosting Hackster Holidays, Finale: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Tuesday!Stream Hackster Holidays, Finale on Tuesday!
Dennis V
Published © GPL3+

USB MIDI Adapter

Simple USB to MIDI adapter based on an Arduino Micro or Leonardo, optionally with the ability to filter the MIDI data.

BeginnerFull instructions provided2 hours24,595
USB MIDI Adapter

Things used in this project

Hardware components

Pro Micro - 5V/16MHz
SparkFun Pro Micro - 5V/16MHz
or other Atmega32U4 board such as Arduino Micro, Arduino Pro Micro or Arduino Leonardo
×1
6n137 Opto coupler
×1
1N4148 – General Purpose Fast Switching
1N4148 – General Purpose Fast Switching
×1
Capacitor 100 nF
Capacitor 100 nF
×1
Resistor 220 ohm
Resistor 220 ohm
×3
Resistor 10k ohm
Resistor 10k ohm
×1
Through Hole Resistor, 470 ohm
Through Hole Resistor, 470 ohm
×1
LED (generic)
LED (generic)
×1
led holder
something to mount the LED in the plastic case
×1
DIN Audio / Video Connector, 5 Contacts
DIN Audio / Video Connector, 5 Contacts
plus bolts and nuts to mount the connectors
×2
Case
A plastic case to fit all the components in
×1
PCB
A piece of generic PCB
×1
PCB mounts
Something to mount your PCB to the case, such as nylon standoffs
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Schematic

Schematic in Fritzing format

Code

Source code for basic MIDI to USB interface

Arduino
/*
 * USB MIDI adapter.
 * 
 * ---
 * 
 * To allow larger sysex packages, modify the Control Surface library as follows:
 * 
 * In:
 * src\MIDI_Parsers\MIDI_MessageTypes.hpp
 * change:
 * uint8_t length;
 * to:
 * size_t length;
 * 
 * In:
 * src/Settings/Settings.hpp
 * change:
 * constexpr size_t SYSEX_BUFFER_SIZE = 128;
 * to:
 * constexpr size_t SYSEX_BUFFER_SIZE = 320;
 * 
 * This should be fixed when Control Surface 2.x will be released.
 * 
 * ---
 * 
 * To use a different USB device name, edit hardware/arduino/avr/boards.txt in the AVR Core.
 * 
 * First go to:
 * Windows: C:\Users\{username}\AppData\Local\Arduino15
 * macOS: /Users/{username}/Library/Arduino15
 * Linux: home/{username}/.arduino15
 * 
 * Then find boards.txt in the AVR core (the version in the path might be different):
 * packages\arduino\hardware\avr\1.8.6\boards.txt
 * 
 * Change:
 * leonardo.build.usb_product="Arduino Leonardo"
 * to:
 * leonardo.build.usb_product="..."
 * change it back after uploading the project to your Arduino device if you want to use the default name for other projects.
 */

#include <Control_Surface.h> // Include the Control Surface library

USBMIDI_Interface midiusb;
// use this one instead to dump all MIDI data to the serial monitor
// USBDebugMIDI_Interface midiusb;
HardwareSerialMIDI_Interface midiser = {Serial1, MIDI_BAUD};

// Create a MIDI pipe factory to connect the MIDI interfaces to eachother and to the Control Surface
MIDI_PipeFactory<5> pipes;

// Example for adding extra controllers:
// CCPotentiometer pot = { A0, MIDI_CC::Expression_Controller };

// pin to which the power LED is connected
const int ledPin = 10;

// setup code
void setup() {
  Serial.begin(115200);

  // turn on the power LED
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  // forward MIDI USB to MIDI serial
  midiusb >> pipes >> midiser;
  // forward MIDI serial to MIDI USB
  midiser >> pipes >> midiusb;
  // send control suface messages only to MIDI USB
  Control_Surface >> pipes >> midiusb;

  // connect both MIDI USB and serial to control surface
  midiser >> pipes >> Control_Surface;
  midiusb >> pipes >> Control_Surface;

  // initialize Control Surface _after_ connecting the interfaces
  Control_Surface.begin();
}

// main processing loop
void loop() {
  Control_Surface.loop();
}

Source code for MIDI to USB adapter with "all notes off" filter

Arduino
/*
 * USB MIDI adapter with "all notes off" filter.
 * 
 * ---
 * 
 * To allow larger sysex packages, modify the Control Surface library as follows:
 * 
 * In:
 * src\MIDI_Parsers\MIDI_MessageTypes.hpp
 * change:
 * uint8_t length;
 * to:
 * size_t length;
 * 
 * In:
 * src/Settings/Settings.hpp
 * change:
 * constexpr size_t SYSEX_BUFFER_SIZE = 128;
 * to:
 * constexpr size_t SYSEX_BUFFER_SIZE = 320;
 * 
 * This should be fixed when Control Surface 2.x will be released.
 * 
 * ---
 * 
 * To use a different USB device name, edit hardware/arduino/avr/boards.txt in the AVR Core.
 * 
 * First go to:
 * Windows: C:\Users\{username}\AppData\Local\Arduino15
 * macOS: /Users/{username}/Library/Arduino15
 * Linux: home/{username}/.arduino15
 * 
 * Then find boards.txt in the AVR core (the version in the path might be different):
 * packages\arduino\hardware\avr\1.8.6\boards.txt
 * 
 * Change:
 * leonardo.build.usb_product="Arduino Leonardo"
 * to:
 * leonardo.build.usb_product="..."
 * change it back after uploading the project to your Arduino device if you want to use the default name for other projects.
 */

#include <Control_Surface.h> // Include the Control Surface library

USBMIDI_Interface midiusb;
// use this one instead to dump all MIDI data to the serial monitor
// USBDebugMIDI_Interface midiusb;
HardwareSerialMIDI_Interface midiser = {Serial1, MIDI_BAUD};

// Create a MIDI pipe factory to connect the MIDI interfaces to eachother and to the Control Surface
MIDI_PipeFactory<4> pipes;

// Example for adding extra controllers:
// CCPotentiometer pot = { A0, MIDI_CC::Expression_Controller };

// pin to which the power LED is connected
const int ledPin = 10;

// Custom MIDI callback that prints incoming messages.
struct MyMIDI_Callbacks : MIDI_Callbacks {
 
  // Callback for channel messages (notes, control change, pitch bend, etc.).
  void onChannelMessage(Parsing_MIDI_Interface &midi) override {
    ChannelMessage cm = midi.getChannelMessage();

    if (cm.header == 0xb0 && cm.data1 == 0x7b) {
      // ignore "all notes off" messages
      return;
    } else if (cm.header == 0x90 && cm.data2 == 0x00) {
      // convert "note on" messages with velocity of 0 to "note off" messages
      cm.header = 0x80;
    }

    midiusb.send(cm);
  }
 
  // Callback for system exclusive messages
  void onSysExMessage(Parsing_MIDI_Interface &midi) override {
    SysExMessage se = midi.getSysExMessage();

    // forward system exclusive messages without changes
    midiusb.send(se);
  }
 
  // Callback for real-time messages
  void onRealTimeMessage(Parsing_MIDI_Interface &midi) override {
    RealTimeMessage rt = midi.getRealTimeMessage();

    // forward real-time messages without changes
    midiusb.send(rt);
  }
 
} callbacks;

// setup code
void setup() {
  Serial.begin(115200);

  // turn on the power LED
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  // forward MIDI USB to MIDI serial
  midiusb >> pipes >> midiser;
  // send control suface messages only to MIDI USB
  Control_Surface >> pipes >> midiusb;

  // connect both MIDI USB and serial to control surface
  midiser >> pipes >> Control_Surface;
  midiusb >> pipes >> Control_Surface;

  // initialize Control Surface _after_ connecting the interfaces
  Control_Surface.begin();

  // set the callback methods
  midiser.setCallbacks(callbacks);
}

// main processing loop
void loop() {
  Control_Surface.loop();
}

Credits

Dennis V
2 projects • 7 followers

Comments