I got inspiration from someone using a wand who had the tip of the wand light up with a battery cell and an LED light. I figured that I wanted something to happen when you use the wand. We recently learned how to make sounds in p5, so I thought I could make an interactive music box where you feel like a wizard. I was informed that I could use a musical instrument shield instead of using p5. After receiving the shield, I learned that I had a lot more freedom in creativity with the project. I brainstormed other possibilities that could happen and thought that a nice visual would make the project pop, so I added thin “cylinders” that would light up so you know which note was selected. After discussing the project with a friend outside of class (Jawon Richard) we went over all the materials I would need and what the overall project should look like. The only way my project would work is by using infrared sensors and LEDs. I would then need wood for laser cutting the base of the box, PLA/PETG for 3D printing the cylinders, 5 different color LEDs, an Arduino Uno, a potentiometer, and a speaker. I designed the box and each cylinder using Fusion 360 and got the wand design from Thingiverse. Each cylinder took a bit more than 10 hours to print.
For the final result of the project, the user gets to hold a wand that has an IR LED at the end and whenever you point to an IR sensor, that selected sensor will then have the LED light up the cylinder and make a musical pitch it is assigned to. The music box is on a pentatonic scale so any user can make a nice melody. After pointing to the selected cylinder, the length of the note being played depends on the instrument selected. However, there is a maximum amount of time a note can go on which is 1.05 seconds. That is how long it takes for the LEDs to turn on and then fade away as well. The LEDs stay constant. Without the fade, we wouldn’t be able to play more than one note. We would have to wait until one note finishes before moving to the next.
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
byte rootNote = 65; //The MIDI note value to be played
byte resetMIDI = 4; //Tied to VS1053 Reset line
byte ledPin = 13; //MIDI traffic inidicator
int instrument = 0;
const int sensor1 = A0;
const int sensor2 = A1;
const int sensor3 = A2;
const int sensor4 = A3;
const int sensor5 = A4;
const int LED1 = 5;
const int LED2 = 6;
const int LED3 = 9;
const int LED4 = 10;
const int LED5 = 11;
const int pot = A5;
//const int speaker = 3; // just a reminder
double fadeSpeed = 5;
double LED1Brightness = 0;
double LED2Brightness = 0;
double LED3Brightness = 0;
double LED4Brightness = 0;
double LED5Brightness = 0;
void setup() {
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(LED4, OUTPUT);
pinMode(LED5, OUTPUT);
pinMode(pot, INPUT);
// Serial.begin(9600);
Serial.begin(57600);
mySerial.begin(31250);
// reset MIDI
pinMode(resetMIDI, OUTPUT);
digitalWrite(resetMIDI, LOW);
delay(100);
digitalWrite(resetMIDI, HIGH);
delay(100);
talkMIDI(0xB0, 0x07, 120); //0xB0 is channel message, set channel volume to near max (127)
}
void loop() {
instrument = map(analogRead(pot), 0, 1023, 0, 127);
// 0x79 = GM1 Melotic, 0x78 = GM1 and GM2 Percussion
talkMIDI(0xB0, 0, 0x79);
Serial.print(" Instrument: ");
Serial.println(instrument, DEC);
talkMIDI(0xC0, instrument, 0);
if (digitalRead(sensor1) == LOW) {
LED1Brightness = 255;
analogWrite(LED1, LED1Brightness);
Serial.print("LED1Brightness: ");
Serial.println(LED1Brightness);
//Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
noteOn(0, rootNote, 60);
} else {
analogWrite(LED1, LED1Brightness);
if (LED1Brightness > 0 && LED1Brightness - fadeSpeed >= 0) {
LED1Brightness = LED1Brightness - fadeSpeed;
analogWrite(LED1, LED1Brightness);
} else {
noteOff(0, rootNote, 1);
LED1Brightness = 0;
}
Serial.print("LED1Brightness: ");
Serial.println(LED1Brightness);
}
if (digitalRead(sensor2) == LOW) {
LED2Brightness = 255;
analogWrite(LED2, LED2Brightness);
Serial.print("LED2Brightness: ");
Serial.println(LED2Brightness);
//Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
noteOn(0, rootNote + 2, 60);
} else {
analogWrite(LED2, LED2Brightness);
if (LED2Brightness > 0 && LED2Brightness - fadeSpeed >= 0) {
LED2Brightness = LED2Brightness - fadeSpeed;
analogWrite(LED2, LED2Brightness);
} else {
noteOff(0, rootNote + 2, 1);
LED2Brightness = 0;
}
Serial.print("LED2Brightness: ");
Serial.println(LED2Brightness);
}
if (digitalRead(sensor3) == LOW) {
LED3Brightness = 255;
analogWrite(LED3, LED3Brightness);
Serial.print("LED3Brightness: ");
Serial.println(LED3Brightness);
//Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
noteOn(0, rootNote + 4, 60);
} else {
analogWrite(LED3, LED3Brightness);
if (LED3Brightness > 0 && LED3Brightness - fadeSpeed >= 0) {
LED3Brightness = LED3Brightness - fadeSpeed;
analogWrite(LED3, LED3Brightness);
} else {
noteOff(0, rootNote + 4, 1);
LED3Brightness = 0;
}
Serial.print("LED3Brightness: ");
Serial.println(LED3Brightness);
}
if (digitalRead(sensor4) == LOW) {
LED4Brightness = 255;
analogWrite(LED4, LED4Brightness);
Serial.print("LED4Brightness: ");
Serial.println(LED4Brightness);
//Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
noteOn(0, rootNote + 7, 60);
} else {
analogWrite(LED4, LED4Brightness);
if (LED4Brightness > 0 && LED4Brightness - fadeSpeed >= 0) {
LED4Brightness = LED4Brightness - fadeSpeed;
analogWrite(LED4, LED4Brightness);
} else {
noteOff(0, rootNote + 7, 1);
LED4Brightness = 0;
}
Serial.print("LED4Brightness: ");
Serial.println(LED4Brightness);
}
if (digitalRead(sensor5) == LOW) {
LED5Brightness = 255;
analogWrite(LED5, LED5Brightness);
Serial.print("LED5Brightness: ");
Serial.println(LED5Brightness);
//Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
noteOn(0, rootNote + 9, 60);
} else {
analogWrite(LED5, LED5Brightness);
if (LED5Brightness > 0 && LED5Brightness - fadeSpeed >= 0) {
LED5Brightness = LED5Brightness - fadeSpeed;
analogWrite(LED5, LED5Brightness);
} else {
noteOff(0, rootNote + 9, 1);
LED5Brightness = 0;
}
Serial.print("LED5Brightness: ");
Serial.println(LED5Brightness);
}
}
//Send a MIDI note-on message. Like pressing a piano key
//channel ranges from 0-15
void noteOn(byte channel, byte note, byte attack_velocity) {
talkMIDI( (0x90 | channel), note, attack_velocity);
}
//Send a MIDI note-off message. Like releasing a piano key
void noteOff(byte channel, byte note, byte release_velocity) {
talkMIDI( (0x80 | channel), note, release_velocity);
}
//Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that data values are less than 127
void talkMIDI(byte cmd, byte data1, byte data2) {
digitalWrite(ledPin, HIGH);
mySerial.write(cmd);
mySerial.write(data1);
//Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes
//(sort of: http://253.ccarh.org/handout/midiprotocol/)
if( (cmd & 0xF0) <= 0xB0)
mySerial.write(data2);
digitalWrite(ledPin, LOW);
}