MIDI Control Surface - Guitar Pedal Board

blosmusic

New member
Hey Folks,

I've been working on a project for college and wanted to share the finished product as I think it will be of help to others. I have built two versions, the first with a Teensy LC and the second with a Teensy 3.2. I found references to different parts of the code on the forums but reckoned it would be easier for others to see all the components working together.

I'm also including this link showing it in action and how to set it up in some DAW's.
-------------------------------------------------------------------------------------------------------------------------

/*Microcontroller for USB-MIDI communication created by Ben Lamb O'Sullivan - hi@benlambosullivan.com

Make sure to select the correct Board: "Teensy XX" and USB Type: "MIDI" in the Tools menu.

This sketch allows a user to define a number of potentiometers, LEDS, and I/O buttons as per their design.

Potentiometers can be set up for use as control dials or expression functions depending on the user requirements.

In the first section, the user should input the number of buttons, leds, dial potentiometers, and expression potentiometers
they have been created for their microcontroller.

Next, they should enter the pin values for each into the buttonPins, ledPins, potPins, & expPins arrays.

For the microcontroller to effectively send MIDI messages to your DAW, you will need to enter the
MIDI CTRL Channel numbers in the ctrlChanButtons, ctrlChanPots, & ctrlExpPots arrays.

NOTE: IF USING ANOTHER MIDI DEVICE MAKE SURE MIDI CC & NOTE VALUES WONT CLASH

*/
#include <ResponsiveAnalogRead.h>
#include <Bounce.h>

//****ENTER ALL USER PARAMETERS HERE*******

//****************************
//ENTER ALL ASSIGNED BUTTON PIN VALUES HERE
//BUTTONS & LEDS WILL BE DIGITAL PINS
//****************************
//------------------------------------------------------------------------------------------------------------
const int numButtons = 4; //Change to the total number of buttons you have assigned
const int numLeds = 3; //Change to the total number of LEDs you have assigned
const int bounceTime = 10; //5ms bounce time minimum between io states.

const int buttonPins[numButtons] = {0, 2, 4, 6}; //List each assigned pin for digital input
const int ctrlChanButtons[numButtons] = {60, 61, 62, 63}; //Enter the note values for each MIDI input channel {60, 61, 62, etc}

const int ledPins[numLeds] = {1, 3, 5}; //List each pins that LEDs are assigned to

Bounce digitalButtons[] = {
//Uncomment & add in pin values for each button you assign -> no comma after the last one
Bounce (buttonPins[0], bounceTime),
Bounce (buttonPins[1], bounceTime),
Bounce (buttonPins[2], bounceTime),
Bounce (buttonPins[3], bounceTime)
// Bounce (buttonPins[4], bounceTime),
// Bounce (buttonPins[5], bounceTime),
// Bounce (buttonPins[6], bounceTime),
// Bounce (buttonPins[7], bounceTime)
};

//****************************
//ENTER ALL ASSIGNED POT PIN VALUES HERE
//POTENTIOMETERS WILL BE ANALOGUE PINS
//****************************
const int numPots = 9; //Change to the total number of potentiometers you have assigned
int potPins[numPots] = {A8, A0, A1, A2, A3, A4, A5, A6, A7}; //Enter the pins values. For analogues pins they may be written {A0, A1, etc}
int ctrlChanPots[numPots] = {85, 86, 87, 88, 89, 90, 91, 92, 93}; //Enter theCC values for Potentiometer input channel {10, 11, 12, etc}

ResponsiveAnalogRead analoguePots[]{
//Uncomment & add in pin values for each button you assign -> no comma after the last one
{potPins[0], true},
{potPins[1], true},
{potPins[2], true},
{potPins[3], true},
{potPins[4], true},
{potPins[5], true},
{potPins[6], true},
{potPins[7], true},
{potPins[8], true}
// {potPins[9], true}
// {potPins[10], true},
};

//****************************
//ENTER ALL ASSIGNED EXPRESSION VALUES HERE.
//POTENTIOMETERS WILL BE ANALOGUE PINS.
//MIDI WILL READ BETWEEN minExpVal & maxExpVal.
//OUTSIDE THESE VALUES EXP IS BYPASSED.
//NOTE: EXPRESSION POTS VALUES DON'T HAVE LEDS.
//****************************
const int expPots = 1;
int expPins[expPots] = {A9};
int ctrlExpPots[expPots] = {70};

const int minExpVal = 5; //Set min/max values for expression pedal.
const int maxExpVal = 127; //Outside these values expression pedal is bypassed.
const int bypassExp = 0; //Set min/max as 0/127 for volume pedal.

//------------------------------------------------------------------------------------------------------------

//****************************
//CONST PARAMS FOR BUTTONS & LEDS
//****************************
byte lastButton = LOW; //LEDs off by default
byte currentButton = LOW;
byte ledState = LOW;
const int buttonToggle = 99; //channel is active

//****************************
//INITIAL SETUP PARAMS FOR POTENTIOMETERS & EXPRESSION
//****************************
const int channel = 1; //MIDI Channel Number is defaulted to 1 -> only change if your controller uses banks
const int diff = 2; //minimum value difference to prevent jitter -> depends on potentiometers used
const int safetyDelay = 5; //delay to ignore chatter between changes
elapsedMillis msec = 0; //Create a small delay to prevent unwanted messages/changes for smoother function

int prevPotValue[numPots] = {}; //Set initial pot arrays to ensure new values will be compared
int newPotValue[numPots] = {}; //This will read the updated pot values

int prevExpValue[expPots] = {}; //Set initial expression arrays to ensure new values read
int newExpValue[expPots] = {}; //This will read the updated exp values

//****************************
//SETUP FUNCTION FOR DIGITAL PARAMS
//****************************
void setup() {
//SETUP PINS
Serial.begin(9600); //Output values to Serial for debugging

//****************************
//INITIALISE BUTTON PINS
//****************************
for(int i = 0; i < numButtons; i++){
pinMode(buttonPins, INPUT_PULLUP);
}

//****************************
//INITIALISE LED PINS
//****************************
for(int i = 0; i < numLeds; i++){
pinMode(ledPins, OUTPUT);
digitalWrite(ledPins, HIGH);
}
}

//****************************
//MAIN LOOP FOR CONTINUOUS CONTROL
//****************************
void loop() {

ioButtons();
dialPots();
expressionPot();
noRelayMsg();

}

//****************************
//BUTTON FUNCTION
//****************************
void ioButtons(){

//CONTINUOUSLY CHECK BUTTON STATE
for(int i = 0; i < numButtons; i++){

digitalButtons.update();

//CHECK FOR FALLING EDGE -> BUTTON ENGAGED
if(digitalButtons.fallingEdge()){
usbMIDI.sendControlChange(ctrlChanButtons, buttonToggle, channel);
digitalWrite(ledPins, !digitalRead(ledPins)); //Toggles led when button is pressed
//Serial Text for Debugging
Serial.print("Switch: ");
Serial.print(buttonPins);
Serial.print(", LED: ");
Serial.print(ledPins);
Serial.print(", Channel: ");
Serial.print(ctrlChanButtons);
Serial.print(", State: ON ");
Serial.println(buttonToggle);

}
//CHECK FOR RISING EDGE -> BUTTON DISENGAGED
if(digitalButtons.risingEdge()){
usbMIDI.sendControlChange(ctrlChanButtons, buttonToggle, channel);
digitalWrite(ledPins, !digitalRead(ledPins)); //Toggles led when button is pressed
//Serial Text for Debugging
Serial.print("Switch: ");
Serial.print(buttonPins);
Serial.print(", LED: ");
Serial.print(ledPins);
Serial.print(", Channel: ");
Serial.print(ctrlChanButtons);
Serial.print(", State: OFF ");
Serial.println(buttonToggle);
}
delay(safetyDelay); //Safety to prevent button chatter
}
}

//****************************
//POTENTIOMETER FUNCTION
//****************************
void dialPots(){

if(msec >= 20){
msec = 0;

for(int i = 0; i < numPots; i++){
analoguePots.update();

if(analoguePots.hasChanged()){
newPotValue = analoguePots.getValue() / 8; //Divide voltage by 8 to get MIDI value 0-127

if(abs(newPotValue - prevPotValue) > diff){
prevPotValue = newPotValue;
usbMIDI.sendControlChange(ctrlChanPots, newPotValue, channel);
Serial.print("Pot: "); //Output to serial for debugging
Serial.print(potPins);
Serial.print(" Channel: ");
Serial.print(ctrlChanPots);
Serial.print(" Value: ");
Serial.println(newPotValue);

}
}
}
}
}
//****************************
//EXPRESSION PEDAL FUNCTION
//****************************
void expressionPot(){

//VARIATION OF ORIGINAL POTENTIOMETER FUNCTION FOR
//AN EXPRESSION PEDAL WHICH ONLY RECEIVE MIDI VALUES
//BETWEEN A USER DEFINED MAX/MIN. FUNCTION CONTAINS MORE CONDITIONS THAN
//RESPONSIVEANALOGUEREAD CLASS USED ABOVE.

for(int i = 0; i < expPots; i++){

newExpValue = analogRead(expPins) / 8; //Divide voltage by 8 to get MIDI value 0-127

//ONLY SEND MESSAGES IF INPUT IS BETWEEN USER SET MAX/MIN VALUES
if(newExpValue >= minExpVal && newExpValue <= maxExpVal){
if(abs(newExpValue - prevExpValue) > diff){
prevExpValue = newExpValue;
usbMIDI.sendControlChange(ctrlExpPots, newExpValue, channel);
Serial.print("Exp: "); //Output to serial for debugging
Serial.print(expPins);
Serial.print(" & its value is: ");
Serial.println(newExpValue);
}
} //BYPASS EXPRESSION IF OUTSIDE DEFINED VALUES
else if(newExpValue < minExpVal || newExpValue > maxExpVal){
if(abs(newExpValue - prevExpValue) > diff){
prevExpValue = newExpValue;
newExpValue = bypassExp;
usbMIDI.sendControlChange(ctrlExpPots, newExpValue, channel); //Exp CC = 0 when not used
Serial.print("Exp: "); //Output to serial for debugging
Serial.print(expPins);
Serial.print(" & its value is: ");
Serial.print(newExpValue);
Serial.println(" [OFF]");
}
}
}
}

//******************************************
//PREVENT UNWANTED MIDI RETURNS IN SOME DAWS
//******************************************
void noRelayMsg(){
while (usbMIDI.read()) {
//Ignore incoming messages.
//Prevents unwanted relays
//from device back into DAW
//http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
}
}
 

Attachments

  • MicrocontrollerSubmission_4Modules.ino
    10.4 KB · Views: 37
Back
Top