Aussie_CrocHunter
Well-known member
I've got a pretty awesome piece of code here, mainly thanks to Oddson - it's a 6-switch MIDI controller with 5 main switches (latching) and 1 SPST momentary switch. Holding the momentary switch down change to the next bank and LED states for the red/green LED rings are saved for each switch in each bank (so the LEDs change when the bank changes). There is one expression pedal and a TRS MIDI send using serial MIDI.
I have a simpler but also more specific case I want to change the code for but I'm not really sure how to disentagle myself from the arrays.
I want to mix the 5 switches between PC and CC commands. So switch 1 (first bank) might be CC 69 with val 8, but then Switch 2 (first bank still) is CC 69 with val 3, then switch 8 (bank 2) is a PC 21 message.
do i just have to write out line by line which each switch should do then give it a "codename" in the array? Then how would I keep the LED state tracking?
Another thing to throw in there is that I'd like to use "#define" or "const int" up the top so that people can edit the code easily to change switch assignments (PC, CC, Values, midi channel etc. )
What do you think my method for re-writing should be?
btw, I'll need as much demonstration/help as possible!
I have a simpler but also more specific case I want to change the code for but I'm not really sure how to disentagle myself from the arrays.
I want to mix the 5 switches between PC and CC commands. So switch 1 (first bank) might be CC 69 with val 8, but then Switch 2 (first bank still) is CC 69 with val 3, then switch 8 (bank 2) is a PC 21 message.
do i just have to write out line by line which each switch should do then give it a "codename" in the array? Then how would I keep the LED state tracking?
Another thing to throw in there is that I'd like to use "#define" or "const int" up the top so that people can edit the code easily to change switch assignments (PC, CC, Values, midi channel etc. )
What do you think my method for re-writing should be?
btw, I'll need as much demonstration/help as possible!
Code:
//************LIBRARIES USED**************
// 'include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle'
#include <MIDI.h>
#include <Bounce.h>
// include the ResponsiveAnalogRead library
#include <ResponsiveAnalogRead.h>
//'usbMIDI.h library is added automatically when code is compiled as a MIDI device'
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
// ******CONSTANT VALUES********
//********** PIN DEFINITIONS
const int NUM_PEDALS = 1; // number of Analog PINS
const int D_PINS = 5; // number of Digital PINS in main group (excl tap/bank)
const int ANALOG_PINS[NUM_PEDALS] = {A10};
const int DIGITAL_PINS[D_PINS] = {0,1,2,3,4}; // pins to switchs
const int RED_LED_PINS[D_PINS] = {6,22,10,17,19};
const int GREEN_LED_PINS[D_PINS] = {24,9,16,18,20};
const int MODE_TAP_PIN = 5; // momentary switch to set tempo and select bank
const int MODE_TAP_LED_PIN = 15; // pin to LED for tempo/bank indicator
//********** MIDI DEFINITIONS*************
// MODIFY THIS SECTION TO CUSTOMISE YOUR MIDISTOMP SIX
const int firstchannel = 1; // MIDI channel for USB MIDI
const int secondchannel = 5; // MIDI channel for TRS MIDI
const int CCID[NUM_PEDALS] = {1}; //Expression Pedal CCs - HX Stomp Expression pedal emulation uses CCs 1, 2, and 3 for emulating pedals 1,2,3
const int MODE_COUNT = 3; // number of rows of banks
//CC configuration matrix!!
const int MIDI_CC_NUMS[MODE_COUNT][D_PINS] = { //rows are banks up to MODE_COUNT
{80,81,82,83,84},
{85,86,87,88,89},
{90,91,92,93,94}
};
const int TAP_CC = 64; //HX Stomp's default Tap Tempo CC is 64
const int ON_Value = 127; // note-one velocity sent from buttons (should be 65 to 127)
//********** PHYSICAL DEFINITIONS
const int BOUNCE_TIME = 30; // 5 ms is usually sufficient
const int modeThreshold = 800; // how long to hold before mode changes
const int flashOnTime = 150; // how long flashed LED is on
const int flashOffTime = 250; // how long flashed LED is off
const bool LED_ON = LOW; // LOW for active LOW wiring
const bool LED_OFF = HIGH; // HIGH for active LOW wiring
const int onClocks = 4; // number of clock messages with LED on for tempo flash
const int waitflash = 2; // number of dark flash cylces after bank change before tempo flash resumes
//******VARIABLES***********
// a data array to remember the current state of each switch
boolean state[MODE_COUNT][D_PINS];
elapsedMillis modeTimer,flashTimer;
boolean modeSelectActive = false;
int bank = 0 ;
int flashcount= (-1*waitflash); // default is effective sequence stop of flash counter
int shiftUp; // keeps track of whether the mode change needs to be handled (true) or was (false)
int modeLED; // keeps track of whether LED is on without testing it..
int ClockCount; // for tempo tracking
boolean tempoFlashOn = true;// tempo flash defaults to on
// a data array and a lagged copy to tell when MIDI changes are required
byte data[NUM_PEDALS];
byte dataLag[NUM_PEDALS];
//************INITIALIZE LIBRARY OBJECTS**************
// initialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[NUM_PEDALS] {
ResponsiveAnalogRead(ANALOG_PINS[0], true),
//ResponsiveAnalogRead(ANALOG_PINS[1], true),
};
// initialize the bounce objects
Bounce digital[] = {
Bounce(DIGITAL_PINS[0],BOUNCE_TIME),
Bounce(DIGITAL_PINS[1], BOUNCE_TIME),
Bounce(DIGITAL_PINS[2], BOUNCE_TIME),
Bounce(DIGITAL_PINS[3], BOUNCE_TIME),
Bounce(DIGITAL_PINS[4], BOUNCE_TIME)
};
Bounce modeTap = Bounce(MODE_TAP_PIN, BOUNCE_TIME);
//************SETUP**************
void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI);
// init the thresholds for the ResponsiveAnalogeRead objects
for (int n = 0; n < NUM_PEDALS; n++) {
analog[n].setActivityThreshold(20);
}
//'set a handle for returning control change messages'
usbMIDI.setHandleControlChange(OnControlChange);
usbMIDI.setHandleSongPosition(onSongPosition);
usbMIDI.setHandleClock(onClock);
usbMIDI.setHandleStart(onStart);
//'loop to configure input pins and internal pullup resisters for digital section'
for (int i=0;i<D_PINS;i++){
pinMode(DIGITAL_PINS[i], INPUT_PULLUP);
pinMode(RED_LED_PINS[i], OUTPUT);
pinMode(GREEN_LED_PINS[i], OUTPUT);
}
pinMode(MODE_TAP_PIN, INPUT_PULLUP);
pinMode(MODE_TAP_LED_PIN, OUTPUT);
digitalWrite(MODE_TAP_LED_PIN, LED_OFF);
for (int i=0;i<D_PINS;i++){
digitalWrite(GREEN_LED_PINS[i], LED_OFF); // - GREEN OFF
digitalWrite(RED_LED_PINS[i], LED_ON); // - RED ON
}
}
//************LOOP**************
void loop() {
getAnalogData();
getMain();
getModeTap();
flasher();
while (usbMIDI.read()) {
//' controllers must call .read() to keep the queue clear even if they are not responding to MIDI'
}
while (MIDI.read()){
}
}
//************DIGITAL SECTION**************
void getMain(){
for (int i=0;i<D_PINS;i++){
digital[i].update();
if (digital[i].fallingEdge() || digital[i].risingEdge()) {
if (state[bank][i]) {
usbMIDI.sendControlChange(MIDI_CC_NUMS[bank][i], 0, firstchannel);
MIDI.sendControlChange(MIDI_CC_NUMS[bank][i], 0, secondchannel);
digitalWrite(RED_LED_PINS[i], LED_ON);
digitalWrite(GREEN_LED_PINS[i], LED_OFF);
}else{
usbMIDI.sendControlChange(MIDI_CC_NUMS[bank][i], ON_Value, firstchannel);
MIDI.sendControlChange(MIDI_CC_NUMS[bank][i], ON_Value, secondchannel);
digitalWrite(RED_LED_PINS[i], LED_OFF);
digitalWrite(GREEN_LED_PINS[i], LED_ON);
}
state[bank][i] = !state[bank][i] ;
}
}
}
//************ANALOG SECTION**************
void getAnalogData() {
int valX;
int adcValue = 0;
for (int i = 0; i < NUM_PEDALS; i++) {
// update the ResponsiveAnalogRead object every loop
analog[i].update();
// if the repsonsive value has change, print out 'changed'
if (analog[i].hasChanged()) {
adcValue = analog[i].getValue();
valX = (map(adcValue, 60, 890, 0, 127)); //Change the upper first two numbers -
//upper and lower - to adjust the midi range of your expression pedal
valX = constrain(valX, 0, 127); //map all numbers to 0-127 to avoid negative numbers
data[i] = valX;
if (data[i] != dataLag[i]) {
dataLag[i] = data[i];
usbMIDI.sendControlChange(CCID[i], data[i], firstchannel);
MIDI.sendControlChange(CCID[i], data[i], secondchannel);
}
}
}
}
//************MODE/TAP SECTION**************
void getModeTap(){
modeTap.update();
if (modeTap.fallingEdge()) {
usbMIDI.sendControlChange(TAP_CC, ON_Value, firstchannel);
MIDI.sendControlChange(TAP_CC, ON_Value, secondchannel);
modeTimer = 0;
shiftUp = true;
tempoFlashOn = false;
flashcount = 0; // is this error or magic?
Serial.println("suspend tempo on tap");
}
if (modeTap.risingEdge()){
shiftUp = false;
if (modeTimer<modeThreshold){
tempoFlashOn = true;
Serial.println("resume tempo no mode change");
}
}
if (modeTimer>modeThreshold && shiftUp) {
shiftUp = false;
bank++;
bank = bank%MODE_COUNT;
for (int i = 0; i < D_PINS ; i++){
digitalWrite(GREEN_LED_PINS[i], !state[bank][i]);
digitalWrite(RED_LED_PINS[i], state[bank][i]);
}
// set counter of flashes 'owed' -- count them down after main part
flashcount = bank + 1;
flashTimer = 0 ; // is this needed?
}
}
void flasher(){
if (flashcount>= -1*waitflash){
if (flashcount> 0){
if (flashTimer>(flashOnTime+flashOffTime)){
flashcount-- ;// decrement flashcount
flashTimer = 0;
if (modeLED){
modeLED = false;
digitalWrite(MODE_TAP_LED_PIN, LED_OFF);
}
}else{
if (modeLED == false && flashTimer>flashOnTime){
modeLED = true;
digitalWrite(MODE_TAP_LED_PIN, LED_ON);
}
}
}else{
if (flashTimer>(flashOnTime+flashOffTime)){
flashcount-- ;// decrement flashcount
flashTimer = 0;
}
}
}else{
if (!tempoFlashOn){
tempoFlashOn = true;
Serial.println(flashcount);
Serial.println("resume tempo after bank select");
}
}
}
void OnControlChange(byte rcvChannel, byte controller, byte value) {
if (rcvChannel == firstchannel){
for (int i = 0; i < D_PINS ; i++){
if (MIDI_CC_NUMS[bank][i] == controller) {
if (value >= 64) {
digitalWrite(GREEN_LED_PINS[i], LED_ON);
digitalWrite(RED_LED_PINS[i], LED_OFF); //'receiving >64 turns green on and red off'
state[bank][i] = true;
}else{
digitalWrite(GREEN_LED_PINS[i], LED_OFF);
digitalWrite(RED_LED_PINS[i], LED_ON); //'receiving <64 turns red on and green off'
state[bank][i] = false;
} // 'if not the controller for i then skip this loop'
}
}
}
}
void onClock() {
if (tempoFlashOn){
if (ClockCount<=onClocks){
digitalWrite(MODE_TAP_LED_PIN, LED_ON);
}else{
digitalWrite(MODE_TAP_LED_PIN, LED_OFF);
}
}
ClockCount = (ClockCount+1)%24;
}
void onStart(){
ClockCount = 0;
}
void onSongPosition(uint16_t semiQ){
ClockCount= semiQ*6 ;
}