Code:
/*
TODO
Refactor input code turn everthing into functions for easier maintanance and fewer global variables
Add an initial calibration routine to prevent initial flood of midi data on startup
Rethink encoder code, it seems to be a little slow
Possible issue with encoder buttons
Implement messages queue'ing system to buffer messages before sending (possible resolution to encoder issue)
*/
//#include <ps2.h>
//#include <Trackpad.h>
#include <WProgram.h>
#include <Midi.h>
#define NUM_POTS 13
#define NUM_BUTTONS 16
#define BTN_DEBOUNCE 75
#define NUM_ENCODERS 2
#define SMOOTHING 3
#define POT_SELECT_PINS {2,3,4}; //A, B, C on 4051
#define POT_READ_PINS {0,1}
#define MIDI_CHANNEL 1
#define XY_SENSITIVITY 25
#define XY_CC_X 71 // xy pad X CC#
#define XY_CC_Y 70 // xy pad Y CC#
#define XY_NOTE 69 // A-4
#define XY_MIN_X 1320
#define XY_MAX_X 5480
#define XY_MIN_Y 1245
#define XY_MAX_Y 4490
#define XY_CLOCK 18 // Orange Wire
#define XY_LATCH 19 // Blue Wire
#define ENC1_A 8
#define ENC1_B 9
#define ENC2_A 8
#define ENC2_B 9
#define ENC_PORT PINB
#define ENC_MODE_REL 1
#define ENC_MODE_ABS 2
#define ENC_MODE ENC_MODE_REL
#define CW 0b01
#define CCW 0b11
#define CLOCK_4021 7
#define LATCH_4021 6
#define DATA_4021 5
#define ON 0
#define OFF 1
/* Debug Defines */
#define DEBUG_POT 1
#define DEBUG_BTN 2
#define DEBUG_PAD 4
#define DEBUG_ENC 8
#define DEBUG_ALL 15
#define DEBUG false
#define BENCH false
#define DEBUG_SEL DEBUG_POT
/* Debug Defines */
class MyMidi : public Midi {
public:
MyMidi(HardwareSerial &s) : Midi(s) {}
void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) {
sendNoteOn(channel, note, velocity);
}
void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) {
sendNoteOff(channel, note, velocity);
}
void handleControlChange(unsigned int channel, unsigned int controller, unsigned int value) {
sendControlChange(channel, controller, value);
}
};
/* returns byte: bits 1,2 are encoder 1... bits 2,3 are encoder 2... 0b11 is CCW 0b01 is CW */
byte read_two_encoders() {
int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
static uint8_t old_AB1, old_AB2 = 0;
byte rtn = 0;
old_AB1 <<= 2; //remember previous state
old_AB1 |= (ENC_PORT & 0b11); //add current state
old_AB2 <<= 2; //remember previous state
old_AB2 |= (ENC_PORT & 0b1100) >> 2; //add current state
rtn |= (enc_states[(old_AB1 & 0b1111)]) & 0b11;
return rtn | ((enc_states[(old_AB2 & 0b1111)]) & 0b11) << 2;
}
//Trackpad xyPad(XY_CLOCK, XY_LATCH);
MyMidi midi(Serial);
byte potReadPins[] = POT_READ_PINS;
byte potSelectPins[] = POT_SELECT_PINS;
byte buttons1, lastButtons = B11111111; // Default state of buttons
byte buttons2 = B11111111; // Default state of buttons
byte encValues[NUM_ENCODERS] = {1,1};
byte prevEncValues[NUM_ENCODERS] = {1,1};
byte counter = 0; // for benchmarking
boolean buttonState[NUM_BUTTONS] = {};
boolean lastButtonState[NUM_BUTTONS] = {};
int potValues[NUM_POTS] = {};
int prevPotValues[NUM_POTS] = {};
unsigned int allButtons = 0;
unsigned long lastBtn = 0; // for debouncing buttons
unsigned long current = 0; // for benchmarking
unsigned long running = 0; // for benchmarking
unsigned long benchmarks[4] = {0,0,0,0};
void setup() {
if (DEBUG||BENCH) Serial.begin(38400);
else midi.begin(0);
pinMode(LATCH_4021, OUTPUT);
pinMode(CLOCK_4021, OUTPUT);
pinMode(DATA_4021, INPUT);
pinMode(ENC1_A, INPUT);
pinMode(ENC1_B, INPUT);
pinMode(ENC2_A,INPUT);
pinMode(ENC2_B,INPUT);
for (byte i=0;i < 3;i++) pinMode(potSelectPins[i], OUTPUT);
for (byte i=0;i < NUM_POTS;i++) potValues[i] = prevPotValues[i] = 0;
for (byte i=0;i < NUM_BUTTONS;i++) buttonState[i] = lastButtonState[i] = 1;
if (DEBUG||BENCH) Serial.println("Begin");
}
void loop() {
if (BENCH) current = micros();
midi.poll();
/*--------------| BUTTONS |--------------*/
digitalWrite(LATCH_4021,1);delayMicroseconds(20);digitalWrite(LATCH_4021,0);
buttons1 = shiftIn(DATA_4021, CLOCK_4021, LSBFIRST);
buttons2 = shiftIn(DATA_4021, CLOCK_4021, LSBFIRST);
allButtons = word(buttons1, buttons2);
if ((allButtons != lastButtons) && (micros() - lastBtn > BTN_DEBOUNCE)) {
lastBtn = micros();lastButtons = allButtons;
for (byte i=0;i<NUM_BUTTONS;i++){
if (!bitRead(allButtons, i)) buttonState[i] = ON;
else buttonState[i] = OFF;
if (buttonState[i] != lastButtonState[i]) {
lastButtonState[i] = buttonState[i];
if (buttonState[i] == OFF) {
if (DEBUG && (DEBUG_SEL & DEBUG_BTN)) {Serial.print("Button ");Serial.print(i+1,DEC);Serial.println(": OFF");}
else midi.sendNoteOff(MIDI_CHANNEL, i, 0); // Stop the note
} else {
if (DEBUG && (DEBUG_SEL & DEBUG_BTN)) {Serial.print("Button ");Serial.print(i+1,DEC);Serial.println(": ON");}
else midi.sendNoteOn(MIDI_CHANNEL, i, 127); // Send the note
}
}
}
}
if (BENCH) {
benchmarks[0] += micros()-current;
current = micros();
}
/*--------------| BUTTONS |--------------*/
/*--------------| POTS |--------------*/
byte chipSelect = 0;
for(int i = 0; i < NUM_POTS; i++) {
PORTD = (NUM_POTS > 8 && i >= 8) ? (i % 8) << 2 : i << 2; // set pins 2, 3 and 4 to value between 0 (00000) and 7 (11100) to select the pot
if (i > 0 && (i % 8 == 0)) chipSelect++; // increase chip select index every 8 pots
potValues[i] = analogRead(potReadPins[chipSelect]);
if (abs(potValues[i] - prevPotValues[i]) > SMOOTHING) {
prevPotValues[i] = potValues[i];
if (!DEBUG) midi.sendControlChange(MIDI_CHANNEL, i, map(potValues[i],5,1020,0,127));
}
if (DEBUG && (DEBUG_SEL & DEBUG_POT)) {Serial.print(" P");Serial.print(i+1,DEC);Serial.print(":");Serial.print(potValues[i],DEC);}
}
if (DEBUG && (DEBUG_SEL & DEBUG_POT)) Serial.println();
if (BENCH) {
benchmarks[1] += micros()-current;
current = micros();
}
/*--------------| POTS |--------------*/
/*--------------| Encoders |--------------*/
static byte encoderCnt = 0;
byte enc1,enc2,encValue = 0;
encValue = read_two_encoders();
if(encValue && (++encoderCnt % 4) == 0) {
enc1 |= encValue & 0b11;
if (enc1 == CW) {
if (ENC_MODE & ENC_MODE_REL) {
if (DEBUG && (DEBUG_SEL & DEBUG_ENC)) Serial.println("ENC1: ->");
else midi.sendControlChange(MIDI_CHANNEL,30,1);
}
if (ENC_MODE & ENC_MODE_ABS) {
encValues[0]++;
if(encValues[0] >= 127) encValues[0] -= 127;
midi.sendControlChange(MIDI_CHANNEL,40,encValues[0]);
}
} else if (enc1 == CCW) {
if (ENC_MODE & ENC_MODE_REL) {
if (DEBUG && (DEBUG_SEL & DEBUG_ENC)) Serial.println("ENC1: <-");
else midi.sendControlChange(MIDI_CHANNEL,30,127);
}
if (ENC_MODE & ENC_MODE_ABS) {
encValues[0]--;
if(encValues[0] <= 0) encValues[0] += 127;
midi.sendControlChange(MIDI_CHANNEL,40,encValues[0]);
}
}
enc2 |= (encValue >> 2) & 0b11;
if (enc2 == CW) {
if (ENC_MODE & ENC_MODE_REL) {
if (DEBUG && (DEBUG_SEL & DEBUG_ENC)) Serial.println("ENC2: ->");
else midi.sendControlChange(MIDI_CHANNEL,31,1);
}
if (ENC_MODE & ENC_MODE_ABS) {
encValues[1]++;
if(encValues[1] >= 127) encValues[1] -= 127;
midi.sendControlChange(MIDI_CHANNEL,41,encValues[1]);
}
} else if (enc2 == CCW) {
if (ENC_MODE & ENC_MODE_REL) {
if (DEBUG && (DEBUG_SEL & DEBUG_ENC)) Serial.println("ENC2: <-");
else midi.sendControlChange(MIDI_CHANNEL,31,127);
}
if (ENC_MODE & ENC_MODE_ABS) {
encValues[1]--;
if(encValues[1] <= 0) encValues[1] += 127;
midi.sendControlChange(MIDI_CHANNEL,41,encValues[1]);
}
}
}
if (BENCH) {
benchmarks[3] += micros()-current;
current = micros();
}
/*--------------| Encoders |--------------*/
///*--------------| XY Pad |--------------*/
// packet_t * packet;
// packet = xyPad.getNewPacket();
// static boolean xyOn = false;
// if (packet->z > XY_SENSITIVITY) {
// if (!xyOn) {
// xyOn = true;
// if (DEBUG && (DEBUG_SEL & DEBUG_PAD)) Serial.println("XY Pad ON");
// else midi.sendNoteOn(MIDI_CHANNEL, XY_NOTE, 127);
// }
// if (DEBUG && (DEBUG_SEL & DEBUG_PAD)) {
// Serial.print("X: ");Serial.print(packet->x,DEC);Serial.print(" Y: ");Serial.println(packet->y,DEC);
// } else {
// midi.sendControlChange(MIDI_CHANNEL, XY_CC_X, constrain(map(packet->x, XY_MIN_X, XY_MAX_X, 0, 127), 0, 127));
// midi.sendControlChange(MIDI_CHANNEL, XY_CC_Y, constrain(map(packet->y, XY_MIN_Y, XY_MAX_Y, 0, 127), 0, 127));
// }
// } else {
// if (xyOn) {
// xyOn = false;
// if (DEBUG && (DEBUG_SEL & DEBUG_PAD)) Serial.println("XY Pad OFF");
// else midi.sendNoteOff(MIDI_CHANNEL, XY_NOTE, 0);
// }
// }
// if (BENCH) {
// benchmarks[2] += micros()-current;
// current = micros();
// }
///*--------------| X/Y Pad |--------------*/
if (BENCH) {
counter++;
if (counter >= 10) {
Serial.print("(ms) Btn: ");Serial.print(benchmarks[0]/counter,DEC);
Serial.print(" Pot: ");Serial.print(benchmarks[1]/counter,DEC);
// Serial.print(" Pad: ");Serial.print(benchmarks[2]/counter,DEC);
Serial.print(" Enc: ");Serial.println(benchmarks[3]/counter,DEC);
counter = benchmarks[0] = benchmarks[1] = benchmarks[2] = benchmarks[3] = 0;
}
}
}
Bookmarks