/* MIDI-enabled Laser Harp SOURCE: http://open-source-energy.org/?topic=1129.0 See: MIDI Technical Specifications http://en.wikipedia.org/wiki/MIDI#Technical_specifications */ #define MIDI_LASER_COUNT 9 #define MIDI_LASER_OCTAVE_DOWN 0 #define MIDI_LASER_OCTAVE_UP 8 short midiCalibrateAmbientLight = 1023; boolean midiLaserState[MIDI_LASER_COUNT] = {false, false, false, false, false, false, false, false, false}; byte midiNotes[MIDI_LASER_COUNT] = {0, 0, 2, 4, 5, 7, 9, 11, 0}; byte midiOctave = 5; byte midiPinLaser[MIDI_LASER_COUNT] = {3, 4, 5, 6, 7, 8, 9, 10, 11}; byte midiPinVelocity = A0; unsigned long midiRateLimit[MIDI_LASER_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned long midiRateLimitThreshold = 35; unsigned long midiRateLimitThresholdOctave = 70; byte midiVelocity = 127; void setup() { calibrateAmbientLight(); midiInitSerial(); midiInitPins(); midiIntroSong(); } void loop() { midiReadLasers(); midiReadVelocity(); } void calibrateAmbientLight() { delay(100); midiCalibrateAmbientLight = analogRead(midiPinVelocity); } void midiIntroSong() { delay(1); midiSendNoteOn(60, 127); delay(125); midiSendNoteOff(60); midiSendNoteOn(64, 127); delay(125); midiSendNoteOff(64); midiSendNoteOn(67, 127); delay(125); midiSendNoteOff(67); midiSendNoteOn(72, 127); delay(250); midiSendNoteOff(72); midiSendNoteOn(67, 127); delay(125); midiSendNoteOff(67); midiSendNoteOn(72, 127); delay(500); midiSendNoteOff(72); } boolean midiHandleOctave(byte thePin, boolean theState) { if (!theState) {return false;} if ((thePin == MIDI_LASER_OCTAVE_DOWN) && midiOctave == 0) {return false;} if ((thePin == MIDI_LASER_OCTAVE_UP) && midiOctave == 9) {return false;} midiOctaveKill(); switch(thePin) { case MIDI_LASER_OCTAVE_DOWN: midiOctave--; break; case MIDI_LASER_OCTAVE_UP: midiOctave++; break; } return true; } boolean midiHandleRateLimit(byte thePin) { unsigned long theMillis = millis(); unsigned long theThreshold = 0; switch (thePin) { case MIDI_LASER_OCTAVE_DOWN: case MIDI_LASER_OCTAVE_UP: theThreshold = midiRateLimitThresholdOctave; break; default: theThreshold = midiRateLimitThreshold; break; } if (theMillis - midiRateLimit[thePin] >= theThreshold) { midiRateLimit[thePin] = theMillis; return true; } return false; } void midiHandleReadLaser(byte thePin, boolean theState) { if ((midiLaserState[thePin] != theState) && midiHandleRateLimit(thePin)) { midiLaserState[thePin] = theState; if ((thePin == MIDI_LASER_OCTAVE_DOWN) || (thePin == MIDI_LASER_OCTAVE_UP)) { midiHandleOctave(thePin, theState); } else if (theState) { midiSendNoteOn(midiNotes[thePin] + (12 *midiOctave), midiVelocity); } else { midiSendNoteOff(midiNotes[thePin] + (12 *midiOctave)); } } } void midiInitPins() { for (byte thePin = 0; thePin < MIDI_LASER_COUNT; thePin++) { pinMode(midiPinLaser[thePin], INPUT); } } void midiInitSerial() { Serial.begin(31250); } void midiOctaveKill() { for (byte thePin = 0; thePin < MIDI_LASER_COUNT; thePin++) { if ((thePin == MIDI_LASER_OCTAVE_DOWN) || (thePin == MIDI_LASER_OCTAVE_UP)) {continue;} midiHandleReadLaser(thePin, LOW); } } void midiReadLasers() { for (byte thePin = 0; thePin < MIDI_LASER_COUNT; thePin++) { midiHandleReadLaser(thePin, digitalRead(midiPinLaser[thePin])); } } void midiReadVelocity() { midiVelocity = map(analogRead(midiPinVelocity), 0, midiCalibrateAmbientLight, 1, 127); } void midiSendCC(byte theCC, byte theValue) { Serial.write(B10110000); Serial.write(theCC); Serial.write(theValue); } void midiSendNoteOff(byte theNote) { Serial.write(B10000000); Serial.write(theNote); Serial.write(0); delay(1); } void midiSendNoteOn(byte theNote, byte theVelocity) { Serial.write(B10010000); Serial.write(theNote); Serial.write(theVelocity); delay(1); }