Skip to content

Instantly share code, notes, and snippets.

@yrrah
Last active December 16, 2015 09:49
Show Gist options
  • Save yrrah/5415948 to your computer and use it in GitHub Desktop.
Save yrrah/5415948 to your computer and use it in GitHub Desktop.
#include <SD.h>
//#include <MIDI.h>
#include <DmxSimple.h> //limited to 64 channels in DmxSimple.h to save memory
//define DEBUG 1
#define MIDI_BAUDRATE 31250
#define COMPILE_MIDI_IN 1 // Set this setting to 1 to use the MIDI input.
#define COMPILE_MIDI_OUT 0 // Set this setting to 1 to use the MIDI output.
#define COMPILE_MIDI_THRU 0 // Set this setting to 1 to use the MIDI Soft Thru feature
#define USE_SERIAL_PORT Serial
#define USE_RUNNING_STATUS 0
#define USE_1BYTE_PARSING 1
#define USE_CALLBACKS 0
#define MIDI_SYSEX_ARRAY_SIZE 64
#define LISTEN_CHAN 0
#define CASE_VAL_L 1
#define CASE_VAL_H 2
#define MIDI_VAR 3
#define MSG_TYPE 4
#define FG_ADDR 5
#define FG_LENGTH 6
#define CURRENT_F 7
#define PITCH 0
#define VELOCITY 1
#define POT1 41
#define POT2 42
#define POT3 43
#define POT4 44
#define FADER 45
File myFile;
char* temp = "";
int** caseArray;
int fgcount=0; //number of frame groups & corresponding cases
int maxChannel=20;
double global_note, global_velocity;
void loadFrame(int FrameID){
int i;
int chan, val, upVal;
char in,in2;
#ifdef DEBUG
Serial.print("Load Frame Group:");
Serial.print(FrameID);
Serial.print(" Frame:");
Serial.println(caseArray[FrameID][CURRENT_F]);
#endif
//seek to location of frame group on SD card
myFile.seek(caseArray[FrameID][FG_ADDR]);
//find location of frame
i=0;
while(i<=caseArray[FrameID][CURRENT_F]){
while(myFile.read()!='%');
i++;
}
//read and execute DMX instructions
in = myFile.read();
while(myFile.available()&&in!='%'&&in!='#'){
switch(in){
case 'S':
case 'P':
case 'F':
case 'M':
in2 = myFile.read();
myFile.readBytes(temp,2);
chan = asciiHexToInt(temp,2);
myFile.readBytes(temp,2);
val = asciiHexToInt(temp,2);
myFile.readBytes(temp,2);
upVal = asciiHexToInt(temp,2);
#ifdef DEBUG
Serial.flush();
Serial.print("DMX Instruction: chan ");
Serial.print(chan,HEX);
Serial.print(", ");
Serial.print(val,HEX);
Serial.print(", ");
Serial.println(upVal,HEX);
#endif
double potValue;
int out;
switch(in){
case 'S'://ST = Static
DmxSimple.write(chan,val);
break;
case 'P':
switch(in2){
case '1'://P1 = Potentiometer 1
potValue = analogRead(POT1);
break;
case '2'://P1 = Potentiometer 2
potValue = analogRead(POT2);
break;
case '3'://P1 = Potentiometer 3
potValue = analogRead(POT3);
break;
case '4'://P1 = Potentiometer 4
potValue = analogRead(POT4);
break;
case '5'://P1 = Fader / Slider
potValue = analogRead(FADER);
break;
}
out = (int)((potValue/1023)*(upVal-val) + val);
DmxSimple.write(chan,out);
break;
case 'F':
switch(in2){
case 'U'://FU = Fade Up
case 'D'://FD = Fade Down
break;
}
break;
case 'M':
Serial.print(val);
Serial.print(" ");
Serial.println(upVal);
switch(in2){
case '1'://M1 = MIDI Note
out = (int)((global_note/127)*(upVal-val) + val);
break;
case '2'://M2 = MIDI Velocity
out = (int)((global_velocity/127)*(upVal-val) + val);
break;
}
Serial.println(float2s(out,5));
DmxSimple.write(chan,out);
break;
}
break;
default:
#ifdef DEBUG
Serial.println("DMX Instuction Type not implemented yet");
Serial.print(caseArray[FrameID][CURRENT_F]);
Serial.print(" ");
Serial.print(FrameID);
Serial.print(" ");
Serial.print(in);
Serial.println(in2);
#endif
break;
}
in = myFile.read();
}
//increment frame counter
if(++caseArray[FrameID][CURRENT_F]>=caseArray[FrameID][FG_LENGTH])
caseArray[FrameID][CURRENT_F]=0;
}
void loadCase(){
int i;
caseArray = (int**) malloc(fgcount*sizeof(int*));
for (i = 0; i < fgcount; i++){
caseArray[i] = (int*) malloc(8*sizeof(int));
//MIDI Listen Channel
myFile.readBytes(temp,2);
caseArray[i][LISTEN_CHAN] = asciiHexToInt(temp,2);
//MIDI low case value
myFile.readBytes(temp,2);
caseArray[i][CASE_VAL_L] = asciiHexToInt(temp,2);
//MIDI high case value
myFile.readBytes(temp,2);
caseArray[i][CASE_VAL_H] = asciiHexToInt(temp,2);
//MIDI varible (pitch,velocity,etc)
myFile.readBytes(temp,1);
caseArray[i][MIDI_VAR] = asciiHexToInt(temp,1);
//MIDI message type (note on, note off, etc)
myFile.readBytes(temp,2);
caseArray[i][MSG_TYPE] = asciiHexToInt(temp,2);
//FG address
//caseArray[i][FG_ADDR] gets set in loadScene()
//caseArray[i][FG_LENGTH] gets set in loadScene()
caseArray[i][CURRENT_F] = 0;
#ifdef DEBUG
Serial.flush();
Serial.print("------ Case Array Index ");
Serial.print(i);
Serial.println(" -------");
Serial.print("MIDI Listen Channel ");
Serial.println(caseArray[i][0]);
Serial.print("MIDI low case value ");
Serial.println(caseArray[i][1]);
Serial.print("MIDI high case value ");
Serial.println(caseArray[i][2]);
Serial.print("MIDI varible ");
Serial.println(caseArray[i][3]);
Serial.print("MIDI message type ");
Serial.println(caseArray[i][4]);
Serial.flush();
#endif
}
}
void loadScene(){
int i;
int looplength;
//free the memory for the old case array if it exists
if(fgcount!=0){
for (i = 0; i < fgcount; i++)
free(caseArray[i]);
free(caseArray);
}
myFile.readBytes(temp,2);
fgcount = asciiHexToInt(temp,2);
myFile.readBytes(temp,2);
looplength = asciiHexToInt(temp,2);
myFile.readBytes(temp,2);
maxChannel = asciiHexToInt(temp,2);
#ifdef DEBUG
Serial.print("fgcount ");
Serial.println(fgcount);
Serial.print("looplength ");
Serial.println(looplength);
Serial.print("maxChannel ");
Serial.println(maxChannel);
#endif
//create new case array
loadCase();
//set FG addresses in case array
i = 0;
for(i = 0; i<fgcount; i++){
while(myFile.read()!='#');
myFile.readBytes(temp,2);
caseArray[i][FG_LENGTH] = asciiHexToInt(temp,2);
caseArray[i][FG_ADDR] = myFile.position();
#ifdef DEBUG
Serial.print("FG located at ");
Serial.println(caseArray[i][5]);
#endif
}
}
void setup(){
DmxSimple.usePin(7);
DmxSimple.maxChannel(8);
//pinMode(3, OUTPUT);
// MIDI.begin(MIDI_CHANNEL_OMNI);
#ifdef DEBUG
Serial.print("Initializing SD card...");
#endif
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.*/
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(20, OUTPUT);
if (!SD.begin(20)) {
#ifdef DEBUG
Serial.println("initialization failed!");
#endif
return;
}
#ifdef DEBUG
Serial.println("initialization done.");
#endif
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
myFile = SD.open("qq.scn", FILE_READ);
if (!myFile) {
// if the file didn't open, print an error:
#ifdef DEBUG
Serial.println("error opening scene");
#endif
}
loadScene();
//myFile.close();
}
int asciiHexToInt(char* a, int length){
//converts acii representation of hex eg 'ff' to 0xFF
int val;
int in;
int out=0;
for(int i=length-1;i>=0;i--){
in = a[i];
if(in>='A'&&in<='F'){
val = in-55;
}
else if(in>='a'&&in<='f'){
val = in-87;
}
else if(in>='0'&in<='9'){
val = in-48;
}
else return -1;
out += val * (int)ceil((pow(16,length-1-i)));
}
return out;
}
void loop(){
boolean dmx=0;
int i;
if(usbMIDI.read())
dmx = handleMIDI(usbMIDI.getType(), usbMIDI.getChannel(),usbMIDI.getData1(),usbMIDI.getData2());
// else if(MIDI.read())
// handleMIDI(MIDI.getType(), MIDI.getChannel(),MIDI.getData1(),MIDI.getData2());
else return;
if(!dmx)
for(i=0; i<maxChannel; i++)
DmxSimple.write(i,0);
}
boolean handleMIDI(int midiType, int midiChan, int note, int velocity) {
global_note = note;
global_velocity = velocity;
int midiValue=0;
int i;
switch (midiType) {
case 0:// NoteOff // Note Off
midiType = 0x80;
break;
case 1:// NoteOn // Note On
midiType = 0x90;
break;
default:// InvalidType // For notifying errors
midiType = 0;
break;
}
//#ifdef DEBUG
Serial.print("Type: ");
Serial.print(midiType);
Serial.print(" Chan: ");
Serial.print(midiChan);
Serial.print(" note: ");
Serial.print(note);
Serial.print(" velocity: ");
Serial.println(velocity);
//#endif
//loop through all cases
for(int i=0; i<fgcount; i++){
//check to see if correct message type (Note on, Note off, etc)
if(caseArray[i][MSG_TYPE]==midiType
&& caseArray[i][LISTEN_CHAN]==midiChan)
{
//get relevant incoming midi data
switch(caseArray[i][MIDI_VAR]){
case PITCH:
midiValue=note;
break;
case VELOCITY:
midiValue=velocity;
break;
}
//do comparison and load frame if true
if(midiValue>=caseArray[i][CASE_VAL_L]
&& midiValue<=caseArray[i][CASE_VAL_H])
{
loadFrame(i);
return 1;
}
}
}
return 0;
}
char * float2s(double f, unsigned int digits){
int index = 0;
static char s[16]; // buffer to build string representation
// handle sign
if (f < 0.0)
{
s[index++] = '-';
f = -f;
}
// handle infinite values
if (isinf(f))
{
strcpy(&s[index], "INF");
return s;
}
// handle Not a Number
if (isnan(f))
{
strcpy(&s[index], "NaN");
return s;
}
// max digits
if (digits > 9) digits = 9;
long multiplier = pow(10, digits); // fix int => long
int exponent = int(log10(f));
double g = f / pow(10, exponent);
if ((g < 1.0) && (g != 0.0))
{
g *= 10;
exponent--;
}
long whole = long(g); // single digit
long part = long((g-whole)*multiplier); // # digits
char format[16];
sprintf(format, "%%ld.%%0%dld E%%+d", digits);
sprintf(&s[index], format, whole, part, exponent);
return s;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment