This WIKI is a tutorial series i am writing to assist those that want to make a midi controller.
Feel free to ask questions or ask for examples in this thread, i will be making new replies on topics in the future and will link them to this first post. This way we can have a discussion about this topic, can ask and answer questions, but we can also keep organized with the tutorial posts. Feel free to make requests for topics to be covered, but i already have a rough outline for what will be covered, since we want to make sure certain things are well understood first.
I am targeting this WIKI to people that may not be very comfortable coding. I aim to keep this an example focused tutorial series.
Don’t fuss too much about whether it is “elegant”. If it feels like a hack but it works, remember that a CPU is literally a rock we trick into thinking.
Next we need to download and add the Control Surface library to our coding environment, since it is not a standard library that comes with the software we just downloaded.
Next just add the library using the path in the image below. In the box that opens up, just navigate to where you downloaded the zip file, select it and hit the open button. What this does for you is extract this zip and place it into arduino’s libraries path. (This is found in C:\Users%UserProfile%\Documents\Arduino\libraries on windows for example.) You dont need to go through that unless you want to remove libraries later.
The coding environment should be good to go for now!
No personal experience, but that teensy is compatible with this library’s MIDIUSB lib unsurprisingly. The pinouts are identical, its all just a few extra features and clock speeds I reckon. Sparkfun has a writeup. The thing is, most basic controller functions are fine with just a nano. Although witht he nano, you cant use the MIDI over USB functionality. i dont know what benefit you’d get from going 4.0 you dont already get just from picking a teensy already. Unless you plan on doing a lot of floating point arithmetic. Which i argue you can just work around for midi controller work.
I have not experimented with using the teensy as an audio interface (implemented in 5 lines of code with a DAC like the PCM5102), but this library can help in that regard as well. Again, it comes down to what you need. From my research i think even for synth work a 3.2 is going to be overkill and thats great cause it means you can be a little less efficient and get something working.
It all really depends on what you need it for, but even the 3.2 is fast enough to process audio speed.
Here is a link to an article talking about I2S DACs:
MIDI itself is a protocol one can use to control instruments like hardware synths and even software. It allows for up to 16 “channels” at a time. Right now, just think of those channels as different separators that give us some organization.
MIDI CC (Control Change) messages have a number which indicate what the conventions of MIDI say the message should be used to control, and a value to be sent. It is important to know that these Control Number parameters are just convention, not rules. That said, the convention exists with the reason that you may encounter some undesirable behavior if you hook up a controller you made to some other software that expects a specific thing.
#include <Control_Surface.h> // Include the Control Surface library
// Instantiate a MIDI over USB interface.
USBMIDI_Interface midi;
// Instantiate a CCButton object
CCButton button = {
// Push button on pin 5:
5,
// General Purpose Controller #1 on MIDI channel 1:
{MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};
void setup() {
Control_Surface.begin(); // Initialize Control Surface
}
void loop() {
Control_Surface.loop(); // Update the Control Surface
}
Code Breakdown:
Includes
#include <Control_Surface.h>
This line will take all that code in the library, and make it available for you to use in your project.
Midi Interface Initialization
USBMIDI_Interface midi;
This line will create a new midi “interface” using USB. All you need to know here is that this is what will enable communication from your controller to what’s being controlled. There are a few different types of interface to choose from, and depending on the board you selected, you may be limited in which you can select.
If using a nano or uno board, you have to select a serial based midi interface for use with a 5-pin MIDI din cable like this:
The definition for this interface is instead like this, so if that applies, just use this instead:
// Select the serial port to use.
auto &serial = Serial;
// Instantiate a Serial MIDI interface at the default MIDI baud rate.
SerialMIDI_Interface<decltype(serial)> midi = {serial, MIDI_BAUD};
This is just defining all of the details about your button (or other components later down the road).
CCButton is the type of MIDI output element you want to define. You give it the name “button”, but to define more, you will want to name them differently.
After the equals sign, there is a comma separated list of parameters you specify inside of curly braces, including an entry which itself a comma separated list of items in curly braces.
So if i wanted to define more buttons and assign them different names, digital pins on the microcontroller, MIDI CC Numbers and MIDI channels, can do it like this:
Notice that i have the same CC numbers “General_Purpose_Controller_1” in two channels. This is a fine way to get more CC numbers without using unconventional numbers. Also, you are allowed to either specify the actual number or this human readable constants already defined for us in the library.
void setup() {
Control_Surface.begin(); // Initialize Control Surface
}
Arduino code has two functions that are standard. The setup() function is run once and will usually be used to start things up in an initial state. This is exactly what this code here does for the control surface. Dont worry about what it does, just know you need to plop that Control_Surface.begin() function in the setup function.
Loop Function
void loop() {
Control_Surface.loop(); // Update the Control Surface
}
The other standard function you find is the loop() function. This is where things well… loop. The Control Surface Library handles all of the update routines to send and receive midi messages here using its Control_Surface.loop() function.
The GUI configuration is pretty interesting, and i was wondering myself how best to enable users to configure hardware i would make. However, I thought the price could be reduced.
That said, the features are great, and the board has a lot of connectivity.
The software is open source so you’re not tied to their choice of hardware. You can apparently run it on an Arduino Mega2560, which is available locally sourced in the UK for less than £10 postage free.
Internally it’s an Arduino Mega clone with mocoLUFA on the 16u2 chip so that I can swap between Arduino and USB Midi. I used Pimp my mocoLUFA to build the firmware so that I could give it a descriptive name in the list of USB devices. You need to be happy programming the chip with the 6 pin ICSP headers to do it, which is likely to be the only stumbling block most people will find.
I’ve been planning on using either the Control Surface library or a combination of hardware handling libraries because I want to be able to do some coding directly on the board, like remapping the 16 buttons to do different tasks. That’s why there’s a suggestion of a piano keyboard layout of little buttons at the top, under the OLED and rotary encoder - as an untalented, uncoordinated meat bag, being able to assign chords/arpeggios to the buttons will let me circumvent my failings
Regarding OpenDeck, I’ve used it quite a bit, although never completed a project using it. The developer Igor is really, really helpful and has taken the project a long way. The official board was expensive because he had to support the development somehow; the official board isn’t available any more as he’s been moving on to more powerful architectures (case in point - STM32 support has landed in v5) and I gather from his Instagram that he’s making money building bespoke controllers with OpenDeck inside right now. It’s a really good platform to work on though, if a bit complicated to get the initial installation done.
yep! in fact i did do that. I just havent gotten around to writing anything about it here yet. The Control Surface lib makes using IO Expanders, shift registers etc SOOOO easy!