#include<MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
#include<CapacitiveSensor.h>
#include <LiquidCrystal.h>
#define ControlChange 0xB0
#define NoteOn 0x90
//Arduino Pin Assignments
const int motorDown = 5; //H-Bridge control to make the motor go down
const int motorUp = 6; //H-Bridge control to make the motor go up
const int wiper = A0; //Position of fader relative to GND (Analog 0)
const int touchSend = 4; //Send pin for Capacitance Sensing Circuit (Digital 7)
const int touchReceive = 2; //Receive pin for Capacitance Sensing Circuit (Digital 8)
const int channelLeft = 12; // the number of the channelLeft (Digital 12) pin
const int channelRight = 13; // the number of the channelRight (Digital 13) pin
//Variables
double faderMax = 0; //Value read by fader's maximum position (0-1023)
double faderMin = 0; //Value read by fader's minimum position (0-1023)
int faderChannel = 0; //Value from 1-8
int chLeftBtn = 0;
int chRightBtn = 0;
int faderPositionLoop;
bool touched = false; //Is the fader currently being touched?
bool positionUpdated = false; //Since touching, has the MIDI position been updated?
String ascii = "";
String oldAscii = "";
bool compare = true;
//LCD pins
LiquidCrystal lcd(52, 50, 46, 44, 42, 40);
byte channel1LCD[] {0xf0, 0x00, 0x00, 0x66, 0x05, 0x00, 0x10};
CapacitiveSensor touchLine = CapacitiveSensor(touchSend, touchReceive);
void setup() {
// put your setup code here, to run once:
Serial.begin(31250);
MIDI.begin(MIDI_CHANNEL_OMNI); //Receive messages on all MIDI channels
MIDI.turnThruOff(); //We don't need MIDI through for this
MIDI.setHandleSystemExclusive(handle_sysex);
pinMode (motorUp, OUTPUT);
pinMode (motorDown, OUTPUT);
calibrateFader();
}
void loop() {
int newPosition;
// update physical fader position
checkTouch(); // check if phyisical fader has been touched
if (!positionUpdated) { // if it has update midi to protools
updateFaderMidi();
newPosition = (((float)(analogRead(wiper) - faderMin) / (faderMax - faderMin)) * 16383);
updateFader(faderPositionLoop);
positionUpdated = true;
}
else {
faderPositionLoop = checkMIDI(); // run midi check and return fader position from protools
updateFader(faderPositionLoop); // update physical fader with midi info
}
}
void calibrateFader() {
//Send fader to the top and read max position
digitalWrite(motorUp, HIGH);
delay(1000);
digitalWrite(motorUp, LOW);
faderMax = analogRead(wiper) - 5;
//Send fader to the bottom and read min position
digitalWrite(motorDown, HIGH);
delay(1000);
digitalWrite(motorDown, LOW);
faderMin = analogRead(wiper) + 5;
}
// check for incoming midi signals
int checkMIDI() {
static byte velocity1 = 0;
static byte velocity2 = 0;
static int faderPosition = 0;
static int oldMidi = 0;
if (MIDI.read() && MIDI.getChannel() == 1 && MIDI.getType() == ControlChange && MIDI.getData1() == 0x00) // check for MSB
{
velocity1 = MIDI.getData2();
}
if (MIDI.read() && MIDI.getChannel() == 1 && MIDI.getType() == ControlChange && MIDI.getData1() == 0x20) // Check for LSB
{
velocity2 = MIDI.getData2();
}
faderPosition = (((velocity1 << 7) + velocity2) >> 4); //bitwise math to combine MSB and LSB
return faderPosition ; // remember to initialize using variable assignment with function call
}
void updateFader(int fposition) {
if (fposition < analogRead(wiper) - 10 && fposition > faderMin && !touched) {
digitalWrite(motorDown, HIGH);
while (fposition < analogRead(wiper) - 10 && !touched) {}; //Loops until motor is done moving
digitalWrite(motorDown, LOW);
}
else if (fposition > analogRead(wiper) + 10 && fposition < faderMax && !touched) {
digitalWrite(motorUp, HIGH);
while (fposition > analogRead(wiper) + 10 && !touched) {}; //Loops until motor is done moving
digitalWrite(motorUp, LOW);
}
}
void checkTouch() {
int movedFader;
//For the CapacitiveSensor comparison below,
//700 is arbitrary and may need to be changed
//depending on the fader cap used (if any).
if (!touched && touchLine.capacitiveSensor(30) >= 3000) {
touched = true;
//Send MIDI Touch On Message
MIDI.send(ControlChange, 0x0f, 0x00, 0x01);
MIDI.send(ControlChange, 0x2f, 0x40, 0x01);
digitalWrite(motorUp, LOW);
digitalWrite(motorDown, LOW);
}
else if (touched && touchLine.capacitiveSensor(30) < 3000) {
touched = false;
MIDI.send(ControlChange, 0x0f, 0x00, 0x01);
MIDI.send(ControlChange, 0x2f, 0x00, 0x01);
}
if (touched) {
positionUpdated = false;
}
}
void updateFaderMidi() {
static int oldValue = 0; // set old value to 0 only for first time
int velocity = faderPosition();
if (oldValue != velocity) {
byte faderMSB = (velocity >> 7) ; // get MSB value in 7 bit
MIDI.send(ControlChange, 0x00, faderMSB, 0x01); // send MSB value
byte faderLSB = (velocity & 0x7f); // get LSB value
MIDI.send(ControlChange, 0x20, faderLSB, 0x01); // send new value
oldValue = velocity;
}
}
//Returns a MIDI pitch bend value for the fader's current position
//Cases ensure that there is a -infinity (min) and max value despite possible math error
int faderPosition() {
int fposition = analogRead(wiper);
int returnValue = 0;
if (fposition <= faderMin) {
returnValue = 0;
}
else if (fposition >= faderMax) {
returnValue = 16383;
}
else {
returnValue = ((float)(fposition - faderMin) / (faderMax - faderMin)) * 16383;
}
return returnValue;
}