A MIDI controller can send and receive MIDI messages to your PC, allowing direct control of your software. Not only that, but the controls can generally be mapped to anything your like. So what might be a volume fader for one person can be an effect filter for another.
This article will describe how to build and program a custom arcade button MIDI controller, while trying to keep the price below $100. It is aimed at electronics and programming novices.
Step 1: What You'll Need
1 x DFRduino (cheaper Arduino clone) $28.80
1 x USB cable (A to B connector, like that on a printer) $3.95
1 x Plastic enclosure $15.75
12 x Sanwa 24mm arcade buttons $26.28 (USD)
4 x 10k linear potentiometer $4.88
4 x Pot knobs $3.80
2 x 10k linear sliding potentiometer $7.54
2 x Slider knobs $2.04
5 x 10mm M3 nylon threaded spacers $2.00 (I got a bag of 25 for $9.95)
4 x 16mm countersunk M3 screws $1.00
3 x 4mm M2 self tapping screws $0.75
1 x 4.7 kΩ resistor $0.10
4 x stick on rubber feet $2.00
All of the above can be found at most online electronics stores (I use the excellent Little Bird Electronics ), except for the Sanwa arcade buttons which can be found at arcade replacement parts stores, or from DJ TechTools . It pays to purchase one or two spare buttons and perhaps a spare potentiometer in the event that the part is faulty or you accidentally make it faulty.
Small gauge stranded wire (22 AWG), preferably in three or more different colours
About 1m of 2.5mm heat shrink
Power drill or drill press
Drill bits (2mm, 3mm, 7mm, and 11mm)
Spade bit (24mm) $12.49
10mm hexagonal wrench or spanner
Small riffler files $15 for pack of 10
Step 2: Design
The inspiration for this article comes from DJ TechTools ' MIDI Fighter , specifically the grid layout of arcade buttons. The use of arcade buttons appeals to me as they are nice and large, and don't feel mushy unlike some rubberised buttons.
So with that in mind, let's begin the design. It helps to use some sort of diagramming software to aid in the design process such as Microsoft Visio or the open source Dia . This will help in terms of component dimensions and scale so you know everything will fit.
When designing your MIDI controller, remember that an Arduino only has 6 analogue inputs for knobs/sliders and 12 digital inputs for buttons/switches (technically it has 14, but two of those will be used for serial communications to the computer). The analogue inputs can also double as digital inputs so you could have up to 18 buttons on your design, or 17 buttons and 1 slider, or 16 buttons and 2 sliders, etc down to 12 buttons and 6 sliders.
Also try to find the dimensions of all of the components you wish to use so you have a good idea of what will and won't fit, and the clearance you'll need to give each component. For example the sliding potentiometers I've chosen have a travel length of 60mm, but then there's the extra clearance required on either side of the slider for the slider knob.
More analogue and digital inputs could be used with the aid of shift registers, multiplexers, or extra microcontrollers, but that is beyond the scope of this article.
I initially wanted to make a copy of the MIDI Fighter, so I drew up a basic 4 x 4 grid of arcade buttons based on the arcade button's dimensions (27mm total diameter, 24mm mounting hole). Although it looked kinda cool, I also wanted some analogue inputs such as knobs and faders. I also didn't want to go through the hassle of cutting my own acrylic to make the case. So I decided then I'd find a plastic enclosure to house the controls and base the design around those dimensions.
After a bit of hunting around for different enclosures, I eventually settled on this keyboard enclosure . Its dimensions are 189mm x 134mm, with a sloping height from 32mm up to 54.7mm. When choosing your enclosure make sure that your components are going to fit inside it. The mounting depth for the arcade buttons is exactly 32mm, so they will fit in the enclosure I've chosen.
Given this enclosure isn't square, I went for a 5 x 3 button arrangement and squeezed in a couple of sliding potentiometers up the top. When working out how to place the sliders, make sure to leave enough room for movement of the slider knob so it doesn't hit any other components. You'll have to find out the dimensions of the slider knob you wish to use so you can accurately place the slider. As the enclosure is higher at the back it also provides room to mount the Arduino clone underneath the buttons and sliders.
At this stage I'd recommend printing out a 1:1 sized copy of the design to ensure the layout feels natural, and all of the components are easily reachable. My design felt good, but I felt like I was wasting the Arduino's six analogue inputs with only two sliders.
Final Design 1
For the final design I removed the left most column of buttons and replaced it with a column of four rotary potentiometers, so now all six analogue inputs will be used. I also packed the components a bit more tightly together so they'd fit within the recess on the front panel.
Once you're happy with your design, go ahead and order the necessary components. Remember to check the knobs you've chosen will actually fit the sliding/rotary potentiometers. Some rotary knobs are designed for a 'D' type shaft, while others are designed for shaft with 18 teeth, while others simply screw onto the shaft.
Final Design 2
After about a week all of the components arrived, but I immediately noticed the sliders were too long (the dimensions on the datasheet were incorrect so I thought they were shorter). So rather than going through the hassle of exchanging them, I tweaked the design and swapped the sliders and rotary potentiometers around. I also measured the dimensions of the enclosure recess to ensure everything fit correctly.
Step 3: Construction
As you probably saw in the design phase, all of the dimensions for where components are to be placed are marked out. Not only does this aid the design layout, but is also useful when it comes to marking out where to cut the enclosure. I've included the schematic for my final controller design. Remember to mark out any screw holes or other mounting holes (I needed some extras for each rotary potentiometer).
Based on the schematic there are three types of holes to be made; a small 7mm hole for the rotary potentiometers, a larger 24mm hole for the arcade buttons, and a long narrow groove for the sliding potentiometers. We'll also need another small hole on the rear of the enclosure for connecting the USB cable to the Arduino board, and obviously any screw holes.
Measure and Mark Where to Cut
There are two ways to go about this step. The first is to grab a ruler and pencil and, using the schematic as a reference, mark out the center of each hole and the grooves for the sliders.
The second method (which I recently discovered on this Intructable ) is to print out a 1:1 sized copy of the schematic and stick it to the enclosure's surface. This in effect does all of the required marking and can reduce error at the same time. Given that's the case, I went with this second option.
Attached is a 1:1 schematic in pdf form, ready to print. When printing make sure it isn't being scaled before being sent off to the printer. Simply cut around the dotted rectangle so the paper will fit in the recess on the front panel, then stick it down using double sided tape. To cut the paper I'd recommend grabbing a metal ruler and a safety blade, then line up the ruler with the dotted line and run the blade down its length. This way the cuts will be nice and straight. Make sure you have something protecting your work surface underneath!
Drill the Holes
When drilling the holes it's a good idea to drill a small pilot hole first and then use the larger bits to drill the full sized holes. Start by drilling through the center of each arcade button marking on the schematic with a 2mm bit, and then do the same for the rotary potentiometer markings.
Switch over to a 7mm bit and drill through the rotary pot pilot holes to expand them. At this point I took the paper schematic off the enclosure because it was just going to get torn to shreds. Switch over to a 24mm spade bit and drill out the pilot holes for the arcade buttons. When using the spade bit remember to take it slowly to get a nice and circular hole. Make sure you have a sturdy grip or a clamp holding the enclosure lid to your work surface, else it will jump around a bit when drilling.
Getting Into the Groove
Grab a second print out of the schematic and stick it to the enclosure lid. Using a 3mm bit, drill out the screw holes for the sliding potentiometers. Now comes the tedious/fun part. To make the groove, drill a series of holes all the way down the length of the groove. The holes should be separated by no more than 1-2mm. Take your time and try to keep the holes as straight as possible.
After all of the holes have been drilled, use the countersinking bit to countersink the screw holes for the sliding potentiometers. These holes need to be countersunk otherwise the slider knob would hit the exposed screw head when it reaches the top or bottom of the groove. When drilling these I only drilled out a small amount at a time. Then I'd grab one of the countersunk screws and put it through the hole to check if the head was flush with the top of the lid. Repeat this as many times as necessary to get the nicest finish possible.
Now use the riffler files to remove the plastic between the holes which run the length of the slider groove. Also gently file the inner sides of the groove so it's as straight and as smooth as possible.
Step 4: Mounting
Each of the arcade buttons will just push into their hole and snap into place. Try and mount them so the legs are vertical relative to the enclosure. This will make wiring a bit easier in the next step.
The rotary potentiometers have a washer and hexagonal nut screwed on to them. Remove both, and then insert the potentiometer through their corresponding holes from the underside of the enclosure lid. Hold it in place, and then from the top side slide the washer and screw the nut down around the potentiometer shaft using the hexagonal spanner. Ensure that each potentiometer is facing the same direction when screwing them in. If the pots you have are like mine, there's a small metal guide which should fit into the little 2mm hole next to the potentiometer hole. This helps to stop it from twisting loose.
From the top side of the lid, insert the four 16mm M3 screws into the holes above and below the sliding potentiometers. On the underside screw a 10mm spacer onto each screw until it just touches the plastic. There should be around 2mm of exposed thread on the bottom of the screw. After doing this for all four screws, get one of the sliding potentiometers and line it up with two of the screws on the underside of the lid. Ensure the slider is oriented so the two legs which are close together are toward the bottom of the enclosure (the narrow end).
Using a screwdriver screw each of the screws into the potentiometers mounting holes. Don't over tighten otherwise you'll start boring the drill through the plastic lid.
What About the Arduino?
I'm glad you asked! With everything mounted in the enclosure lid, attempt to fit it to the enclosure base (without the Arduino inside). You may find (like I did) that the sliding potentiometer legs are slightly too long to fit in the enclosure when it's closed. I simply used a pair of needle nose pliers and bent each leg at about half of length at a 90 degree angle.
Now that everything fits grab the Arduino and place it inside the case towards the back, with the USB socket facing the back. I found that I could actually line up one of the enclosure's PCB stand-offs with the hole nearest the USB on the Arduino, which would mean the USB socket sat flush with the back wall once a hole had been cut.
Gently close the lid to ensure none of the components touch the Arduino. If the components do touch it, shift the Arduino to another location and try again. You may find that the arcade button legs get in the way of the Arduino. Rather than bending them like the slider legs, pop the arcade button out and insert it again at a different angle.
More Drilling and Filing?
This is the last of it, I promise! Once you've decided on the location of the Arduino, mark out where to cut a hole for the USB socket. The USB socket itself is about 12mm wide and 11mm high. Using the 11mm drill bit, drill an opening straight down on to the edge of the enclosure until the tip of the drill is about half way down.
Take your regular file and square up the edges of the opening. Sit your Arduino's USB socket in the opening to check if it fits. If not, file away some more. Repeat this process until the USB socket sits nicely in the rectangular opening.
You will also need to file a small section out of the bottom edge of the enclosure lid to accommodate the top of the USB socket. Place the lid onto the enclosure base and mark out where to file based on the opening in the base. Take out the components from the lid if you haven't already, then file away about 2mm. Check the USB socket fits with the Arduino inside the case.
One Last Thing
We need a couple of stand-offs for the Arduino PCB. I chose to cut in half one of the 10mm nylon spacers, and then glue each half to the base of the enclosure where the remaining screws for the Arduino needed to go.
Step 5: Wiring
The ATMega328 chip used on the Arduino contains internal pull-up resistors, so we won't need to wire individual resistors for each of the arcade buttons. This greatly simplifies the controller wiring. So all that needs to be done to wire the arcade buttons is to solder one leg to ground, and connect the other leg to one of the digital inputs on the Arduino board.
That said, pin 13 can not be used as a digital input with the internal pull-up resistor. See the pullup resistors section in the Digital Pins article on the Arduino website for the reasons why. For this pin we'll be using an external pull-down resistor. If you're unsure what a pull-up/pull-down resistor does, check out this great tutorial on ladyada.net .
Wiring the potentiometers requires a ground wire, a wire to the one of the Arduino analogue inputs, and a third +5V wire. As the potentiometer is rotated or adjusted, the resistance of the potentiometer changes between the ground and +5V wire. According to Ohm's law, voltage = current*resistance, so with a constant input current and a variable input resistance, the output voltage will be variable. It's this variable voltage that the Arduino reads on the analogue pins.
The attached wiring diagram (created with the great Fritzing software) shows how to wire up each of the components to the Arduino board. The black wire represents ground, the red wire represents +5V, the purple and orange wires are digital inputs to the Arduino, and the blue and green wires are analogue inputs to the Arduino. Note that the ground wires and +5V wires have been bridged between the buttons and potentiometers.
Before proceeding to the next step you may find it helpful to print out a copy of the wiring diagram to refer to whilst you solder.
Step 6: Soldering
We'll start by soldering all of the ground connections to the potentiometers. Cut a length of black wire approximately 80mm long, and two more lengths approximately 50mm long. Strip about 8mm of the insulation from each end of the wires. Now line up one end of each wire, and twist the copper of all three wires together. We'll be attaching this group of wires to pin one of the top left rotary potentiometer. The 80mm wire will then go to the ground pin of the Arduino, while the other two wires will go to the adjacent rotary and sliding potentiometers.
Tin the twisted end of the trio of wires with some solder so the wires are fused together. Don't solder it to the potentiometer yet though!
Cut a short length of heat shrink tubing (about 12mm) and slide it over the twisted end of the wires, making sure it's at least 20mm from the exposed copper and solder. Now go ahead and solder the twisted wire to the potentiometer leg. Once that's done you can slide the heat shrink over the leg, protecting the soldered joint. Just leave the heat shrink loose for now, and we'll apply heat to it later once we've done all of the soldering.
Now cut another 50mm length of black wire and strip each end. Line up one end of the wire with the free end of one of the 50mm wires from before. Twist the copper of the two wires together, and then tin the joint. Again don't solder the joint yet, but first cut some heat shrink and slide it over the tinned wires. Solder the twisted wires to pin one of the second rotary potentiometer and slide the heat shrink over the joint.
Repeat this process for each potentiometer leg and arcade button leg, referring to the wiring diagram. Not every joint will be the same, so make sure you know what wire needs to go where. Don't solder anything to the bottom right most arcade button (on pin 13) as it's quite different and covered in the next section. When all of the ground wires and +5V wires have been soldered, roughly measure and cut the analogue and digital input wires and solder them in place. Tin the tips of the free end of each wire and insert them into the Arduino board.
Pin 13 and the Pull-down Resistor
As mentioned in the previous step, pin 13 requires a pull-down resistor so it can be read by the Arduino. Referring to the wiring diagram, solder the resistor to the common (black) wire of button 11. Solder a short length of black wire to the other end of the resistor so it can reach button 12. Now twist together the end of the short black wire with the data wire which will connect pin 13 to button 12. Solder the wires together, and then solder the pair of wires to one of the legs on button 12.
Run a wire from the +5V leg of rotary potentiometer four to the free leg of button 12 (see the long red wire on the right in the photo below). Solder the wire to the potentiometer and button.
Closing the enclosure
Sounds simple enough, but just be sure that none of the components interfere with the wires connecting to the Arduino. Note in the second photo that all of the digital input wires run to the right of the Arduino board. This allows room for the first column of arcade buttons to sit nicely above the Arduino without crushing it.
You may require a little force when fitting the lid to the base. If it won't close properly, try and see what components or wires are getting in the way. You may need to bend a few button legs and rearrange some wires for it to close nicely. Once the lid is on, screw it all together with the included screws.
Add the rubber feet to each corner of the base (not over the screw holes just in case you need access inside) and you're done!
Step 7: Programming
First things first, we need to program the Arduino board. If this is your first encounter with an Arduino board, you'll need to setup the Arduino IDE on your PC so it can talk to the Arduino and you can load programs on to it. To do this simply follow the Getting Started guide on the Arduino homepage. You will also need to install the Timer1 library . Download it and unzip it to /hardware/libraries/Timer1/
Edit: As of MIDI_Controller_2011-03-21.zip, Timer1 is no longer needed.
Once your Arduino is up and running, we'll need to load a sketch on it that reads all of the digital and analogue channels and converts that info into MIDI messages. Those MIDI messages are then sent serially over the USB cable to the PC.
Download the attached sketch and upload it to your Arduino. The code has been documented so you can see what is going on. In a nutshell the code continually polls all of the digital and analogue inputs checking for changes. If a change is detected (a button was pressed or a slider was moved), a MIDI message corresponding to the input is sent to the PC.
One thing to note is that the logic for when a button is pressed and released may seem a bit backwards. When a button is pressed the digital input goes 'low', and when it's released it goes 'high'. This is to do with the internal pull up resistor and the buttons being wired to ground in the previous step.
When there is no input to the digital pin (no button is being pressed), the input is being pulled up, or high, hence the name. So the default state of the digital pin is high. Each button was wired to ground so that when a button is pressed, the pin will read low.
Code revision history:
- Updated to support Arduino 1.0 (updated Serial.print to Serial.write)
- Added default #defines for Teensy 2.0 and Teensy++ 2.0 digital pins
- Removed #defines for Teensy 1.0 as usbMIDI is not supported
- Teensy USB code added (thanks to Tim Crawford).
- Updated with #defines for Arduino Mega and Teensy USB for easy compilation
- Removed TimerOne library. Each analogue pin now maintains its own time since it was last moved, rather than one timer for all pins. This stops sending jittery movements on analogue inputs which haven't been touched.
- Modified analogue input logic so only pins moved within the timer period are updated, not all of them.
- Experimental code added for higher speed (but less accurate) analogue reads
- Reduced analogue timer length from 1000ms to 250ms
- Updated MIDI output to send same MIDI signals as official MIDI Fighter
- Reduced debounce length from 5ms to 2ms
- Initial Release
Step 8: Software
Firstly you need a virtual MIDI port to connect to your audio or video software. I'd recommend MIDI Yoke on Windows (if you're using Vista or 7, you will need to disable UAC to install the driver). I did try using LoopBe1 and while it works the majority of the time, the automatic feedback detection kicks in when making rapid knob/slider movements, essentially killing your MIDI control. If you're on OS X you can setup a virtual MIDI port using IAC driver under Audio MIDI Setup (there instructions at the link below).
The second bit of software required converts MIDI messages coming in on a serial port to messages on a MIDI port. There are a number of software solutions to do this, but I use the simply named Serial-MIDI Converter by SpikenzieLabs. It's Java based so will run on Windows, OS X and Linux.
Once everything has been installed and setup, fire up Serial-MIDI Converter and configure it by pressing the matching letter in the list of items to match your serial and MIDI port settings. I use the settings COM 5 (yours may vary), 115200 kbps, In From MIDI Yoke 1 and Out To MIDI Yoke 1. Once you've gone through the setup, hit some of the buttons on your MIDI controller. You should see the little Serial RX and TX indicators in the bottom right of the window flash green.
Step 9: MIDI Mapping
There is no limitation on what you map to where, so just experiment and play around with things until you feel comfortable. My initial controller mapping for Traktor is below. All inputs act on the selected deck, except for the two sliders.
Deck A Volume - Slider 1
Deck B Volume - Slider 2
Chained Effect 1 Amount - Pot 1
Chained Effect 2 Amount - Pot 2
Chained Effect 3 Amount - Pot 3
Effect 1 On - Button 1
Effect 2 On - Button 2
Effect 3 On - Button 3
Play/Pause - Button 4
Cue points 1-8 - Buttons 5-12
Step 10: Future Enhancements
There are a number of things I'd like to add and change in future MIDI controllers.
1. Create a simple software/hardware architecture to allow for easily expandable I/O. This would be through the use of additional microcontrollers or dedicated I/O chips.
2. Utilise the LUFA library to make the controller a true USB MIDI controller, and not rely on extra PC software.
3. Update the Arduino sketch to support 14-bit MIDI messages
4. Build a CNC machine for cutting out holes in the enclosure (you may have noticed some of the button holes I made are a bit wonky).