![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
piano 4 octaves, 8 notes, 3 threads, 2 outputs, no bug, clean code, comments, remove old .h
Fork of Nucleo_piano_CS435 by
Diff: main.cpp
- 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