Skip to content

Instantly share code, notes, and snippets.

@yrrah
Last active December 16, 2015 09:49
Show Gist options
  • Select an option

  • Save yrrah/5415948 to your computer and use it in GitHub Desktop.

Select an option

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 NOTE_ON 'n'
File myFile;
char* temp = "";
int** caseArray;
int fgcount=0; //number of frame groups & corresponding cases
int maxChannel=20;
void loadFrame(int FrameID){
int i;
int chan, val;
char in;
#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!='#'){
if(in=='S'){
//static instruction
myFile.readBytes(temp,2);
chan = asciiHexToInt(temp,2);
myFile.readBytes(temp,2);
val = asciiHexToInt(temp,2);
DmxSimple.write(chan,val);
#ifdef DEBUG
Serial.flush();
Serial.print("DMX Instruction: chan ");
Serial.print(chan,HEX);
Serial.print(", ");
Serial.println(val,HEX);
#endif
}else{
#ifdef DEBUG
Serial.println("DMX Instuction Type not implemented yet");
Serial.print(caseArray[FrameID][CURRENT_F]);
Serial.print(" ");
Serial.println(FrameID);
#endif
}
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("1.scn", FILE_READ);
if (!myFile) {
// if the file didn't open, print an error:
#ifdef DEBUG
Serial.println("error opening test.txt");
#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) {
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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment