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. /media/uploads/mdu7078/buzzer001.png

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.

Committer:
mdu7078
Date:
Mon Apr 29 19:03:21 2013 +0000
Revision:
1:51cf7b1a96bd
Parent:
0:07a4aa44fe9c
Child:
2:c33ed3d85f97
Refactoring finished.  Split Music.cpp -> Notes.cpp with note definitions and useful lookup function.   Parse function is still incomplete...

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mdu7078 0:07a4aa44fe9c 1 /* * * * * * * * * * * * * * * * * * * * * * * * * * *
mdu7078 0:07a4aa44fe9c 2 * This is a simple music library for the mbed. *
mdu7078 0:07a4aa44fe9c 3 * *
mdu7078 0:07a4aa44fe9c 4 * Created by: Michael Dushkoff (mad1841@rit.edu) *
mdu7078 0:07a4aa44fe9c 5 * * * * * * * * * * * * * * * * * * * * * * * * * * */
mdu7078 0:07a4aa44fe9c 6
mdu7078 0:07a4aa44fe9c 7 #include "mbed.h"
mdu7078 0:07a4aa44fe9c 8 #include "Music.h"
mdu7078 0:07a4aa44fe9c 9
mdu7078 1:51cf7b1a96bd 10 music::music(PinName M0, double freq) : _M0(M0), _freq(freq) {
mdu7078 0:07a4aa44fe9c 11 _flipper.attach(this,&music::flip,1/(2*_freq));
mdu7078 0:07a4aa44fe9c 12 }
mdu7078 0:07a4aa44fe9c 13
mdu7078 0:07a4aa44fe9c 14 void music::freq(double freq){
mdu7078 0:07a4aa44fe9c 15 _freq=freq;
mdu7078 0:07a4aa44fe9c 16 _flipper.detach();
mdu7078 0:07a4aa44fe9c 17 _flipper.attach(this,&music::flip,1/(2*_freq));
mdu7078 0:07a4aa44fe9c 18 }
mdu7078 0:07a4aa44fe9c 19
mdu7078 0:07a4aa44fe9c 20 void music::flip(){
mdu7078 0:07a4aa44fe9c 21 _M0 = !_M0;
mdu7078 0:07a4aa44fe9c 22 }
mdu7078 0:07a4aa44fe9c 23
mdu7078 0:07a4aa44fe9c 24 /*
mdu7078 0:07a4aa44fe9c 25 * This parses a given character array into an m_song
mdu7078 0:07a4aa44fe9c 26 * Format:
mdu7078 1:51cf7b1a96bd 27 * <note_letter><[sharp]><octave>:<length>, . . .
mdu7078 0:07a4aa44fe9c 28 * Example (Super Mario Bros.):
mdu7078 1:51cf7b1a96bd 29 * E3:8; E3:8; R:8; E3:8; R:8; C3:8; E3:4; G3:4; R:4; G2:4; R:4;
mdu7078 1:51cf7b1a96bd 30 *
mdu7078 1:51cf7b1a96bd 31 * Sharp notes are represented with the # symbol as shown below:
mdu7078 1:51cf7b1a96bd 32 * C#:4;
mdu7078 0:07a4aa44fe9c 33 *
mdu7078 0:07a4aa44fe9c 34 * song - The song character array
mdu7078 0:07a4aa44fe9c 35 * num - The number of characters in the array
mdu7078 0:07a4aa44fe9c 36 */
mdu7078 0:07a4aa44fe9c 37 m_song music::parse(char* song, int num){
mdu7078 0:07a4aa44fe9c 38 m_song out;
mdu7078 1:51cf7b1a96bd 39 char curnote = ' '; // Note
mdu7078 1:51cf7b1a96bd 40 int octave = 0; // Octave
mdu7078 1:51cf7b1a96bd 41 char dur[] = "00"; // Duration
mdu7078 1:51cf7b1a96bd 42 int flag = 0; // Complete flag
mdu7078 1:51cf7b1a96bd 43 int sharp = 0; // Sharp flag
mdu7078 0:07a4aa44fe9c 44
mdu7078 1:51cf7b1a96bd 45 for (int i=0; i<num; i++){
mdu7078 1:51cf7b1a96bd 46 switch(song[i]){
mdu7078 1:51cf7b1a96bd 47 case 'A':
mdu7078 1:51cf7b1a96bd 48 //A Note
mdu7078 1:51cf7b1a96bd 49 curnote = 'A';
mdu7078 1:51cf7b1a96bd 50 break;
mdu7078 1:51cf7b1a96bd 51 case 'B':
mdu7078 1:51cf7b1a96bd 52 //B Note
mdu7078 1:51cf7b1a96bd 53 curnote = 'B';
mdu7078 1:51cf7b1a96bd 54 break;
mdu7078 1:51cf7b1a96bd 55 case 'C':
mdu7078 1:51cf7b1a96bd 56 //C Note
mdu7078 1:51cf7b1a96bd 57 curnote = 'C';
mdu7078 1:51cf7b1a96bd 58 break;
mdu7078 1:51cf7b1a96bd 59 case 'D':
mdu7078 1:51cf7b1a96bd 60 //D Note
mdu7078 1:51cf7b1a96bd 61 curnote = 'D';
mdu7078 1:51cf7b1a96bd 62 break;
mdu7078 1:51cf7b1a96bd 63 case 'E':
mdu7078 1:51cf7b1a96bd 64 //E Note
mdu7078 1:51cf7b1a96bd 65 curnote = 'E';
mdu7078 1:51cf7b1a96bd 66 break;
mdu7078 1:51cf7b1a96bd 67 case 'F':
mdu7078 1:51cf7b1a96bd 68 //F Note
mdu7078 1:51cf7b1a96bd 69 curnote = 'F';
mdu7078 1:51cf7b1a96bd 70 break;
mdu7078 1:51cf7b1a96bd 71 case 'G':
mdu7078 1:51cf7b1a96bd 72 //G Note
mdu7078 1:51cf7b1a96bd 73 curnote = 'G';
mdu7078 1:51cf7b1a96bd 74 break;
mdu7078 1:51cf7b1a96bd 75 case 'R':
mdu7078 1:51cf7b1a96bd 76 //Rest
mdu7078 1:51cf7b1a96bd 77 curnote = 'R';
mdu7078 1:51cf7b1a96bd 78 break;
mdu7078 1:51cf7b1a96bd 79 case '#':
mdu7078 1:51cf7b1a96bd 80 //Sharp set
mdu7078 1:51cf7b1a96bd 81 sharp = 1;
mdu7078 1:51cf7b1a96bd 82 break;
mdu7078 1:51cf7b1a96bd 83 case '0':
mdu7078 1:51cf7b1a96bd 84 if (flag == 0){
mdu7078 1:51cf7b1a96bd 85 //Octave set
mdu7078 1:51cf7b1a96bd 86
mdu7078 1:51cf7b1a96bd 87 }
mdu7078 1:51cf7b1a96bd 88 else {
mdu7078 1:51cf7b1a96bd 89 //Duration set
mdu7078 1:51cf7b1a96bd 90
mdu7078 1:51cf7b1a96bd 91 }
mdu7078 1:51cf7b1a96bd 92 break;
mdu7078 1:51cf7b1a96bd 93 case '1':
mdu7078 1:51cf7b1a96bd 94 if (flag == 0){
mdu7078 1:51cf7b1a96bd 95 //Octave set
mdu7078 1:51cf7b1a96bd 96
mdu7078 1:51cf7b1a96bd 97 }
mdu7078 1:51cf7b1a96bd 98 else {
mdu7078 1:51cf7b1a96bd 99 //Duration set
mdu7078 1:51cf7b1a96bd 100
mdu7078 1:51cf7b1a96bd 101 }
mdu7078 1:51cf7b1a96bd 102 break;
mdu7078 1:51cf7b1a96bd 103 case '2':
mdu7078 1:51cf7b1a96bd 104 if (flag == 0){
mdu7078 1:51cf7b1a96bd 105 //Octave set
mdu7078 1:51cf7b1a96bd 106
mdu7078 1:51cf7b1a96bd 107 }
mdu7078 1:51cf7b1a96bd 108 else {
mdu7078 1:51cf7b1a96bd 109 //Duration set
mdu7078 1:51cf7b1a96bd 110
mdu7078 1:51cf7b1a96bd 111 }
mdu7078 1:51cf7b1a96bd 112 break;
mdu7078 1:51cf7b1a96bd 113 case '3':
mdu7078 1:51cf7b1a96bd 114 if (flag == 0){
mdu7078 1:51cf7b1a96bd 115 //Octave set
mdu7078 1:51cf7b1a96bd 116
mdu7078 1:51cf7b1a96bd 117 }
mdu7078 1:51cf7b1a96bd 118 else {
mdu7078 1:51cf7b1a96bd 119 //Duration set
mdu7078 1:51cf7b1a96bd 120
mdu7078 1:51cf7b1a96bd 121 }
mdu7078 1:51cf7b1a96bd 122 break;
mdu7078 1:51cf7b1a96bd 123 case '4':
mdu7078 1:51cf7b1a96bd 124 if (flag == 0){
mdu7078 1:51cf7b1a96bd 125 //Octave set
mdu7078 1:51cf7b1a96bd 126
mdu7078 1:51cf7b1a96bd 127 }
mdu7078 1:51cf7b1a96bd 128 else {
mdu7078 1:51cf7b1a96bd 129 //Duration set
mdu7078 1:51cf7b1a96bd 130
mdu7078 1:51cf7b1a96bd 131 }
mdu7078 1:51cf7b1a96bd 132 break;
mdu7078 1:51cf7b1a96bd 133 case '5':
mdu7078 1:51cf7b1a96bd 134 if (flag == 0){
mdu7078 1:51cf7b1a96bd 135 //Octave set
mdu7078 1:51cf7b1a96bd 136
mdu7078 1:51cf7b1a96bd 137 }
mdu7078 1:51cf7b1a96bd 138 else {
mdu7078 1:51cf7b1a96bd 139 //Duration set
mdu7078 1:51cf7b1a96bd 140
mdu7078 1:51cf7b1a96bd 141 }
mdu7078 1:51cf7b1a96bd 142 break;
mdu7078 1:51cf7b1a96bd 143 case '6':
mdu7078 1:51cf7b1a96bd 144 if (flag == 0){
mdu7078 1:51cf7b1a96bd 145 //Octave set
mdu7078 1:51cf7b1a96bd 146
mdu7078 1:51cf7b1a96bd 147 }
mdu7078 1:51cf7b1a96bd 148 else {
mdu7078 1:51cf7b1a96bd 149 //Duration set
mdu7078 1:51cf7b1a96bd 150
mdu7078 1:51cf7b1a96bd 151 }
mdu7078 1:51cf7b1a96bd 152 break;
mdu7078 1:51cf7b1a96bd 153 case '7':
mdu7078 1:51cf7b1a96bd 154 if (flag == 0){
mdu7078 1:51cf7b1a96bd 155 //Octave set
mdu7078 1:51cf7b1a96bd 156
mdu7078 1:51cf7b1a96bd 157 }
mdu7078 1:51cf7b1a96bd 158 else {
mdu7078 1:51cf7b1a96bd 159 //Duration set
mdu7078 1:51cf7b1a96bd 160
mdu7078 1:51cf7b1a96bd 161 }
mdu7078 1:51cf7b1a96bd 162 break;
mdu7078 1:51cf7b1a96bd 163 case '8':
mdu7078 1:51cf7b1a96bd 164 if (flag == 0){
mdu7078 1:51cf7b1a96bd 165 //Octave set
mdu7078 1:51cf7b1a96bd 166
mdu7078 1:51cf7b1a96bd 167 }
mdu7078 1:51cf7b1a96bd 168 else {
mdu7078 1:51cf7b1a96bd 169 //Duration set
mdu7078 1:51cf7b1a96bd 170
mdu7078 1:51cf7b1a96bd 171 }
mdu7078 1:51cf7b1a96bd 172 break;
mdu7078 1:51cf7b1a96bd 173 case '9':
mdu7078 1:51cf7b1a96bd 174 if (flag == 0){
mdu7078 1:51cf7b1a96bd 175 //Octave set
mdu7078 1:51cf7b1a96bd 176
mdu7078 1:51cf7b1a96bd 177 }
mdu7078 1:51cf7b1a96bd 178 else {
mdu7078 1:51cf7b1a96bd 179 //Duration set
mdu7078 1:51cf7b1a96bd 180
mdu7078 1:51cf7b1a96bd 181 }
mdu7078 1:51cf7b1a96bd 182 break;
mdu7078 1:51cf7b1a96bd 183 case ':':
mdu7078 1:51cf7b1a96bd 184 flag = 1;
mdu7078 1:51cf7b1a96bd 185 break;
mdu7078 1:51cf7b1a96bd 186 case ';':
mdu7078 1:51cf7b1a96bd 187 if (flag == 1){
mdu7078 1:51cf7b1a96bd 188
mdu7078 1:51cf7b1a96bd 189
mdu7078 1:51cf7b1a96bd 190 //Reset values
mdu7078 1:51cf7b1a96bd 191 flag = 0;
mdu7078 1:51cf7b1a96bd 192 sharp = 0;
mdu7078 1:51cf7b1a96bd 193 dur[0] = '0';
mdu7078 1:51cf7b1a96bd 194 dur[1] = '0';
mdu7078 1:51cf7b1a96bd 195 curnote = ' ';
mdu7078 1:51cf7b1a96bd 196 octave = 0;
mdu7078 1:51cf7b1a96bd 197 }
mdu7078 1:51cf7b1a96bd 198 else{
mdu7078 1:51cf7b1a96bd 199 //Default to quarter note:
mdu7078 1:51cf7b1a96bd 200 }
mdu7078 1:51cf7b1a96bd 201 break;
mdu7078 1:51cf7b1a96bd 202 }
mdu7078 1:51cf7b1a96bd 203 }
mdu7078 0:07a4aa44fe9c 204 return out;
mdu7078 0:07a4aa44fe9c 205 }
mdu7078 0:07a4aa44fe9c 206
mdu7078 0:07a4aa44fe9c 207 /*
mdu7078 0:07a4aa44fe9c 208 * This plays a given song string at a given tempo
mdu7078 0:07a4aa44fe9c 209 *
mdu7078 0:07a4aa44fe9c 210 * song - The song character array
mdu7078 0:07a4aa44fe9c 211 * tempo - The specified beats per minute
mdu7078 0:07a4aa44fe9c 212 * num - The number of characters in the array
mdu7078 0:07a4aa44fe9c 213 */
mdu7078 0:07a4aa44fe9c 214 void music::play(char* song, double tempo, int num){
mdu7078 0:07a4aa44fe9c 215 double dl;
mdu7078 0:07a4aa44fe9c 216 m_song msng = parse(song, num);
mdu7078 0:07a4aa44fe9c 217
mdu7078 0:07a4aa44fe9c 218 /* Play m_song */
mdu7078 0:07a4aa44fe9c 219 for (int i=0; i<msng.len; i++){
mdu7078 0:07a4aa44fe9c 220 // Output the frequency:
mdu7078 0:07a4aa44fe9c 221 freq(msng.note[i].freq);
mdu7078 0:07a4aa44fe9c 222 // Calculate delay:
mdu7078 0:07a4aa44fe9c 223 dl = 60/(tempo/(msng.note[i].duration));
mdu7078 0:07a4aa44fe9c 224 // Wait for the note to be complete
mdu7078 0:07a4aa44fe9c 225 wait(dl);
mdu7078 0:07a4aa44fe9c 226 }
mdu7078 1:51cf7b1a96bd 227
mdu7078 1:51cf7b1a96bd 228 //Deallocate song:
mdu7078 1:51cf7b1a96bd 229 msng.len = 0;
mdu7078 1:51cf7b1a96bd 230 free(msng.note);
mdu7078 0:07a4aa44fe9c 231 }