Program and libraries to run the MusicPlay game designed for ECE 4180 in Spring 2020.

Dependencies:   Speaker mbed mbed-rtos 4DGL-uLCD-SE PinDetect

Files at this revision

API Documentation at this revision

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

4DGL-uLCD-SE.lib Show annotated file Show diff for this revision Revisions of this file
PinDetect.lib Show annotated file Show diff for this revision Revisions of this file
SongPlayer.h Show annotated file Show diff for this revision Revisions of this file
Speaker.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- /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();
     }
 }