Program and libraries to run the MusicPlay game designed for ECE 4180 in Spring 2020.
Dependencies: Speaker mbed mbed-rtos 4DGL-uLCD-SE PinDetect
Revision 1:e84293b09274, committed 2020-04-30
- Comitter:
- onsideiut
- Date:
- Thu Apr 30 20:57:15 2020 +0000
- Parent:
- 0:9439ccb44422
- Commit message:
- ECE4180 Final Design Project Code Submission
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/4DGL-uLCD-SE.lib Thu Apr 30 20:57:15 2020 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/4180_1/code/4DGL-uLCD-SE/#2cb1845d7681
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PinDetect.lib Thu Apr 30 20:57:15 2020 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/AjK/code/PinDetect/#cb3afc45028b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SongPlayer.h Thu Apr 30 20:57:15 2020 +0000 @@ -0,0 +1,41 @@ +#include "mbed.h" +// new class to play a note on Speaker based on PwmOut class +class SongPlayer +{ +public: + SongPlayer(PinName pin) : _pin(pin) { +// _pin(pin) means pass pin to the constructor + } +// class method to play a note based on PwmOut class + void PlaySong(float frequency[], float duration[], float volume=1.0) { + vol = volume; + notecount = 0; + _pin.period(1.0/frequency[notecount]); + _pin = volume/2.0; + noteduration.attach(this,&SongPlayer::nextnote, duration[notecount]); + // setup timer to interrupt for next note to play + frequencyptr = frequency; + durationptr = duration; + //returns after first note starts to play + } + void nextnote(); +private: + Timeout noteduration; + PwmOut _pin; + int notecount; + float vol; + float * frequencyptr; + float * durationptr; +}; +//Interrupt Routine to play next note +void SongPlayer::nextnote() +{ + _pin = 0.0; + notecount++; //setup next note in song + if (durationptr[notecount]!=0.0) { + _pin.period(1.0/frequencyptr[notecount]); + noteduration.attach(this,&SongPlayer::nextnote, durationptr[notecount]); + _pin = vol/2.0; + } else + _pin = 0.0; //turn off on last note +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Speaker.lib Thu Apr 30 20:57:15 2020 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/zchen311/code/Speaker/#41292907c9cb
--- a/main.cpp Fri Nov 28 18:00:06 2014 +0000 +++ b/main.cpp Thu Apr 30 20:57:15 2020 +0000 @@ -1,75 +1,496 @@ #include "mbed.h" #include "rtos.h" +#include "uLCD_4DGL.h" +#include "Speaker.h" +#include "SongPlayer.h" DigitalOut myled(LED1); PwmOut myled2(LED2); PwmOut myled3(LED3); PwmOut myled4(LED4); -inline float random_number(){ - return (rand()/(float(RAND_MAX))); -} +uLCD_4DGL uLCD(p28,p27,p30); // serial tx, serial rx, reset pin; + +AnalogIn touchg(p17); +AnalogIn touchr(p16); +AnalogIn touchb(p15); + +float gVal = 0.0; +float rVal = 0.0; +float bVal = 0.0; + +Mutex stdio_mutex; + +Speaker mySpeaker(p21); + +SongPlayer mySpeakerSP(p21); + +//States: {STARTSCREEN = 0, MENU = 1, SONG1 = 2, SONG2 = 3, LISTENMODE = 4}; +int currState = 0; +int prevState = 0; +int selected = 1; + +float score = 10.0; +int numPlayedS1 = 0; +int numPlayedS2 = 0; +int passedPlayS1 = 0; +int passedPlayS2 = 0; + +float t = 2.5; // tempo controller + +DigitalIn pbL(p9); +DigitalIn pbR(p8); + + + +float ramblinFirst[] = {783.991, 698.456,622.254,622.254,622.254,698.456, + 783.991,783.991,783.991,698.456,622.254,698.456, + 698.456,698.456,622.254,587.330,622.254}; +float ramblinSecond[] = {1.0/t,0.5/t,0.9/t,0.4/t,1.0/t,0.5/t,0.9/t, + 0.4/t,0.5/t,0.5/t,0.5/t,0.4/t,0.4/t, + 0.5/t,1.0/t,0.5/t,2.5/t}; +float ramblinThird[] = {0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1, + 0.1,0.1,0.1,0.1,0.1,0.1,0.1}; + +//int ramblinRows[24]; +//int imagineRows[70]; +// +//int ramblinColors[24]; +//int imagineColors[70]; + +class MovingNotes +{ +protected: + int y_pos; + int x_pos; + int moving; + float freq; + float dur; + float val; +public: + void setStart(int h) {y_pos = h;} + void setWidth (int w) {x_pos = w;} + void setMoving (int m) {moving = m;} + void setFreq(float f) {freq = f;} + void setDur (float d) {dur = d;} + void setVal (float v) {val = v;} + // int getFreq() {return freq;} +// int getDur() {return dur;} +// int getVal() {return val;} + virtual void draw()= 0; + virtual void update(){} +}; + +MovingNotes * ramb_ptr[17]; + +class redNotes: public MovingNotes +{ + virtual void draw() + { + uLCD.filled_circle(x_pos, y_pos, 10, RED); + } + virtual void update() { + if (moving == 1) { + gVal = touchg.read(); + rVal = touchr.read(); + bVal = touchb.read(); + if (x_pos == 18 && y_pos > 90 && y_pos < 144 && gVal >0.5f) { + score++; + mySpeaker.PlayNote(freq,dur,val); + } else if (x_pos == 64 && y_pos > 90 && y_pos < 144 && rVal >0.5f) { + score++; + mySpeaker.PlayNote(freq,dur,val); + } else if (x_pos == 110 && y_pos > 90 && y_pos < 144 && bVal >0.5f) { + score++; + mySpeaker.PlayNote(freq,dur,val); + } + if (y_pos < 144) { + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 11; + uLCD.filled_circle(x_pos, y_pos, 10, RED); + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 11; + uLCD.filled_circle(x_pos, y_pos, 10, RED); + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 11; + uLCD.filled_circle(x_pos, y_pos, 10, RED); + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 11; + uLCD.filled_circle(x_pos, y_pos, 10, RED); + } else { + setMoving(0); + y_pos = 35; + } + } + } +}; + +class blueNotes: public MovingNotes +{ + virtual void draw() + { + uLCD.filled_circle(x_pos, y_pos, 10, BLUE); + } + virtual void update() { + if (moving == 1) { + gVal = touchg.read(); + rVal = touchr.read(); + bVal = touchb.read(); + if (x_pos == 18 && y_pos > 90 && y_pos < 144 && gVal >0.5f) { + score++; + mySpeaker.PlayNote(freq,dur,val); + } else if (x_pos == 64 && y_pos > 90 && y_pos < 144 && rVal >0.5f) { + score++; + mySpeaker.PlayNote(freq,dur,val); + } else if (x_pos == 110 && y_pos > 90 && y_pos < 144 && bVal >0.5f) { + score++; + mySpeaker.PlayNote(freq,dur,val); + } + if (y_pos < 144) { + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 9; + uLCD.filled_circle(x_pos, y_pos, 10, BLUE); + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 9; + uLCD.filled_circle(x_pos, y_pos, 10, BLUE); + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 9; + uLCD.filled_circle(x_pos, y_pos, 10, BLUE); + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 9; + uLCD.filled_circle(x_pos, y_pos, 10, BLUE); + } else { + setMoving(0); + y_pos = 35; + } + } + } +}; + +class greenNotes: public MovingNotes +{ + virtual void draw() + { + uLCD.filled_circle(x_pos, y_pos, 10, GREEN); + } + virtual void update() { + if (moving == 1) { + gVal = touchg.read(); + rVal = touchr.read(); + bVal = touchb.read(); + if (x_pos == 18 && y_pos > 90 && y_pos < 144 && gVal >0.5f) { + score++; + mySpeaker.PlayNote(freq,dur,val); + } else if (x_pos == 64 && y_pos > 90 && y_pos < 144 && rVal >0.5f) { + score++; + mySpeaker.PlayNote(freq,dur,val); + } else if (x_pos == 110 && y_pos > 90 && y_pos < 144 && bVal >0.5f) { + score++; + mySpeaker.PlayNote(freq,dur,val); + } + if (y_pos < 144) { + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 18; + uLCD.filled_circle(x_pos, y_pos, 10, GREEN); + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 18; + uLCD.filled_circle(x_pos, y_pos, 10, GREEN); + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 18; + uLCD.filled_circle(x_pos, y_pos, 10, GREEN); + Thread::wait(1000.00*0.1); + uLCD.filled_circle(x_pos, y_pos, 10, BLACK); + y_pos += 18; + uLCD.filled_circle(x_pos, y_pos, 10, GREEN); + } else { + setMoving(0); + y_pos = 35; + } + } + } +}; void beacon(void const *args){ while(1) { - //LED warm up effect using PWM - for(int i=0; i<50; i++) { - myled2 = i/50.0; - Thread::wait(1000.0*0.02); + if (!pbL) { + if (currState == 0) { + prevState = 0; + currState = 1; + Thread::wait(1000.00*0.5); + } else if (currState == 1) { + if (selected == 1) { + printf("play ramblin wreck"); + currState = 2; + prevState = 1; + Thread::wait(1000.00*0.5); + } else if (selected == 2) { + printf("play other song"); + currState = 3; + prevState = 1; + Thread::wait(1000.00*0.5); + } else if (selected == 3) { + currState = 4; + prevState = 1; + Thread::wait(1000.00*0.5); + } else if (selected == 4) { + currState = 0; + prevState = 1; + Thread::wait(1000.00*0.5); + } + } else if (currState == 2 || currState == 3 || currState == 4) { + score = 0; + numPlayedS1 = 0; + numPlayedS2 = 0; + currState = 1; + Thread::wait(1000.00*0.5); + } + printf("pbL "); + printf("currState: %d", currState); + printf(" prevstate: %d\n", prevState); + } else if (!pbR) { + + if (currState == 0) { + prevState = 0; + currState = 1; + Thread::wait(1000.00*0.2); + } else if (currState == 1) { + selected++; + if (selected >= 5) { + selected = 1; + } + Thread::wait(1000.00*0.5); + } + printf("pbR "); + printf("currState: %d", currState); + printf(" prevstate: %d\n", prevState); } - //LED at full brightness level - myled2 = 1.0; - Thread::wait(1000.0*0.25); - //LED cool down effect using PWM - for(int i=49; i>0; i--) { - myled2 = i/50.0; - Thread::wait(1000.0*0.02); - } - //LED off - myled2 = 0.0; - Thread::wait(1000.0*1.5); } } void welding(void const *args) { - float x = 0.0; while(1) { - //get a new random number for PWM - x = random_number(); - //add some exponential brightness scaling - //for more of a fast flash effect - myled3 = x*x*x; - //fast update rate for welding flashes - Thread::wait(1000.0*0.02); - //add a random pause between welds - if (random_number()>0.9925) { - myled3 = 0.0; - Thread::wait(1000.0*4.0*random_number()); + if (currState == 4) { // Listen to RW + stdio_mutex.lock(); + Thread::wait(1000.00*1); + if (prevState != 4) { + uLCD.cls(); + } + mySpeaker.PlayNote(783.991,1.0/t,0.1); // G + mySpeaker.PlayNote(698.456,0.5/t,0.1); //F + mySpeaker.PlayNote(622.254,0.9/t,0.1); //E flat + mySpeaker.PlayNote(0.0,0.1/t,0.0); //separation between the same notes + mySpeaker.PlayNote(622.254,0.4/t,0.1); //E flat + mySpeaker.PlayNote(0.0,0.1/t,0.0); + mySpeaker.PlayNote(622.254,1.0/t,0.1); //E flat + mySpeaker.PlayNote(698.456,0.5/t,0.1); //F + mySpeaker.PlayNote(783.991,0.9/t,0.1); // G + mySpeaker.PlayNote(0.0,0.1/t,0.0); + mySpeaker.PlayNote(783.991,0.4/t,0.1); // G + mySpeaker.PlayNote(0.0,0.1/t,0.0); + mySpeaker.PlayNote(783.991,0.5/t,0.1); // G + mySpeaker.PlayNote(698.456,0.5/t,0.1); //F + mySpeaker.PlayNote(622.254,0.5/t,0.1); //E flat + mySpeaker.PlayNote(698.456,0.4/t,0.1); //F + mySpeaker.PlayNote(0.0,0.1/t,0.0); + mySpeaker.PlayNote(698.456,0.4/t,0.1); //F + mySpeaker.PlayNote(0.0,0.1/t,0.0); + mySpeaker.PlayNote(698.456,0.5/t,0.1); //F + mySpeaker.PlayNote(622.254,1.0/t,0.1); //E flat + mySpeaker.PlayNote(587.330,0.5/t,0.1); //D + mySpeaker.PlayNote(622.254,2.5/t,0.1); //E flat + mySpeaker.PlayNote(0.0,0.5/t,0.0); //rest then repeat + Thread::wait(1000.00*0.5); + prevState = 4; + stdio_mutex.unlock(); + break; + } else if (currState == 2) { //Playing Ramblin Wreck + stdio_mutex.lock(); + if (prevState != 2) { + uLCD.text_width(1); + uLCD.text_height(2); + uLCD.locate(5,5); + uLCD.color(RED); + uLCD.printf("3 "); + Thread::wait(1000.00*0.4); + uLCD.printf("2 "); + Thread::wait(1000.00*0.4); + uLCD.printf("1 "); + Thread::wait(1000.00*0.4); + uLCD.printf("GO!"); + Thread::wait(1000.00*0.3); + uLCD.cls(); + } + // Set up Background + uLCD.line(42,25-4,42,127,WHITE); + uLCD.line(2*42+1,25-4,2*42+1,127,WHITE); + uLCD.circle(20,127-20,20,GREEN); + uLCD.circle(64,127-20,20,RED); + uLCD.circle(127-20,127-20,20,BLUE); + uLCD.rectangle(2,20,127,2,WHITE); + uLCD.locate(1,1); + uLCD.printf("Score: %f",score); + if (numPlayedS1 < 17) { + ramb_ptr[numPlayedS1] -> draw(); + ramb_ptr[numPlayedS1] -> setMoving(1); + numPlayedS1++; + float waitTime = 0.17 - numPlayedS1*0.01; + Thread::wait(1000.00*waitTime); + } + for (int i=0; i < 17; i++) { + ramb_ptr[i] -> update(); + } + gVal = touchg.read(); + rVal = touchr.read(); + bVal = touchb.read(); + + if (gVal > 0.5f) { + uLCD.circle(20,107,19,GREEN); + uLCD.circle(20,107,21,GREEN); + } else { + uLCD.circle(20,107,19,BLACK); + uLCD.circle(20,107,21,BLACK); + } + if (rVal > 0.5f) { + uLCD.circle(64,107,19,RED); + uLCD.circle(64,107,21,RED); + } else { + uLCD.circle(64,107,19,BLACK); + uLCD.circle(64,107,21,BLACK); + } + if (bVal > 0.5f) { + uLCD.circle(107,107,19,BLUE); + uLCD.circle(107,107,21,BLUE); + } else { + uLCD.circle(107,107,19,BLACK); + uLCD.circle(107,107,21,BLACK); + } + stdio_mutex.unlock(); + prevState = 2; + } else if (currState == 3) { //Playing Song2 + //stdio_mutex.lock(); + Thread::wait(1000.00*1); + prevState = 3; + //stdio_mutex.unlock(); } } } -void lighthouse(void const *args){ - float y=0.0; - while(1) { - for(double x=0.0; x <= 3.14159; x = x + 0.0314159) { - y = sin(x); //nice periodic function 0..1..0 - myled4 = y*y*y;//exponential effect - needs a sharp peak - Thread::wait(1000.0*.025); - } - myled4 = 0.0; - //most lighthouses have a 5 second delay - so add another 2.5 - Thread::wait(1000.0*2.5); - } -} + + + + int main() { + // Set up PushButtons + pbL.mode(PullUp); + pbR.mode(PullUp); + Thread thread2(beacon); Thread thread3(welding); - Thread thread4(lighthouse); - //main runs standard LED blink demo + //Thread thread4(lighthouse); + + // Set up Random Note Positions + set_time(1256729738); // by updating this creates new values each compilation + srand( static_cast<unsigned int>(time(0))); + + // create random assigner for each note + for (int i=0; i < 17; i++) { + int ramblinColors = rand() % 3; + int ramblinRows = rand() % 3; + int x = 0; + if (ramblinRows == 0) { + x = 18; + } else if (ramblinRows == 1) { + x = 64; + } else if (ramblinRows == 2) { + x = 110; + } + if (ramblinColors == 0) { + ramb_ptr[i] = new redNotes; + } else if (ramblinColors == 1) { + ramb_ptr[i] = new greenNotes; + } else if (ramblinColors == 2) { + ramb_ptr[i] = new blueNotes; + } + ramb_ptr[i] -> setStart(35); + ramb_ptr[i] -> setWidth(x); + ramb_ptr[i] -> setFreq(ramblinFirst[i]); + ramb_ptr[i] -> setDur(ramblinSecond[i]); + ramb_ptr[i] -> setVal(ramblinThird[i]); + } + while(1) { + gVal = touchg.read(); + rVal = touchr.read(); + bVal = touchb.read(); + // LED to Indicate Program Running myled = 1; Thread::wait(1000.0*0.2); myled = 0; Thread::wait(1000.0*0.2); + // Display Startup Page + stdio_mutex.lock(); + if (currState == 0) { + if (prevState != 0) { + uLCD.cls(); + } + uLCD.text_width(2); + uLCD.text_height(3); + uLCD.color(BLUE); + uLCD.locate(1.4, 0); + uLCD.printf("Welcome to \nMusicPlay"); + + uLCD.text_width(1); + uLCD.text_height(1); + uLCD.color(RED); + uLCD.locate(3.5, 12); + uLCD.printf("Press Either Button to Start"); + prevState = 0; + } else if (currState == 1) { // Display Menu + if (prevState != 1) { + uLCD.cls(); + } + uLCD.text_width(1); + uLCD.text_height(1); + if (selected == 1) { + uLCD.color(RED); + } else { + uLCD.color(BLUE); + } + uLCD.locate(2, 1); + uLCD.printf("Ramblin Wreck"); + if (selected == 2) { + uLCD.color(RED); + } else { + uLCD.color(BLUE); + } + uLCD.locate(6, 3); + uLCD.printf("Song2"); + if (selected == 3) { + uLCD.color(RED); + } else { + uLCD.color(BLUE); + } + uLCD.locate(3, 5); + uLCD.printf("Just Listen!"); + if (selected == 4) { + uLCD.color(RED); + } else { + uLCD.color(BLUE); + } + uLCD.locate(7, 7); + uLCD.printf("Back"); + prevState = 1; + } + stdio_mutex.unlock(); } }