/* Control a set of solenoids with MIDI
* Note on messages trigger solenoids, and they will be turned off after a certain amount of ms has passed
*/
int MIDI_note=-1;
int MIDI_Channel=1;
int sol1=2;
int sol2=3;
int sol3=4;
int sol4=5;
int sol5=6;
const int NoteEvent_size=64; //last note in array (buffer)
const unsigned long noteOffDelay=1000; //time (in ms) before note is turned off
const int pinOffset=58; // Only use MIDI note range from 60 (C3) and up, so 60 will trigger pin 2
int note=0;
typedef struct {int midiNote;int noteTime;} NoteEvent_t;
/* NoteEvent_tail is index in circular buffer for the first note to be removed */
/* NoteEvent_head is index in circular buffer for the next note to be added */
/* If NoteEvent_count == 0 then list is empty */
/* If NoteEvent_count == NoteEvent_size then list is full */
NoteEvent_t NoteEvent[NoteEvent_size];
int NoteEvent_tail = 0;
int NoteEvent_head = 0;
int NoteEvent_count = 0;
bool inline NoteEventFull() {return NoteEvent_count == NoteEvent_size; };
bool inline NoteEventEmpty() {return NoteEvent_count == 0; };
int inline NoteEventNext(int eventIndex) {return (eventIndex+1)%NoteEvent_size; };
void inline WriteNoteEventPin(int NoteEventIndex, int state) {
digitalWrite(NoteEvent[NoteEventIndex].midiNote-pinOffset,state); //turn off solenoid
}
void setup() {
Serial.begin(115200);
while (!Serial) {}
usbMIDI.setHandleNoteOn(myNoteOn);
//usbMIDI.setHandleNoteOff(myNoteOff);
//usbMIDI.setHandleControlChange(myControlChange);
pinMode(sol1, OUTPUT);
pinMode(sol2, OUTPUT);
pinMode(sol3, OUTPUT);
pinMode(sol4, OUTPUT);
pinMode(sol5, OUTPUT);
/*
for (int i=0;i<(NoteEvent_size+1);i++){
for (int j=0;j<2;j++) {
noteOff[j][i]=0;
}
}
*/
}
int overflowevent = 0;
uint32_t maxupdatetime = 0;
elapsedMillis looptime;
uint32_t updatetime = 0;
void loop() {
updatetime = micros();
usbMIDI.read(MIDI_Channel);
turnNotesOff();
if ((MIDI_note>59)&&(MIDI_note<65)) {
int checkNote=checkIfNotePlaying(MIDI_note);
if (checkNote==0) {
playNote(MIDI_note);
}
MIDI_note = -1;
}
//delay(5);
}
//Read note no messages from external units
void myNoteOn(byte channel, byte note, byte velocity) {
MIDI_note=note;
}
//turn off all notes that have been on for more than noteOffDelay
void turnNotesOff() {
unsigned long realTime=millis();
while ((NoteEvent_count > 0) && ( (realTime-NoteEvent[NoteEvent_tail].noteTime)>=noteOffDelay)) {
WriteNoteEventPin(NoteEvent_tail, 0);
NoteEvent_count -= 1;
NoteEvent_tail = (NoteEvent_tail+1) % NoteEvent_size;
}
}
//check if note has been played recently without being turned off
int checkIfNotePlaying(int playNote) {
for (int i = NoteEvent_tail, count=NoteEvent_count; count>0; i = (i+1)%NoteEvent_size, count=count-1) {
if (NoteEvent[i].midiNote == playNote ) return 1;
}
return 0;
}
//play note
//save note information
void playNote (int newNote) {
if (NoteEventFull()) { /* Buffer full, remove oldest, NoteEvent_tail */
WriteNoteEventPin(NoteEvent_tail, 0);
NoteEvent_count -= 1;
NoteEvent_tail = (NoteEvent_tail+1) % NoteEvent_size;
}
NoteEvent[NoteEvent_head].midiNote = newNote;
Serial.printf("play %i on %i \n",newNote, NoteEvent[NoteEvent_head].midiNote-pinOffset);
WriteNoteEventPin(NoteEvent_head, 1);
unsigned long noteOffTime=millis();
NoteEvent[NoteEvent_head].noteTime=noteOffTime;
NoteEvent_count += 1;
NoteEvent_head=(NoteEvent_head+1)%NoteEvent_size;
}