Playback Mode Source Code

/*
EXPLANATION OF PLAYBACK MODE

5 Maps uploaded from the GUI:
Maps are different setups for Buttons and all the values contained within them.

10 Buttons per Map:
Buttons are analog joysticks with momentary digital switches on the z-axis.

3 Positions per Button:
Positions are different ways to move a Button:
Low = Low range on the analog stick.
Middle = High reading on the digital switch.
High = High range on the analog stick.

3 Slots per Position:
Slots are places that store Properties of Abilities.
Each Slot value in the fullArray contains two bytes:
Which Map and which Slot on that Map

3 Properties of Abilities per Slot:
Properties include a Declarator of Ability,
Ability, and degree of Ability.
EXAMPLE: Properties for Slot[0]
Property[0] = 1 // a note-on channel change
Property[1] = 144 // note-on for channel one
Property[2] = 254 // an unused byte

Properties for Slot[1]
Property[3] = 4 // an octave change
Property[4] = 146 // octave change on channel 3
Property[5] = 48 // (48 - 60) + pitches on channel 3
*/

#include // Library for Flash memory. This lets us store values in memory so that we can recall our maps without uploading again.
PROGMEM prog_uint16_t savedArray[2250];

byte fullArray[2250]; //This stores all the numbers we'll need for everything.

boolean uploadMode = false; // True if the digital read of the PBULpin is 0, and it runs communication with the GUI from the computer
boolean playbackMode = false; // True if the digital read of the PBULpin is 1, and it runs communication with the CDo
boolean uploadComplete = false; // True once fullArray is loaded up with Serial.read from the GUI.
boolean valuesSaved = true; // True once fullArray is saved into EEPROM.
boolean valuesLoaded = false; //For loading values from EEPROM when in the beginning of playback mode. This takes 256 seconds.
boolean slotParse = false; //For getting active slot values from the fullArray.
int firstSlotbyte = 0;
int secondSlotbyte = 0;
int slotCounter = 0;
boolean propertyParse = false; //For getting property values for each slot.

int activeMap = 0;
byte slot[450]; // number of possible slot numbers
byte declarator[450];
byte ability[450];
byte degree[450];
int propertyCounter = 0;
int PBULpin = 13;

//variables for mux
int muxValue[16];
int a= 2;
int b= 3;
int c= 4;
int d= 5;
int analog0 = 0;

//variables for midiBytes
byte midiByte1[10];
byte midiByte2[10];
byte midiByte3[10];

void setup() {

// initialize serial communications at 9600 bps:
if(digitalRead(PBULpin) == 0){ //uploadMode
Serial.begin(9600);
uploadMode = true;
}else if(digitalRead(PBULpin) == 1){
Serial.begin(31250);
playbackMode = true;
}

// fill Slots with ("blanks")
for (int i = 0; i < 127; i++) {
slot[i] = 254;
}

//variables for mux
pinMode(analog0, INPUT);
pinMode(a,OUTPUT);
pinMode(b,OUTPUT);
pinMode(c,OUTPUT);
pinMode(d,OUTPUT);
}

void loop() {
//============================
===========================================================
//Upload
if(uploadMode){
if(!uploadComplete){
if (Serial.available () > 0) {
for (int i = 0; i < 512; i++){
fullArray[i] = Serial.read();
//Serial.print(Pvalues[i],BYTE); // Uncomment if you need to check for a problem between Processing and Arduino
}
}
uploadComplete = true;
valuesSaved = false;
}
//----------------------------------------------------------------------------------------
if(!valuesSaved){
for (int i = 0; i < 512; i++){
if (fullArray[i] != 255 && fullArray[i] !=-1){
PROGMEM prog_uint16_t savedArray[i] = fullArray[i];
//delay(100); //uncomment if you need to slow it down
}
}
valuesSaved = true;
}
}
//============================================================================================
//Playback
if(playbackMode){
//Load the fullArray from EEPROM
if(!valuesLoaded){
for (int i = 0; i < 512; i++){
fullArray[i] = pgm_read_word_near(savedArray + i);
/* FOR DEBUGGING
Serial.print(i);
Serial.print("\t");
Serial.print(fullArray[i], DEC);
Serial.println();
*/
}
valuesLoaded = true;
}
//----------------------------------------------------------------------------------------------
// copy Slots from fullArray, look for endByte 254 to be done
for (int i = 0; i < 450; i+=2) {
if (!slotParse) { // logic gate
if (fullArray[i] != 254) {// if the full array hasn't reached the 254 yet...
firstSlotbyte = fullArray[i];
secondSlotbyte = fullArray[i+1];
slots[slotCounter] = firstSlotbyte * secondSlotbyte;
slotCounter++;
} else {
slotCounter++;
slotParse = true; // when it reaches a 254, we're finished with the active slots
}
}
}
//-----------------------------------------------------------------------------------------------
//copy the rest of the fullArray into the property array
if (!propertyParse) {
for (int i = slotCounter; i < 2250; i+=3) { // start looking in full array AFTER the slots
if(fullArray[i] !=254){
declarator[propertyCounter] = fullArray[i];
ability[propertyCounter] = fullArray[i+1];
degree[propertyCounter] = fullArray[i+2];
propertyCounter++;
}
}
propertyParse = true;
}
//------------------------------------------------------------------------------------------------
//Constantly read in multiplexer values
for (int muxPin = 0; muxPin < 16; muxPin ++) {
int pinOne = 1 & muxPin;
int pinTwo = 1 & (muxPin >> 1) ;
int pinThree = 1 & (muxPin >> 2);
int pinFour = 1 & (muxPin >> 3);

digitalWrite(a,pinOne);
digitalWrite(b,pinTwo);
digitalWrite(c,pinThree);
digitalWrite(d,pinFour);

muxValue[muxPin] = analogRead(analog0);

//Serial.print(muxValue[muxPin], DEC);
//Serial.print("\t");
}
//--------------------------------------------------------------------------------------------------
//constantly check to see which map is active
for (int i = 8; i < 13; i ++){
if( muxValue[i]== 1023){
activeMap = i-7;
}
}
//--------------------------------------------------------------------------------------------------
//Joysticks
//Analog low for 1 through 5
for (int i = 0; i < 5; i ++){
if(muxValue[i] < 300){ //if position low on button i
for(int j = 0; j < 450; j++){ // look through the slots array to see if it has active slots
if(slot[j] == i*3 || slot[j] == (i*3)+1 || slot[j] == (i*3)+2){ //if it does then grab the properties and send them to the appropriate function
if(declarator[j] == 1){
channelFunction(ability[j]);
}else if(declarator[j] == 2){
pitchFunction(ability[j]);
}else if(declarator[j] == 3){
velocityFunction(ability[j], degree[j]);
}else if(declarator[j] == 4){
octaveFunction(ability[j],degree[j]);
}else if(declarator[j] == 5){
pitchbendFunction(ability[j]);
}else if(declarator[j] == 6){
ccFunction(ability[j],degre[j];
}
}
}
}
}
}

}