/*************************************************************
MIDI CONTROLLER
by Notes and Volts
www.notesandvolts.com
Version 1.2 **Arduino UNO ONLY!**
*************************************************************/
class Mux
{
public:
Mux(byte outpin_, byte numPins_, bool analog_);
byte outpin;
byte numPins;
bool analog;
};
//************************************************************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
class Button
{
public:
Button(byte pin, byte command, byte value, byte channel, byte debounce);
Button(Mux mux, byte muxpin, byte command, byte value, byte channel, byte debounce);
byte getValue();
void muxUpdate();
void newValue(byte command, byte value, byte channel);
byte Bcommand;
byte Bvalue;
byte Bchannel;
byte Btoggle;
private:
byte _previous;
byte _current;
unsigned long _time;
int _debounce;
byte _pin;
byte _muxpin;
byte _numMuxPins;
byte _value;
byte _command;
bool _busy;
byte _status;
byte _last;
byte _enablepin;
};
//*************************************************************************
class Pot
{
public:
Pot(byte pin, byte command, byte control, byte channel);
Pot(byte potIndex, Mux mux, byte muxpin ,byte command, byte control, byte channel);
void muxUpdate();
void newValue(byte command, byte value, byte channel);
byte getValue();
byte Pcommand;
byte Pcontrol;
byte Pchannel;
byte PIndex;
private:
byte _pin;
byte _muxpin;
byte _numMuxPins;
byte _control;
int _value;
int _oldValue;
bool _changed;
byte _enablepin;
};
Mux::Mux(byte outpin_, byte numPins_, bool analog_)
{
outpin = outpin_;
//enablepin = enablepin_;
numPins = numPins_;
analog = analog_;
if (analog == false) pinMode(outpin, INPUT_PULLUP);
//pinMode(enablepin, OUTPUT);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
}
//****************************************************************************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
Button::Button(byte pin, byte command, byte value, byte channel, byte debounce)
{
_pin = pin;
pinMode(_pin, INPUT_PULLUP);
_value = value;
_command = command;
_debounce = debounce;
_time = 0;
_busy = false;
_status = 0b00000010;
_last = 1;
Bcommand = command;
Bvalue = value;
Bchannel = channel;
Btoggle = 0;
}
Button::Button(Mux mux, byte muxpin, byte command, byte value, byte channel, byte debounce)
{
_pin = mux.outpin;
_numMuxPins = mux.numPins;
_muxpin = muxpin;
_value = value;
_command = command;
_debounce = debounce;
_time = 0;
_busy = false;
_status = 0b00000010;
_last = 1;
Bcommand = command;
Bvalue = value;
Bchannel = channel;
Btoggle = 0;
}
//********************************************************************
Pot::Pot(byte pin, byte command, byte control, byte channel)
{
_pin = pin;
_control = control;
_value = analogRead(_pin);
_value = _value >> 3;
_oldValue = _value << 3;
_value = _value << 3;
Pcommand = command;
Pcontrol = control;
Pchannel = channel;
}
Pot::Pot(byte potIndex, Mux mux, byte muxpin, byte command, byte control, byte channel)
{
_pin = mux.outpin;
_numMuxPins = mux.numPins;
_muxpin = muxpin;
_control = control;
muxUpdate();
_value = analogRead(_pin);
_value = _value >> 3;
_oldValue = _value << 3;
_value = _value << 3;
PIndex = potIndex;
Pcommand = command;
Pcontrol = control;
Pchannel = channel;
}
void Button::muxUpdate()
{
byte temp = _muxpin;
temp = temp << 2;
if (_numMuxPins > 8) PORTD = PORTD & B11000011;
else PORTD = PORTD & B11100011;
PORTD = PORTD | temp;
}
byte Button::getValue()
{
// If BUSY bit not set - read button
if (bitRead(_status, 0) == false) { // If busy false
if (digitalRead(_pin) == _last) return 2; // If same as last state - exit
}
// If NEW Bit set - Key just pressed, record time
if (bitRead(_status, 1) == true) { // If new is true
bitSet(_status, 0); // Set busy TRUE
bitClear(_status, 1); // Set New FALSE
_time = millis();
return 255;
}
// Check if debounce time has passed - If no, exit
if (millis() - _time < _debounce) return 255;
// Debounce time has passed. Read pin to see if still set the same
// If it has changed back - assume false alarm
if (digitalRead(_pin) == _last) {
bitClear(_status, 0); // Set busy false
bitSet(_status, 1); // Set new true
return 255;
}
// If this point is reached, event is valid. return event type
else {
bitClear(_status, 0); // Set busy false
bitSet(_status, 1); // Set new true
_last = ((~_last) & 0b00000001); // invert _last
return _last;
}
}
void Button::newValue(byte command, byte value, byte channel)
{
Bvalue = value;
Bcommand = command;
Bchannel = channel;
}
void Pot::muxUpdate()
{
byte temp = _muxpin;
temp = temp << 2;
if (_numMuxPins > 8) PORTD = PORTD & B11000011;
else PORTD = PORTD & B11100011;
//PORTD = PORTD & B11000011;
PORTD = PORTD | temp;
}
byte Pot::getValue()
{
_value = analogRead(_pin);
int tmp = (_oldValue - _value);
if (tmp >= 8 || tmp <= -8) {
_oldValue = _value >> 3;
_oldValue = _oldValue << 3;
return _value >> 3;
}
return 255;
}
void Pot::newValue(byte command, byte value, byte channel) {
Pcommand = command;
Pcontrol = value;
Pchannel = channel;
}
//***ANY MULTIPLEXERS? (74HC4067)************************************
//MUX address pins must be connected to Arduino UNO pins 2,3,4,5
//A0 = PIN2, A1 = PIN3, A2 = PIN4, A3 = PIN5
//*******************************************************************
//Mux NAME (OUTPUT PIN, , How Many Mux Pins?(8 or 16) , Is It Analog?);
//Mux M1(10, 16, false); //Digital multiplexer on Arduino pin 10
//Analog multiplexer on Arduino analog pin A0
Mux M1(A0, 8, true);
Mux M2(A1, 8, true);
Mux M3(A2, 8, true);
Mux M4(A3, 8, true);
//*******************************************************************
//***DEFINE DIRECTLY CONNECTED BUTTONS*******************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
//** Command parameter 0=NOTE 1=CC 2=Toggle CC **
// Button BU1(2, 0, 60, 1, 5 );
// Button BU2(3, 0, 61, 1, 5 );
// Button BU3(4, 0, 62, 1, 5 );
// Button BU4(5, 0, 63, 1, 5 );
// Button BU5(6, 0, 64, 1, 5 );
// Button BU6(7, 0, 65, 1, 5 );
// Button BU7(8, 1, 64, 1, 5 );
// Button BU8(9, 2, 64, 1, 5 );
//*******************************************************************
//Add buttons used to array below like this-> Button *BUTTONS[] {&BU1, &BU2, &BU3, &BU4, &BU5, &BU6, &BU7, &BU8};
Button *BUTTONS[] {};
//*******************************************************************
//***DEFINE DIRECTLY CONNECTED POTENTIOMETERS************************
//Pot (Pin Number, Command, CC Control, Channel Number)
//**Command parameter is for future use**
//Pot PO1(A0, 0, 1, 1);
//Pot PO2(A1, 0, 10, 1);
//Pot PO3(A2, 0, 22, 1);
//Pot PO4(A3, 0, 118, 1);
//Pot PO5(A4, 0, 30, 1);
//Pot PO6(A5, 0, 31, 1);
//*******************************************************************
//Add pots used to array below like this-> Pot *POTS[] {&PO1, &PO2, &PO3, &PO4, &PO5, &PO6};
Pot *POTS[] {};
//*******************************************************************
//***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, 0, 70, 1, 5);
//Button MBU2(M1, 1, 1, 71, 1, 5);
//Button MBU3(M1, 2, 2, 72, 1, 5);
//Button MBU4(M1, 3, 0, 73, 1, 5);
//Button MBU5(M1, 4, 0, 74, 1, 5);
//Button MBU6(M1, 5, 0, 75, 1, 5);
//Button MBU7(M1, 6, 0, 76, 1, 5);
//Button MBU8(M1, 7, 0, 77, 1, 5);
//Button MBU9(M1, 8, 0, 78, 1, 5);
//Button MBU10(M1, 9, 0, 79, 1, 5);
//Button MBU11(M1, 10, 0, 80, 1, 5);
//Button MBU12(M1, 11, 0, 81, 1, 5);
//Button MBU13(M1, 12, 0, 82, 1, 5);
//Button MBU14(M1, 13, 0, 83, 1, 5);
//Button MBU15(M1, 14, 0, 84, 1, 5);
//Button MBU16(M1, 15, 0, 85, 1, 5);
//*******************************************************************
////Add multiplexed buttons used to array below like this-> Button *MUXBUTTONS[] {&MBU1, &MBU2, &MBU3, &MBU4, &MBU5, &MBU6.....};
Button *MUXBUTTONS[] {};
//*******************************************************************
//***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( 1,M1, 0, 0, 1, 1);
Pot MPO2( 2,M1, 1, 0, 2, 1);
Pot MPO3( 3,M1, 2, 0, 3, 1);
Pot MPO4( 4,M1, 3, 0, 4, 1);
Pot MPO5( 5,M1, 4, 0, 5, 1);
Pot MPO6( 6,M1, 5, 0, 6, 1);
Pot MPO7( 7,M1, 6, 0, 7, 1);
Pot MPO8( 8,M1, 7, 0, 8, 1);
Pot MPO9( 9,M1, 8, 0, 9, 1);
Pot MP10(10,M1, 9, 0,10, 1);
Pot MP11(11,M1,10, 0,11, 1);
Pot MP12(12,M1,11, 0,12, 1);
Pot MP13(13,M1,12, 0,13, 1);
Pot MP14(14,M1,13, 0,14, 1);
Pot MP15(15,M1,14, 0,15, 1);
Pot MP16(16,M1,15, 0,16, 1);
Pot MP17(17,M2, 0, 0,17, 1);
Pot MP18(18,M2, 1, 0,18, 1);
Pot MP19(19,M2, 2, 0,19, 1);
Pot MP20(20,M2, 3, 0,20, 1);
Pot MP21(21,M2, 4, 0,21, 1);
Pot MP22(22,M2, 5, 0,22, 1);
Pot MP23(23,M2, 6, 0,23, 1);
Pot MP24(24,M2, 7, 0,24, 1);
Pot MP25(25,M2, 8, 0,25, 1);
Pot MP26(26,M2, 9, 0,26, 1);
Pot MP27(27,M2,10, 0,27, 1);
Pot MP28(28,M2,11, 0,28, 1);
Pot MP29(29,M2,12, 0,29, 1);
Pot MP30(30,M2,13, 0,30, 1);
Pot MP31(31,M2,14, 0,31, 1);
Pot MP32(32,M2,15, 0,32, 1);
Pot MP33(33,M3, 0, 0,33, 1);
Pot MP34(34,M3, 1, 0,34, 1);
Pot MP35(35,M3, 2, 0,35, 1);
Pot MP36(36,M3, 3, 0,36, 1);
Pot MP37(37,M3, 4, 0,37, 1);
Pot MP38(38,M3, 5, 0,38, 1);
Pot MP39(39,M3, 6, 0,39, 1);
Pot MP40(40,M3, 7, 0,40, 1);
Pot MP41(41,M3, 8, 0,41, 1);
Pot MP42(42,M3, 9, 0,42, 1);
Pot MP43(43,M3,10, 0,43, 1);
Pot MP44(44,M3,11, 0,44, 1);
Pot MP45(45,M3,12, 0,45, 1);
Pot MP46(46,M3,13, 0,46, 1);
Pot MP47(47,M3,14, 0,47, 1);
Pot MP48(48,M3,15, 0,48, 1);
Pot MP49(49,M4, 0, 0,49, 1);
Pot MP50(50,M4, 1, 0,50, 1);
Pot MP51(51,M4, 2, 0,51, 1);
Pot MP52(52,M4, 3, 0,52, 1);
Pot MP53(53,M4, 4, 0,53, 1);
Pot MP54(54,M4, 5, 0,54, 1);
Pot MP55(55,M4, 6, 0,55, 1);
Pot MP56(56,M4, 7, 0,56, 1);
Pot MP57(57,M4, 8, 0,57, 1);
Pot MP58(58,M4, 9, 0,58, 1);
Pot MP59(59,M4,10, 0,59, 1);
Pot MP60(60,M4,11, 0,60, 1);
Pot MP61(61,M4,12, 0,61, 1);
Pot MP62(62,M4,13, 0,62, 1);
Pot MP63(63,M4,14, 0,63, 1);
Pot MP64(64,M4,15, 0,64, 1);
//*******************************************************************
//Add multiplexed pots used to array below like this-> Pot *MUXPOTS[] {&MPO1, &MPO2, &MPO3, &MPO4, &MPO5, &MPO6.....};
Pot *MUXPOTS[] {
&MPO1,
&MPO2,
&MPO3,
&MPO4,
&MPO5,
&MPO6,
&MPO7,
&MPO8,
&MPO9,
&MP10,
&MP11,
&MP12,
&MP13,
&MP14,
&MP15,
&MP16,
&MP17,
&MP18,
&MP19,
&MP20,
&MP21,
&MP22,
&MP23,
&MP24,
&MP25,
&MP26,
&MP27,
&MP28,
&MP29,
&MP30,
&MP31,
&MP32,
&MP33,
&MP34,
&MP35,
&MP36,
&MP37,
&MP38,
&MP39,
&MP40,
&MP41,
&MP42,
&MP43,
&MP44,
&MP45,
&MP46,
&MP47,
&MP48,
&MP49,
&MP50,
&MP51,
&MP52,
&MP53,
&MP54,
&MP55,
&MP56,
&MP57,
&MP58,
&MP59,
&MP60,
&MP61,
&MP62,
&MP63,
&MP64
};
//*******************************************************************
//************************************************************
//***SET THE NUMBER OF CONTROLS USED**************************
//************************************************************
//---How many buttons are connected directly to pins?---------
byte NUMBER_BUTTONS = 0;
//---How many potentiometers are connected directly to pins?--
byte NUMBER_POTS = 0;
//---How many buttons are connected to a multiplexer?---------
byte NUMBER_MUX_BUTTONS = 0;
//---How many potentiometers are connected to a multiplexer?--
byte NUMBER_MUX_POTS = 64;
//************************************************************
void setup() {
Serial.begin(9600);
}
void loop() {
// if (NUMBER_BUTTONS != 0) updateButtons();
// if (NUMBER_POTS != 0) updatePots();
// if (NUMBER_MUX_BUTTONS != 0) updateMuxButtons();
if (NUMBER_MUX_POTS != 0) updateMuxPots();
}
//*****************************************************************
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
Serial.println(message);
break;
case 1: //CC
Serial.println(message);
break;
case 2: //Toggle
if (BUTTONS[i]->Btoggle == 0) {
Serial.println(message);
BUTTONS[i]->Btoggle = 1;
}
else if (BUTTONS[i]->Btoggle == 1) {
Serial.println(message);
BUTTONS[i]->Btoggle = 0;
}
break;
}
}
// Button is not pressed
if (message == 1) {
switch (BUTTONS[i]->Bcommand) {
case 0:
Serial.println(message);
break;
case 1:
Serial.println(message);
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
//Serial.println(message);
break;
case 1: //CC
//Serial.println(message);
break;
case 2: //Toggle
if (MUXBUTTONS[i]->Btoggle == 0) {
//Serial.println(message);
MUXBUTTONS[i]->Btoggle = 1;
}
else if (MUXBUTTONS[i]->Btoggle == 1) {
//Serial.println(message);
MUXBUTTONS[i]->Btoggle = 0;
}
break;
}
}
// Button is not pressed
if (message == 1) {
switch (MUXBUTTONS[i]->Bcommand) {
case 0:
Serial.println(message);
break;
case 1:
Serial.println(message);
break;
}
}
}
}
//***********************************************************************
void updatePots() {
for (int i = 0; i < NUMBER_POTS; i = i + 1) {
byte potmessage = POTS[i]->getValue();
if (potmessage != 255) Serial.println(potmessage);
}
}
//***********************************************************************
void updateMuxPots() {
// Serial.println("updateMuxPots");
for (int i = 0; i < NUMBER_MUX_POTS; i = i + 1) {
byte index = MUXPOTS[i]->PIndex;
//Serial.println(i);
MUXPOTS[i]->muxUpdate();
byte potmessage = MUXPOTS[i]->getValue();
delay(10);
if (potmessage != 255) {
Serial.print(index);
Serial.print(":");
Serial.println(potmessage);
}
}
}