loading

UPDATE (03-04-2017):You can find an updated version of the code on my GitHub. All things hardware related in this Instructable are still valid, but the code has been updated. Things like TeeOnArdu no longer work with the newer versions of the Arduino IDE, so use the code from GitHub instead.

If you're interested in an updated version of this Instructable, just leave a comment or send me a message, and if there's a sufficiently high demand (and if I can find the time), I'll try to update it.


Hello, and welcome to this instructable on how to build a custom, cheap and easy USB MIDI controller, based on Arduino. The best news: no hassle with USB-to-MIDI interfaces, or software tools like Hairless MIDI, just plug 'n' play!

I included readable, basic code for both the Arduino Uno (or Mega) and the Leonardo (or Micro), and I created a MIDI controller library, for those not so comfortable with the programming language, or for those who just want a quick controller without having to write the code yourself. (The library is explained in step 13.)

Check out the video of the finished project here.

I've been playing around with both Arduino and DAWs (Digital Audio Workstation) for quite some time now, so when I needed a MIDI controller, I decided to build one myself, rather than buying one.

While browsing through the Google results, I came across Fuzzy-Wobble's instructable "A Framework For Making Affordable & Stylish Modular Controllers (USB to MIDI, HID, or Serial)". The controllers looked amazing, and I really wanted to build a controller like this. The only problem was the fact that Fuzzy-Wobble's controllers were based on Teensy microcontrollers, and I only had a couple Arduino's laying around. So, the search continued ...

Then I found Dimitri Diakopoulos's HIDUINO project. Using his custom firmware, you could let an Arduino show up as a USB MIDI device. More on this in just a second. After playing around with the Uno for some time, I felt kind of limited by the 6 analog inputs of the board. So I took my Arduino Leonardo with its 12 analog inputs, thinking that MIDI over USB should be possible, since it has USB capabilities built in the main chip? Well, not exactly ... A quick Google search told me that the Arduino software didn't support MIDI over USB. Ugh. So I gave up, and continued using the Uno. But a few days later, while browsing Adafruit, I saw this neat product, the Adafruit Trellis, a LED and button matrix. On its own, nothing too spectacular, but one of the related guides was the UNTZtrument MIDI controller, using the Trellis, and - you guessed it - an Arduino Leonardo as microcontroller. In the 'software' part of the tutorial, they explained how they brought MIDI over USB capabilities to the Leonardo.

This is based on the fact that the Leonardo uses the ATmega32u4 microprocessor, that is also used by some Teensies. Some clever guys wrote some code which made it possible to use the Teensy libraries with the Leonardo, and inside the Arduino IDE. So once these special libraries are installed, you can easily use MIDI with the Leonardo, just like with the Uno!

Great, time to design some awesome MIDI controllers, and make a Remix 2.0 of Fuzzy-Wobble's Instructable!

Step 1: Hardware Shopping

There are just 5 things that you really need to build your own MIDI controller, everything else is optional.

Necessary:

  • Arduino or Teensy
  • Potentiometers
  • Potentiometer knobs
  • Wires
  • Enclosure
  • USB cable

I went for the Leonardo + headers, since it's easier to plug in all the wires, instead of having to solder them all to the Arduino. The Leonardo is now 'retired' but the Arduino Micro uses the same chip, so it should work as well. (But I haven't been able to try this, so I can't confirm.

These are the potentiometers I used, and these are the knobs. Make sure your knobs fit your potentiometers! There are three major types of shafts: D-shafts, solid shafts and knurled shafts (mostly with 18 teeth and a slit in the middle). You should also pay attention to the shaft diameter.
I used an old cigar box as an enclosure. The wood is soft, so easy to drill and cut.

Optional:

  • Faders (linear potentiometers)
  • Fader knobs
  • Toggle switches
  • Momentary switches
  • I/O expanders
  • Analog multiplexers
  • LEDs
  • Jack sockets
  • ...

These are the faders I used, and these are the knobs. These are the toggle switches I used. I took some jack sockets from an old cassette deck.

Prices

What was the total cost of my controller?

  • 1x Arduino Leonardo + headers - €22,-
  • 8x potentiometer - €12,96 @€1,62/pc
  • 8x potentiometer knob - €4,96 @€0,62/pc
  • 4x fader - €8,16 @€2,04/pc
  • 4x fader knob - €4,28 @€1,07/pc
  • 5x toggle switch - €9,75 @€1,95/pc
  • 1x blue led - €0,50
  • +/- 10m of wire - €1,50 @€0,15/m
  • 1x enclosure - free
  • 3x jack socket - free
  • 1x RCA socket - free

Total: €64,11

I think that's quite good, since Fuzzy-Wobble's "Teensy Monster"-board on its own costs $84,99 (€76,46).

Uno vs. Leonardo

Let's think about what kind of I/O we will need for our controller.

  • Digital I/O - for switches, buttons, LEDs, port expanders and multiplexers, ...
  • Digital inputs with interrupts - for rotary encoders (and easier for momentary buttons)
  • Analog inputs - for potentiometers and faders
  • Analog outputs - for LEDs (and maybe analog meters?)

And what do these boards have to offer?

Uno:

  • 18 digital I/O*
  • 2 interrupt capable pins
  • 6 analog inputs
  • 6 analog outputs (PWM)

(*) Digital pins 0 and 1 can not be used as I/O, because they are needed for serial communication with the computer (through the onboard ATmega16U2).

Leonardo:

  • 20 digital I/O
  • 5 interrupt capable pins
  • 12 analog pins
  • 7 analog outputs (PWM)

Well, the Uno is no match for the Leonardo, you'd say? Not necessarily, the Uno might just fit your needs if you don't need lots of I/O. Secondly, the USB to Serial chip on the Uno is the same as on the Mega 2560, and this one obviously has much more I/O. I haven't tested this however ... Most of the software should be the same as for the Uno.

So, if you want more than 6 potentiometers, you'll need a Leonardo or Micro (or an Uno with analog multiplexers or a Mega 2560). Well, that's a lot of choices actually ... I'll be covering the Leonardo and the Uno, but feel free to try some other boards, and let me know in the comments, or with your own Instructable. I'm really curious about your projects!

Edit (25-12-2015): I can now confirm that the library supports the Teensy 3.2 as well. It has a staggering 21 analog inputs, plus another 18 digital pins (38 digital I/O in total), and all pins are interrupt capable.
Use the guide for Arduino Leonardo to use a Teensy with this Instructable. The only difference is that you don't have to install TeeOnArdu.

So, in conclusion: You can use this Instructable with an Arduino Uno, Mega, Mega 2560, Due, Leonardo, Micro, Lilypad USB, or with a Teensy.

If you're using an Uno, Due or Mega, follow the instructions for the Uno,
If you're using a Leonardo, Micro, Lillypad USB or Teensy, use the instructions for the Leonardo

Step 2: Design Layout

The advantage of building it yourself is not being limited to one design. You can create your own crazy controller that fits your needs, and you can even add in extra knobs later on.

I work a lot with Tracktion 6. It's an awesome DAW for very little money. It has loads of features, and is easy to use. They even have a free Linux version. Anyway, I mostly use my 4 faders as volume control for 4 channels. When I need more than 4 channels, I use the 4 toggle switches on the front panel. The first switch switches fader 1 between channel 1 and 5, the second switch switches fader 2 between channel 2 and 6, and so on. The four potentiometers on the top panel are for equalization (High, high mid, low mid, low). The ones on the right panel are assigned to all kinds of stuff, like panning, gain, effects, frequency, ... The LED on the right is connected to pin 13, so it fades when starting up, and is used to give some basic feedback.

On the left, there are 2 RCA connectors, 2 jack connectors, and 1 stereo jack for headphones. These are not connected to the Arduino, but go straight to the faders, so I can use it as a passive mixer.

With a pencil, I drew everything on the cigar box (so I could erase it afterwards).

Step 3: Drilling and Cutting

Well, this step is pretty straightforward: just drill the appropriate holes to fit your buttons and potentiometers.
When trying to mount the potentiometers, i found out my box was a little bit to thick, so I had to use my Dremel to cut out some wood around the holes, so I could make the wood thinner, and sink the nut. (see image)

I also used my Dremel to cut out the holes for the faders, this is a little bit tricky, so you may want to try it on some other piece of wood you have lying around.

Don't screw anything in just yet, you first have to solder wires to every component.

Step 4: Connections

Were going to hook up our potentiometers and faders as simple voltage dividers. You can read more on this Wikipedia page if you're not familiar with this principle.

If you take a look at the schematic, you can see 2 resistors. R1 is the resistor between the right pin of the potentiometer and the wiper (center pin), and R2 the resistor between the left pin and the wiper. Since our potentiometer has a fixed value (50kΩ in this case), R1 + R2 will always be 50kΩ, while R2 can vary between 0Ω and 50kΩ. Therefore, the fraction will always result in a number between 0 and 1. Multiply this by 5V (Vin), and you'll get a voltage between 0V and 5V on your output. This voltage can be read by the Arduino's ADC (analog to digital converter), and represents the position of the potentiometer (or fader).

So basically, you connect the left pin to the ground, the right pin to the 5V pin on the Arduino, and the center pin to an analog input. Simple, right?

Buttons are even easier: just connect one pin of the switch to the ground and the other pin to a pin of the Arduino.
It works like this: the Arduino has an internal pull up resistor. When the switch is open, the digital input gets 5V through the resistor, and thus a digital 1. When the switch is closed, the input is connected directly to ground, thus a digital 0. This may be a little counter-intuitive however: button pressed is digital zero, and button released is digital one.

Step 5: Soldering and Mounting

Potentiometers and faders

  1. Cut one red and one black wire, long enough so it can connect 4 potentiometers to the Arduino.
  2. Use your wire strippers to strip of the insulation on both ends.
  3. Put the potentiometers upside down in the holes you just drilled.
  4. Use your wire strippers to cut through the insulation, and create a spot with bare wire, at the same distance as the distance between the potentiometers.
  5. Twist this piece of bare wire around one of the pins of the second potentiometer, and solder it into place. Do this in such a way that the wiper connects to the pin with the red wire when you turn the shaft to the right (see picture 6).
  6. Solder the end of the wire to the first potentiometer.
  7. Repeat steps 4 and 5 for all other potentiometers in this line (4 in my case).
  8. Repeat steps 2-7 for the black wire.
  9. Take another 4 wires, and strip off the insulation.
  10. Solder one end to the center pin of one of the potentiometers.
  11. Add some solder to the other end. This will make the wire thicker and stronger, and easier to plug into the headers of the Arduino. (see last picture)
  12. Repeat these 11 steps for every potentiometer or fader you have.


! Make sure you cut your wires long enough. Longer wires are much easier to plug into the Arduino !

Buttons and switches

  1. Take a black piece of wire and strip off the insulation of both ends.
  2. Use the same technique as described above, to connect all grounds together (center pin of the toggle switch, or one of the two pins of a push button).
  3. Take another piece of wire, and strip off the insulation of both ends.
  4. Solder one end to a second pin of the switch.
  5. Add some solder to the other end, to plug into the header of the Arduino.

LEDs

  1. Solder a 330Ω resistor in series with the LED, to the long pin (the rounded side)*.
  2. Solder a red wire to the other end of the resistor. This is the +5V.
  3. Solder a black wire to the short leg of the LED (the flat side).
  4. Add some solder to the other end of the black wire, to plug into the header of the Arduino.

(*) It doesn't really matter where you put the resistor, as long as the polarity of the LED is correct.

! Always use a resistor in series with your LEDs, otherwise, there are only two ways this can go: 1. you fry your LED; 2. you fry your Arduino !

Mount everything

Using the appropriate nuts and screws, mount everything in your enclosure. If an LED doesn't stay in place, you could add some glue.

I used two pieces of double-sided tape to keep the Arduino in place, and I made a small hole in the back panel for the USB cable.

Connect everything

Pretty straightforward:

  1. Connect all grounds together, and add a little piece of black wire to connect to the Arduino's ground. You could also link them in a chain.
  2. Connect all +5V's together, and add a little piece of red wire to connect to the Arduino's +5V. You could also link them in a chain.
  3. Connect all other wires to the appropriate Arduino pin. Potentiometers and faders go to analog inputs**, and switches go to digital inputs. LEDs go to a digital output.

(**) On the Leonardo, analog inputs A6-A11 are located on the digital header. They are marked with a white dot, and their numbers are written on the back of the board.

Step 6: Code Time! Well, Almost ...

Arduino Uno

For the Uno, you'll have to flash the ATmega16U2* on the board with Dimitri Diakopoulos's custom firmware. This is a HEX file you burn to the chip using Atmel's Flip software. The firmware takes input from the main microprocessor of the Uno (ATmega328P) and converts it to the MIDI over USB protocol.

(*) The main microprocessor of the Uno (ATmega328P) has no USB capabilities. Instead, it has a serial connection on pin 0 and 1, with a second microprocessor (ATmega16U2, this is the little black square between the USB connector and the TX and RX LEDs). This chip is programmed to be a USB-to-Serial converter, and is recognized by the computer as a (virtual) serial or COM port. By uploading your own firmware to the chip, it can be virtually any USB device, including a MIDI device.

Programming the Uno and MIDI

Because the ATmega328P relies on the serial connection established by the ATmega16U2 for uploading new Arduino sketches, you can't change your program while running the MIDI firmware. That's why we will be writing our program first, and burn the MIDI firmware after uploading our program to the ATmega328.

You can delete the MIDI firmware at any time, and reinstall the original Arduino Uno serial firmware.

We'll have to upload the sketch before we can flash the ATmega16U2, so I'll explain this process later on.

Arduino Leonardo

The Leonardo just needs a special library to use the Teensy MIDI functions on Arduino. It is a piece of software, called TeeOnArdu. It was originally written by Georg Werner, but it doesn't work with the latest versions of the Arduino IDE, that's why I rebuilt large parts of it myself, to be fully compatible with Arduino 1.6.x.
Here's how to install all the necessary software to get MIDI working on the Leonardo (or Micro):

  1. Download the official Arduino IDE from their site. I tried both version 1.6.7 and 1.6.8.
  2. Unzip and/or install the IDE and run it.
  3. Go to your /Arduino/ folder and create a folder named hardware.
    (Where is your Documents folder if you're on Windows, or your users home directory on Linux)
  4. Download the attached TeeOnArdu - 2016-08-22.zip and unzip it in your /Arduino/hardware folder.
    The structure should be/Arduino/hardware/TeeOnArdu/avr/ ...
  5. Close the Arduino IDE.
  6. If you are on Linux, execute the following command in a terminal:
    sudo usermod -a -G dialout $USER

    to add your user to the dialout group to gain access to the serial ports. Then log out and back in again.

  7. Relaunch the Arduino IDE, and open the Tools>Board menu. There should now be an option "Arduino AVR Boards: TeeOnArdu". Select it.
  8. Go to Tools>USB Type and select MIDI.

Following instructions are the old ones, just for reference:
Linux (Ubuntu)

  1. Download the official Arduino IDE 1.0.6 here. You need 1.0.6, other versions will not work.
  2. Create a new folder in your home directory called 'Executables'.
  3. Extract the arduino-1.0.6-linux64.tgz file you just downloaded into the new Executables folder.
  4. Download the Teensyduino installer from here.
  5. In the 'other files' section on the same page, click 'Linux udev rules', and hit CTRL+S to save.
  6. Remove the .txt extension in the save dialog, and choose 'all files' instead of .txt before saving (but keep the .rules extension). Then save it in your 'Downloads' folder.
  7. Open a terminal window using CTRL+ALT+T, or via your application menu.
  8. Execute this command to copy the udev rules into the right folder.
    sudo cp Downloads/49-teensy.rules /etc/udev/rules.d/
  9. Go to you Downloads folder using your file browser. Right click the teensyduino.64bit file you downloaded in step 4, and choose 'Properties'.
  10. Under the 'Permissions' tab, check the box 'Allow executing file as program'. Then close this window.
  11. Double-click teensyduino.64bit to run the installer.
  12. Press 'next'.
  13. Then, browse to your 'arduino-1.0.6' folder inside your 'Executables' folder. Once you do this, the 'next' button should no longer be grayed out. Click 'next'.
  14. Check the 'MIDI' box, and other libraries, if necessary for your project. (You could also select 'all' if you wish to). Then click 'next' again.
  15. Then click 'Install'.
  16. Download Fricklr's 'TeeOnArdu'-software from GitHub. On the right hand side, there is a button 'Download ZIP'.
  17. Extract the ZIP file in your Downloads folder, and open the files in your file browser.
  18. There should be a folder called 'TeeOnArdu-master'. Double-click it and copy the directory 'TeeOnArdu'.
  19. Go to your /home/Executables/arduino-1.0.6/hardware folder, and past the TeeOnArdu folder here.
  20. In the terminal (CTRL+ALT+T), go to the Arduino directory:
    cd Executables/arduino-1.0.6/
  21. Run the Arduino software:
    ./arduino
  22. Inside the Arduino software, under 'Tools', select 'TeeOnArdu (Leo on TeensyCore)' as your board.
  23. Set 'USB-Type' to 'MIDI'.
  24. Now you're ready to use MIDI with your Leonardo!

The instructions for Windows and Mac are very similar, they can be found on the Adafruit page. Note that the version is different. The Adafruit tutorial uses Arduino 1.0.5, but you need 1.0.6. Also, don't use the Adafruit download links, but use the links in steps 1, 4 and 16 (mentioned above).

Teensy

Teensies have their own libraries, so it is sufficient to just install the Arduino IDE and the Teensyduino add-on:

  1. Download the official Arduino IDE from their site. I recommend version 1.6.9.
  2. Unzip and/or install the IDE.
  3. If you are on Linux, execute the following command in a terminal:
    sudo usermod -a -G dialout $USER

    to add your user to the dialout group to gain access to the serial ports.

  4. Go to the Teensyduino download page, download it, and carefully follow the instructions.

  5. Open the Arduino IDE, go to Tools>Board, and select the right Teensy.

  6. Go to Tools>USB Type and select MIDI.

MIDI messages

Before we start programming, let's first try to understand what MIDI is.

MIDI (Musical Instrument Digital Interface) was developed in 1982, and is a standard for communication between musical instruments, as the name implies. The original signals were transferred over an old-fashioned DIN 41524 connector. Nowadays, most MIDI devices have a USB connector, to connect them to a computer. However, the protocol itself hasn't changed.

A MIDI message consists of 3 bytes, and has 4 parts:

  1. Status Byte: in our case, this will consist of a 'channel message' and a 'channel'.
  2. Data Byte 1: a 7-bit number.
  3. Data Byte 2: another 7-bit number.

For our MIDI controller, we'll be using only 3 different channel messages: noteOn, noteOff and ControlChange.

  • NoteOn:
    channel message: 0b1001* (0x9)**
    channel: 0b0000-0b1111 (0x0-0xF)
    data 1: note number: 0-127
    data 2: velocity***: 0-127
  • NoteOff:
    channel message: 0b1000 (0x8)
    channel: 0b0000-0b1111 (0x0-0xF)
    data 1: note numer: 0-127
    data 2: velocity: 0-127
  • ControlChange:
    channel message: 0b1011 (0xB)
    channel: 0b0000-0b1111 (0x0-0xF)
    data 1: controller number: 0-119****
    data 2: controller value: 0-127

(*) 0b means binary notation.
(**) 0x means hexadecimal notation.
(***) The velocity is how hard a key is hit.
(****) Controller numbers 120-127 are not available for normal controllers, but are reserved for operating modes.

Note: there are other messages as wel (see links at the bottom of this step). For example a pitch bend message has its own 4 first bits, and is not a control change message, it has no controller number, so it can store a 14-bit value. This is used by higher end MIDI controllers, when higher resolution is required. However, there can only be a maximum of 16 pitch benders (1 for each of the 16 channels).

NoteOn and noteOff are used for the keys of a digital piano, for example. Here are the note numbers with their corresponding musical notes. The middle C (C4) is mapped to 60, and 440Hz (A4) is mapped to 69. We will be using these notes for our buttons and switches: noteOn when the button is pressed, and noteOff when the button is released. I recommend using channel 1 (0b0000), but when you have more than 128 buttons, you'll need a second channel. Data 1 will be the note number, the address if you will, of the button, and Data 2 (the velocity, how hard you strike the note) doesn't really matter for a button (though it does if you want pressure/velocity sensitive pads for example). We'll just make it 127 (100%).

General notation noteOn: 1001 cccc 0nnnnnnn 0vvvvvvv
where cccc is the channel, nnnnnnn is the number of the button, and vvvvvvv the velocity
For example: pressing button 15 (0b00001111) on channel 1 would send this message: 1001 0000 00001111 01111111

General notation noteOff: 1000 cccc 0nnnnnnn 0vvvvvvv
where cccc is the channel, nnnnnnn is the number of the button, and vvvvvvv the velocity
For example: releasing button 15 (0b00001111) on channel 1 would send this message: 1000 0000 00001111 01111111


ControlChange messages are used for controllers that can have a wide range of values, like a potentiometer, or a fader. This value has 7 bits, so it has a range from 0 to 127 (0% - 100%). Here is a list of all controllers and their corresponding numbers.

General notation ControlChange: 1011 cccc 0nnnnnnn 0vvvvvvv
where cccc is the channel, nnnnnnn is the number of the controller, and vvvvvvv the value of the controller.
For example: turning the volume (controller number 7 or 0b00000111) of channel 8 (0b1000) to the maximum (127 or 0b01111111) will send this message: 1011 1000 00000111 01111111

More information about the MIDI protocol can be found on midi.org, in this PDF, or on Wikipedia.

Step 7: The Code - Analog

The Uno

I added a lot of comments to this piece of code. Try to read them to understand the code, and adapt it to your own needs.

I attached a .ZIP file with the code.

Extract it and open it with the Arduino IDE. Connect your Arduino via USB. Select the right board and port from the 'Tools' menu, and hit CTRL+U to compile your code and upload it to the board.
Then hit CTRL+SHIFT+M to open the serial monitor. Select a baud rate of 115200 in the drop-down menu in the right corner. Wait for the LED on pin 13 to light up. You should see 6 different messages. When you turn one of the potentiometers, you should see more messages.

If this works, you can proceed to the next step.

The Leonardo

I added a lot of comments to this piece of code. Try to read them to understand the code, and adapt it to your own needs.

I attached a .ZIP file with the code.

Extract it and open it with the Arduino IDE. Connect your Arduino via USB. Make sure your board is set to 'TeeOnArdu', and 'USB-Type' is set to 'MIDI'. Select the right port from the 'Tools' menu, and hit CTRL+U to compile your code and upload it to the board. If the upload fails, try uploading again, while pressing the reset button on the Arduino when uploading.

When the uploading is complete, unplug the USB cable, and plug it back in. Your computer should now recognize your Leonardo as a MIDI device.

Step 8: The Code - Analog: Testing

The Uno

The code for the ATmega328 is now uploaded, but the ATmega16U2 is still just a serial - USB converter. Now we need to program it to be a serial - MIDI-over-USB converter.

This is how you do it on Windows (Vista - 10) :

  1. Download the latest Java Runtime Environment from the Java site.
  2. Run the java installer.
  3. Click 'install'.
  4. Close the installer when finished.
  5. Download 'Flip' from the Atmel site.
  6. Run the installer.
  7. Click 'next'.
  8. Accept the terms in the License agreement and click 'next'.
  9. Click 'next'.
  10. Click 'install'.
  11. Click 'next' when completed.
  12. Click 'finished'.
  13. Now, connect the Arduino to your computer, and use a small screwdriver to connect the reset pin of the second ICSP header to the ground. This is the 6-pin ICSP header close to the USB port. (see image)
    The ATmega16U2 is now in DFU mode (Device Firmware Update). Read more here.
  14. Go to the Control Panel in Windows. Click 'Hardware and Sound'.
  15. Under 'Devices and Printers', click 'Device Manager'.
  16. In Device Manager, there is a category 'Other devices'. In this category, there should be something like 'Arduino Uno DFU' or 'ATmega16U2 DFU'. Right click the device, and select 'Update Driver Software'.
  17. Choose 'Browse my computer for driver software'
  18. Then hit 'Browse...' and browse to C:\Program Files\Atmel\Flip 3.4.7\usb in the new window.
  19. Make sure 'Include subfolders' is checked, then click 'Next'.
  20. In the Windows Security window that pops up, click 'Install'.
  21. You should get a notification that Windows has successfully updated the driver software for 'AT90USB162'.
  22. Download the Arduino firmware from the Arduino GitHub page by clicking 'RAW' and then CTRL+S to save.
  23. Change the location to your Downloads folder, delete the .txt extension, and choose 'All files' (keep the .hex extension). Then hit 'Save'.
  24. Download Dimitri Diakopoulos's HIDUINO firmware from his GitHub page. Again, hit 'RAW', CTRL+S, delete the .txt extension, choose 'All files' and save it.
  25. Open the Flip software.
  26. Hit CTRL+S to select a device, choose 'ATmega16U2', and click 'OK'.
  27. Hit CTRL+U, and click 'Open' to open the USB connection.
  28. Hit CTRL+L to load a HEX file.
  29. Browse to your Downloads folder and load the 'arduino_midi.hex' file you downloaded in step 24.
  30. Make sure all 4 boxes on the left hand side are checked, and click 'Run'.
  31. Once this is finished, you can unplug the Arduino. Now it is no longer in DFU mode.
  32. Go back to the Device Manager, and check if the Arduino shows up as a MIDI device, under 'Sound, video and game controllers'.
  33. Now your Arduino is a working MIDI controller!

For more info, and instructions for Mac and Linux, check out the Arduino hacking page. Just make sure you use the right file names of your HEX files.

I included a .tar archive with the two scripts I use to flash in Linux (dfu-programmer is installed by default in recent versions of Ubuntu).

Just extract the .tar.gz, open the folder in a terminal, and use ./MIDI* and ./Serial* to respectively upload the MIDI firmware or the USB-to-Serial firmware.

The Leonardo

The Leonardo is already ready to use as MIDI controller.

Testing

Open your favorite audio production or DJ software and go to settings. The Arduino should now show up in the 'MIDI' tab. You can now create a custom control surface.

Because this is different for every program, I'll be showing it on Mixxx, a free, open source, all platform digital DJ software.

  1. Turn all knobs and faders to zero.
  2. Connect your Arduino to your computer if you haven't already.
  3. Open Mixxx.
  4. Hit CTRL+P to open the preferences.
  5. Under the 'MIDI controller' tab, find your Arduino, and enable it.
  6. At the bottom of the window, click 'MIDI Learning Wizard'.
  7. Click 'OK' when prompted to apply the settings, then click 'Begin'.
  8. To assign the shown control to the right knob, just move the knob or fader, then click 'Next'. If you don't want to assign the shown control, just click 'Skip'.
  9. When you're ready, just close the wizard window, and click 'OK' in the preferences window.
  10. Move the controls on your MIDI controller, and watch them move on the screen.
  11. Congratulations, you built your own MIDI controller!

Step 9: The Code - Digital

What about my switches?

Don't worry, we can easily adapt the code to support the switches and buttons too.
Now we'll be using the noteOn and noteOff messages I mentioned earlier (see step 6).

The Uno

If you want to upload a new sketch to your Uno, you first have to reinstall the Serial-to-USB firmware on the ATmega16U2. To do this, repeat steps 25 to 31 of the previous step, but now load the Arduino-usbserial-atmega16u2-Uno-Rev3.hex file you downloaded in step 22 and 23 of the previous step. (Or use the shell script from step 8 if you're on Linux or Mac.)

If you check Device Manager again, the Arduino should show up under 'Ports (COM & LPT)'.

The new sketch is in the attached .ZIP file. Extract it, and open it in the Arduino IDE.

Try to read the comments, and adapt it to your own needs.

After you have uploaded the sketch, you'll need Flip again, to flash the HIDUINO HEX file. (See step 8 for help)

Once Flip has finished, unplug the USB cable, plug it back in, and you're ready to go!

The Leonardo

You don't need to change anything to the firmware in order to upload the new sketch, but you may need to press the reset button while uploading.

The new sketch is in the attached .ZIP file. Extract it, and open it in the Arduino IDE.

Try to read the comments, and adapt it to your own needs.

Press 'Upload' or hit CTRL+U, press the reset button on the Leonardo (immediately after the compiling is complete), and you're ready to go!

Step 10: Hey, What About Rotary Encoders?

About rotary encoders

Potentiometers and faders are great for controlling volumes and frequencies, but sometimes you find yourself in need of something that can turn forever, so you can scroll through your playlists, or maybe you're a DJ and you want to add jog wheels to your controller to scratch. That's when rotary encoders come in.

They may look like a potentiometer, but there are 3 major differences:

  1. A rotary encoder can turn forever, while a potentiometer has a fixed range (usually around 270°).
  2. A rotary encoder sends digital signals, while a potentiometer 'outputs' analog voltages.
  3. A rotary encoder sends relative messages, while a potentiometer reports its absolute angle.

Decoding a rotary encoder

Before we can use them, we first have to understand how they work. There's a long document in the Arduino Playground, but I'll try to give a quick explanation.

A rotary encoder basically consists of two switches. When it's turned, the two pins of these switches (A & B) will be connected and disconnected from the common pin (C). (See image 1, credit: RobotRoom)
This results in two square waves. These square waves are identical, but the timing is different. We say that they are 90° out of phase: the second wave starts its cycle when the first wave is at 1/4 of its cycle. (90° is 1/4 of a full 360°, hence the '90° out of phase'. A & B are also called 'quadrature outputs', because they are a 'quarter' out of phase.)

Take a look at the second image (source: Arduino Playground). Let's assume we turn the encoder clockwise (CW on the image). Every time the A signal rises, (red vertical line) the B signal is high, and every time the A signal falls (green line), the B signal is low. Now imagine turning it counterclockwise (CCW). Now every time the A signal rises (green line), the B signal is low, and every time the A signal falls (red line), the B signal is high. So by checking the B value when the A value changes, we know what direction the shaft is going in. This is also true for the changes of the B channel. By counting the pulses, we know how much we rotate it.

Because checking pin A and B in the loop of our sketch would be too slow if there are other things running as well, and we don't want to miss any change of them, we use interrupts. Here are some great pages about interrupts: the Arduino Reference, Nick Gammon's site, and chapter 11 in the Atmel Datasheet (Uno or Leonardo).

Interrupts are, simply put, parts of your code that only execute when something is triggered, like a pin change. The main loop is interrupted, and the ISR or Interrupt Service Routine is called. It's way more complex than this, but it's impossible to explain in one Instructable. Anyway, if we attach an interrupt to the pins of the rotary encoder, we can make sure we don't miss any pin change, no matter what is going on in the other parts of our code. You can read more on this in the previous links, but we won't be worrying to much about interrupts, since we'll be using PJRC's encoder library, which handles this for us.

There are two kinds of rotary encoders: mechanical, and optical. The first image is a mechanical one: there's a static and a moving piece of metal, and they make or brake connections. The second type is an optical encoder: there are two beams of (mostly infrared) light, and a spinning disk with teeth interrupts the disk. If the distance between the beams is the right ratio compared to the width of the teeth, their square waves will be 90° out of phase. There's an example in image 3 (source: Kawasaki Heavy Industries). It's also possible to have two rings of slits, that are already in the right phase on the disk.

There's one problem with mechanical encoders, and that is due to the fact that the connection is never perfect. You can have small spikes when connecting and disconnecting, and the Arduino will also detect those, and give us wrong readings. A simple solution is to add two 100nF capacitors between our A and B outputs and the ground.

Step 11: Connecting the Rotary Encoders

Soldering

Whoa easy, put that soldering iron down for just now, first check the datasheet of your specific encoder, to see what's the common pin. If you don't have the datasheet, try connection it to two LEDs (+resistor ! ). Connect the anodes of the LEDs to the +5V of an Arduino or other power supply, connect their cathodes via two resistors to two of the pins of the encoder, and connect the third pin to the ground of the Arduino. Now slowly turn the encoder. LED 1 should light up first, then LED2, then LED1 should go out, and finally LED2 should go out. The order of the LEDs lighting up should be like this: (○ ○) (● ○) (● ●) (○ ●) (○ ○).If this is the case, the common, or C pin of the encoder is the one you connected to the ground. If this is not the case, and the LEDs go on or off simultaneously, swap two wires and try again. (Don't worry, you will eventually find the right pin, there are only 3 possibilities.) The order of pin A and B doesn't matter.

Soldering BIS

Okay, go ahead, you can solder the wires to it. Use a black one for the common pin and two red ones to the A and B pins. It's easier to solder the wires horizontally, and it will be less likely for the pins to break. (See image 1)

Then add some solder to the other end of the wire, to fit nicely into the Arduino header. Now take 2 100nF ceramic capacitors. (100nF = 0.1μF, their code is 104 - 10×10⁴ pF) Their job is to eliminate noise and smooth the outputs. Solder them between the ground and an output. Take the first capacitor and twist one leg around one if the wires to keep it in place while soldering. (See image 2) Solder it to the right pins. Then take the second capacitor, bend the legs, like in the third picture, and twist-connect the ground-leg of the first cap and the second. Solder it together, and it look something like the fourth image.
Finally, cut off the capacitor legs, and install it in your enclosure.

Connecting to the Arduino

Connect the black wire of the common pin to the ground. Now connect the A and B wire to two interrupt pins on the Arduino.
On the Leonardo, these are pin 0, 1, 2 and 3. On the Uno, it's only 2 and 3. This information can be found on the attachInterrupt reference page.
If you really need more encoders, you could use one interrupt pin, and one normal pin per encoder, or even in extreme cases two normal pins, but this is not at all recommended, it will give very poor results.
There is no need to add external pull-up resistors, you can use the internal ones, even when using interrupts.

Step 12: Programming With the Encoders

Encoder libraries

The easiest way to use encoders in your program is to use an encoder library. I used the PJRC encoder library.

To use it in your sketch, copy the encoder folder into your Arduino 'libraries' folder, restart the Arduino IDE, and include the header file in your sketch, by adding this line at the top of your file:

#include <Encoder.h>

More about libraries on the Arduino site.

Then simply create a member of the encoder class:
Encoder name(pin_1, pin_2); where name is the name you want to give to the encoder, and pin_1 & pin_2 are the pins where you connect the encoder.

That's it, no hassle with interrupts, the library handles it all for you.

When you need the value of the encoder, just use:
name.read(); where name is the name you gave it earlier. The read function returns a long.

If you want, you can take a quick look at the examples that come with the library. (File > Examples > Encoder)

Relative messages

The read function returns an absolute value for the position (that resets every time you disconnect the power, however, unlike a potentiometer). This is perfectly fine for most applications, but MIDI is different: it uses relative numbers for rotary encoders. What this means, is that the controller sends the difference between the new and the old value of the encoder, so if for example the read function's last value was 96, and you turn the encoder clockwise for 1 step, the new value will be 97 obviously, but the Arduino shouldn't send 97. Instead, it sends the difference: 97-96 = +1. If you turned 1 step counterclockwise, it would be -1. Simple.

What about more steps? If you rotate the encoder quickly for, say 4 steps, there are 2 things that can happen: One, the Arduino sends its MIDI fast enough to read the encoder at least 4 times while you turn it. This means it will send 4 messages with '+1'. Two, if it isn't fast enough to refresh the read function 4 times, it will discover that the read function has changed more than 1 step since last time. For example, the read function's last value was 97, you turn 4 steps and read again. This will give you 101: 101 - 97 = 4. No problem, the Arduino will just send 1 message with '+4'.

There might be a few compatibility issues, due to the fact that you can't really send negative numbers over MIDI. There are three ways to send the sign of a number.

  1. Add 64. This is probably the simplest one. This basically maps 0 to 64 (which is 128/2). For example, if I want to send -1, I add 64, = 63 and I send it. If I want to send +1, I also add 64, = 65. If I just send 64, the computer will do nothing, because it knows it's a displacement of 0. (On the computer side, they just subtract 64, and you can use the result like nothing ever happened.)
  2. Sign bit. On computers, signed values are mostly saved with a sign bit. The sign bit is the most significant bit. When it's 0, the number defined by the other bits is positive, when it's 1, the number is negative. In a MIDI message, this is bit 6 (the 7th bit, since it's 0 based). For example: +4 would be 0b00000100, and -4 would be 0b01000100.
  3. A third way is to define +1 as 0, and -1 as 127. We can continue this: +2 = 1, and -2 = 126, etc. until +63 = 63, and -63 = 65.

So, if your encoder does strange things in your particular software, like jumping really far if you only rotate one step, you can change this in your program.

However, maybe you don't really need to write your own program ...

Step 13: The Library

In the intro of this Instructable, I promised you an easy way to program your own MIDI controller. Well, here it is!

It is a library that tries to compromise between great customizability and user-friendly code, accessible for Arduino beginners.

It currently supports potentiometers, faders, switches, buttons, rotary encoders, and has an easy function to send MIDI commands.
I am planning to add more LED output, and Pitch Bend Control support in the near future.

Installing the MIDI_controller library

This library relies on the MIDI functionalities of the software we installed earlier (Teensyduino, TeeOnArdu, HIDUINO etc.) so head back to step 6 & 8 and install them. Don't get discouraged by the seemingly long install procedure, if you follow the instructions, you should be fine. Once everything is set up, it is really easy to use!

The MIDI_controller library itself is installed like any other Arduino library.

These are the instructions for Arduino IDE 1.6.x:

  1. Download the library included at the bottom of this step.
  2. In the 'Sketch' menu click 'IncludeLibrary...' and then 'Add .ZIP Library...'.
  3. Browse to your Downloads directory, double-click it, and in the right-hand column, select MIDI_controller.zip.
  4. Click 'Ok'.
  5. Restart the IDE to load the keywords (so you get the orange color for functions etc.)

That's it.

How to use it

First add the library to your sketch by simply typing this line at the top of your file:

#include <MIDI_controller.h>

The library has currently 4 classes: Analog, Digital, DigitalLatch, and Encoder.

A class has a set of functions, and a set of variables. Some are private, and are used inside the class, others are public, and can be called from outside the class. More on classes here.

The first step in using a class is creating a member of the class. This is mostly done before the setup, so you can use the member everywhere in the program.

For example, lets add a member 'potentiometer' of the class Analog:
Analog potentiometer(blah, blah, blah ... );
(Just ignore the blah for now)

Now that the member is created, we can use the functions of Analog on it, for example, the refresh function:
potentiometer.refresh();
Just like Arduino functions like digitalWrite, you can't use those functions outside of the setup or the loop.

For explanation of what the functions do and what they are made for, read following reference.

Analog

The analog class is meant for analog inputs, like potentiometers and faders (or analog sensors that output a value between 0 and 5V). An invalid pin number will result in the LED on pin 13 blinking at 1Hz.

Create member

  • Analog (byte pin, byte controller, byte channel, byte resolution);

pin is the analog pin to read from. It's connected to the wiper of the potentiometer.

controller is the MIDI controller number (data 1 in the MIDI message). This is how it will appear in your MIDI software, like a unique address.

channel is the MIDI channel.

resolution is the resolution of the analog reading. A resolution of 2 would give only 2 possible values (0 and 127), a resolution of 3 would give 3 possible values (0, 63 and 127). A resolution of 128 gives 128 possible values (0-127), this is the default, because it's all 7-bit numbers. (MIDI uses 7-bit numbers for sending values) Use a value lower than 128, like 64, if there's a lot of noise on your input, for example if the controller keeps on sending 0,1,0,1,0,1,0,1, ... Use 128 if you want to use the maximum available resolution.

Functions

  • refresh();

This function checks the input, and if it has changed since last time refresh was called, it sends the new value over MIDI (on the predefined controller number and channel).

  • bank(byte pin, byte controller, byte channel);

This function enables you to use one analog input (together with a switch) for multiple controls. If the switch is in the OFF position, the controller and channel will be those that were defined during member creation, if the switch is in the ON position, the controller and channel will be those that were entered as arguments of this function.

pin is the digital pin with the switch connected. The internal pull-up resistor will be enabled.

controller is the controller to use when the switch is on.

channel is the channel to use when the switch is on.

  • detachBank();

This function disables the bank functionality that was set up with the function bank. The controller and channel will be those that were defined during member creation again, regardless of the state of the switch.
The pin of the switch defined in the bank function will be set as an input without pull-up resistor again.

Constants

  • None.

Examples

  • Analog_example
  • Analog_bank_example

Digital

The Digital class is meant for use with switches and buttons. It sends a noteOn message when the button is pressed, and a noteOff message when the button is released. Connect your switches between the input pin and the ground, the internal pull-up resistors will be used. An invalid pin number will result in the LED on pin 13 blinking at 1Hz.

Create member

  • Digital (byte pin, byte note, byte channel, byte velocity);

pin is the digital pin with the button connected.

note is the MIDI note to send. 60 is middle C, and every half note is plus or minus one. You can compare this to the controller number in Analog.

channel is the MIDI channel.

velocity is how hard the note is hit. This doesn't matter for a normal button, as long as it's not 0. (It does matter however for touch sensitive pads for example.)

Functions

  • refresh();

This function checks the input, and if it has changed since last time refresh was called, it sends the appropriate message: noteOn when the button is pressed, noteOff when the button is released.

  • bank(byte pin, byte note, byte channel);

This function enables you to use one button (together with a switch) for multiple controls. If the switch is in the OFF position, the note and channel will be those that were defined during member creation, if the switch is in the ON position, the note and channel will be those that were entered as arguments of this function.

pin is the digital pin with the switch connected. The internal pull-up resistor will be enabled.

note is the note to use when the switch is on.

channel is the channel to use when the switch is on.

  • detachBank();

This function disables the bank functionality that was set up with the function bank. The note and channel will be those that were defined during member creation again, regardless of the state of the switch. The pin of the switch defined in the bank function will be set as an input without pull-up resistor again.

Constants

  • None.

Examples

  • Digital_example
  • Digital_bank_example

DigitalLatch

The DigitalLatch class is meant to use with toggle switches, that are not momentary. It sends both a noteOn and a noteOff message, every time the state changes. The delay between the on and off message can be set. If the state changes before the delay has finished, the noteOff message is sent anyway, and another 'pulse' is started: another noteOn message is sent, and after the set delay, the noteOff message is sent as well.
This class is useful if you want to use the 'mute' or 'solo' buttons in your software with non-momentary toggle switches. If you switch on the switch, the appropriate track is muted, when you switch the switch off again, the track will be un-muted, for example.
Connect your switches between the input pin and the ground, the internal pull-up resistors will be used. An invalid pin number will result in the LED on pin 13 blinking at 1Hz.

Create member

  • DigitalLatch (byte pin, byte note, byte channel, byte velocity, int delay);

pin is the digital pin with the switch connected. The internal pull-up resistor will be enabled.

note is the MIDI note to send. 60 is middle C, and every half note is plus or minus one. You can compare this to the controller number in Analog.

channel is the MIDI channel.

velocity is how hard the note is hit. This doesn't matter for a normal switch, as long as it's not 0.

delay is the delay between the noteOn and noteOff messages, in milliseconds. 100ms works great. Do not enter 0.

Functions

  • refresh();

This function checks the input, and it sends the appropriate message, as explained in the description off this class. (Note: the noteOff message is not sent, if this function isn't called again, after sending the noteOn message. If you just put this in your loop, however, you should be fine.)

  • bank(byte pin, byte note, byte channel);

This function enables you to use one switch (together with a bank switch) for multiple controls. If the bank switch is in the OFF position, the note and channel will be those that were defined during member creation, if the bank switch is in the ON position, the note and channel will be those that were entered as arguments of this function.

pin is the digital pin with the switch connected. The internal pull-up resistor will be enabled.

note is the note to use when the switch is on.

channel is the channel to use when the switch is on.

  • detachBank();

This function disables the bank functionality that was set up with the function bank. The note and channel will be those that were defined during member creation again, regardless of the state of the switch. The pin of the switch defined in the bank function will be set as an input without pull-up resistor again.

Constants

  • None.

Examples

  • DigitalLatch_example
  • DigitalLatch_bank_example


RotaryEncoder

This library is meant to use with a quadrature encoder. It's adapted from PJRC's encoder library. It sends relative messages. The way negative values are handled can be set. Connect the common pin of the encoder to the ground, the internal pull-up resistors will be used. An invalid pin number will result in the LED on pin 13 blinking at 1Hz.

Create member

  • RotaryEncoder(byte pin1, byte pin2, byte controller, byte channel, int speedMultiply, byte pulsesPerStep, byte mode);

pin1 is the first interrupt pin with the encoder connected.

pin2 is the second interrupt pin with the encoder connected.

controller is the MIDI controller number (data 1 in the MIDI message). This is how it will appear in your MIDI software, like a unique address.

channel is the MIDI channel.

speedMultiply is the value that will be multiplied with the relative displacement, if the encoder is not fast enough in your software. If, for example, speedMultiply is set to 5, and the encoder were to send a '+1' message, a '+5' message will now be sent. Default is 1.

pulsesPerStep is the number of pulses the encoder outputs when you turn it one step or click. On a normal rotary encoder, this is 4. When you set it to 4, it will change 1 unit in your software per click you turn, instead of 4. This is mostly more logical. For jog wheels however, you may want to set it to 1, to take advantage of the full resolution of the wheel. Use 'NORMAL_ENCODER' or 'JOG' as argument.

mode is the way the MIDI message is sent (in order to make it a signed number). There are 3 modes available. Use 'ADD_64', 'SIGN_BIT' or 'POS1_NEG127' as argument.

Functions

  • refresh();

This function checks the encoder position, and if it has changed since last time, the relative change is sent over MIDI.

Constants

  • NORMAL_ENCODER

set pulsesPerStep to 4, for normal rotary encoders.

  • JOG

set pulsesPerStep to 1, for jog wheels.

  • ADD_64

First mode for relative MIDI messages. This is probably the simplest one. This basically maps 0 to 64 (which is 128/2). For example, if I want to send -1, I add 64, = 63 and I send it. If I want to send +1, I also add 64, = 65. If I just send 64, the computer will do nothing, because it knows it's a displacement of 0. (On the computer side, they just subtract 64, and you can use the result like nothing ever happened.)

  • SIGN_BIT

Second mode for relative MIDI messages. On computers, signed values are mostly saved with a sign bit. The sign bit is the most significant bit. When it's 0, the number defined by the other bits is positive, when it's 1, the number is negative. In a MIDI message, this is bit 6 (the 7th bit, since it's 0 based). For example: +4 would be 0b00000100, and -4 would be 0b01000100.

  • POS1_NEG127

Third mode for relative MIDI messages. Define +1 as 1, and -1 as 127. We can continue this: +2 = 2, and -2 = 126, etc. until +63 = 63, and -63 = 65.

Examples

  • Encoder_example

sendMidi.h

This is not a class, it's just two functions. It automatically finds out what Arduino you are using, and chooses the right settings to send a MIDI. (NOTE: it is already automatically included if you include the MIDI_controller library, since the classes rely on it for MIDI communication.)

Functions

  • setupMidi(byte ledPin, delay);

Sets up the MIDI connection. Run once in setup.

ledPin is the pin with the LED connected. Usually this is 13. The LED will blink every time a message is sent. If you don't want this, or if you want to use all your pins as inputs, use 'NO_BLINK'.

delay is the delay (in milliseconds) to add after every message that sent. 5 or 10ms works fine. Increase for stability, decrease for faster response. Use 'NO_DELAY' to continue as soon as the message is sent, without delay. (NOTE: it is normal for the 'blink led' to become very dim if you use short or no delay, this is just because the on-time is very short.)

  • sendMidi(byte messageType, byte channel, byte data1, byte data2);

Sends a MIDI message.

messageType is the type of message, like noteOn, noteOff or CC. This is a 4-bit number.

channel is the MIDI channel. This is a 4-bit number as well.

data1 is the first data byte. This is a 7-bit number.

data2 is the second data byte. This is also a 7-bit number.

NOTE: read step 6 for more information on MIDI messages.

  • sendMidi(byte messageType, byte channel, int data);

Sends a MIDI message

messageType is the type of message, like Program Change or Pitch Bend.

channel is the MIDI channel. This is a 4-bit number as well.

data is the value to be sent. 7-bit in case of a Program Change, to pick an instrument for a channel, or a number between -8192 and 8191 in case of a Pitch Bend.

Constants

  • NO_BLINK

The LED will blink not blink when a message is sent. The LED pin will also not be set as output.

  • NO_DELAY

No delay will be added after the message is sent.

  • NOTE_ON

Message type: 0x90, use to turn on a note. Use NOTE_OFF or send again with velocity = 0 to turn off again.

  • NOTE_OFF

Message type: 0x80, use to turn off a note.

  • CC

Message type: 0xB0 (Control Change), use to send analog values, like values from a potentiometers.

  • PROGRAM_CHANGE

Message type: 0xC0 (Program Change), use to set the instrument of a certain channel. (Channel 10 is percussion).

  • PITCH_BEND

Message type: 0xE0 (Pitch Bend), use to send large analog values.

Debug

In the MIDI_controller library folder, there is a file 'debug.h'. If you are having problems with your MIDI messages, uncomment the "#define DEBUG" line. This will send all MIDI messages over Serial, at 9600 baud, in HEX notation. You could also use tools like 'midisnoop' to troubleshoot MIDI messages.

NOTE: don't forget to comment the line out again to use USB MIDI again.

Examples

  • sendMidi_example_intoxicated

Step 14: Final Thoughts

By now, you should have a working MIDI controller in front of you, congratulations!

If not, check the library documentation in the previous step, and don't hesitate to ask me a question in the comments.

If you want to share your own controller, feel free to post your photos and links in the comments!

What's next?

I am currently working on the implementation of MIDI output (lights in the buttons, LED circles, VU meters, displays, etc.) This is really not an easy task, because MIDI controller manufacturers use proprietary protocols.

I'm also experimenting with system exclusive messages, that can have any length, and are used to address settings other than the control change messages.

Thanks a lot for reading this (rather long) Instructable, I really hope you learned something new, and that you are motivated to build your own MIDI controller!

Tttapa, 30/08/2015

(edit: 23/08/2016)

<p>Hi tttapa ,thank you for this great tutorial . I am only using your TeenOnArdu library to light up some Led with midi notes , but when i try to mask to a specific channel it breaks .</p><p>i am modifying the example Teensy/USB_MIDI/PrintIncomming OnNoteOn function like so :</p><p>void OnNoteOn(byte channel, byte note, byte velocity) {</p><p> if(channel == B0111 ){</p><p> if(note == B0000001){analogWrite(ledPin, 127);}</p><p>}</p><p>if i comment the channel line , everything is fine , but when i try to mask to a channel , i get nothing anymore . i wanted to ask you if you modified something in TeenOnArdu that would make making channels inmpossible ?</p><p>Thank you for your time .</p>
<p>Don't use TeeOnArdu, use MIDIUSB. </p>
<p>Sorry man , but it was working all along , the software i was trying it with was the problem , i when to my friend and tried it on his software , everything 's running perfectly . i tried to understand MIDIUSB example but it is less simple. thanks you for everything . </p>
<p>you re right , i dont know why i thought it would not appear as a midi instrument , but it does . i ll explore this way , thanks for your help </p>
<p>i use a ATmega32u4 with usb capabilities not a ATmega328P with ATmega16U2 . why not use teeOnArdu ? i might have missed somthing ? </p>
<p>Thanks very much for your splendid work! The example.ino's within the controller zip file are easy to customise. As for me I have a Leonardo build in a my humble little controller with big 4 x 10 cm. alps faders and 1 button to switch channels. I adjusted the code for the number of faders and it works well. Rock&amp;Roll!</p><p>Although the faders are of good quality, they now and then have erratic behaviour, a continuous switching between values. I soldered 100n capacitors on the faders but it doesn't help much. Is it possible to integrate some sort of smoothing loop in the code? I really appreciate your effort, thanks again for this great tutorial.</p>
<p>I've added averaging support to the library, you can find <a href="https://github.com/tttapa/MIDI_controller/releases/tag/1.2">version 1.2 on GitHub</a>. You can check out the Analog example to see how it works, I haven't updated the Wiki yet.</p><p>Glad to hear that it works!</p><p>Pieter</p>
<p>Cool project! I have TeeOnArdu and the zip library uploaded on a Leonardo, and the library added (#include) to the sketch. My computer sees the Leonardo as a MIDI controller, but I'm not getting any MIDI data from turning the potentiometers. I'm a beginner at Arduino &mdash; do I need to edit/add to the library myself, or should it be ready to go and running if I have everything wired up correctly? Any advice on finding/fixing the problem would be much appreciated! </p>
TeeOnArdu is no longer supported. But there's a much better way now, using the MIDIUSB library.<br>You can find the new version on my GitHub: https://github.com/tttapa/MIDI_controller
<p>Does this MIDI controller support Ableton Live?</p>
<p>Hi, I've just tested it with Leonardo. Works fine. Great Job!</p><p>Few questions/comments</p><p>1. Can I use only one interrupt input and one regular input per rotary encoder? I need 4 encoders</p><p>2. Would it be possible to switch banks through variable not input? This would enable software bank changes (like layers in some lighting/sound controllers) </p><p>3. Can I use banks for rotary encoders?</p><p>4. How it's going with midi read? One of ideas would be switching banks through midi incoming requests (and get it synchronized with physical input) </p><p>Marcin</p>
<p>Glad to hear that it works!</p><p>1. I haven't tried it yet, but it should work just fine: <a href="https://www.pjrc.com/teensy/td_libs_Encoder.html" rel="nofollow">https://www.pjrc.com/teensy/td_libs_Encoder.html</a></p><p>2. You can check in the source files how the bank support is implemented, it's really not that hard to change it. If I find the time, I may add it on GitHub.</p><p>3. Same answer, you can easily change it in the source files if you want to.</p><p>4. It's a bit harder to make it platform independent. But if you're only using a Leonardo, you can just use the <a href="https://www.arduino.cc/en/Reference/MIDIUSB" rel="nofollow">MIDIUSB</a> read function.</p><p>If you've got any further questions, you can always just leave me a message.</p><p>Pieter </p>
<p>Works with Arduino Pro Micro :-) </p>
<p>You don't have to use TeeOnArdu with the new library, just follow the instructions in the readme, and it should work. I don't know why you are getting all those errors: I've never used the Bounce library in my examples.</p><p>Try:</p><p>1. Deleting ~/Arduino/hardware/TeeOnArdu and ~/Arduino/libraries/MIDI_controller<br>2. Downloading the newest library from <a href="https://github.com/tttapa/MIDI_controller" rel="nofollow">GitHub</a> and install it (Sketch &gt; include library &gt; add .ZIP library)<br>3. Install the MIDIUSB library, as explained in the ReadMe<br>4. Open File &gt; Examples &gt; MIDI_controller &gt; Digital_example<br>5. Select Arduino/Genuino Micro as your board <br>6. Try to compile it<br>7. Connect your Arduino and upload the sketch.<br>8. If it doesn't upload, try resetting the Arduino while uploading (this may take a few tries)</p><p>Hope this works!<br>Pieter</p><p>P.S: Maybe you could send me a private message, because these comments are becoming quite a mess.</p>
<p>Where does it say that? In device manager? In the Arduino IDE? What does it say when you click Tools&gt;Board info?</p>
As far as I know, the Pro Micro is not an official Arduino board, so the core files don't come with the Arduino IDE and you have to download them from the Adafruit website.<br>What do you mean by 'show up'?
<p>Install the MIDIUSB library (see ReadMe.md), install the GitHub library (make sure to delete/move the old one). Then install the Adafruit Pro Micro Arduino IDE Core, select Pro Micro from the Tools menu, and upload. If that doesn't work, try selecting the Arduino Leonardo as your Tools&gt;Board.</p><p>DFU-flashing MIDI firmware won't work, that's for Arduino UNO and MEGA only.</p>
<p>First of all, I want to thank you a lot for the detailed guide of yours. It's been very helpful. The code for analog and digital inputs is working fine, but I had no luck with the midi library you included in the last step. I checked analog file of the library and noticed that the line #define CC 0xb0 was comment, so I removed it. However I am still not able to use the library. When I turn the pots, the led is blinking but I get no midi information. I hope you can help me with this, again, thank you so much for the guide.</p>
<p>What board are you using?</p><p>You could checkout the improved library on <a href="https://github.com/tttapa/MIDI_controller" rel="nofollow">GitHub</a>.</p>
<p>Hello,</p><p>Can you give few name of free software running on OSX and compatible with this project?</p><p>Thx,</p>
<p>DJ: Mixxx (free, open-source)</p><p>DAW: Reaper (free evaluation version), Ardour (open-source free trial, cheap executable, or free if you build it from source code), Garage Band, MU.Lab ...</p><p>In general: any program that accepts MIDI input or MIDI control.</p>
Hi, very cool ! I want to build a controller that is only a drum pad controller using Piezo sensors. Will this work for that? Was thinking of using the arduino mega because of the 16 analog inputs (think I'll use 13).<br><br>Was just wondering about getting my PC to see it as a midi controller. Will the tips here work for that?
<p>Yes, it will work, but you'll have to add support for velocity sensitive notes. It's not that hard, all you have to do is create a duplicate of the Analog class (Analog.h and Analog.cpp) and change the status message from CC to NOTE_ON. Then add some code to prevent re-triggering, and it should work.</p><p>Check out the improved library on <a href="https://github.com/tttapa/MIDI_controller" rel="nofollow">GitHub</a>.</p><p>If you didn't buy the Mega yet, I'd recommend an Arduino Due or a Teensy 3.2, since they have native USB support. This will make programming a whole lot easier. The Teensy is much smaller as well, and ~$12 cheaper. Keep in mind that it's 3.3V though.</p>
<p>Anyone made this with a Arduino Pro Micro? I have made some MIDI Controllers with Teensy and also UNO by following the instructions of this tutorial. </p><p>I have tried to make a MIDI Controller using Arcore and Pro Micro with no luck so If anyone has a sketch they would like to share? that would be awesome. </p><p>Photo shows one that is fully build the other one I am just starting to build. </p><p>Cheers! and awesome Instructable! </p>
<p>That looks great! Thanks for sharing!</p><p>I'm working on a new version of the library, you can find it on <a href="https://github.com/tttapa/MIDI_controller" rel="nofollow">GitHub</a>. I've tested it with a Leonardo, and it worked, so the Pro Micro should work as well (it's the same microcontroller). Installation is explained in the ReadMe, and documentation is in the Wiki. (Code written for the library in this Instructable should still work though.)<br>If you have any questions or comments, just let me know.</p><p>Hope this helps!<br>Pieter</p>
<p>Thank you for your very informative and detailed piece of work. I am glad I found it finaly. I am in the process of building a Arduino based (TeeOnArdu Pro-Micro) MIDI Controller. But apart from its real purpose it should be used to control a Amateur Radio SDR Software which is prepared to receive MIDI messages and map them to various functions. The software can also be used with commercial MIDI DJ Desks as well. The most MIDI sketches I found are not using rotary encoders and the few ones with encoders, did not work with my setup. I already get pots and buttons working but I like to swap the pots against encoders. Can your project handle encoders as well? </p><p>Since this is my first arduino project ever, I did not now much about programming and MIDI in particular. Would you be so kind to help me to get things up and running? If you need more information's I suggest you to sent me a mail to not ruin the thread because of it's different use.</p>
<p>I explained how to use encoders in steps 10, 11 and 12. But it's much easier to use the library in step 13, it has support for encoders built-in. You can download the .ZIP file at the bottom of step 13, check out the example 'Encoder_example.ino' in the 'MIDI_controller/examples' folder of the .ZIP.</p>
<p>i followed the steps but all it seems to have done is ruin my leonardo - when i plug it in - it is not recognized as a midi device - also on &quot;devices&quot; in the windows control panel - when you first connect it it says &quot;leonardo bootloader&quot; - then after a few seconds, that disappears and .... nothing. Is there any way to get it back to being an ordinary leonardo again&gt;?</p>
<p>Select the &quot;leonardo bootloader&quot; port, then press reset right before uploading. I tried this both on an official Leonardo and a Chinese clone, and it shows up and works as MIDI device.</p>
<p>Hi i want to make a controller following this guide and using mega 2560 with 16u2. Its first time I got in contact with arduino and I have no idea about coding. So,</p><p>Can I just use MIDI_Controller Uno Digital script and change the number of analog and digital inputs (I'll use 12 analog and about 30 digital) on lines 10 and 12? Should I also add something on lines 19, 25, 30 and further down the code?</p>
<p>I'm looking at a file from step 9. I saw few more down in comments but I don't know which is the latest one.Also, is it possible to test the sketch without flashing hiduino firmware using some software like midiyoke i hairless or something like that, also connecting just one or two pots and buttons? Just to see if it will work before spending more money on pots and buttons</p>
<p>The attachment in step 9 is the latest version.</p><p>To change the number of analog inputs, you have to change the definition on line 10, and the array on lines 19-20 (the number of elements should equal the number on line 10). Let's say you want to use 12 analog inputs: then change the value on line 10 to 12, and add some controllers to the array on line 19, so that it contains 12 items in total. The first controller will map to A0, the second to A1 etc ... The last controller will be A11.</p><p>To change the number of digital inputs, change line 12 to the desired amount, change the notes array on lines 24-26 and the switches array on lines 29-31 to contain the same number of elements as set on line 12.</p><p>You can of course use tools like Hairless to debug, and trying it out with a small amount of switches and pots is indeed recommended. You just have to change the baud rate to something that's supported by Hairless, like 115200 baud, for example.</p>
<p>Your tutorial is pretty comprehensive and i want to thank you for it.</p><p>Can you recommend me a good rotary encoder? i want something that gives me a soft clickless touch, like those found in the akai miniak or alesis micron. </p><p>Thanks in advance.</p>
<p>Not really ... I got mine out of an old microwave oven, so that's not the best quality ... You may want to look at optical encoders as well, they have a much higher resolution, and most of them don't click. (They're a bit more expensive though.)</p>
<p>hi tttapa,</p><p>I really appreciate your project ! However, I think I have similar problem than Norbert. Everything seems to work, but the midi messages are very strange. Could it be the baud rate ? any ideas ?</p>
Could you tell me what board and what OS you are using? I'll take a look at it!
I am using windows 10 and Arduino uno Rev. 3 with an ATmega16u2 as a chip.<br><br>I detected that when I change the baud rate, the information sent by my controls are different. For example, I have a switch. With &quot;MIDI_Controller_Uno_DIG.ino&quot; and 115200 baud rate, it send me a pitch bend, with 31200 a aftertouch, and with 9600 a strange (C-1) note on...
<p>I'm sorry for the extremely late reply, I just got a new Uno in the mail yesterday. It seems like the HIDuino MIDI firmware expects a baud rate of 31250 (the standard MIDI baud) and the library uses 115200, since this was the correct baud rate way back when I wrote the code. I used this old firmware for years, so didn't notice any problems.<br>Anyway, you can change it in the file sendMidi.cpp, on lines 13, 16 &amp; 19, change 115200 to 31250, and you should be good to go (untested, will try as soon as possible).</p>
<p>mmmm. I wanted to try this morning. So I did again all the steps. But I can't succeed to have the same results than before. Now, I am quite surprise because my arduino send midi message continuously... Next round in some days !</p><p>By the way, thanks a lot for your help,</p><p>Cheers, </p><p>Pierre</p>
<p>I've just uploaded my new code, tried it with both a Leonardo and an Uno, and I can confirm that it works now. Hope you get it working too, if there's any problems, just let me know!</p><p>Pieter</p>
<p>mmmm, I am trying the Digital Example, everything works, except it is not the good value... :(.</p>
Did you use literally the same code? What notes do you expect, and what notes do you get? Can you send me the exact MIDI messages?
<p>At least it gives me notes now :) but that's F or G :(</p>
<p>Hey great instructable, but for some reason in my IDE the option to change usb type is greyed out, and as such the IDE can't verify or compile the sketch as usbMIDI command isn't one that recognises. Any ideas?</p>
<p>Yesterday, I rebuilt the TeeOnArdu core, it was just copied from the Arduino IDE 1.0, and bodged until it worked in version 1.6. I started from the normal Leonardo core, and added the TeeOnArdu MIDI-specific functions afterwards. Everything seems to work fine, so I'm gonna do some more tests, and I'll upload my new version as soon as possible</p>
<p>hello, your tuto his very good, I 'm studying it but i can't download onedrive file, midi_library and .uno of step 7. sorry for my english</p>
<p>I'm sorry, Microsoft took all my OneDrive space :( Anyway, I added it as an insert in the Instructable. (BTW, I recently tried to install everything again, both the software for the Uno and for the Leonardo, and it didn't work, seems like they updated some of the programs ... I'm working on it, if I find a solution, I'll update the Instructable. )</p>
<p>Hi tttapa, i have a number of questions:</p><p>1. There are two code we should upload the second one?</p><p>2. can i use tactile switches? the toggles remain in HIGH state.</p><p>3. how do i install the library in windows for leonardo? the same as in UNO?</p><p>Regards</p><p>Thank You</p>
1. The code in step 7 is for analog inputs, like potentiometers and faders. The code in step 9 is for both switches and analog inputs.<br><br>2. Yes you can use tactile switches, just connent one leg to the ground, and the other one to the input. Use the Digital class of the library.<br><br>3. The library automatically selects the right Arduino (Uno, Leonardo or Mega) so it will always use the correct code, as long as you select the right board from the Tools menu. <br>If you get errors like 'usbMIDI was not declared in this scope', you probably didn't install the Teesnyduino and TeeOnArdu libraries, or you didn't select the right board and usb mode in the Tools menu.<br><br>Hope this helps!<br>Pieter
<p>Thanks alot,</p><p>it cleared all the mess.</p><p>Thanks alot</p><p>Taha</p>

About This Instructable

63,241views

459favorites

License:

More by tttapa:Raspberry Pi AirPlay receiver How to install Ubuntu 14.04 alongside Windows Getting started with Ubuntu 
Add instructable to: