piano 4 octaves, 8 notes, 3 threads, 2 outputs, no bug, clean code, comments, remove old .h

Dependencies:   TextLCD

Fork of Nucleo_piano_CS435 by karine aknin

Revision:
9:9a36b66869fa
Parent:
8:781b03221397
--- a/main.cpp	Wed Jul 04 21:47:32 2018 +0000
+++ b/main.cpp	Thu Jul 05 01:08:36 2018 +0000
@@ -8,21 +8,25 @@
  
 // Define Bus In for Buttons (Do, Re, Mi, Fa, Sol, La, Si, Do)
 BusIn Bus_In(PA_0, PA_1, PA_4, PB_0, PA_10, PB_3, PB_5, PB_4);
-
+ 
 // Define the PWM speaker
 PwmOut speaker(PB_10);
-
-//Define Bus In for Gamme Button
-BusIn Bus_In_Gamme(PB_9);
+ 
+// Define Bus In for Octave Button
+BusIn Bus_In_Octave(PB_9);
+ 
+// Define Serial
+Serial pc(PA_2, PA_3);
    
 //Define variables for sound
-struct  NoteReference {
-    char    name[4];
-    int     mask;
-    double  frequency;
-    double  add[4];
+struct  NoteReference { // struct note reference
+    char    name[4]; // note name
+    int     mask; // note mask for pressed of not
+    double  frequency; // note base frequency (octave 0)
+    double  add[4]; // add value for octave balancing (from octave 0 to 3)
     };
-    
+
+// NoteReference tab for 8 notes (1 octave)    
 NoteReference   noteReference[8] = {    {"Do", 0x1, 262.0, {0.0, -1.0, -1.5, -3.0}},
                                         {"Re", 0x2, 294.0, {0.0, -1.0, -1.0, -3.0 }},
                                         {"Mi", 0x4, 330.0, {0.0, -1.0, -1.5, -3.0}},
@@ -32,152 +36,218 @@
                                         {"Si", 0x40, 494.0, {0.0, 0.0, -1.0, -1.0}},
                                         {"Do", 0x80, 523.0, {0.0, 0.0, 0.0, 0.0}}
                                     };
-volatile int    stateButtons = 0;
-volatile int    stateButtonGamme = 0;
-volatile int    gamme = 0;
-
+volatile int    stateButtons = 0; // State of notes buttons
+volatile int    stateButtonOctave = 0; // State of octave button
+volatile int    octave = 0; // octave value
+ 
 //Define variable for display
-char     bufferOutput[30] = "";
-
+char     bufferOutput[30] = ""; // buffer for notes and octave
+ 
 //Define variables for synchronization
-Mutex   lockBufferOutput;
-Mutex   lockGamme;
- 
-void    refresh_state_button()
+Mutex   lockBufferOutput; // Mutex for BufferOutput variable
+Mutex   lockOctave; // Mutex for octave variable
+
+/**
+    Function that refresh the value of
+    stateButtons depending on data input from
+    Bus_In.
+**/ 
+void    refresh_state_buttons()
 {
    stateButtons = Bus_In & Bus_In.mask(); // read the bus and mask out bits not being used
 }
- 
+
+/**
+    Function that output notes on the buzzer.
+**/ 
 void        play_music(int notes, double frequency)
 {
-   speaker.period(1.0 / frequency);
-   while (stateButtons == notes) {
-     refresh_state_button();
+   speaker.period(1.0 / frequency); // set the period to 1 / frequency of notes
+   while (stateButtons == notes) { // while button is pressed
+     refresh_state_buttons(); // refresh stateButtons
    }
 }
 
-double      generate_frequency(double frequency, int actualGamme)
+/**
+    Function that generate a frequency depending on pressed notes
+    and actual octave.
+**/ 
+double      generate_frequency(double frequency, int actualOctave)
 {
-    frequency = 0.0;
-    lockBufferOutput.lock();
-    strcpy(bufferOutput, "");
-    for (int i = 0; i < 8; i++) {
-        if (!(stateButtons & noteReference[i].mask))
+    frequency = 0.0; // init frequency to 0
+    lockBufferOutput.lock(); // lock lockBufferOutput Mutex for writing new notes on bufferOutput variable
+    strcpy(bufferOutput, ""); // init bufferOuput to empty string
+    for (int i = 0; i < 8; i++) { // iterate on all element of noteReference tab
+        if (!(stateButtons & noteReference[i].mask)) // if note is pressed
         {
-            frequency += noteReference[i].frequency * pow(2.0, (double)actualGamme) + noteReference[i].add[actualGamme];
-            strcat(bufferOutput, noteReference[i].name);
-            strcat(bufferOutput, " ");
+            // add note frequency to frequency (base frequency * 2^octave + add)
+            frequency += noteReference[i].frequency * pow(2.0, (double)actualOctave) + noteReference[i].add[actualOctave];
+            strcat(bufferOutput, noteReference[i].name); // concatenate bufferOutput and new note name
+            strcat(bufferOutput, " "); // concatenate with space separator
         }
     }
-    lockBufferOutput.unlock();
-    return (frequency);
+    lockBufferOutput.unlock(); // unlock bufferOutput at the end of the loop, end of writing
+    return (frequency); // return the frequency to play on buzzer
 }
- 
-void        check_buttons(double frequency, int actualGamme)
+
+/**
+    Check if buttons if pressed and play notes
+    otherwise set duty cycle to 0.
+**/
+void        check_buttons(double frequency, int actualOctave)
 {
-    if (stateButtons == 0xFF)
+    if (stateButtons == 0xFF) // if nothing pressed
     {
-        speaker = 0;
-        lockBufferOutput.lock();
-        strcpy(bufferOutput, "");
-        lockBufferOutput.unlock();
+        speaker = 0; // duty cycle equal to 0
+        lockBufferOutput.lock(); // lock BufferOutput Mutex for writing on bufferOutput variable
+        strcpy(bufferOutput, ""); // set bufferOutput to empty string
+        lockBufferOutput.unlock(); // unlock BufferOutput Mutex
     }
-    else {
-        lockGamme.lock();
-        actualGamme = gamme;
-        lockGamme.unlock();
-        frequency = generate_frequency(frequency, actualGamme);
-        speaker = 0.5;
-        play_music(stateButtons, frequency);
+    else { // if buttons pressed
+        lockOctave.lock(); // lock lockOctave Mutex for reading octave value
+        actualOctave = octave; // read octave value
+        lockOctave.unlock(); // unlock lockOctave Mutex
+        frequency = generate_frequency(frequency, actualOctave); // generate frequency depending on notes and octave
+        speaker = 0.5; // set duty cycle to 0.5 for volume
+        play_music(stateButtons, frequency); // play notes on buzzer
     }
 }
 
+/**
+    Thread for playing notes.
+    check states of buttons notes and play music.
+**/ 
 void    run_music()
 {
-    double  frequency = 0.0;
-    int     actualGamme = 0;
+    double  frequency = 0.0; // double for total frequency
+    int     actualOctave = 0; // int for actual octave
     
-    while (true)
+    while (true) // Infinte loop to catch buttons notes events
     {
-        refresh_state_button();
-        check_buttons(frequency, actualGamme);
-        Thread::wait(100);
+        refresh_state_buttons(); // refresh state_buttons
+        check_buttons(frequency, actualOctave); // check if buttons are pressed and play music
+        Thread::wait(100); // Thread wait 100 for scheduling
     }
 }
 
+/**
+    Function that will display notes and gammes on LCD screen and
+    PC device.
+    Only called when a change on BufferOutput occurs.
+**/
+void    refresh_display_notes(char *old_buffer)
+{
+    lcd.cls(); // clear LCD screen
+    lockOctave.lock(); // lock lockOctave Mutex for reading octave variable 
+    if (strcmp(bufferOutput, "")) // if buffer not empty
+    {
+        lcd.printf("%s- O[%d]", bufferOutput, octave); // display notes and actual octave on LCD screen
+        pc.printf("Play notes: %s with octave %d\n", bufferOutput, octave); // display notes and actual octave on PC device
+    }
+    else 
+    {
+        lcd.printf("Octave = %d", octave); // only display octave on screen if no button pressed
+        pc.printf("Release notes\n");  // display release message on PC device
+    }
+    lockOctave.unlock(); // unlock lockOctave
+    strcpy(old_buffer, bufferOutput); // save value bufferOutput in old_buffer
+}
+
+/**
+    Function that will display the octave on screen
+    if a change in octave occurs.
+**/
+int    refresh_display_octave(int old_octave)
+{
+    lockOctave.lock(); // lock lockOctave for reading octave variable
+    if (old_octave != octave) // if change occurs
+    {
+        lcd.cls(); // clear screen
+        lcd.printf("Octave = %d", octave); // display new octave on LCD screen
+        pc.printf("[INFO] - Change octave %d to octave %d\n", old_octave, octave); // display new octave on PC device 
+        old_octave = octave; // save the new value to old_octave
+    }
+    lockOctave.unlock(); // Unlock lockOctave
+    return old_octave; // return old_octave
+}
+
+/**
+    Thread display function that output
+    notes and octaves on the LCD screen
+    and the PC device by Serial.
+**/ 
 void    run_display()
 {
-    char    old_buffer[30] = "";
-    int     old_gamme = 0;
+    char    old_buffer[30] = ""; // buffer of old value BufferOutput variable, init to empty string by default
+    int     old_octave = 0; // value for old octave variable, init to zero by default
     
-    lockBufferOutput.lock();
-    lockGamme.lock();
-    lcd.printf("Gamme = %d", gamme);
-    lockGamme.unlock();
-    lockBufferOutput.unlock();
-    while(true)
+    lockOctave.lock(); // Lock lockOctave Mutex for reading octave variable
+    lcd.printf("Octave = %d", octave); // Display default octave on screen until event occurs
+    lockOctave.unlock(); // Unlock lockOctave Mutex
+    while(true) // Infinite loop to run display
     {
-        lockBufferOutput.lock();
-        if (strcmp(old_buffer, bufferOutput))
-        {
-            lcd.cls();
-            lockGamme.lock();
-            if (strcmp(bufferOutput, ""))
-                lcd.printf("%s- g[%d]", bufferOutput, gamme);
-            else
-                lcd.printf("Gamme = %d", gamme);
-            lockGamme.unlock();
-            strcpy(old_buffer, bufferOutput);
-        }
-        else {
-            lockGamme.lock();
-            if (old_gamme != gamme)
-            {
-                lcd.cls();
-                lcd.printf("Gamme = %d", gamme);
-                old_gamme = gamme;
-            }
-            lockGamme.unlock();
-        }
-        lockBufferOutput.unlock();
-        Thread::wait(100);
+        lockBufferOutput.lock(); // Lock lockBufferOutput Mutex for reading BufferOutput
+        if (strcmp(old_buffer, bufferOutput)) // if bufferOutput has change
+            refresh_display_notes(old_buffer); // output notes 
+        else
+            old_octave = refresh_display_octave(old_octave); // else output gamme if change
+        lockBufferOutput.unlock(); // Unlock lockBufferOutput Mutex
+        Thread::wait(100); // Thread wait 100 for synchronization
     }
 }
-
-void     check_state_button_gamme()
+ 
+/**
+    Function that refresh the value of 
+    stateButtonOctave variable based on the
+    input data from Bus_In_Octave.
+**/
+void     check_state_button_octave()
 {
-    stateButtonGamme = Bus_In_Gamme & Bus_In_Gamme.mask();
+    stateButtonOctave = Bus_In_Octave & Bus_In_Octave.mask();
 }
 
-void    run_gamme()
+/**
+    Thread for Octave.
+    
+    Catch octave button state and increment
+    the octave value if button has been pressed.
+**/
+void    run_octave()
 {
-    while(true)
+    while(true) // Infinite loop for octave Thread
     {
-        check_state_button_gamme();
-        if (stateButtonGamme == 0x0)
+        check_state_button_octave(); // refresh state_button_octave
+        if (stateButtonOctave == 0x0) // if button is pressed
         {
-            lockGamme.lock();
-            gamme = (gamme == 3) ? 0 : gamme + 1;
-            lockGamme.unlock();
-            while (stateButtonGamme == 0x0)
-                check_state_button_gamme();
+            lockOctave.lock(); // lock lockOctave Mutex, enter in critical section
+            octave = (octave == 3) ? 0 : octave + 1; // increment octave or set to 0
+            lockOctave.unlock(); // unlock lockOctave Mutex, end of critical section
+            while (stateButtonOctave == 0x0) // continue check button state until it is unpressed
+                check_state_button_octave(); // refresh state_button_octave
         }
-        Thread::wait(100);
+        Thread::wait(100); // Thread wait 100 for scheduling
     }
 }
-
+ 
+/**
+    Main function Piano Project.
+    
+    Launch 3 threads for playing music, display notes
+    and octaves.
+**/
 int main()
 {
-    Thread  music_thread;
-    Thread  display_thread;
-    Thread  gamme_thread;
+    Thread  music_thread; // Thread for playing music
+    Thread  display_thread; // Thread for display notes and octave
+    Thread  octave_thread; // Thread for octave
     
-    lcd.printf("CS435 : Piano Project\n");
+    lcd.printf("CS435\nPiano Project"); // Print welcome string on LCD screen
     wait(3);
-    lcd.cls();
+    lcd.cls(); // Clear the screen
  
-    music_thread.start(run_music);
-    display_thread.start(run_display);
-    gamme_thread.start(run_gamme);
-    while(1);
+    music_thread.start(run_music); // Start music thread
+    display_thread.start(run_display); // Start display thread
+    octave_thread.start(run_octave); // Start octave thread
+    
+    while(1); // Infinite loop for main thread
 }
\ No newline at end of file