SkillAgentSearch skills...

Control Surface

Arduino library for creating MIDI controllers and other MIDI devices.

Install / Use

npx skills add tttapa/Control-Surface

Installs into whichever agent you are using.

README

CI Tests Test Coverage Examples GitHub Documentation

Control Surface Control Surface

<hr>

Control Surface is an Arduino library for building MIDI controllers and control surfaces.

At its core, the library features a flexible MIDI abstraction layer with support for serial 5-pin DIN MIDI, MIDI over USB, MIDI over BLE, etc. These MIDI interfaces are compatible with a wide range of Arduino boards (a full table can be found here) and are useful in any Arduino MIDI project.

In addition to MIDI input/output, Control Surface also provides easy-to-use utilities intended for building MIDI controllers, supporting controls that send MIDI messages ─ like potentiometers, push buttons, rotary encoders, etc. ─ and controls that react to incoming MIDI messages ─ LEDs, displays, and so on. More advanced controls that combine MIDI input and output ─ such as motorized faders ─ are supported as well.

In projects with large numbers of inputs and outputs, Control Surface allows you to seamlessly add multiplexers, shift registers and other port expanders, and treat them as if they were ordinary GPIO pins.

Table of contents
<span class="mono"></span>Example usage
<span class="mono"></span>Getting started
<span class="mono"></span>Documentation
<span class="mono"></span>Feature overview
<span class="mono"></span>Supported boards
<span class="mono"></span>Change log and updating

Example usage

An extensive list of examples can be found in the documentation. Below are a handful of simple examples that give an idea of how the Control Surface library can be used.

Example 1: A complete sketch for a MIDI controller with a potentiometer that sends out MIDI Control Change message can be written in just five lines of code:

#include <Control_Surface.h>

USBMIDI_Interface midi;
CCPotentiometer pot { A0, MIDI_CC::General_Purpose_Controller_1 };

void setup() { Control_Surface.begin(); }
void loop() { Control_Surface.loop(); }

Example 2: Larger MIDI controllers can be implemented very easily as well, with clean and easy to modify code. The following sketch is for 8 potentiometers (connected using an analog multiplexer) that send out MIDI Control Change messages over USB. A detailed walkthrough of this example can be found on the Getting Started page.

#include <Control_Surface.h>  // Include the library
 
USBMIDI_Interface midi;  // Instantiate a MIDI Interface to use
 
// Instantiate an analog multiplexer
CD74HC4051 mux {
  A0,       // Analog input pin
  {3, 4, 5} // Address pins S0, S1, S2
};
 
// Create an array of CCPotentiometer objects that send out MIDI Control Change 
// messages when you turn the potentiometers connected to the 8 inputs of the mux.
CCPotentiometer volumePotentiometers[] {
  { mux.pin(0), { MIDI_CC::Channel_Volume, Channel_1 } },
  { mux.pin(1), { MIDI_CC::Channel_Volume, Channel_2 } },
  { mux.pin(2), { MIDI_CC::Channel_Volume, Channel_3 } },
  { mux.pin(3), { MIDI_CC::Channel_Volume, Channel_4 } },
  { mux.pin(4), { MIDI_CC::Channel_Volume, Channel_5 } },
  { mux.pin(5), { MIDI_CC::Channel_Volume, Channel_6 } },
  { mux.pin(6), { MIDI_CC::Channel_Volume, Channel_7 } },
  { mux.pin(7), { MIDI_CC::Channel_Volume, Channel_8 } },
};
 
void setup() {
  Control_Surface.begin();  // Initialize the Control Surface
}

void loop() {
  Control_Surface.loop();  // Update the Control Surface
}

Example 3: Control Surface also supports many types of MIDI inputs. For example, an LED that turns on when a MIDI Note On message for middle C is received:

#include <Control_Surface.h>

USBMIDI_Interface midi;
NoteLED led { LED_BUILTIN, MIDI_Notes::C[4] };

void setup() { Control_Surface.begin(); }
void loop() { Control_Surface.loop(); }

Example 4: Control Surface's MIDI interfaces can also be used directly, for example, to implement a MIDI-over-USB to MIDI-over-BLE adapter:

#include <Control_Surface.h>

// Instantiate MIDI over BLE and MIDI over USB interfaces
BluetoothMIDI_Interface midi_ble;
USBMIDI_Interface midi_usb;
// Pipes allow routing between MIDI interfaces
BidirectionalMIDI_Pipe pipes;

void setup() {
  // Route the MIDI input from the USB interface to the BLE interface,
  // and the MIDI input from the BLE interface to the USB interface
  midi_usb | pipes | midi_ble;
  // Initialize the MIDI interfaces
  MIDI_Interface::beginAll();
}

void loop() {
  // Continuously poll all interfaces and route the traffic between them
  MIDI_Interface::updateAll();
}

Getting started

See the Getting Started page to get started using the library.
It'll also point you to the Installation Instructions.

The MIDI tutorial might be useful if you want to use Control Surface as a regular MIDI library, for sending and receiving MIDI messages.

Documentation

Detailed documentation for this library can be found here:
Documentation
Arduino examples can be found here:
Examples

The User Manual is the best entry point to the documentation. To get a complete overview of all features of the Control Surface library, have a look at the following section and at the Topics page.

You can find an answer to some frequently asked questions on the FAQ page.

Feature overview

This library turns your Arduino-compatible board into a MIDI control surface.
Just connect some push buttons, potentiometers, LEDs ... and declare them in your code.

The following sections give a brief overview of the features of the library.

MIDI Interfaces

  • MIDI over USB
  • Serial MIDI (e.g. 5-pin DIN MIDI)
  • Debug MIDI (prints out the messages in a readable format, and allows you to input text based messages, like a MIDI monitor)
  • MIDI over Bluetooth LE
  • AppleMIDI over WiFi or Ethernet

<sub>MIDI Interfaces documentation</sub>

MIDI Control Output

  • Push buttons and toggle switches
  • Potentiometers, faders and other analog sensors
  • Rotary encoders
  • Scanning keyboard matrices

Digital inputs are debounced, and analog inputs are filtered using digital filters and hysteresis. This results in high accuracy without noise, without introducing latency.

These MIDI control outputs can be used to send MIDI notes, Control Change, Pitch Bend, Program/Patch change, etc.

<sub>MIDI Output Elements documentation</sub>

MIDI Control Input

  • LEDs (e.g. to indicate whether a track is muted/armed/soloed)
  • LED rings (e.g. to indicate the position of a pan knob)
  • LED strips (using the FastLED library)
  • VU meters
  • OLED displays
  • 7-segment displays

A large portion of the Mackie Control Universal (MCU) protocol is implemented.

<sub>MIDI Input Elements documentation</sub>

Motorized faders

<sub>Control Surface Motor Fader documentation</sub>

Bank support

All controls can be arranged in banks: for example, if you have only 4 physical faders, you can make them bankable, so they can be used to control the volume of many more different tracks. Changing banks can be done using push buttons, rotary encoders, etc.
Apart from banks and bank selectors, you can also add transposers to change the key of your notes, for example.

Extended input/output

In order to save some IO pins, the library natively supports multiplexers (e.g. 74HC4051 or 74HC40

Related Skills

View on GitHub
GitHub Stars1.6k
CategoryDevelopment
Updated3d ago
Forks164

Languages

C++

Security Score

100/100

Audited on Aug 4, 2026

No findings