A Simple VPO
/*
MIDI merger
==========================
This MIDI merge sketch is designed to scan a 32 pedal board and
output the corresponding MIDI codes via serial port 0 on channel 1 (0).
It also receives MIDI input via serial ports 0 (Gt.), 1 (Sw.) and 2 (Pos.).
The data received are assigned to MIDI channels 2 (1), 3 (2) and 4 (3)
respectively and are then merged and transmitted out through port 0.
The 32 organ pedal switches are arranged in a 4x8 matrix and are diode isolated.
Columns are connected to, pins 10-13. Scanning is accomplished by driving
these pins low (negative logic). Input is sampled via pins 2-9.
These inputs are normally high by using internal pullup resistors.
Low C is at pin 2x10, C# at pin 3x10 etc.
Equipment: Arduino Mega 2560 with three MIDI shields to accomodate three manuals.
created 2015 OCT 10
modified 2015 OCT 10
by John Coenraads
*/
// Declarations==========================================
//Counters (old Fortran habit)
int i, j, k;
int colCount, rowCount; //matrix column (pins 2-5) and row (pins 6-13) count
byte inputBit; //input data from port D
byte noteNumber; //noteNumber for pedal scan, low C = 36
const byte debounceCount = 5; //Note ON if count = 4, OFF if count = 0
byte debounceArray [73]; //holds debounce count for each pedal switch
byte onOffArray [73]; //HIGH if note is on, LOW if note is off
//Receive variables
byte noteStatusRx;
byte noteNumberRx;
byte noteVelocityRx;
//Flag to keep track of last valid status (0x90,0x80)
byte statusBuffer = 0, statusBuffer1 = 0, statusBuffer2 = 0;
//Initialize =========================================================
void setup()
{
delay (2000); // 2 second delay to let inputs stabilize
// Set MIDI baud rate:
Serial.begin(31250); Serial1.begin(31250); Serial2.begin(31250);
//Clear serial input buffers
while (Serial.available() > 0)
{Serial.read();}
while (Serial1.available() > 0)
{Serial1.read();}
while (Serial2.available() > 0)
{Serial2.read();}
//Initialize Pins 10 to 13 for output (normally high)
for (i = 10; i < 14; i++)
{
pinMode (i, OUTPUT);
digitalWrite (i, HIGH);
}
//Initialize Pins 2 to 9 for input (default). Normally high (via internal pullups)
for (i = 2; i < 10; i++)
{ pinMode (i, INPUT_PULLUP);}
//Initialize debounce count array to zero
for (i= 0; i < 73; i++)
{debounceArray[i] = 0; onOffArray [i] = LOW;}
}
//Main Loop ===========================================================
void loop()
{
if (Serial.available ())
{processSerial();}
if (Serial1.available ())
{processSerial1();}
if (Serial2.available ())
{processSerial2();}
scanPedal();
}
//Scan pedal input, convert to MIDI and output via port 0, channel 1.
void scanPedal ()
{
noteNumber = 36; //start at low C
for (colCount = 10; colCount < 14; colCount++)
{
digitalWrite (colCount, LOW);
for (rowCount = 2; rowCount < 10 ; rowCount++)
{
inputBit = digitalRead(rowCount); //read bit
if (inputBit == HIGH) //bit HIGH, switch open
{ turnNoteOFF(); }
else //bit LOW, switch closed
{ turnNoteON(); }
noteNumber++; //move on to next note
}
digitalWrite (colCount, HIGH);
}
}
//Turn note on. Debouncing is achieved by requiring that several turnNoteON requests
//are received before sending out noteOn MIDI message
void turnNoteON ()
{
if (debounceArray[noteNumber] < debounceCount)
{
debounceArray [noteNumber] = debounceArray [noteNumber] + 1;
if ((debounceArray[noteNumber] == debounceCount) && (onOffArray[noteNumber] == LOW))
{
onOffArray[noteNumber] = HIGH;
Serial.write (0x90); //note ON, channel 1
Serial.write (noteNumber);
Serial.write (0x7f); //medium velocity
}
}
}
//Turn note off. Debouncing is achieved by requiring that several turnNoteOFF requests
//are received before sending out noteOff MIDI message
void turnNoteOFF ()
{
if (debounceArray[noteNumber] > 0)
{
debounceArray [noteNumber] = debounceArray [noteNumber] - 1;
if ((debounceArray[noteNumber] == 0) && (onOffArray[noteNumber] == HIGH))
{
onOffArray[noteNumber] = LOW;
Serial.write (0x90); //note ON, channel 1
Serial.write (noteNumber);
Serial.write (0); //zero velocity = turn OFF note
}
}
}
//Process data received for serial port 0 (Great): status, note number, velocity
void processSerial ()
{
noteStatusRx = Serial.read ();
if (noteStatusRx > 0x7F) //is status byte
{
if ((noteStatusRx == 0x90) || //channel 1, note ON
(noteStatusRx == 0x80)) //channel 1, note OFF
{
statusBuffer = noteStatusRx;
while (!Serial.available()) {} //wait for serial data, port 0
noteNumberRx = Serial.read ();
while (!Serial.available()) {} //wait for serial data, port 0
noteVelocityRx = Serial.read ();
if (noteStatusRx == 0x80) { noteVelocityRx = 0;}
Serial.write (0x91); //output on channel 2, port 0
Serial.write (noteNumberRx);
Serial.write (noteVelocityRx);
}
else //not 0x90 or 0x80
{
statusBuffer = 0;
}
}
else //is data byte
{
if (statusBuffer != 0)
{
noteNumberRx = noteStatusRx;
noteStatusRx = statusBuffer;
while (!Serial.available()) {} //wait for serial data
noteVelocityRx = Serial.read ();
if (noteStatusRx == 0x80) { noteVelocityRx = 0;}
Serial.write (0x91); //output on channel 2, port 0
Serial.write (noteNumberRx);
Serial.write (noteVelocityRx);
}
}
}
//Process data received for serial port 1 (Swell): status, note number, velocity
void processSerial1 ()
{
noteStatusRx = Serial1.read ();
if (noteStatusRx > 0x7F) //is status byte
{
if ((noteStatusRx == 0x90) || //channel 1, note ON
(noteStatusRx == 0x80)) //channel 1, note OFF
{
statusBuffer1 = noteStatusRx;
while (!Serial1.available()) {} //wait for serial data, port 1
noteNumberRx = Serial1.read ();
while (!Serial1.available()) {} //wait for serial data, port 1
noteVelocityRx = Serial1.read ();
if (noteStatusRx == 0x80) { noteVelocityRx = 0;}
Serial.write (0x92); //output on channel 3, port 0
Serial.write (noteNumberRx);
Serial.write (noteVelocityRx);
}
else //not 0x90 or 0x80
{
statusBuffer1 = 0;
}
}
else //is data byte
{
if (statusBuffer1 != 0)
{
noteNumberRx = noteStatusRx;
noteStatusRx = statusBuffer1;
while (!Serial1.available()) {} //wait for serial data
noteVelocityRx = Serial1.read ();
if (noteStatusRx == 0x80) { noteVelocityRx = 0;}
Serial.write (0x92); //output on channel 3, port 0
Serial.write (noteNumberRx);
Serial.write (noteVelocityRx);
}
}
}
//Process data received for serial port 2 (Positive): status, note number, velocity
void processSerial2 ()
{
noteStatusRx = Serial2.read ();
if (noteStatusRx > 0x7F) //is status byte
{
if ((noteStatusRx == 0x90) || //channel 1, note ON
(noteStatusRx == 0x80)) //channel 1, note OFF
{
statusBuffer2 = noteStatusRx;
while (!Serial2.available()) {} //wait for serial data
noteNumberRx = Serial2.read ();
while (!Serial2.available()) {} //wait for serial data
noteVelocityRx = Serial2.read ();
if (noteStatusRx == 0x80) { noteVelocityRx = 0;}
Serial.write (0x93); //output on channel 4, port 0
Serial.write (noteNumberRx);
Serial.write (noteVelocityRx);
}
else //not 90 or 80
{
statusBuffer2 = 0;
}
}
else //is data byte
{
if (statusBuffer2 != 0)
{
noteNumberRx = noteStatusRx;
noteStatusRx = statusBuffer2;
while (!Serial2.available()) {} //wait for serial data
noteVelocityRx = Serial2.read ();
if (noteStatusRx == 0x80) { noteVelocityRx = 0;}
Serial.write (0x93); //output on channel 4, port 0
Serial.write (noteNumberRx);
Serial.write (noteVelocityRx);
}
}
}
// trace procedure
void trace (byte info)
{
Serial.write (0xF3);
Serial.write (info);
}