#include <MIDI.h>
#include "Controller.h"
/*************************************************************
MIDI CONTROLLER 1.2
by Notes and Volts
www.notesandvolts.com
With some mods by Pat
Added per element value map / constrain for Pots - not yet for multiplex
Useful for pots whose wiper does not reach either end of the resistance track
eg. joysticks or optical expression pedals using an LDR.
Added option to direct per element output to alternative serial ports for pots
tho is not used in this code iteration
Originally, this code was for UNO, however was usually used on a MEGA without multiplexers.
The aim is to shoehorn this code into a Teensy 3.5, the end result being:-
A class compliant USB - Midi interface / control surface for 5 Gizmos.
In this iteration of the code, the multiplexer handling has been extended so we're
outputting bits 0 - 5. A 74LS138 is used to point to 3 x 4067's.
Debounce is set to zero coz we're using R/S latch hardware debounce.
Why? Coz the chosen press button switches are SPDT and I happened to have a bag of 4093's and
er well, a carryover from radio days - reject out of band crap before movin to the next stage.
*************************************************************/
//************************************************************
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
//************************************************************
//***SET THE NUMBER OF CONTROLS USED**************************
//************************************************************
//---How many buttons are connected directly to pins?---------
byte NUMBER_BUTTONS = 3;
//---How many potentiometers are connected directly to pins?--
byte NUMBER_POTS = 2;
//---How many buttons are connected to a multiplexer?---------
byte NUMBER_MUX_BUTTONS = 43;
//---How many potentiometers are connected to a multiplexer?--
byte NUMBER_MUX_POTS = 0;
//*******************************************************************
//*** MULTIPLEXERS? *************************************************
//MUX address pins must be connected to Arduino MEGA pins 22,23,24,25,26,27
//A0 = PIN22, A1 = PIN23, A2 = PIN24, A3 = PIN25 A4 = PIN26, A5 = PIN27
//*******************************************************************
//Mux NAME (OUTPUT PIN, , How Many Mux Pins?(8 or 16) , Is It Analog?);
Mux M1(30, NUMBER_MUX_BUTTONS, false); //Digital multiplexer on Mega pin 30
Mux M2(3, NUMBER_MUX_POTS, true); //Analog multiplexer on MEGA pin 3
//*******************************************************************
//***DEFINE DIRECTLY CONNECTED POTENTIOMETERS************************
//Pot (Pin Number, Command, CC Control, MidiPortNumber, Channel Number, MapInLow, MapInHigh, MapOut Low, MapOutHigh)
//**Command parameter is for future use**
//Pot PO1 (Pin Number, Command, CC Control, MidiPort, Channel Number, inLow, inHigh, outLow, outHigh)
Pot PO1(A0, 0, 14, 1, 16, 10, 1010, 0, 127);
Pot PO2(A1, 0, 15, 1, 16, 10, 1010, 0, 127);
//Pot PO3(A14, 0, 1, 1, 1, 0, 1023, 0, 127);
//Pot PO4(A13, 0, 11, 1, 1, 0, 1023, 0, 127);
//Pot PO5(A0, 0, 5, 1, 1, 0, 1023, 0, 127);
//Pot PO6(A1, 0, 91, 1, 1, 0, 1023, 0, 127);
//Pot PO7(A2, 0, 93, 1, 1, 0, 1023, 0, 127);
//Pot PO8(A3, 0, 7, 1, 1, 0, 1023, 0, 127);
//*******************************************************************
//Add pots used to array below like this-> Pot *POTS[] {&PO1, &PO2, &PO3, &PO4, &PO5, &PO6};
Pot *POTS[] {&PO1, &PO2};
//*******************************************************************
//***DEFINE DIRECTLY CONNECTED BUTTONS*******************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
//** Command parameter 0=NOTE 1=CC 2=Toggle CC **
Button BU1(4, 1, 102, 16, 5 );
Button BU2(3, 1, 103, 16, 5 );
Button BU3(2, 1, 104, 16, 5 );
//Button BU4(35, 2, 69, 16, 0 );
//Button BU5(53, 2, 64, 16, 0 );
//Button BU6(51, 2, 66, 16, 0 );
//Button BU7(49, 0, 43, 16, 0 );
//Button BU8(47, 0, 44, 16, 0 );
//Button BU9(45, 0, 45, 16, 0 );
//Button BU10(43, 0, 46, 16, 0 );
//Button BU11(41, 0, 47, 16, 0 );
//Button BU12(39, 0, 48, 16, 0 );
//Button BU13(37, 0, 49, 16, 0 );
//Button BU14(35, 0, 50, 16, 0 );
//Button BU15(33, 0, 51, 16, 0 );
//Button BU16(31, 0, 52, 16, 0 );
//Button BU17(29, 0, 53, 16, 0 );
//*******************************************************************
//Add buttons used to array below like this-> Button *BUTTONS[] {&BU1, &BU2, &BU3, &BU4, &BU5, &BU6, &BU7, &BU8, &BU9, &BU10, &BU11, &BU12, &BU13, &BU14, &BU15, &BU16, BU17};
Button *BUTTONS[] {&BU1, &BU2, &BU3};
//*******************************************************************
//***DEFINE BUTTONS CONNECTED TO MULTIPLEXER*************************
Button::Button(Mux mux, byte muxpin, byte command, byte value, byte channel, byte debounce);
//** Command parameter 0=NOTE 1=CC 2=Toggle CC **
Button MBU1(M1, 0, 1, 64, 16, 0); // Mute 1
Button MBU2(M1, 1, 1, 65, 16, 0); // Mute 2
Button MBU3(M1, 2, 1, 66, 16, 0); // Mute 3
Button MBU4(M1, 3, 1, 67, 16, 0); // Mute 4
Button MBU5(M1, 4, 1, 68, 16, 0); // Mute 5
Button MBU6(M1, 5, 1, 69, 16, 0); // Mute 6
Button MBU7(M1, 6, 1, 70, 16, 0); // Mute 7
Button MBU8(M1, 7, 1, 71, 16, 0); // Mute 8
Button MBU9(M1, 8, 1, 72, 16, 0); // Mute 9
Button MBU10(M1, 9, 1, 73, 16, 0); // Mute 10
Button MBU11(M1, 10, 1, 74, 16, 0); // Mute 11
Button MBU12(M1, 11, 1, 75, 16, 0); // Mute 12
Button MBU13(M1, 12, 1, 90, 16, 0); // Clear Track
Button MBU14(M1, 13, 1, 93, 16, 0); // Mark
Button MBU15(M1, 14, 1, 94, 16, 0); // Copy
Button MBU16(M1, 15, 1, 95, 16, 0); // Splat
Button MBU17(M1, 16, 1, 76, 16, 0); // Select 1
Button MBU18(M1, 17, 1, 77, 16, 0); // Select 2
Button MBU19(M1, 18, 1, 78, 16, 0); // Select 3
Button MBU20(M1, 19, 1, 79, 16, 0); // Select 4
Button MBU21(M1, 20, 1, 80, 16, 0); // Select 5
Button MBU22(M1, 21, 1, 81, 16, 0); // Select 6
Button MBU23(M1, 22, 1, 82, 16, 0); // Select 7
Button MBU24(M1, 23, 1, 83, 16, 0); // Select 8
Button MBU25(M1, 24, 1, 84, 16, 0); // Select 9
Button MBU26(M1, 25, 1, 85, 16, 0); // Select 10
Button MBU27(M1, 26, 1, 86, 16, 0); // Select 11
Button MBU28(M1, 27, 1, 87, 16, 0); // Select 12
Button MBU29(M1, 28, 1, 88, 16, 0); // Toggle Solo
Button MBU30(M1, 29, 1, 89, 16, 0); // Toggle Transposable Track
Button MBU31(M1, 30, 1, 91, 16, 0); // Toggle Trig Next Seq
Button MBU32(M1, 31, 1, 92, 16, 0); // Toggle Click Track
Button MBU33(M1, 32, 1, 76, 1, 0); // Select 1
Button MBU34(M1, 33, 1, 77, 1, 0); // Select 2
Button MBU35(M1, 34, 1, 78, 1, 0); // Select 3
Button MBU36(M1, 35, 1, 79, 1, 0); // Select 4
Button MBU37(M1, 36, 1, 80, 1, 0); // Select 5
Button MBU38(M1, 37, 1, 81, 1, 0); // Select 6
Button MBU39(M1, 38, 1, 82, 1, 0); // Select 7
Button MBU40(M1, 39, 1, 83, 1, 0); // Select 8
Button MBU41(M1, 40, 1, 84, 1, 0); // Select 9
Button MBU42(M1, 41, 1, 85, 1, 0); // Select 10
Button MBU43(M1, 42, 1, 86, 1, 0); // Select 11
Button MBU44(M1, 43, 1, 87, 1, 0); // Select 12
Button MBU45(M1, 44, 1, 88, 1, 0); // Toggle Solo
Button MBU46(M1, 45, 1, 89, 1, 0); // Toggle Transposable Track
Button MBU47(M1, 46, 1, 91, 1, 0); // Toggle Trig Next Seq
Button MBU48(M1, 47, 1, 92, 1, 0); // Toggle Click Track
//*******************************************************************
////Add multiplexed buttons used to array below like this-> Button *MUXBUTTONS[] {&MBU1, &MBU2, &MBU3, &MBU4, &MBU5, &MBU6.....};
Button *MUXBUTTONS[] {&MBU1,&MBU2,&MBU3,&MBU4,&MBU5,&MBU6,&MBU7,&MBU8,&MBU9,&MBU10,&MBU11,&MBU12,&MBU13,&MBU14,&MBU15,&MBU16,
&MBU17,&MBU18,&MBU19,&MBU20,&MBU21,&MBU22,&MBU23,&MBU24,&MBU25,&MBU26,&MBU27,&MBU28,&MBU29,&MBU30,&MBU31,&MBU32,
&MBU33,&MBU34,&MBU35,&MBU36,&MBU37,&MBU38,&MBU39,&MBU40,&MBU41,&MBU42,&MBU43,&MBU44,&MBU45,&MBU46,&MBU47,&MBU48};
//*******************************************************************
//***DEFINE POTENTIOMETERS CONNECTED TO MULTIPLEXER*******************
//Pot::Pot(Mux mux, byte muxpin, byte command, byte control, byte channel)
//**Command parameter is for future use**
//Pot MPO1(M2, 0, 1, 1, 1);
//Pot MPO2(M2, 1, 1, 7, 1);
//Pot MPO3(M2, 2, 1, 50, 1);
//Pot MPO4(M2, 3, 1, 55, 2);
//Pot MPO5(M2, 4, 1, 50, 1);
//Pot MPO6(M2, 5, 1, 55, 2);
//Pot MPO7(M2, 6, 1, 50, 1);
//Pot MPO8(M2, 7, 1, 55, 2);
//Pot MPO9(M2, 8, 1, 50, 1);
//Pot MPO10(M2, 9, 1, 55, 2);
//Pot MPO11(M2, 10, 1, 50, 1);
//Pot MPO12(M2, 11, 1, 55, 2);
//Pot MPO13(M2, 12, 1, 50, 1);
//Pot MPO14(M2, 13, 1, 55, 2);
//Pot MPO15(M2, 14, 1, 50, 1);
//Pot MPO16(M2, 15, 1, 55, 2);
//*******************************************************************
//Add multiplexed pots used to array below like this-> Pot *MUXPOTS[] {&MPO1, &MPO2, &MPO3, &MPO4, &MPO5, &MPO6.....};
Pot *MUXPOTS[] {};
//*******************************************************************
void setup() {
MIDI1.begin();
}
void loop() {
if (NUMBER_BUTTONS != 0) updateButtons();
if (NUMBER_POTS != 0) updatePots();
if (NUMBER_MUX_BUTTONS != 0) updateMuxButtons();
// if (NUMBER_MUX_POTS != 0) updateMuxPots(); // we'll cross that bridge when we get to it...
}
//*****************************************************************
void updateButtons() {
// Cycle through Button array
for (int i = 0; i < NUMBER_BUTTONS; i = i + 1) {
byte message = BUTTONS[i]->getValue();
// Button is pressed
if (message == 0) {
switch (BUTTONS[i]->Bcommand) {
case 0: //Note
MIDI1.sendNoteOn(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
break;
case 1: //CC
MIDI1.sendControlChange(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
break;
case 2: //Toggle
if (BUTTONS[i]->Btoggle == 0) {
MIDI1.sendControlChange(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
BUTTONS[i]->Btoggle = 1;
}
else if (BUTTONS[i]->Btoggle == 1) {
MIDI1.sendControlChange(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
BUTTONS[i]->Btoggle = 0;
}
break;
}
}
// Button is not pressed
if (message == 1) {
switch (BUTTONS[i]->Bcommand) {
case 0:
MIDI1.sendNoteOff(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
break;
case 1:
MIDI1.sendControlChange(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
break;
}
}
}
}
//*******************************************************************
void updateMuxButtons() {
// Cycle through Mux Button array
for (int i = 0; i < NUMBER_MUX_BUTTONS; i = i + 1) {
MUXBUTTONS[i]->muxUpdate();
byte message = MUXBUTTONS[i]->getValue();
// Button is pressed
if (message == 0) {
switch (MUXBUTTONS[i]->Bcommand) {
case 0: //Note
MIDI1.sendNoteOn(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
break;
case 1: //CC
MIDI1.sendControlChange(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
break;
case 2: //Toggle
if (MUXBUTTONS[i]->Btoggle == 0) {
MIDI1.sendControlChange(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
MUXBUTTONS[i]->Btoggle = 1;
}
else if (MUXBUTTONS[i]->Btoggle == 1) {
MIDI1.sendControlChange(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
MUXBUTTONS[i]->Btoggle = 0;
}
break;
}
}
// Button is not pressed
if (message == 1) {
switch (MUXBUTTONS[i]->Bcommand) {
case 0:
MIDI1.sendNoteOff(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
break;
case 1:
MIDI1.sendControlChange(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
break;
}
}
}
}
//***********************************************************************
void updatePots() {
for (int i = 0; i < NUMBER_POTS; i = i + 1) {
byte potmessage = POTS[i]->getValue();
if (potmessage != 255) switch (POTS[i]->PmidiPort) {
case 0:
MIDI1.sendControlChange(POTS[i]->Pcontrol,potmessage, POTS[i]->Pchannel);
break;
case 1:
MIDI1.sendControlChange(POTS[i]->Pcontrol,potmessage, POTS[i]->Pchannel);
break;
}
}
}
//***********************************************************************
void updateMuxPots() {
for (int i = 0; i < NUMBER_MUX_POTS; i = i + 1) {
MUXPOTS[i]->muxUpdate();
byte potmessage = MUXPOTS[i]->getValue();
if (potmessage != 255) MIDI1.sendControlChange(MUXPOTS[i]->Pcontrol, potmessage, MUXPOTS[i]->Pchannel);
}
}