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

Committer:
aknin001
Date:
Thu Jul 05 01:08:36 2018 +0000
Revision:
9:9a36b66869fa
Parent:
8:781b03221397
final project finish tested and commented

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bcostm 0:5701b41769fd 1 #include "mbed.h"
Aliened 3:ca0d5d72f842 2 #include "TextLCD.h"
aknin001 5:824785b64822 3 #include <string.h>
aknin001 5:824785b64822 4 #include <math.h>
aknin001 7:d2fe1a5e79ed 5
Aliened 3:ca0d5d72f842 6 // Define screen
Aliened 3:ca0d5d72f842 7 TextLCD lcd(PA_8, PA_9, PC_7, PB_6, PA_7, PA_6, PA_5); // RS, RW, E, D4-D7
Aliened 3:ca0d5d72f842 8
aknin001 5:824785b64822 9 // Define Bus In for Buttons (Do, Re, Mi, Fa, Sol, La, Si, Do)
aknin001 5:824785b64822 10 BusIn Bus_In(PA_0, PA_1, PA_4, PB_0, PA_10, PB_3, PB_5, PB_4);
aknin001 9:9a36b66869fa 11
Aliened 3:ca0d5d72f842 12 // Define the PWM speaker
Aliened 3:ca0d5d72f842 13 PwmOut speaker(PB_10);
aknin001 9:9a36b66869fa 14
aknin001 9:9a36b66869fa 15 // Define Bus In for Octave Button
aknin001 9:9a36b66869fa 16 BusIn Bus_In_Octave(PB_9);
aknin001 9:9a36b66869fa 17
aknin001 9:9a36b66869fa 18 // Define Serial
aknin001 9:9a36b66869fa 19 Serial pc(PA_2, PA_3);
aknin001 7:d2fe1a5e79ed 20
Aliened 3:ca0d5d72f842 21 //Define variables for sound
aknin001 9:9a36b66869fa 22 struct NoteReference { // struct note reference
aknin001 9:9a36b66869fa 23 char name[4]; // note name
aknin001 9:9a36b66869fa 24 int mask; // note mask for pressed of not
aknin001 9:9a36b66869fa 25 double frequency; // note base frequency (octave 0)
aknin001 9:9a36b66869fa 26 double add[4]; // add value for octave balancing (from octave 0 to 3)
aknin001 5:824785b64822 27 };
aknin001 9:9a36b66869fa 28
aknin001 9:9a36b66869fa 29 // NoteReference tab for 8 notes (1 octave)
aknin001 8:781b03221397 30 NoteReference noteReference[8] = { {"Do", 0x1, 262.0, {0.0, -1.0, -1.5, -3.0}},
aknin001 8:781b03221397 31 {"Re", 0x2, 294.0, {0.0, -1.0, -1.0, -3.0 }},
aknin001 8:781b03221397 32 {"Mi", 0x4, 330.0, {0.0, -1.0, -1.5, -3.0}},
aknin001 8:781b03221397 33 {"Fa", 0x8, 349.0, {0.0, 0.5, -1.0, 2.0}},
aknin001 8:781b03221397 34 {"Sol", 0x10, 392.0, {0.0, 0.0, 0.0, 0.0}},
aknin001 8:781b03221397 35 {"La", 0x20, 440.0, {0.0, 0.0, 0.0, 0.0}},
aknin001 8:781b03221397 36 {"Si", 0x40, 494.0, {0.0, 0.0, -1.0, -1.0}},
aknin001 8:781b03221397 37 {"Do", 0x80, 523.0, {0.0, 0.0, 0.0, 0.0}}
aknin001 8:781b03221397 38 };
aknin001 9:9a36b66869fa 39 volatile int stateButtons = 0; // State of notes buttons
aknin001 9:9a36b66869fa 40 volatile int stateButtonOctave = 0; // State of octave button
aknin001 9:9a36b66869fa 41 volatile int octave = 0; // octave value
aknin001 9:9a36b66869fa 42
aknin001 7:d2fe1a5e79ed 43 //Define variable for display
aknin001 9:9a36b66869fa 44 char bufferOutput[30] = ""; // buffer for notes and octave
aknin001 9:9a36b66869fa 45
aknin001 7:d2fe1a5e79ed 46 //Define variables for synchronization
aknin001 9:9a36b66869fa 47 Mutex lockBufferOutput; // Mutex for BufferOutput variable
aknin001 9:9a36b66869fa 48 Mutex lockOctave; // Mutex for octave variable
aknin001 9:9a36b66869fa 49
aknin001 9:9a36b66869fa 50 /**
aknin001 9:9a36b66869fa 51 Function that refresh the value of
aknin001 9:9a36b66869fa 52 stateButtons depending on data input from
aknin001 9:9a36b66869fa 53 Bus_In.
aknin001 9:9a36b66869fa 54 **/
aknin001 9:9a36b66869fa 55 void refresh_state_buttons()
Aliened 3:ca0d5d72f842 56 {
aknin001 8:781b03221397 57 stateButtons = Bus_In & Bus_In.mask(); // read the bus and mask out bits not being used
Aliened 3:ca0d5d72f842 58 }
aknin001 9:9a36b66869fa 59
aknin001 9:9a36b66869fa 60 /**
aknin001 9:9a36b66869fa 61 Function that output notes on the buzzer.
aknin001 9:9a36b66869fa 62 **/
aknin001 5:824785b64822 63 void play_music(int notes, double frequency)
Aliened 3:ca0d5d72f842 64 {
aknin001 9:9a36b66869fa 65 speaker.period(1.0 / frequency); // set the period to 1 / frequency of notes
aknin001 9:9a36b66869fa 66 while (stateButtons == notes) { // while button is pressed
aknin001 9:9a36b66869fa 67 refresh_state_buttons(); // refresh stateButtons
Aliened 3:ca0d5d72f842 68 }
Aliened 3:ca0d5d72f842 69 }
aknin001 8:781b03221397 70
aknin001 9:9a36b66869fa 71 /**
aknin001 9:9a36b66869fa 72 Function that generate a frequency depending on pressed notes
aknin001 9:9a36b66869fa 73 and actual octave.
aknin001 9:9a36b66869fa 74 **/
aknin001 9:9a36b66869fa 75 double generate_frequency(double frequency, int actualOctave)
aknin001 8:781b03221397 76 {
aknin001 9:9a36b66869fa 77 frequency = 0.0; // init frequency to 0
aknin001 9:9a36b66869fa 78 lockBufferOutput.lock(); // lock lockBufferOutput Mutex for writing new notes on bufferOutput variable
aknin001 9:9a36b66869fa 79 strcpy(bufferOutput, ""); // init bufferOuput to empty string
aknin001 9:9a36b66869fa 80 for (int i = 0; i < 8; i++) { // iterate on all element of noteReference tab
aknin001 9:9a36b66869fa 81 if (!(stateButtons & noteReference[i].mask)) // if note is pressed
aknin001 8:781b03221397 82 {
aknin001 9:9a36b66869fa 83 // add note frequency to frequency (base frequency * 2^octave + add)
aknin001 9:9a36b66869fa 84 frequency += noteReference[i].frequency * pow(2.0, (double)actualOctave) + noteReference[i].add[actualOctave];
aknin001 9:9a36b66869fa 85 strcat(bufferOutput, noteReference[i].name); // concatenate bufferOutput and new note name
aknin001 9:9a36b66869fa 86 strcat(bufferOutput, " "); // concatenate with space separator
aknin001 8:781b03221397 87 }
aknin001 8:781b03221397 88 }
aknin001 9:9a36b66869fa 89 lockBufferOutput.unlock(); // unlock bufferOutput at the end of the loop, end of writing
aknin001 9:9a36b66869fa 90 return (frequency); // return the frequency to play on buzzer
aknin001 8:781b03221397 91 }
aknin001 9:9a36b66869fa 92
aknin001 9:9a36b66869fa 93 /**
aknin001 9:9a36b66869fa 94 Check if buttons if pressed and play notes
aknin001 9:9a36b66869fa 95 otherwise set duty cycle to 0.
aknin001 9:9a36b66869fa 96 **/
aknin001 9:9a36b66869fa 97 void check_buttons(double frequency, int actualOctave)
Aliened 3:ca0d5d72f842 98 {
aknin001 9:9a36b66869fa 99 if (stateButtons == 0xFF) // if nothing pressed
aknin001 5:824785b64822 100 {
aknin001 9:9a36b66869fa 101 speaker = 0; // duty cycle equal to 0
aknin001 9:9a36b66869fa 102 lockBufferOutput.lock(); // lock BufferOutput Mutex for writing on bufferOutput variable
aknin001 9:9a36b66869fa 103 strcpy(bufferOutput, ""); // set bufferOutput to empty string
aknin001 9:9a36b66869fa 104 lockBufferOutput.unlock(); // unlock BufferOutput Mutex
aknin001 6:58bab17100a2 105 }
aknin001 9:9a36b66869fa 106 else { // if buttons pressed
aknin001 9:9a36b66869fa 107 lockOctave.lock(); // lock lockOctave Mutex for reading octave value
aknin001 9:9a36b66869fa 108 actualOctave = octave; // read octave value
aknin001 9:9a36b66869fa 109 lockOctave.unlock(); // unlock lockOctave Mutex
aknin001 9:9a36b66869fa 110 frequency = generate_frequency(frequency, actualOctave); // generate frequency depending on notes and octave
aknin001 9:9a36b66869fa 111 speaker = 0.5; // set duty cycle to 0.5 for volume
aknin001 9:9a36b66869fa 112 play_music(stateButtons, frequency); // play notes on buzzer
Aliened 3:ca0d5d72f842 113 }
Aliened 3:ca0d5d72f842 114 }
Aliened 3:ca0d5d72f842 115
aknin001 9:9a36b66869fa 116 /**
aknin001 9:9a36b66869fa 117 Thread for playing notes.
aknin001 9:9a36b66869fa 118 check states of buttons notes and play music.
aknin001 9:9a36b66869fa 119 **/
aknin001 7:d2fe1a5e79ed 120 void run_music()
aknin001 7:d2fe1a5e79ed 121 {
aknin001 9:9a36b66869fa 122 double frequency = 0.0; // double for total frequency
aknin001 9:9a36b66869fa 123 int actualOctave = 0; // int for actual octave
aknin001 7:d2fe1a5e79ed 124
aknin001 9:9a36b66869fa 125 while (true) // Infinte loop to catch buttons notes events
aknin001 7:d2fe1a5e79ed 126 {
aknin001 9:9a36b66869fa 127 refresh_state_buttons(); // refresh state_buttons
aknin001 9:9a36b66869fa 128 check_buttons(frequency, actualOctave); // check if buttons are pressed and play music
aknin001 9:9a36b66869fa 129 Thread::wait(100); // Thread wait 100 for scheduling
aknin001 7:d2fe1a5e79ed 130 }
aknin001 7:d2fe1a5e79ed 131 }
Aliened 3:ca0d5d72f842 132
aknin001 9:9a36b66869fa 133 /**
aknin001 9:9a36b66869fa 134 Function that will display notes and gammes on LCD screen and
aknin001 9:9a36b66869fa 135 PC device.
aknin001 9:9a36b66869fa 136 Only called when a change on BufferOutput occurs.
aknin001 9:9a36b66869fa 137 **/
aknin001 9:9a36b66869fa 138 void refresh_display_notes(char *old_buffer)
aknin001 9:9a36b66869fa 139 {
aknin001 9:9a36b66869fa 140 lcd.cls(); // clear LCD screen
aknin001 9:9a36b66869fa 141 lockOctave.lock(); // lock lockOctave Mutex for reading octave variable
aknin001 9:9a36b66869fa 142 if (strcmp(bufferOutput, "")) // if buffer not empty
aknin001 9:9a36b66869fa 143 {
aknin001 9:9a36b66869fa 144 lcd.printf("%s- O[%d]", bufferOutput, octave); // display notes and actual octave on LCD screen
aknin001 9:9a36b66869fa 145 pc.printf("Play notes: %s with octave %d\n", bufferOutput, octave); // display notes and actual octave on PC device
aknin001 9:9a36b66869fa 146 }
aknin001 9:9a36b66869fa 147 else
aknin001 9:9a36b66869fa 148 {
aknin001 9:9a36b66869fa 149 lcd.printf("Octave = %d", octave); // only display octave on screen if no button pressed
aknin001 9:9a36b66869fa 150 pc.printf("Release notes\n"); // display release message on PC device
aknin001 9:9a36b66869fa 151 }
aknin001 9:9a36b66869fa 152 lockOctave.unlock(); // unlock lockOctave
aknin001 9:9a36b66869fa 153 strcpy(old_buffer, bufferOutput); // save value bufferOutput in old_buffer
aknin001 9:9a36b66869fa 154 }
aknin001 9:9a36b66869fa 155
aknin001 9:9a36b66869fa 156 /**
aknin001 9:9a36b66869fa 157 Function that will display the octave on screen
aknin001 9:9a36b66869fa 158 if a change in octave occurs.
aknin001 9:9a36b66869fa 159 **/
aknin001 9:9a36b66869fa 160 int refresh_display_octave(int old_octave)
aknin001 9:9a36b66869fa 161 {
aknin001 9:9a36b66869fa 162 lockOctave.lock(); // lock lockOctave for reading octave variable
aknin001 9:9a36b66869fa 163 if (old_octave != octave) // if change occurs
aknin001 9:9a36b66869fa 164 {
aknin001 9:9a36b66869fa 165 lcd.cls(); // clear screen
aknin001 9:9a36b66869fa 166 lcd.printf("Octave = %d", octave); // display new octave on LCD screen
aknin001 9:9a36b66869fa 167 pc.printf("[INFO] - Change octave %d to octave %d\n", old_octave, octave); // display new octave on PC device
aknin001 9:9a36b66869fa 168 old_octave = octave; // save the new value to old_octave
aknin001 9:9a36b66869fa 169 }
aknin001 9:9a36b66869fa 170 lockOctave.unlock(); // Unlock lockOctave
aknin001 9:9a36b66869fa 171 return old_octave; // return old_octave
aknin001 9:9a36b66869fa 172 }
aknin001 9:9a36b66869fa 173
aknin001 9:9a36b66869fa 174 /**
aknin001 9:9a36b66869fa 175 Thread display function that output
aknin001 9:9a36b66869fa 176 notes and octaves on the LCD screen
aknin001 9:9a36b66869fa 177 and the PC device by Serial.
aknin001 9:9a36b66869fa 178 **/
aknin001 7:d2fe1a5e79ed 179 void run_display()
aknin001 7:d2fe1a5e79ed 180 {
aknin001 9:9a36b66869fa 181 char old_buffer[30] = ""; // buffer of old value BufferOutput variable, init to empty string by default
aknin001 9:9a36b66869fa 182 int old_octave = 0; // value for old octave variable, init to zero by default
aknin001 7:d2fe1a5e79ed 183
aknin001 9:9a36b66869fa 184 lockOctave.lock(); // Lock lockOctave Mutex for reading octave variable
aknin001 9:9a36b66869fa 185 lcd.printf("Octave = %d", octave); // Display default octave on screen until event occurs
aknin001 9:9a36b66869fa 186 lockOctave.unlock(); // Unlock lockOctave Mutex
aknin001 9:9a36b66869fa 187 while(true) // Infinite loop to run display
aknin001 7:d2fe1a5e79ed 188 {
aknin001 9:9a36b66869fa 189 lockBufferOutput.lock(); // Lock lockBufferOutput Mutex for reading BufferOutput
aknin001 9:9a36b66869fa 190 if (strcmp(old_buffer, bufferOutput)) // if bufferOutput has change
aknin001 9:9a36b66869fa 191 refresh_display_notes(old_buffer); // output notes
aknin001 9:9a36b66869fa 192 else
aknin001 9:9a36b66869fa 193 old_octave = refresh_display_octave(old_octave); // else output gamme if change
aknin001 9:9a36b66869fa 194 lockBufferOutput.unlock(); // Unlock lockBufferOutput Mutex
aknin001 9:9a36b66869fa 195 Thread::wait(100); // Thread wait 100 for synchronization
aknin001 7:d2fe1a5e79ed 196 }
aknin001 7:d2fe1a5e79ed 197 }
aknin001 9:9a36b66869fa 198
aknin001 9:9a36b66869fa 199 /**
aknin001 9:9a36b66869fa 200 Function that refresh the value of
aknin001 9:9a36b66869fa 201 stateButtonOctave variable based on the
aknin001 9:9a36b66869fa 202 input data from Bus_In_Octave.
aknin001 9:9a36b66869fa 203 **/
aknin001 9:9a36b66869fa 204 void check_state_button_octave()
aknin001 7:d2fe1a5e79ed 205 {
aknin001 9:9a36b66869fa 206 stateButtonOctave = Bus_In_Octave & Bus_In_Octave.mask();
aknin001 7:d2fe1a5e79ed 207 }
aknin001 7:d2fe1a5e79ed 208
aknin001 9:9a36b66869fa 209 /**
aknin001 9:9a36b66869fa 210 Thread for Octave.
aknin001 9:9a36b66869fa 211
aknin001 9:9a36b66869fa 212 Catch octave button state and increment
aknin001 9:9a36b66869fa 213 the octave value if button has been pressed.
aknin001 9:9a36b66869fa 214 **/
aknin001 9:9a36b66869fa 215 void run_octave()
aknin001 7:d2fe1a5e79ed 216 {
aknin001 9:9a36b66869fa 217 while(true) // Infinite loop for octave Thread
aknin001 7:d2fe1a5e79ed 218 {
aknin001 9:9a36b66869fa 219 check_state_button_octave(); // refresh state_button_octave
aknin001 9:9a36b66869fa 220 if (stateButtonOctave == 0x0) // if button is pressed
aknin001 7:d2fe1a5e79ed 221 {
aknin001 9:9a36b66869fa 222 lockOctave.lock(); // lock lockOctave Mutex, enter in critical section
aknin001 9:9a36b66869fa 223 octave = (octave == 3) ? 0 : octave + 1; // increment octave or set to 0
aknin001 9:9a36b66869fa 224 lockOctave.unlock(); // unlock lockOctave Mutex, end of critical section
aknin001 9:9a36b66869fa 225 while (stateButtonOctave == 0x0) // continue check button state until it is unpressed
aknin001 9:9a36b66869fa 226 check_state_button_octave(); // refresh state_button_octave
aknin001 7:d2fe1a5e79ed 227 }
aknin001 9:9a36b66869fa 228 Thread::wait(100); // Thread wait 100 for scheduling
aknin001 7:d2fe1a5e79ed 229 }
aknin001 7:d2fe1a5e79ed 230 }
aknin001 9:9a36b66869fa 231
aknin001 9:9a36b66869fa 232 /**
aknin001 9:9a36b66869fa 233 Main function Piano Project.
aknin001 9:9a36b66869fa 234
aknin001 9:9a36b66869fa 235 Launch 3 threads for playing music, display notes
aknin001 9:9a36b66869fa 236 and octaves.
aknin001 9:9a36b66869fa 237 **/
bcostm 0:5701b41769fd 238 int main()
bcostm 0:5701b41769fd 239 {
aknin001 9:9a36b66869fa 240 Thread music_thread; // Thread for playing music
aknin001 9:9a36b66869fa 241 Thread display_thread; // Thread for display notes and octave
aknin001 9:9a36b66869fa 242 Thread octave_thread; // Thread for octave
aknin001 7:d2fe1a5e79ed 243
aknin001 9:9a36b66869fa 244 lcd.printf("CS435\nPiano Project"); // Print welcome string on LCD screen
aknin001 7:d2fe1a5e79ed 245 wait(3);
aknin001 9:9a36b66869fa 246 lcd.cls(); // Clear the screen
aknin001 7:d2fe1a5e79ed 247
aknin001 9:9a36b66869fa 248 music_thread.start(run_music); // Start music thread
aknin001 9:9a36b66869fa 249 display_thread.start(run_display); // Start display thread
aknin001 9:9a36b66869fa 250 octave_thread.start(run_octave); // Start octave thread
aknin001 9:9a36b66869fa 251
aknin001 9:9a36b66869fa 252 while(1); // Infinite loop for main thread
aknin001 7:d2fe1a5e79ed 253 }