WIKI: How to make a DIY MIDI controller easily

Quick example of a single CC button

This example comes directly from the github wiki for the library itself:
https://tttapa.github.io/Control-Surface-doc/Doxygen/d9/d2e/CCButton_8ino-example.html

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.

Here is a handy list:


Here is the simple hookups for each board:


Code Example:


#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:
image

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};

The full list can be found here:
https://tttapa.github.io/Control-Surface-doc/Doxygen/dc/df0/group__MIDIInterfaces.html

Definitions

CCButton button = {
  5,
  {MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};

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:

CCButton name_of_button_01 = {
  5,
  {MIDI_CC::General_Purpose_Controller_1, CHANNEL_1},
};

CCButton name_of_button_02 = {
  6,
  {MIDI_CC::General_Purpose_Controller_2, CHANNEL_1},
};

CCButton name_of_button_03 = {
  7,
  {MIDI_CC::General_Purpose_Controller_1, CHANNEL_2},
};

CCButton name_of_button_04 = {
  8,
  {MIDI_CC::General_Purpose_Controller_2, CHANNEL_2},
};

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.

image

The list of constants available are found here:
https://tttapa.github.io/Control-Surface-doc/Doxygen/d4/dbe/namespaceMIDI__CC.html#a6eb9900d522be13f07efce201817046d


Setup Function

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.


Its really that simple.

9 Likes