Control Surface_ Control Surface
Control Surface_ Control Surface
Main Page User Manual Related Pages Topics Namespaces Classes Files Examples Search
Control Surface
C I Tests passing Test Coverage 85.7% Examples passing GitHub 1.2k Documentation main
Control Surface
Control Surface is an Arduino library for building MIDI controllers and control surfaces.
At its core, the library features a exible 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
¶ Example usage
¶ Getting started
¶ Documentation
Generated by 1.10.
¶ Feature overview
¶ Supported boards
¶ 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 ve lines of code:
#include <Control_Surface.h>
USBMIDI_Interface midi;
CCPotentiometer pot { A0, MIDI_CC::General_Purpose_Controller_1 };
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.
// 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] };
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>
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 nd 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
Digital inputs are debounced, and analog inputs are ltered using digital lters 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.
VU meters
OLED displays
7-segment displays
Motorized faders
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 74HC4067) to read many switches or potentiometers, Shift Registers (e.g.
74HC595) to drive many LEDs, MAX7219 LED drivers, etc.
→ Extended IO documentation
Audio
If you are using a Teensy 3.x or 4.x, you can use it as a USB audio interface. Just add an I²S DAC (e.g. PCM5102) and 5 lines of code, and you can start playing audio
through your Teensy, by combining Control Surface with the Teensy Audio library.
You can also add volume controls and VU meters for these audio connections.
Thanks to the structure of the library, you can easily add your own MIDI or display elements, using some minimal, high level code. All low level stuff is completely
reusable (e.g. all MIDI operations, debouncing switches, ltering analog inputs, and so on).
Installation
Download the repository as a ZIP archive by going to the home page of the repository and clicking the green Code button in the top right, then choosing “Download
ZIP”.
Alternatively, click the following direct download link: https://github.com/tttapa/Control-Surface/archive/refs/heads/main.zip
Open the Arduino IDE, and go to the Sketch > Include Library > Add .ZIP Library menu.
Then navigate to your downloads directory where you just downloaded the library.
Select it, and click Ok.
Supported boards
For each commit, the continuous integration tests compile the examples for the following boards:
Arduino UNO
Arduino Mega
Arduino Leonardo
Teensy 3.2
Teensy 4.1
Arduino Due
Arduino Nano Every
Arduino Nano 33 IoT
Arduino Nano 33 BLE
ESP8266
ESP32
ESP32-S3
Raspberry Pi Pico
This covers a very large part of the Arduino platform, and similar boards will also work. For example, the Arduino Nano, Mega, Micro, Pro Micro, Teensy 2.0, Teensy LC,
Teensy 3.x, Teensy 4.x are all known to work.
If you have a board that's not supported, please open an issue and let me know!
Note that MIDI over USB and MIDI over Bluetooth are not supported on all boards. See the MIDI over USB documentation page for a table with supported features per
board.
(b0f4d63)
Replace MIDI_Notes::X(n) by MIDI_Notes::X[n] to avoid issues with the Arduino F(...) macro.
(7b0eee1)
Speed up compilation by removing many source les that were only used for testing.
(07b8729)
Improved Mbed OS USB MIDI implementation.
(d7a4e69)
Added support for BluetoothMIDI_Interface on the Raspberry Pi Pico W.
(196b5fc)
Added ArduinoBLE backend for BluetoothMIDI_Interface .
(d4d7435)
Completely refactored BluetoothMIDI_Interface , with support for the NimBLE and ArduinoBLE backends.
(9c4cdd4)
More upper case constants and enumerators have been deprecated. For example, ControlChange should be used instead of CONTROL_CHANGE . If you continue
using the old versions, you will get a compiler warning. These old versions will be removed in a future version of Control Surface.
(aaf6eea)
The upper case CHANNEL_x and CABLE_x constants have been deprecated in favor of the title case versions Channel_x and Cable_x . This was done to avoid
con icts with macros de ned by the ArduinoCore-renesas.
For the same reason, the CS namespace has been renamed to cs .
(47b2d5e)
The Encoder class has been replaced by AHEncoder . The code has been cleaned up and support was added for newer boards like the Raspberry Pi Pico.
(c35f29c)
The SoftwareSerial MIDI interfaces are now in separate header les that have to be included explicitly if you want to use them. The headers in question are
SoftwareSerialMIDI_Interface.hpp and SoftwareSerialDebugMIDI_Interface.hpp . This prevents rede nition errors of pin change interrupt vectors even if
SoftwareSerial is not used.
(bf8fb66)
The abbreviated MIDI send functions (such as sendCC() ) have been deprecated in favor of the full names (e.g. sendControlChange() ). See the MIDI_Sender
documentation for a full overview.
(cf32e7e)
Control_Surface.setMIDIInputCallbacks() now takes four arguments instead of three, because a System Common callback was added.
(b727931)
The MIDI note name for the note F has been changed from F to F_ in order to avoid con icts with the F() macro and its functional equivalent introduced here.
It is now recommended to use MIDI_Notes::C(4) instead of note(C, 4) .
(a81bd19)
Classes that make use of the SPI interface now require you to pass the SPI object as a constructor argument. This allows you to use SPI1 or SPI2 (if available
for your hardware).
(c6e35b9)
The NoteBitmapDisplay class has been renamed to BitmapDisplay .
(37b6901)
The NoteValueLED and CCValueLED classes (and similar) have been replaced by NoteLED and CCLED respectively.
The display elements BitmapDisplay , VPotDisplay , VUDisplay etc. are now generic in the type of value that they display. In most cases, you should be able to
update your sketch by adding <> after the type names, e.g. BitmapDisplay<> , VPotDisplay<> , etc.
(1a21d13)
The line numbers of LCDDisplay are now one-based: 1 is the rst line and 2 is the second line. This is more consistent with the track parameter and the API of
the rest of the library. (Before, the rst line was 0 and the second line was 1 .)
(40e3d7a)
Control Surface now comes with an Encoder library out of the box. You no longer have to install or include Encoder.h in your sketches.
1.x
(8a3b1b3)
Before, Control_Surface.MIDI() was used to get the MIDI interface used by Control Surface. This method was removed, because you can now connect multiple
interfaces to Control Surface, using the MIDI Pipe routing system. To send MIDI using Control Surface, you can now use Control_Surface.sendCC(...) and the
other similar methods directly.
(8a3b1b3)
For the same reason as the bullet above, the MultiMIDI_Interface was removed, and has been replaced by the MIDI Pipe routing system.
(bca6e11)
The color mapper for NoteRangeFastLED and the like now takes a second parameter that represents the index of the LED within the LED strip.
(3c01c7d)
The maximum supported ADC resolution is now used by default (e.g. 13 bits on Teensy 3.x, 12 bits on ESP32).
This increases the accuracy of analog inputs and controls for the Control Surface library, but could cause problems if your code uses other libraries that expect
the resolution to be 10 bits.
You can change the default resolution to 10 bits in src/AH/Settings/Settings.hpp if you have to.
(31edaa6)
The mapping function is now applied before applying hysteresis.
This means that the input and output values of the function should be 16 - ANALOG_FILTER_SHIFT_FACTOR bits wide instead of 7. By default this is 14 bits. You
can get the maximum value in a portable way by using the FilteredAnalog<>::getMaxRawValue() function.
The signature of the mapping function is now analog_t f(analog_t raw) , where the return value and raw are both numbers in [0, 16383] by default.