I'm using an Arduino Leonardo for sending MIDI In and Out messages to Ableton Live.
Components include a Potentiometer, a Capacitive Touch Sensor, and a DC Motor, which I'm powering with a L298N Motor Driver.
Right now I have it set up so that I can record automation in by moving the potentiometer, send a MIDI note in when I'm touching the fader, and follow automation using the DC Motor.
The problem that I'm having is that when I go to play my tracks, the automation that I recorded with the potentiometer is deactivated, and therefore my motor doesn't respond. I believe this is because I'm sending MIDI Input and Output at the same time. Here's the current version of the code:
#include <Control_Surface.h>
#include <CapacitiveSensor.h>
int minimumCp = 200;
int lastfaderPosition = 0; // previous state of the button
const byte touchSend = 7;
const byte touchReceive = 8;
CapacitiveSensor touchSensor = CapacitiveSensor(touchReceive, touchSend);
USBMIDI_Interface midi;
CCPotentiometer faderPosition { A0, MIDI_CC::General_Purpose_Controller_1 };
int incomingChannel;
int incomingNote;
int incomingVelocity;
const byte mainFaderPin = 0;
const byte motorUp = 4;
const byte motorDown = 5;
const byte motorPWM = 6;
byte motorSpeed = 150;
byte tolerance = 40;
double faderMax = 0;
double faderMin = 0;
struct MyMIDI_Callbacks : FineGrainedMIDI_Callbacks<MyMIDI_Callbacks> {
void onControlChange(Channel channel, uint8_t controller, uint8_t value, Cable cable) {
incomingNote = controller;
incomingVelocity = value;
}
void onProgramChange(Channel channel, uint8_t program, Cable cable) {
Serial << "Program Change: " << channel << ", program " << program << ", "
<< cable << endl;
}
void onAfterTouchChannel(Channel channel, uint8_t pressure, Cable cable) {
Serial << "Channel Pressure: " << channel << ", pressure " << pressure
<< ", " << cable << endl;
}
void onPitchBend(Channel channel, uint16_t bend, Cable cable) {
Serial << "Pitch Bend: " << channel << ", bend " << bend << ", " << cable
<< endl;
}
void onSystemExclusive(SysExMessage se) {
Serial << F("System Exclusive: [") << se.length << "] "
<< AH::HexDump(se.data, se.length) << ", " << se.cable << endl;
}
void onTimeCodeQuarterFrame(uint8_t data, Cable cable) {
Serial << "MTC Quarter Frame: " << data << ", " << cable << endl;
}
void onSongPosition(uint16_t beats, Cable cable) {
Serial << "Song Position Pointer: " << beats << ", " << cable << endl;
}
void onSongSelect(uint8_t songnumber, Cable cable) {
Serial << "Song Select: " << songnumber << ", " << cable << endl;
}
void onTuneRequest(Cable cable) {
Serial << "Tune Request: " << cable << endl;
}
void onClock(Cable cable) { Serial << "Timing Clock: " << cable << endl; }
void onStart(Cable cable) { Serial << "Start: " << cable << endl; }
void onContinue(Cable cable) { Serial << "Continue: " << cable << endl; }
void onStop(Cable cable) { Serial << "Stop: " << cable << endl; }
void onActiveSensing(Cable cable) {
Serial << "Active Sensing: " << cable << endl;
}
void onSystemReset(Cable cable) {
Serial << "System Reset: " << cable << endl;
}
} callback;
void setup() {
touchSensor.set_CS_AutocaL_Millis(0xFFFFFFFF);
midi.setCallbacks(callback);
Control_Surface.begin();
pinMode(motorDown, OUTPUT);
pinMode(motorUp, OUTPUT);
pinMode(motorPWM, OUTPUT);
Serial.begin(250000);
calibrateFader();
}
void calibrateFader() {
digitalWrite(motorUp, HIGH);
analogWrite(motorPWM, motorSpeed);
delay(300);
digitalWrite(motorUp, LOW);
faderMax = analogRead(mainFaderPin) - tolerance;
digitalWrite(motorDown, HIGH);
analogWrite(motorPWM, motorSpeed);
delay(300);
digitalWrite(motorDown, LOW);
faderMin = analogRead(mainFaderPin) + tolerance;
}
void loop() {
int faderPos = analogRead(mainFaderPin);
int totalCp = touchSensor.capacitiveSensor(9);
Control_Surface.loop();
if ((faderPos == lastfaderPosition) && (totalCp <= minimumCp) && (incomingNote == 16)) {
updateFader(incomingVelocity * 8);
}
if ((faderPos == lastfaderPosition) && (totalCp > minimumCp)) {
midi.sendNoteOn({37, CHANNEL_2}, 127);
digitalWrite(motorUp, LOW);
digitalWrite(motorDown, LOW);
}
if (((faderPos < lastfaderPosition - 1) || (faderPos > lastfaderPosition + 1)) && (totalCp > minimumCp)) {
digitalWrite(motorUp, LOW);
digitalWrite(motorDown, LOW);
}
if (((faderPos < lastfaderPosition - 1) || (faderPos > lastfaderPosition + 1)) && (totalCp <=minimumCp)) {
// Stop Sending MIDI, and receive it only
}
lastfaderPosition = faderPos;
}
void updateFader(int position) { //Function to move fader to a specific position between 0-1023 if it's not already there
if (position < analogRead(mainFaderPin) - tolerance && position > faderMin) {
digitalWrite(motorDown, HIGH);
while (position < analogRead(mainFaderPin) - tolerance) {}; //Loops until motor is done moving
digitalWrite(motorDown, LOW);
}
else if (position > analogRead(mainFaderPin) + tolerance && position < faderMax) {
digitalWrite(motorUp, HIGH);
while (position > analogRead(mainFaderPin) + tolerance) {}; //Loops until motor is done moving
digitalWrite(motorUp, LOW);
}
}
Note that when I use this version with an Arduino UNO, the whole thing works. I've tried discussing this with a few who are far more experienced than I, but surprisingly they were unable to provide insight as to why.
#include <SoftwareSerial.h> // MIDI Input
#include <MIDI.h> // MIDI Output
#include <CapacitiveSensor.h>
#define rxPin 0 // Input (Grey)
#define txPin 1 // Output (Yellow)
SoftwareSerial midiSerial (rxPin, txPin);
const byte wiper = 0; //Position of fader relative to GND (Analog 0)
const byte motorUp = 4;
const byte motorDown = 5;
const byte motorPWM = 6;
const byte touchSend = 7;//Send pin for Capacitance Sensing Circuit (Digital 7)
const byte touchReceive = 8; //Receive pin for Capacitance Sensing Circuit (Digital 8)
unsigned int incomingCommand;
unsigned int incomingNote;
unsigned int incomingVelocity;
byte motorSpeed = 150; // Raise if the fader is too slow (0-255)
byte minimumCp = 200; // Raise if the fader is too sensitive (0-16383)
byte tolerance = 10; // Raise if the fader is too shaky (0-1023)
double faderMax = 1023; //Value read by fader's maximum position (0-1023)
double faderMin = 0; //Value read by fader's minimum position (0-1023)
long lastDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 15; // the debounce time; increase if the output flickers
int lastfaderValue = 0;
int targetPosition;
byte ch1Vol = 176;
byte fullVel = 127;
byte ch_1 = 1;
byte Db_1 = 1;
CapacitiveSensor touch = CapacitiveSensor(touchReceive, touchSend);
MIDI_CREATE_DEFAULT_INSTANCE();
void setup() {
touch.set_CS_AutocaL_Millis(0xFFFFFFFF);
midiSerial.begin(31250);
MIDI.begin();
pinMode(motorDown, OUTPUT);
pinMode(motorUp, OUTPUT);
pinMode(motorPWM, OUTPUT);
calibrateFader(); }
void calibrateFader() {
digitalWrite(motorUp, HIGH);
analogWrite(motorPWM, motorSpeed);
delay(300);
digitalWrite(motorUp, LOW);
faderMax = analogRead(wiper) - tolerance;
digitalWrite(motorDown, HIGH);
analogWrite(motorPWM, motorSpeed);
delay(300);
digitalWrite(motorDown, LOW);
faderMin = analogRead(wiper) + tolerance; }
void loop() {
int faderPos = analogRead(wiper);
int faderHiResMIDI = ((faderPos *16.0146627566) - 8191.5);
while ( midiSerial.available()) {
incomingCommand = midiSerial.read();
incomingNote = midiSerial.read();
incomingVelocity = midiSerial.read()*8.05511811024;
if ((incomingVelocity <=1023) && (incomingCommand >127) && (incomingNote <128)) {
midiSerial.write(incomingCommand);
midiSerial.write(incomingNote);
midiSerial.write(incomingVelocity); } }
{ int totalCp = touch.capacitiveSensor(30);
if ( (millis() - lastDebounceTime) > debounceDelay) {
if (totalCp <= minimumCp) {
//if (incomingCommand == ch1Vol) {
updateFader(incomingVelocity); }// } // Not Touching fader
if ((faderPos == lastfaderValue) && (totalCp > minimumCp)) {
MIDI.sendNoteOn(Db_1, fullVel, ch_1); // Touching Fader
digitalWrite(motorDown, LOW);
digitalWrite(motorUp, LOW); }
if (((faderPos > lastfaderValue+1) or (faderPos < lastfaderValue-1)) && (totalCp > minimumCp)) { // Moving Fader
MIDI.sendPitchBend(faderHiResMIDI, ch_1);
digitalWrite(motorDown, LOW);
digitalWrite(motorUp, LOW); }
lastfaderValue = faderPos;
lastDebounceTime = millis(); } } }
void updateFader(int position) { //Function to move fader to a specific position between 0-1023 if it's not already there
if (position < analogRead(wiper) - tolerance && position > faderMin) {
digitalWrite(motorDown, HIGH);
while (position < analogRead(wiper) - tolerance) {}; //Loops until motor is done moving
digitalWrite(motorDown, LOW); }
else if (position > analogRead(wiper) + tolerance && position < faderMax) {
digitalWrite(motorUp, HIGH);
while (position > analogRead(wiper) + tolerance) {}; //Loops until motor is done moving
digitalWrite(motorUp, LOW); } }
updateFader()
being called when it is supposed to be called?updateFader()
is only called whenfaderPos == lastfaderPosition
. This is unlikely to be the case because there will be noise (electrical due to quantisisation and vibration) onint faderPos = analogRead(mainFaderPin)
. Try something likeif (abs(faderPos - lastfaderPosition) < some_threshold)...)
position
is less thanfaderMin
e.g.incomingVelocity
is zero? Or ifposition
is greater thanfaderMax
, e.g.incomingVelocity
is 1016 (or 127 * 8) whenfaderMax
is about 1023 - 40 = 983?