This is a simple sound library for mbed. This sound library uses a Ticker to simulate a 50% duty cycle pwm signal on any pin. The frequency of this signal can be varied to allow sound to be created by any piezoelectric device that is connected to that pin.
Dependents: SuperMbedBall Tono
About
This library allows for a buzzer (or piezoelectric device) to output sound based on any inputted frequency. The library provides predefined note frequencies which make song writing convenient. These definitions can be found here. Some pins may not be able to drive output such as the AnalogIn pins on the LPC11U24 model. Only pin 21 seemed to work well so far on this model.
Hardware
One wire from a buzzer is connected to any pin on the mbed and the other wire is connected directly to ground. To reduce the volume of the buzzer, an optional resistor can be connected in series as shown.
Circuit diagram constructed using CircuitLab.
Usage
A music object is constructed in the following way:
Constructor
#include "Music.h" music ms(p21);
This code snipped attaches a frequency modulating Ticker to the specified pin.
This frequency can be modified by setting:
Frequency
ms.freq(240);
To allow more complex behavior, a parsing function is included that can take in strings of formatted input and turn them into songs. This input must be formatted as specified below:
- A capital letter must be present to specify the note, or R to specify a rest (Only letters A-G, and R are valid)
- An octave must be specified which is any integer from 0 to 8 inclusive
- An optional sharp sign ( # ) can be added to augment the note a half step
- A colon ( : ) must separate the octave and note from the duration
- The duration must be an integer greater than 0, and less than or equal to 64
- To separate notes, a semicolon ( ; ) must be used
Furthermore, the length of the string must be specified in order for the entire string to be parsed and a tempo must be provided (beats per minute). An example of this is shown below:
Play a Song
/* This is a test song */ char s1[] = "E4:8; E4:8; R:8; E4:8; R:8; C4:8; E4:4; G4:4; R:4; G3:4; R:4;"; int len = 61; /* Set up music pin on pin 21 */ music m1(p21); double tempo = 180; m1.play(s1,tempo,len);
This code plays the familiar 7-note opening to the Super Mario Brothers theme song. The possibilities for music creation are limited only by the hard memory limits of the mbed.
Revision 2:c33ed3d85f97, committed 2013-04-30
- Comitter:
- mdu7078
- Date:
- Tue Apr 30 03:49:24 2013 +0000
- Parent:
- 1:51cf7b1a96bd
- Commit message:
- All functions finalized and working!
Changed in this revision
Music.cpp | Show annotated file Show diff for this revision Revisions of this file |
Music.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 51cf7b1a96bd -r c33ed3d85f97 Music.cpp --- a/Music.cpp Mon Apr 29 19:03:21 2013 +0000 +++ b/Music.cpp Tue Apr 30 03:49:24 2013 +0000 @@ -6,25 +6,75 @@ #include "mbed.h" #include "Music.h" +#include "Notes.h" +/* + * This is the minimal constructor that creates a music object + * with 0 initial output frequency on a specified pin + * + * M0 - The pin to output on + */ +music::music(PinName M0) : _M0(M0){ + _flipper.attach(this,&music::flip,0); +} + +/* + * This constructs a music object which has an initial frequency + * equal to a given one + * + * M0 - The pin to output on + * freq - The initial frequency + */ music::music(PinName M0, double freq) : _M0(M0), _freq(freq) { _flipper.attach(this,&music::flip,1/(2*_freq)); } +/* + * This changes the current output frequency to a given one + * + * freq - The given frequency + */ void music::freq(double freq){ _freq=freq; _flipper.detach(); _flipper.attach(this,&music::flip,1/(2*_freq)); } +/* + * This is an internal flipper that allows for a fixed + * frequency oscillation. + */ void music::flip(){ _M0 = !_M0; } /* + * This initializes a given m_song to a given size + * + * *m - The given m_song + * num - The given size + */ +void music::init_song(m_song *m, int num){ + m->len = 0; + m->note = new music_note[((int)(num/5))]; +} + +/* + * This deallocates an m_song by deallocating the notes + * that it contains and setting the length to 0 + * + * *m - The given m_song + */ +void music::dal_song(m_song *m){ + m->len = 0; + delete [] m->note; +// free(m->note); +} + +/* * This parses a given character array into an m_song * Format: - * <note_letter><[sharp]><octave>:<length>, . . . + * <note_letter><[sharp]><octave>:<length>; . . .; * Example (Super Mario Bros.): * E3:8; E3:8; R:8; E3:8; R:8; C3:8; E3:4; G3:4; R:4; G2:4; R:4; * @@ -35,12 +85,16 @@ * num - The number of characters in the array */ m_song music::parse(char* song, int num){ + //Create a new song and initialize it m_song out; + init_song(&out,num); + char curnote = ' '; // Note int octave = 0; // Octave - char dur[] = "00"; // Duration + int dur[] = {0,0}; // Duration int flag = 0; // Complete flag int sharp = 0; // Sharp flag + int inl = 1; // Index of dur[] for (int i=0; i<num; i++){ switch(song[i]){ @@ -83,101 +137,207 @@ case '0': if (flag == 0){ //Octave set - + octave = 0; } else { //Duration set - + if (inl == 0){ + //Shift + dur[0] = dur[1]; + + //Set + dur[1] = 0; + } + else{ + //Set + dur[1] = 0; + inl=0; + } } break; case '1': if (flag == 0){ //Octave set - + octave = 1; } else { //Duration set - + if (inl == 0){ + //Shift + dur[0] = dur[1]; + + //Set + dur[1] = 1; + } + else{ + //Set + dur[1] = 1; + inl=0; + } } break; case '2': if (flag == 0){ //Octave set - + octave = 2; } else { //Duration set - + if (inl == 0){ + //Shift + dur[0] = dur[1]; + + //Set + dur[1] = 2; + } + else{ + //Set + dur[1] = 2; + inl=0; + } } break; case '3': if (flag == 0){ //Octave set - + octave = 3; } else { //Duration set - + if (inl == 0){ + //Shift + dur[0] = dur[1]; + + //Set + dur[1] = 3; + } + else{ + //Set + dur[1] = 3; + inl=0; + } } break; case '4': if (flag == 0){ //Octave set - + octave = 4; } else { //Duration set - + if (inl == 0){ + //Shift + dur[0] = dur[1]; + + //Set + dur[1] = 4; + } + else{ + //Set + dur[1] = 4; + inl=0; + } } break; case '5': if (flag == 0){ //Octave set - + octave = 5; } else { //Duration set - + if (inl == 0){ + //Shift + dur[0] = dur[1]; + + //Set + dur[1] = 5; + } + else{ + //Set + dur[1] = 5; + inl=0; + } } break; case '6': if (flag == 0){ //Octave set - + octave = 6; } else { //Duration set - + if (inl == 0){ + //Shift + dur[0] = dur[1]; + + //Set + dur[1] = 6; + } + else{ + //Set + dur[1] = 6; + inl=0; + } } break; case '7': if (flag == 0){ //Octave set - + octave = 7; } else { //Duration set - + if (inl == 0){ + //Shift + dur[0] = dur[1]; + + //Set + dur[1] = 7; + } + else{ + //Set + dur[1] = 7; + inl=0; + } } break; case '8': if (flag == 0){ //Octave set - + octave = 8; } else { //Duration set - + if (inl == 0){ + //Shift + dur[0] = dur[1]; + + //Set + dur[1] = 8; + } + else{ + //Set + dur[1] = 8; + inl=0; + } } break; case '9': - if (flag == 0){ - //Octave set - - } - else { + if (flag == 1){ //Duration set - + if (inl == 0){ + //Shift + dur[0] = dur[1]; + + //Set + dur[1] = 9; + } + else{ + //Set + dur[1] = 9; + inl=0; + } } break; case ':': @@ -185,15 +345,45 @@ break; case ';': if (flag == 1){ + //Calculate duration + int t1 = (dur[0])*10; + int t2 = dur[1]; + int tst = t1+t2; + if (tst>0 && tst<=64 && curnote != ' '){ + notes n; + + //DEAD CODE: Will work when realloc is fixed + //Create a temporary checker + //music_note* tmpn; //= new music_note[out.len+1]; + + //Reallocate space for note + //tmpn = (music_note*) realloc(out.note, (out.len+1)*sizeof(music_note)); +// if (tmpn == NULL){ +// //Failed to allocate +// free(out.note); +// exit(1); +// } +// out.note = tmpn; + + //Set frequency using lookup function + out.note[out.len].freq = n.get_freq(curnote, sharp, octave); + + //Set duration + out.note[out.len].duration = tst; + + //Increment current song size + out.len=out.len+1; + } //Reset values flag = 0; sharp = 0; - dur[0] = '0'; - dur[1] = '0'; + dur[0] = 0; + dur[1] = 0; curnote = ' '; octave = 0; + inl = 1; } else{ //Default to quarter note: @@ -219,13 +409,17 @@ for (int i=0; i<msng.len; i++){ // Output the frequency: freq(msng.note[i].freq); + // Calculate delay: - dl = 60/(tempo/(msng.note[i].duration)); + dl = (60*4)/(tempo*(msng.note[i].duration)); + // Wait for the note to be complete wait(dl); } + //Stop playing + freq(0); + //Deallocate song: - msng.len = 0; - free(msng.note); + dal_song(&msng); } \ No newline at end of file
diff -r 51cf7b1a96bd -r c33ed3d85f97 Music.h --- a/Music.h Mon Apr 29 19:03:21 2013 +0000 +++ b/Music.h Tue Apr 30 03:49:24 2013 +0000 @@ -25,6 +25,7 @@ class music { public: + music(PinName M0); //basic music constructor music(PinName M0, double freq); //music constructor void freq(double freq); //Frequency setter void play(char* song, double tempo, int num); @@ -34,6 +35,8 @@ /* Private functions */ void flip(); //Flips the output of a pin at a fixed frequency m_song parse(char* song, int num_notes); //Parses a character array into notes + void init_song(m_song *m, int num); //Initialize an m_song + void dal_song(m_song *m); //Deallocate an m_song /* Private variables */ Ticker _flipper;