Coder Social home page Coder Social logo

tttapa / control-surface Goto Github PK

View Code? Open in Web Editor NEW
1.2K 58.0 134.0 94.49 MB

Arduino library for creating MIDI controllers and other MIDI devices.

License: GNU General Public License v3.0

Shell 0.37% C++ 94.38% C 3.11% Python 1.43% CMake 0.22% CSS 0.40% HTML 0.10% Makefile 0.01%
arduino arduino-library midi-controller control-surface midi midi-over-usb midi-over-ble teensy esp32 raspberry-pi-pico

control-surface's Introduction

Build Status Test Coverage Examples GitHub Documentation

Control Surface

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
Example usage
Getting started
Documentation
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 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

MIDI Interfaces documentation

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.

MIDI Output Elements documentation

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.

MIDI Input Elements documentation

Motorized faders

Control Surface Motor Fader documentation

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.

Teensy Audio documentation

Modular and extensible

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, filtering 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
  • Arduino Nano Every
  • Arduino UNO R4 Minima
  • Arduino UNO R4 WiFi
  • 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.

Change log and updating

2.x

  • (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 files 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 conflicts with macros defined 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 files 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 redefinition 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 conflicts 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 first 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 first 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.

control-surface's People

Contributors

dependabot[bot] avatar tttapa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

control-surface's Issues

Track Names for OLED

Hi Pete

More of a question than an issue

I have been looking through the getting stated doc for the oled displays and i am wondering if there is a "Track name" display for the oled display
so i can see what track the controller is on

i set cubase as a mackie controller and changed the track name- in the debugging serial monitor it says Data bye ignored when it send the message through to the controller

So i think it is sending out the messages

What are your thoughts

Cheers Sam

Espressif chips

I was looking for a way to revive old controllers and this looks ideal. Are there any plans to get this working for ESP8266 or the bigger ESP32? They have wireless and BLE onboard along with loads of GPIO and may be cheaper than their Arduino equipvalents.

Invert Potentiometer

I looked, but I don't see a way to invert a potentiometer signal. Is this possible to do? I would rather not need to reverse polarity in hardware. Specifically, I have an array of potentiometers.

Possibility of communication between modules

Hi Pete

Is there a possibility of getting the Arduino boards to communicate with each other so that each module is on the buss with one master module passing the Midi information to/from the PC via usb.
Either over I2C or similar using the spare TX RX ports

If the message is a channel 2 message it only gets recognized by the #2 module

The modules can be programmed exactly the same except for the midi channel number
All of the slaves would only need to be powered by a 9v supply.and connected on the bus.

With this approach there is the possibility of having a modular up to 48 ch mixing console with with (EQ and Dynamics modules) setup using only 3 usb ports (and only 3 generic midi controllers).

i.e.

Fader module 1 : (mega 1 sends and receives midi data to/from Master)
CCPotentiometer potentiometer(A0, {MIDI_CC::Channel_Volume, CHANNEL_1});

Fader Module 2 : (mega 2 sends and receives midi data to/from Master)
CCPotentiometer potentiometer(A0, {MIDI_CC::Channel_Volume, CHANNEL_2});

Master Module: (Mega 16) Passes all information to PC
CCPotentiometer potentiometer(A0, {MIDI_CC::Channel_Volume, CHANNEL_16});

I am about to start the design of the EQ Module and Master Modules
All will have their own controller(Mega) and custom pcb
All Face panels will be laser cut
8 fader assembly img2

How to change leds' channel used in shift register?

Hello Pieter!
I have 3 momentary buttons that connected to multiplexer and send midi notes.
I have 3 leds connected to 3 shift registers

My sketch works fine and leds react to push buttons. The problem is that leds react only on CHANNEL_1, if I change buttons' channel to CHANNEL_2 leds doesn't work.

How can I change leds' channel that react on midi notes?

Here is a piece of code from my sketch:

NoteButton button[] = {
  {mux.pin(0),{note(C, 4), CHANNEL_1}},
  {mux.pin(7),{note(D, 4), CHANNEL_1}},
  {mux.pin(15),{note(E, 4), CHANNEL_1}}
};
  
// Create an array of LEDs that listen to MIDI Note messages, turning on and off
// the LEDs connected to the eight input pins of the shift register
MIDINoteLED leds[] = {
  {sreg.pin(1), note(C, 4)}, // LED pin, address (note number, channel, cable)
  {sreg.pin(9), note(D, 4)},
  {sreg.pin(17), note(E, 4)}
};

Reading a CC value to ShiftReg Vu-Meter

Hello, I want to read a CC value send from Traktor( for example the CC 004 of the channel 3) with a range from 0 to 127 and according to the value, light 8 leds increasingly like a VU-Meter.

I have searched and I only have found in the examples some banks and in the example of the ShiftReg LEDs that it light up all the LEDs, but it doesn0t read the CC value and according to that, make the VUMeter effect.
So, how can I do that?
Thank you so much
Best regards

How to use rgb leds with common anode?

Hello Pieter!
I have one shift register and 3 RGB Leds.
I have 3 buttons in multiplexer
When I press first button red color of led should light up. WHen I press it again a led light should go out.
Second button - green color of second led
Third button - blue color of third led
Usually RGB leds have common cathode, but my rgb leds have common anode.
How should I wire rgb led to shift register in this case?

Can you give me a simple example of buttons and rgb leds for my case?

Potentiometer Calibrated? Need Help

There is a example for Potentiometer map Calibrated like the old version? im trying :

CCPotentiometer potentiometer(A15, {MIDI_CC::Channel_Volume, CHANNEL_2});

const int minimumValue = 10;    // the analog value read when the potentiometer is in the minimum position.
const int maximumValue = 1000; // the analog value read when the potentiometer is in the maximum position.

int mapCalibrated(int value) {
  value = constrain(value, minimumValue, maximumValue); // make sure that the analog value is between the minimum and maximum value
  return map(value, minimumValue, maximumValue, 0, 1023); // map the value from [minimumValue, maximumValue] to [0, 1023]
}

but doesnt work
Thank you

button matrix.ino

With the new "fix" it seems to compile the basic examples but the button-matrix sketch is still giving me error in compile:

Ex.11.Button-Matrix:34:81:` error: no matching function for call to 'ButtonMatrix<4, 3>::ButtonMatrix(<brace-enclosed initializer list>, <brace-enclosed initializer list>, const uint8_t [4][3], int, const uint8_t&)'
 ButtonMatrix<4, 3> buttonmatrix( {2, 3, 4, 5}, {6, 7, 8}, addresses, 1, velocity);
                                                                                 ^
In file included from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Hardware/ButtonMatrix.hpp:78:0,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/MIDI_Outputs/Abstract/MIDIButtonMatrix.hpp:4,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/MIDI_Outputs/CCButtonMatrix.hpp:3,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Control_Surface.h:31,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/examples.old/very-old/Ex.11.Button-Matrix/Ex.11.Button-Matrix.ino:22:
/Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Hardware/ButtonMatrix.ipp:8:1: note: candidate: ButtonMatrix<nb_rows, nb_cols>::ButtonMatrix(PinList<nb_rows>&, PinList<nb_cols>&) [with unsigned char nb_rows = 4; unsigned char nb_cols = 3; PinList<nb_rows> = Array<short unsigned int, 4>; PinList<nb_cols> = Array<short unsigned int, 3>]
 ButtonMatrix<nb_rows, nb_cols>::ButtonMatrix(const PinList<nb_rows> &rowPins,
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Hardware/ButtonMatrix.ipp:8:1: note:   candidate expects 2 arguments, 5 provided
In file included from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/MIDI_Outputs/Abstract/MIDIButtonMatrix.hpp:4:0,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/MIDI_Outputs/CCButtonMatrix.hpp:3,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Control_Surface.h:31,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/examples.old/very-old/Ex.11.Button-Matrix/Ex.11.Button-Matrix.ino:22:
/Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Hardware/ButtonMatrix.hpp:18:7: note: candidate: constexpr ButtonMatrix<4, 3>::ButtonMatrix(const ButtonMatrix<4, 3>&)
 class ButtonMatrix {
       ^~~~~~~~~~~~
/Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Hardware/ButtonMatrix.hpp:18:7: note:   candidate expects 1 argument, 5 provided
Ex.11.Button-Matrix:34:20: error: cannot declare variable 'buttonmatrix' to be of abstract type 'ButtonMatrix<4, 3>'
 ButtonMatrix<4, 3> buttonmatrix( {2, 3, 4, 5}, {6, 7, 8}, addresses, 1, velocity);
                    ^~~~~~~~~~~~
In file included from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/MIDI_Outputs/Abstract/MIDIButtonMatrix.hpp:4:0,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/MIDI_Outputs/CCButtonMatrix.hpp:3,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Control_Surface.h:31,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/examples.old/very-old/Ex.11.Button-Matrix/Ex.11.Button-Matrix.ino:22:
/Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Hardware/ButtonMatrix.hpp:18:7: note:   because the following virtual functions are pure within 'ButtonMatrix<4, 3>':
 class ButtonMatrix {
       ^~~~~~~~~~~~
/Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Hardware/ButtonMatrix.hpp:63:18: note: 	void ButtonMatrix<nb_rows, nb_cols>::onButtonChanged(uint8_t, uint8_t, bool) [with unsigned char nb_rows = 4; unsigned char nb_cols = 3; uint8_t = unsigned char]
     virtual void onButtonChanged(uint8_t row, uint8_t col, bool state) = 0;
                  ^~~~~~~~~~~~~~~
/Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/examples.old/very-old/Ex.11.Button-Matrix/Ex.11.Button-Matrix.ino: In function 'void loop()':
Ex.11.Button-Matrix:40:19: error: 'class Control_Surface_' has no member named 'refresh'
   Control_Surface.refresh();
                   ^~~~~~~
Multiple libraries were found for "SPI.h"
 Used: /Users/brorgustav/Documents/Arduino/Sketches/libraries/SPI
 Not used: /Users/brorgustav/Library/Arduino15/packages/arduino/hardware/samd/1.8.3/libraries/SPI
Using library Control-Surface at version 1.0.0 in folder: /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface 
Using library SPI at version 1.0 in folder: /Users/brorgustav/Documents/Arduino/Sketches/libraries/SPI 
Using library MIDIUSB at version 1.0.4 in folder: /Users/brorgustav/Documents/Arduino/Sketches/libraries/MIDIUSB 
exit status 1
no matching function for call to 'ButtonMatrix<4, 3>::ButtonMatrix(<brace-enclosed initializer list>, <brace-enclosed initializer list>, const uint8_t [4][3], int, const uint8_t&)'

Compiling ex11 button matrix example for MKRZERO

When compiling buttonmatrix.ino:

In file included from /Users/brorgustav/Library/Arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/arm-none-eabi/include/c++/7.2.1/bits/char_traits.h:39:0,
                 from /Users/brorgustav/Library/Arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/arm-none-eabi/include/c++/7.2.1/ios:40,
                 from /Users/brorgustav/Library/Arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/arm-none-eabi/include/c++/7.2.1/ostream:38,
                 from /Users/brorgustav/Library/Arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/arm-none-eabi/include/c++/7.2.1/iterator:64,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Helpers/LinkedList.hpp:9,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Display/DisplayInterface.hpp:4,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Display/DisplayElement.hpp:3,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Control_Surface/Control_Surface_Class.hpp:7,
                 from /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface/src/Control_Surface.h:16,
                 from /Users/brorgustav/Documents/Arduino/Sketches/axiom32_ttappa-lib_mkrzero_keyboard/axiom32_ttappa-lib_mkrzero_keyboard.ino:22:
/Users/brorgustav/Library/Arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/arm-none-eabi/include/c++/7.2.1/bits/stl_algobase.h:243:56: error: macro "min" passed 3 arguments, but takes just 2
     min(const _Tp& __a, const _Tp& __b, _Compare __comp)
                                                        ^
/Users/brorgustav/Library/Arduino15/packages/arduino/tools/arm-none-eabi-gcc/7-2017q4/arm-none-eabi/include/c++/7.2.1/bits/stl_algobase.h:265:56: error: macro "max" passed 3 arguments, but takes just 2
     max(const _Tp& __a, const _Tp& __b, _Compare __comp)
                                                        ^
Multiple libraries were found for "SPI.h"
 Used: /Users/brorgustav/Documents/Arduino/Sketches/libraries/SPI
 Not used: /Users/brorgustav/Library/Arduino15/packages/arduino/hardware/samd/1.8.3/libraries/SPI
Using library Control-Surface at version 1.0.0 in folder: /Users/brorgustav/Documents/Arduino/Sketches/libraries/Control-Surface 
Using library SPI at version 1.0 in folder: /Users/brorgustav/Documents/Arduino/Sketches/libraries/SPI 
Using library MIDIUSB at version 1.0.4 in folder: /Users/brorgustav/Documents/Arduino/Sketches/libraries/MIDIUSB 
exit status 1
Error compiling for board Arduino MKRZERO.

How to make leds react on MidiCC instead of notes?

I have 3 shift registers and 3 leds.
You have an example to use leds that reacts on MidiNote

Is it possible to make leds react on MidiCC instead? How can I do that?

MIDINoteLED leds[] = {
{sreg.pin(1), note(C, 4)}, // LED pin, address (note number, channel, cable)
{sreg.pin(9), note(D, 4)},
{sreg.pin(17), note(E, 4)}
};

How to use Midi CC instead of Note with button?

Hi Pieter!
I want to use button and send midi cc, but in your example : Midi Output/Buttons and Switched/Momentary push buttons/NoteButton you made sending only NoteNumber

How can I change the code to send Midi CC to my DAW instead of NoteNumber with a button?

Can you give me a nexample of using a button that sends midi cc?

How can I read Note ID(Address) and velocity from DAW?

Hi, there!
I want to receive a MIDI signal from the DAW and read it from the Arduino to adjust my LED strip based on Note ID and Velocity.
I'm using Neopixel's strip and hopefully I can read the Note ID and Velocity even if there's no function for that.
The example on the part that receives the MIDI signal seems to be missing these questions.
Can you show me a simple example of reading MIDI Note Signals?

Thanks!

Led with shift register 74hc595 doesn't work by SPI

Hello Pieter!

My board is Arduino Leonardo

I connected a led to shift register SN74HC595N by SPI. It doesn't work. Led blinks fast even if I change a code. It seems it work incorrectly. But if I connect a led in a regular way(digital pins instead of iscp header pins) with a sketch for regular connection it works fine

Did I make wrong wiring?

Here is i connected all the stuff:

arduino leonardo shift register

Here is my sketch:

`#include <Control_Surface.h> // Include the Control Surface library.

using namespace ExtIO; // Bring the ExtIO pin functions into your sketch

// Instantiate a shift register with the SPI slave select pin as latch pin, most
// significant bit first, and a total of 8 outputs.
SPIShiftRegisterOut<8> sreg = {10, MSBFIRST};

const pin_t ledPin = sreg.pin(1); // first pin of the shift register

void setup() {
sreg.begin(); // Initialize the shift registers
pinMode(ledPin, OUTPUT); // You don't even need this line, since
// shift registers are always outputs
}

void loop() {
// Toggle the state of the LED every 1/2 second
digitalWrite(ledPin, HIGH);
delay(700);
digitalWrite(ledPin, LOW);
delay(700);
}`

How can I change button's note with master button?

I tried to semitone the notes assigned to all buttons while pressing the 'master button'.

...
#define MASTERBTN      42
boolean isMaster = false;
...
char noteNames[] = {C, D, E, F, G, A, B};
int noteNum = 3;
...
NoteButton buttons[] = {
  {43, {note(noteNames[0], noteNum), CHANNEL_1}},
  ...
  {33, {note(noteNames[0], noteNum + 2), CHANNEL_1}}
};
...
void loop() {
  if(digitalRead(MASTERBTN) == LOW) {
    if(!isMaster) {
      isMaster = true;
      noteNames[0] = C;
      noteNames[1] = Db;
      noteNames[2] = Eb;
      noteNames[3] = F;
      noteNames[4] = Gb;
      noteNames[5] = Ab;
      noteNames[6] = Bb;
      Serial.println("here we are");
    }
  } else {
    if(isMaster) {
      isMaster = false;
      noteNames[0] = C;
      noteNames[1] = D;
      noteNames[2] = E;
      noteNames[3] = F;
      noteNames[4] = G;
      noteNames[5] = A;
      noteNames[6] = B;
      Serial.println("now here");
    }
  }
  Control_Surface.loop();
  FastLED.show();
}

I could check the serial messages, but the log and MIDI signals did not output the modified note.
How can I change button's note with master button?

botton bank

hi, i am having trouble on a code for a 6 banks of buttonmatrix with 6 leds and two butons for changing banks
buttom matrix is 6 buttons (two rows 3 colums)
i want to be able to choose the note for each button in every bank. i try some of the examples but i get errors with them.
thanks in advance

Use input value in project

Hi,

I Want to use the value of an input in code

example
i get an input for MIDI_CC::Channel_Volume
i want to do some calculations and write it to the serial port

how can i get this to work

(SOLVED) MIDI IN / LED with multiplexer ?

I know this library is under construction, but my questions is there is a way or did it support using Multiplexer for MIDI Input / LEDs for the Final/Alpha Release? Maybe an example?

Thank You

Pro Micro Supported ?

Hi Pieter
Thank you for your work on this great library !

I need to ask - Is Pro Micro ATMega32U4 currently supported?

I tried the Potentiometer example and code compiles and uploads fine, but USB device is not recognized in Windows. This is the same for Control-Surface as well as MIDIController. The unit should be ok, USBMidiKlik seems to be recognized.

This could very well be problems with my toolchain, I just wanted to check if it's supposed to work : )

Thank you a million in advance for clarifying this, and have a nice day.
BR Jesper

rotary encoders

Hi Peter

How you going

So i have updated my library to your latest version of control surface
and just going through and changing all the namespaces
but i cant find any examples of the rotary encoder code lines

can you help me out or point me in the right direction where i can find it

i was using the old RotaryEncoder for my pan control and now it throws an error on compiling
says it does not name a type

sorry to bother you with something so trivial (i really am terrible at any form of coding)

and thanks again you have put a lot of time and effort into this code and i really appreciate it

Getting MIDI Clock from DAW

Hi
First of all thank you for this great library.
I have a sketch that works fine with getting the realtime messages via midi.read() / serial.read() and sync is working fine but once I call Control_Surface.begin() the midi clock timing is messed up.
I saw that there is a "onRealtimeMessage" callback in the documentation but I can't manage to get it to work, can you please share an example on how to define callback for real time midi messages in a sketch?
Thank you.

MMC

Hi,
I am trying to make a simple remote control with MIDI, just play, stop, rec button with feedback from the controlled machine, lighting led for each function. I have tried your library but no way. I am trying to control protools with hui protocol. It seems that MCU does not match HUI.
Do you have a clue?
Thanks?
Pierre

OLED display + midi clock

I see that you already have implemented OLED display possibilities but it is for spi displays. Will it be possible to have the same for I2C ?

Also, I don't find a way to use midi clock to display the bpm from my DAW with,for example, a led. Is it in your plans ?

add led on/off while midi send note

Description of the problem or question

i make usb midi foot controller from your library and your library very good and easy to use .. but i use 8 button and 8 led... i want when button press
led is on and when button press again led is off.. can you teach me how can make easy away for the code or method modif your library?
this is my code

Full code

#include <MIDI_Controller.h>

int led1 = 10;
int led2 = 16;
int led3 = 14;
int led4 = 15;
int led5 = 18;
int led6 = 19;
int led7 = 20;
int led8 = 21;


const uint8_t velocity = 0b1111111; // Maximum velocity (0b1111111 = 0x7F = 127)
const uint8_t C4 = 60;
const uint8_t D4 = 63;
const uint8_t E4 = 64;
const uint8_t F4 = 65;
const uint8_t G4 = 67;
const uint8_t C3 = 48;
const uint8_t B4 = 71;
const uint8_t D3 = 50;

Digital button1(2, C4, 1, velocity);
Digital button2(3, D4, 1, velocity);
Digital button3(4, E4, 1, velocity);
Digital button4(5, F4, 1, velocity);
Digital button5(6, G4, 1, velocity);
Digital button6(7, A3, 1, velocity);
Digital button7(8, B4, 1, velocity);
Digital button8(9, 72, 1, velocity);


void setup () {}

void loop() {
  MIDI_Controller.refresh();
}

Toggle buttons and leds and send midi cc

Hello Pieter!
I have buttons in multiplexer 4067 and leds in shift registers.

When I press a button midi cc with value should be sent and led will light up, when I press the same button again midi cc with another value should be sent and led will go out.
Buttons should be like toggles.
It's like when you press a a button on a footswitch to change preset on midi controller in some guitar VST like Guitar Rig or Bias FX.

Screenshot_1

I saw CCButtonLatched class, is it what I should use for my task?
I didn't find an example with toggle buttons and leds
Can you write me an example how to use buttons as toggles with leds?

Teensy 3.6 Problem with Mux (CD74HC4067) and Reading Buttons

I have a problem that drives me crazy, same wiring and code working 100% on Arduino Mega but on Teensy 3.6 one button affects the other once.

I tried reducing the Teensy CPU Speed to 24MHZ and it looks like it is working correctly,
I searched in the documentation and didn't see a special settings to define once using Teensy...
Am I missing something?

another less urgent question - how can I change the midi device name ? tried renaming the string in Teensy-USB-MIDI-name.c and it didn't work...

Thanks

It's possible? One LED for VU

wonder if there is any implementation to use one LED to inform the intensity of the sound in a particular DAW channel. Something like the led that is used in the MUTE, (MCU :: MUTE_1, 1) only by alternating the led intensity according to volume.

thanks for attention

Dual midi interface

hello Pieter
i got error using dual midi interface... im using lilypad atmega32u4
the problem is when i upload dual midi interface always got error Couldn't find a Board on the selected port. but if i just using USBMIDI_Interface midi always succesfull.

and this my code..

#include <Control_Surface.h>

// Instantiate a MIDI over USB interface.
//USBMIDI_Interface midi;

USBMIDI_Interface usbmidi;
HardwareSerialMIDI_Interface serialmidi = {Serial1, MIDI_BAUD};
MultiMIDI_Interface<2> midi = {{&usbmidi, &serialmidi}};

// Instantiate the momentary pbuush buttons that send out MIDI Note events.
CCButtonLatched  buttons[] = {
    {21, MIDI_CC::Effects_1}, // 
    {19, MIDI_CC::Effects_2},
};

constexpr size_t numberOfButtons = sizeof(buttons) / sizeof(*buttons);

// The pins of the LEDs that will display the state of the buttons
pin_t ledPins[] = {
    18,
    15,
};

constexpr size_t numberOfLEDs = sizeof(ledPins) / sizeof(*ledPins);
static_assert(numberOfButtons == numberOfLEDs,
              "Error: number of buttons is not "
              "the same as the number of LEDs!");
void setup() {
    // Initialize everything
    Control_Surface.begin();

    for (pin_t &pin : ledPins)
        pinMode(pin, OUTPUT);
}

void loop() {
    // Update the control surface: read new MIDI events, and read all inputs
    Control_Surface.loop();

    for (uint8_t i = 0; i < numberOfLEDs; ++i)
        digitalWrite(ledPins[i], buttons[i].getState());
}

HOW TO Modif LIBRARY

HI PIETER..
I want ask about library control surface
how i can make CCButtonlatched.hpp send MIDI CC from modif NoteButtonLatched.hpp.
i want make like example like pushbutton no midi feedback .. but with MIDI CC send..
thanks
Best Regards.

Transpose function

Hi Pete

Does the transpose function work on rotary encoder addresses?

To change the panning from the address i set to another address

This way i can activate/deactivate the encoder button top and adjust the lh or rh panning function in a dual pan setup?

Cheers

How to connect multiple multiplexers and buttons?

Hello Pieter!
I use Multiplexers 4067
I saw your example with multiplexer and button but what if I wanna use multiple multiplexers and many buttons that send midi notes

How should I connect pins of all multiplexers? I mean pins SIG, S0, S1, S2, S3

What code for multiplexers should look like? Can you give me an example?

Send MIDI Note value through a potentiometer.

Hi!

Hope you're doing well.
I am currently in the beginning process of building a MIDI controller which works in a slightly unusual way and I am not too sure where to head in terms of writing the code for one specific action.

To be precise, I would like to use the variable resistance of a potentiometer to assign specific note values to each knob and have it in a way such as:

the potentiometer is all the way to the left at 0 = note off
as it turns clockwise = note on (a specific note for example middle c) and for each incremental change in the position of the knob have it reflect into an increase of midi velocity with the max being at 127.

How is it possible to do this?

Thank you so much for your time in advance,

Kindly

Gio

Motorised Faders

Looking through the files i can see that there are several ways to receive the incoming midi messages from Cubase 8.5 but i am using it a a generic remote. that way io can programm my own functions.
and it works great.
I have managed to get everything working except the shift registers :( any help there with your schematics would be great. i think its my wiring that's wrong

But....

How can i modify this to give me the data from the MIDIcc message to control the motor fader controlled on a Hbridge for instance. https://github.com/codyhazelwood/motorized-fader-arduino such as this.

Other than that this code is awesom and works great on my 2560 with HIDUINO. NICE WORK

sorry im not very good a coding. i have been looking through all the LIB source code and i think i can do it in a similar way to your VU input for instance.

In cubase i have turned the transmit and receive button on and can see on the RX LED on the Board that every time i switch banks in cubase it is sending the data for the Fader position.

I just cannot work out how to use it :(
cubase

#include <Control_Surface.h> // Include the library

const uint8_t velocity = 0b1111111; // Maximum velocity (0b1111111 = 0x7F = 127)
const uint8_t addresses[4][4] = {   // the note numbers corresponding to the buttons in the matrix
  {  1,  2,  3, 13 },
  {  4,  5,  6, 14 },
  {  7,  8,  9, 15 },
  { 10, 11, 12, 16 },
};

// Create a new instance of the class 'ButtonMatrix', called 'buttonmatrix', with dimensions 4 rows and 3 columns, with the rows connected to pins 2, 3, 4 and 5
// and the columns connected to pins 6, 7 and 8, that sends MIDI messages with the notes specified in 'addresses' on MIDI channel 1, with velocity 127
ButtonMatrix<4, 4> buttonmatrix( {14, 15, 16, 17}, {18, 19, 20, 21}, addresses, 1, velocity);

const uint8_t BANK_LEFT = 0x2E;
const uint8_t BANK_RIGHT = 0x2F;
const uint8_t LED1 = 61;// Note number 60 is defined as middle C in the MIDI specification
const uint8_t LED2 = 62;
const uint8_t LED3 = 63;
const uint8_t LED4 = 64;
const uint8_t LED5 = 65;
const uint8_t LED6 = 66;
const uint8_t LED7 = 67;
const uint8_t LED8 = 68;
const uint8_t LED9 = 69;
const uint8_t LED10 = 70;
const uint8_t LED11 = 71;
const uint8_t LED12 = 72;
const uint8_t LED13 = 73;
const uint8_t LED14 = 74;
const uint8_t LED15 = 75;
const uint8_t LED16 = 76;
const uint8_t test = 60;

//_____________________________________________________________________________________________________________________________________________________________________________________________

MIDI_LED leds[] = {
    {22, LED1, 1},
    {23, LED2, 1},
    {24, LED3, 1},
    {25, LED4, 1},
    {26, LED5, 1},
    {27, LED6, 1},
    {28, LED7, 1},
    {29, LED8, 1},
    {30, LED9, 1},
    {31, LED10, 1},
    {32, LED11, 1},
    {33, LED12, 1},
    {34, LED13, 1},
    {35, LED14, 1},
    {36, LED15, 1},
    {37, LED16, 1},
};

Digital switches[] = {
    {2, 0x10, 1, velocity}, 
    {3, 0x11, 1, velocity},
    {4, 0x12, 1, velocity},
    {5, 0x13, 1, velocity},
    {6, 0x14, 1, velocity},
    {7, 0x15, 1, velocity},
    {8, 0x16, 1, velocity},
};

Analog faders[] = {
    {A0, MIDI_CC::Channel_Volume, 1},
    {A1, MIDI_CC::Channel_Volume, 2},
    {A2, MIDI_CC::Channel_Volume, 3},
    {A3, MIDI_CC::Channel_Volume, 4},
};

Digital bankswitch[] = {
     {9, BANK_LEFT, 1},
     {10, BANK_RIGHT, 1},
};

//_____________________________________________________________________________________________________________________________________________________________________________________________

void setup() {}


void loop() {
  // Refresh the MIDI controller (check whether the potentiometer's input has changed since last time, if so, send the new value over MIDI)
  Control_Surface.refresh();
}

How to send Program Change for Bank/Presets

How to send MIDI message with particular preset (bank) number? Let's assume we have buttons: Bank Down, Bank Up.
Bank Down sends decremented by -1 bank value and Bank Up sends incremented by +1 value. I would like to achieve solution for e.g. LED display which would display bank number and preset number.
Is possible and is there any sense?

bank_and_presets

How to use buttons and send Midi CC and Midi Note through multiplexer?

I have multiplexer CD74HC4067, I connected 3 buttons to it.
I didn't find an example how to send midi notes or midi CC through multiplexer
Can you show me a sketch with one or more buttons?

I found wiring in your test sketch
CD74HC4067 mux = {
2, // input pin
{3, 4, 5, 6}, // Address pins S0, S1, S2, S3
// 7, // Optionally, specify the enable pin
};

should I connect 2 pin on Arduino to pin SIG on multiplexer?

Arduino Esplora Example

I tried to use your library with the Arduino Esplora board and got it finally working.

Are you interested to add my code to your examples? Just asking because Arduino does not support the Esplora board any more.
All sensors are handled as potentiometer. Except for the temperature sensor, which crashed my board, and the piezo buzzer.

For the piezo buzzer, it would be nice to have an easy input access based on this library if this inside to goals of your work.

/**
 * Example for accessing sensors and actuators of the Arduino Esplora board with the 
 * Control Surface library
 * 
 * Currently excluded are the temperature sensor (crashed the Board for me) and the 
 * piezo buzzer.
 * See https://www.arduino.cc/en/Reference/EsploraLibrary for accessing them separately
 * 
 * @boards  Arduino Esplora
 *
 *  Written by tarTG, 2019-12-11  
 *  https://github.com/tttapa/Control-Surface
 */

// Include the library
#include <Esplora.h>
#include <Control_Surface.h>

// Instantiate a MIDI Interface to use
USBMIDI_Interface midi;

//Multiplexer interface
CD74HC4067 mux = {
  A4,       // Analog input pin
  {A0, A1, A2, A3} // Address pins S0, S1, S2
};

//Accelerlometer pins
const byte ACCEL_X_PIN = A5;
const byte ACCEL_Y_PIN = A11;
const byte ACCEL_Z_PIN = A6;

//LED pins
const byte RED_PIN    = 5;
const byte BLUE_PIN   = 9;
const byte GREEN_PIN = 10;


using namespace MIDI_Notes;


// Instantiate a NoteButton object
NoteButton EsploraSwitches[] = {
    //Switches 
    { mux.pin(CH_SWITCH_1), {note(C, 4), CHANNEL_1} },   // Down
    { mux.pin(CH_SWITCH_2), {note(D, 4), CHANNEL_1} },   // Left
    { mux.pin(CH_SWITCH_3), {note(E, 4), CHANNEL_1} },   // Up
    { mux.pin(CH_SWITCH_4), {note(F, 4), CHANNEL_1} },   // Right
    { mux.pin(CH_JOYSTICK_SW), {note(G, 4), CHANNEL_1} } // Joystick switch
};

//Sensors are handled as potentiometer
CCPotentiometer potentiometer[] = {
  { mux.pin(CH_SLIDER),{MIDI_CC::Channel_Volume, CHANNEL_1}},     // Slider
  { mux.pin(CH_JOYSTICK_X),{MIDI_CC::Channel_Volume, CHANNEL_2}}, // Joystick X-Axis
  { mux.pin(CH_JOYSTICK_Y),{MIDI_CC::Channel_Volume, CHANNEL_3}}, // Joystick Y-Axis
  { mux.pin(CH_LIGHT),{MIDI_CC::Channel_Volume, CHANNEL_5}},      // light sensor
  { mux.pin(CH_MIC),{MIDI_CC::Channel_Volume, CHANNEL_6}},        // microphone
  { ACCEL_X_PIN,{MIDI_CC::Channel_Volume, CHANNEL_7}},            // accelerometer X-axis
  { ACCEL_Y_PIN,{MIDI_CC::Channel_Volume, CHANNEL_8}},            // accelerometer Y-axis
  { ACCEL_Z_PIN,{MIDI_CC::Channel_Volume, CHANNEL_9}}             // accelerometer Z-axis
};

//example for accessing the LEDs
NoteValueLED leds[] = 
{
  {RED_PIN, note(C, 4)},
  {BLUE_PIN, note(D, 4)},
  {GREEN_PIN, note(E, 4)} 
};

void setup() {
  Control_Surface.begin(); // Initialize Control Surface
}

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

Selectors and banks

Pieter, thank you for an awesome library and just what I need at the moment for my little project of building a midi controller. Please excuse the questions as I am not a developer. I can understand some programming languages when I read through them slowly but get quite lost in the more technical source code.

I have defined 2 banks, 1 to control the octave being played by a group of NoteButtons, and 1 to control the active midi channel. Octave bank is linked to an Increment/Decrement selector and works perfectly. Channel bank also linked to an Increment/Decrement selector that I'm connecting to pin13 to use as an object holder for the banks. I am successfully using the results from turning a potentiometer to set the active midi channel. So both banks work 100%. My problem is that I would like to use a pot as well to change the octave bank. Doing what I did with the other bank does not work however. In fact nothing works if I set the value of the bank using a variable. I can statically change the bank to a value using an actual int. The code uploads but nothing works, as in there are no midi signals going out and my 7 segment led display does not come on.

I'm pretty sure I'm not using the selectors as they are meant to be, but as mentioned I'm not a developer so I cut and paste a lot, and I work from examples to see how to use certain functions etc, and sometimes I can get what the source is trying to tell me.

I cannot for the life of me figure out what is different between the 2 banks where one would allow me to programatically set the bank and the other causes the entire system not to function ?

Apologies for the very lengthy post...

/* Alpaha Station Zero
 * -------------------
 * Midi controler unit using an Arduino to control buttons, slide potentiometers, rotary potentiometers, and a 4 digit 7 segment LED display 
 * 16 buttons will be direct midi inputs for instrument activation
 * 4 slide potentiometers to control effects
 * 4 rotary potentiometers to control changing of setting options which can be used to assign different settings to the effects sliders for eg...
 * 4 digit 7 segment LED display unit which is controlled by the rotary potentiometers giving each bank 10 settings
 * 
 * https://github.com/tttapa/Control-Surface
 */

#include <Control_Surface.h> // Include the Control Surface library
#include "LedControl.h" // Include library to control 4 Digit 7 Segment display

const int speedMultiplier = 1;

const uint8_t velocity = 0b1111111; // Maximum velocity (0b1111111 = 0x7F = 127)

USBMIDI_Interface midi; // Instantiate a MIDI Interface to use

using namespace MIDI_Notes; // Enable midi notes

CD74HC4067 buttonMux = { // Instantiate a multiplexer to connect all 16 buttons
  12,                    // input pin
  {11, 10, 9, 8},        // Address pins S0, S1, S2, S3
};

CD74HC4067 potMux = { // Instantiate a multiplexer to connect all 8 potentiometers (4 rotary, 4 slide)
  A0,                 // input pin
  {A4, A3, A2, A1},   // Address pins S0, S1, S2, S3
};

LedControl fourdig=LedControl(7, 6, 5, 1); // Instantiate a LED Display object, pin 7 = DataIn, pin 6 = CLK, pin 5 = LOAD, 1 max7219

Bank<16> channelBank(1); // Create 16 banks for the 16 midi channels available
IncrementDecrementSelector<16> switchChannel(channelBank, {13, 13}, Wrap::NoWrap);  // Instantiate an increment/decrement button selector to manipulate with a potentiometer as a channel Bank

Bankable::CCPotentiometer controlPots[] = { // Create an array of potentiometers that send out MIDI Control Change messages when you turn the potentiometers (testing Midi-cc and using pots to control banks)
  {{channelBank, BankType::CHANGE_CHANNEL}, potMux.pin(0), {MIDI_CC::Channel_Volume, CHANNEL_1}},
  {{channelBank, BankType::CHANGE_CHANNEL}, potMux.pin(1), {MIDI_CC::Pan, CHANNEL_1}},
  {{channelBank, BankType::CHANGE_CHANNEL}, potMux.pin(2), {MIDI_CC::Modulation_Wheel, CHANNEL_1}},
  {{channelBank, BankType::CHANGE_CHANNEL}, potMux.pin(3), {MIDI_CC::Effects_5, CHANNEL_1}},
//  {potMux.pin(4), {MIDI_CC::Effects_1, CHANNEL_1}},
//  {A3, {MIDI_CC::Effects_1, CHANNEL_1}},
//  {A5, {MIDI_CC::Modulation_Wheel, CHANNEL_1}},
};


Bankable::PBPotentiometer pbFader = { // Instantiate a PBPotentiometer object, Analog pin connected to potentiometer, MIDI Channel 1 
  {channelBank, BankType::CHANGE_CHANNEL}, potMux.pin(4), CHANNEL_1,                
};

Bank<9> octaveBank(12);  // Create 9 banks for the playable octaves with 12 tracks for the notes

IncrementDecrementSelector<9> switchOctave(octaveBank, {4, 3}, Wrap::NoWrap);  // Instantiate an increment/decrement button selector, increment on pin4 and decrement on pin 3, linked to octaveBank

Bankable::NoteButton buttons[] = {  // Instantiate the momentary push buttons that send out MIDI note events.
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(0), note(C, 0), 1}, // bankselector, bank type, digital input pin, note number, channel
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(1), note(Db, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(2), note(D, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(3), note(Eb, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(4), note(E, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(5), note(F, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(6), note(Gb, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(7), note(G, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(8), note(Ab, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(9), note(A, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(10), note(Bb, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(11), note(B, 0), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(12), note(C, 1), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(13), note(Db, 1), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(14), note(D, 1), 1},
    {{octaveBank, BankType::CHANGE_ADDRESS}, buttonMux.pin(15), note(Eb, 1), 1},
};

unsigned long delaytime=10; // set a time to use for global delay

void setup() {
  Control_Surface.begin(); // Setup the Control Surface
  Serial.begin(115200); // Setup Serial output
  buttonMux.begin();                  // Initialize multiplexer for buttons
  buttonMux.pinMode(0, INPUT_PULLUP); // Set the pin mode (setting it for one pin of the multiplexers sets it for all of them)
  potMux.begin();                     // Initialize multiplexer for potentiometers
  potMux.pinMode(0, INPUT_PULLUP);    // Set the pin mode (setting it for one pin of the multiplexers sets it for all of them)

  fourdig.shutdown(0,false);          //The MAX72XX is in power-saving mode on startup, we have to do a wakeup call
  fourdig.setIntensity(0,10);         // Set the brightness of the display -15 to 15
  fourdig.clearDisplay(0);            // Clear the display                       

  switchOctave.set(4);                // Set the starting octave at middle C (C4)

  switchChannel.set(map(controlPots[2].getValue(), 0, 124, 15, 0)); // Set starting channel to pot2 value
}

void loop() {
  switchChannel.set(map(controlPots[3].getValue(), 0, 124, 15, 0));

  //switchOctave.set(map(controlPots[2].getValue(), 0, 124, 15, 0));
  Serial.println(map(controlPots[2].getValue(), 0, 124, 15, 0));
   
  // Show LED display linked to the 4 rotary potentiometers, 1 digit for each individual potentiometer
  fourdig.setDigit(0,4, switchOctave.get(),false);  // set digit 4 to show current octave activated for the Note Buttons
//  fourdig.setChar(0,4, map(controlPots[2].getValue(), 0, 124, 15, 0),false);  // set digit 3 to pot(3) value
  fourdig.setChar(0,3, map(controlPots[3].getValue(), 0, 124, 15, 0),false);  // set digit 3 to pot(3) value
  fourdig.setDigit(0,2, map(controlPots[2].getValue(), 0, 124, 9, 0),false);  // set digit 2 to pot(2) value
  fourdig.setDigit(0,1, map(controlPots[1].getValue(), 0, 124, 9, 0),false);  // set digit 1 to pot(1) value
  fourdig.setDigit(0,0, map(controlPots[0].getValue(), 0, 124, 9, 0),false);  // set digit 0 to pot(0) value
  delay(delaytime);  // a delay is required before clearing the display otherwise the display will simply light up
  fourdig.clearDisplay(0);  // clear the LED display

  Control_Surface.loop();
}

Shift Registers with leds

Hi Pieter!
I want to use shift register 74HC595 to connect 8 leds to Arduino Leonardo. I saw your example TOGGLE LEDs, but I didn't find line with code where you define Arduino pins for connecting shift registers. Shift register require 3 pins for communication with Arduino(latch pin, data pin and clock pin) I just can't find where you define it.

May be there is some file in your library where you did it?

Can you explain this to me?

MIDI input elements mutex lock ESP32 bug

static void updateAllWith(const MIDI_message_matcher &midimsg) {

The updateAllWith functions can be called asynchronously on ESP32. In the function, iterators over the entire linked list of the type of MIDI input elements are used. However, the iterators can be invalidated if the enable/disable (or constructors or destructors) are called from the main thread.

Proposed solution: add a lock to the updateAllWith function, remove the lock in the moveDown function, and make sure that it isn't used anywhere else.

MUX Ext Io

Hi Peter

This is an extension on the mux button issue that was in the closed issues section

Can I use a button matrix with a multiplexer by passing the mux pin numbers to the button matrix constructor?

And can rotary encoders be used with a multiplexer?

Missing define on ESP32

I wanted to try your library on an ESP32, but there is a define missing, so i can't compile.

/Control-Surface-master/src/Helpers/Exit.cpp: In function 'void CS::fatalErrorExit()': Control-Surface-master/src/Helpers/Exit.cpp:10:13: error: 'LED_BUILTIN' was not declared in this scope pinMode(LED_BUILTIN, OUTPUT);

Even if i define LED_BUILTIN in my code, it does not compile.

If i select another board, everything works fine.

Incomplete?

Are you still considering finishing this library? I could really use something like this

Great work

Program Changer with Banks

Hi,
is it possible to make a Program Changer with 4 Buttons in each Bank for sending an individual Program Change command with this library? Because I tried to make the PcBtn bankable but that didn't work. I can't figure out how to accomplish that.
Regards
Paul

Debugging

Hey there Pete

I have uncommented the lines 17 and 19
can you please give detailed description of how to use debugging

i cannot work out where to see the messages (i.e the arduino serial monitor)
and what must be connected

then i can see what messages are being sent to the arduino for fader movements and vu signals
to help with the programing of motor faders and vu meters

For some reason i cannot get any of the software midi monitors to work with cubase
it must take full control of the ports

Cheers for all the help
Sam

Overlapping banks for MIDI inputs

Right now, as soon as a MIDI input element matches an incoming message, it doesn't search any further for other elements that match.

This means that overlapping banks are impossible.

A simple solution would be to allow a setting that tries to match all elements. This isn't super efficient, but I don't think I can do any better without completely refactoring the MIDI input elements.

Inspiration: https://forum.arduino.cc/index.php?topic=627369.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.