We all have our favorite songs, and sometimes playing them would add that extra ‘something’ to our BASIC Stamp applications. This project will demonstrate how to take the sheet music from your favorite songs and play them with the piezospeaker.
A brief introductory video to this project can be found below.
If you are new to the BASIC Stamp microcontroller or to programming, it would be a good idea to review Chapter 8 in What’s a Microcontroller? (#28123) before continuing.
(1) HomeWork Board with BASIC Stamp 2 (#28158)
The BASIC Stamp 2 on a Board of Education (#28103) is also suitable for this activity
(1) Piezo speaker (#900-00001)
Source code for Playing Sheet Music with the Piezo speaker [1]
All that is needed for this project is a piezoelectric speaker. Build the circuit as shown below in Figure 1.
Figure 1 - Piezoelectric Speaker Schematic and Wiring Diagram
Before any PBASIC coding can happen, it would be best to cover the basics of reading sheet music. After all, without knowing how to do that, translating it into code would be tricky business! These next sections will introduce the basics of reading sheet music, so the next time you want to feature a favorite song in a BASIC Stamp application, you’ll be ready to go.
The staff is perhaps the most important building block of reading sheet music. It is a set of 5 lines with 4 spaces in between that holds the information needed for the musician to play the correct notes, in the correct tempo, at the right pitch. Each note on a staff increases by one letter from a line to a space, and by two letters from line to line.
The symbol that appears at the beginning of every staff is known as a clef. This symbol lets the musician know which notes to play as well as the octave to play them in. When reading sheet music, one of two clefs will be used—treble or bass. The treble clef is used for higher notes, such as those for a soprano singer, flute, violin, or for the pianist, any note above “Middle C.” The bass clef is used for lower notes, such as a bass or baritone singer, tuba, trombone, or any note below “Middle C” on a piano.
The image below displays how to read notes for the treble clef, and these notes can be easily remembered through the use of mnemonic devices. For example, the staff lines for the treble clef read: E, G, B, D, F—which can be remembered through the phrase “Every Good Boy Does Fine.” You can also memorize the spaces between the lines as they spell the word “FACE.”
Figure 2 - Trebel Clef Order of Notes
The next image displays how to read notes for the bass clef. Here, the order of notes changes to: G, B, D, F, A which can be remembered the mnemonic device “Good Burritos Don’t Fall Apart.”
Sadly, the spaces between the lines don’t spell anything for the bass clef (A, C, E, G) but you can use the phrase “All Cows Eat Grass” to help you remember.
Figure 3 - Bass Clef Order of Notes
Take a look below and see if you can identify the pattern that is beginning to emerge:
Figure 4 - Octave Example
The notes between and including the “E’s” form what’s known as an octave, or a sequence of 8 musical notes. Octaves are measured note to note, for example: C-to-C or A-to-A. As the octaves increase up the staff, the pitch of each note increases. Conversely, as octaves decrease down the staff, the pitches of the notes decrease.
Since the pitch of a note gets higher or lower depending on the octave, a number system exists to help keep track of each octave. Take another look at Figure 4 above. The first highlighted “E” note is considered to be in the 4th octave, while the second highlighted “E” note is in the 5th octave. Octaves increase or decrease in value from note C to note C. So the first half of the staff (E-F-G-A-B) is in the 4th octave, while the second half (C‑D‑E-F) is in the 5th octave.
The key signature is a series of sharp or flat symbols located directly to the right of the clef. These symbols tell the musician which notes get played a half-step higher (sharp) or a half-step lower (flat). These notes are then played as sharps or flats throughout the entire piece of music, regardless of the octave. For example, the side by side images below demonstrate examples of both sharp and flat key signatures. See if you can determine which notes will get changed based on the mnemonic devices introduced in the “Staff and Clefs” section above.
Figure 5 - Sharp and Flat Key Signatures
The Natural Symbol
Sometimes, regardless of the key signature, certain notes need to be played normally. If this is the case, the natural symbol (shown to the left) will be displayed before the note. This signals the musician that even though the key signature shows the note as sharp or flat, it should be played normally.
One key component to keeping rhythm when playing a piece of music is to know how long a note should last. Note durations are represented by symbols and the best way to remember their ‘values’ is simply through rote memorization. Below is a table of commonly used notes and their durations:
Note Symbol |
Duration |
The whole note is the base note for all other notes in a piece of music. In common time, the whole note lasts 4 beats. |
|
The half note is one-half the value of the whole note. In common time, the half note lasts 2 beats. |
|
The quarter note is one-fourth the value of the whole note. In common time, the quarter note lasts 1 beat. |
|
The eighth note is one-eighth the value of the whole note. In common time, the eighth note lasts half a beat. |
|
The sixteenth note is one-sixteenth the value of the whole note. In common time, the sixteenth note lasts a quarter of a beat. |
Another Way to Denote Eighth and Sixteenth Notes
Sometimes, a sequence of eighth or sixteenth notes can also be connected or beamed. These notes are typically beamed when they occur within the same measure and/or when the composer wants a more “flowing” feel for the notes. To the left are examples of beamed eighth and sixteenth notes.
When playing sheet music, it is just as important to know how long to stop playing (or rest) as it is to know how long to hold a note. Just like there are note durations, there are also rest durations, or the length of time a musician should pause their playing. The durations of rests are the same as those for notes: a quarter rest would last the same amount of time as a quarter note. Below is a table of commonly used rests:
Rest Symbol |
Name |
Whole Rest |
|
Half Rest |
|
Quarter Rest |
|
Eighth Rest |
|
Sixteenth Rest |
On most pieces of music, there is a number that looks like a fraction directly to the right of the key signature. This number is known as the time signature and is crucial to keeping the correct tempo when playing a song. Figure 6, below, demonstrates 4/4 time, which is also known as “common time” and is sometimes denoted with a “c.” Common time means that there are 4 beats in every measure, and the quarter note gets a whole beat. In sheet music, measures are separated by vertical lines.
Figure 6 - "Common Time" Time Signature
Let’s apply the techniques just learned about reading sheet music to an actual song. Since the start of school is just around the corner, the song “School Days” by Will Cobb and Gus Edwards seems most appropriate for this activity. The sheet music for the song is shown in Figure 7.
Figure 7 - "School Days" Sheet Music
So now that we have the sheet music it’s time to map out the notes and octaves so we can easily translate it into PBASIC to play with the piezospeaker. This next section contains some simple steps that you can take to successfully play sheet music with the piezospeaker and BASIC Stamp 2.
The first thing to do when planning to play sheet music with the piezospeaker is to identify the notes to be played. Use the above sheet music and mark the value of each note, and don’t forget to make a note of octave changes and sharps or flats! You can check your work with the filled-in music below.
Figure 8 - "School Days" Sheet Music with Notes
Using the time signature, the next step will be to count out the beats for each measure. This will help determine the duration of each note when playing it on the piezospeaker. The time signature for this song is 3/4, which means that there are three beats in each measure and the quarter note gets one beat. Use the “Note Duration and Rests” section above to count the beats for each measure. You can check your work with following:
Figure 9 - "School Days" Sheet Music with Beats
What does the dot next to some notes mean?
You may have noticed the dot next to the notes in the first four measures. Whenever there is a dot next to a note, the duration of the note increases by one-half its value. For example, since this piece of music is in 3/4 time, a half note lasts 2 beats. A dotted half note, therefore, would last 3 beats total—2 for its value plus one extra since 2/2 = 1.
Congratulations, you have just successfully read a piece of sheet music! Now we’re ready to take what we’ve read and put it into code for the BASIC Stamp. As a quick recap, we need three pieces of information before we can begin our BASIC Stamp code:
This information is going to be stored to EEPROM on the BASIC Stamp. That way, we can use the code as a template for any piece of music that we might want to play. If you recall from Chapter 8 of What’s a Microcontroller? that every note corresponds to a specific frequency which can be played by the BASIC Stamp, as seen here:
Figure 10 - Rightmost Piano Keys and Their Frequencies
You may notice that the frequencies in the above image are two higher than the ones we made note of on the sheet music. This is because the 6th and 7th octaves sound the best through the piezospeaker. So just remember that anytime you are playing sheet music with the piezospeaker, bump the octave up by two in order to get the best sound.
Armed with this knowledge, let’s take a look at the PBASIC code for playing “School Days” with the piezo speaker:
' SchoolDays.bs2 ' Play the 1907 hit "School Days" by Will Cobb and Gus Edwards with the ' piezospeaker. ' {$STAMP BS2} ' {$PBASIC 2.5} Notes DATA "D", "F", "C", "F", "b", "A", "b", "C", "b", "A", "R", "A", "e", "G", "A", "e", "G", "A", "R", "A", "A", "G", "D", "F", "G", "D", "F", "G", "R", "G", "G", "Q" Octaves DATA 7, 6, 7, 6, 6, 6, 6, 7, 6, 6, 6, 6, 7, 6, 6, 7, 6, 6, 6, 6, 6, 6, 7, 6, 6, 7, 6, 6, 6, 6, 6 Durations DATA 2, 2, 2, 2, 2, 4, 2, 4, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2 Dots DATA 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 index VAR Byte offset VAR Nib noteLetter VAR Byte noteFreq VAR Word noteDuration VAR Word noteOctave VAR Nib noteDot VAR Bit DO UNTIL noteLetter = "Q" READ Notes + index, noteLetter LOOKDOWN noteLetter, [ "C", "d", "D", "e", "E", "F", "g", "G", "a", "A", "b", "B", "R", "Q" ], offset LOOKUP offset, [ 4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902, 0, 0 ], noteFreq READ Octaves + index, noteOctave noteOctave = 8 - noteOctave noteFreq = noteFreq / (DCD noteOctave) READ Durations + index, noteDuration noteDuration = 1000 / noteDuration READ Dots + index, noteDot IF noteDot = 1 THEN noteDuration = noteDuration * 3 / 2 FREQOUT 9, noteDuration, noteFreq index = index + 1 LOOP END
The first part of the code defines what song will be played by saving the following to EEPROM:
The code that follows the DATA directives can be used as a template for any song that you may want to play. Basically, each note is read from EEPROM and played at the proper frequency for the correct amount of time. Let’s take a more in-depth look at how the program accomplishes this.
The first part of the code reads the note stored in the Notes DATA directive and places it into a variable named noteLetter.
READ Notes + index, noteLetter
A lookup table is then used to store the corresponding frequency for each note relative to the eighth octave. The eighth octave in musical turns is technically simply the note “C.” However, for mathematical reasons and since the lower octaves don’t play clearly through the piezospeaker, we will define each note of the eighth octave with a frequency and use this octave as a baseline for calculating the frequencies of notes in other octaves.
LOOKDOWN noteLetter, [ "C", "d", "D", "e", "E", "F", "g", "G", "a", "A", "b", "B", "R", "Q" ], offset LOOKUP offset, [ 4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902, 0, 0 ], noteFreq
Seeing as we don’t want every note to be played in the 8th octave, we need to calculate the frequency of each note in the octave we do want to play. Take another look at Figure 10 (previous page [2]) and see if you can detect a pattern when dropping from the note C8 to C7 to C6. Do you notice how their values cut in half each time you drop an octave? For example, the frequency of C8 is 4186 Hz. 4186 divided by 2 is 2093 or the frequency of the note C7. 2093 divided by 2 is 1046.5 or the frequency of the note C6. This pattern continues all the way down the octave, and is how we were able to assign frequency values for notes in our 8th octave.
However, we would have some pretty tedious PBASIC code if we had to keep dividing by 2 in order to get the desired frequency value. There must be an easier way to drop multiple octaves, right? Right! Let’s take the C-note example again: say we wanted to drop from C8 to C6, isn’t that the same as dividing the frequency of C8 by 4? Or, if we wanted to drop from C8 to C5 (523.25 Hz), isn’t that the same as diving the frequency of C8 by 8? By George, I think there’s a pattern emerging here!
By using the 8th octave as a reference, we can divide a note’s frequency by 8, 4, 2 or 1 in order to calculate the frequency values for the 5th, 6th, 7th, and 8th octaves, respectively. To put it in even simpler terms: we could also divide by 23, 22, 21, or 20. To translate this code into PBASIC, we first read the octave from EEPROM and save it to a variable named noteOctave.
READ Octaves + index, noteOctave
Then, in order to calculate the correct power to raise 2 to, we subtract the value in noteOctave from 8. So if noteOctave was 7 now it’s 1. If noteOctave was 6 now it’s 2, etc.
noteOctave = 8 - noteOctave
Lastly, we need to divide the current frequency by 2 raised to the power of noteOctave. In PBASIC we can use the DCD operator, which is a 2n-power decoder of a 4-bit value. So if we divide noteFreq by DCD noteOctave, we are in turn diving by 1, 2, 4, or 8 which will, in turn, give us the correct noteFreq value.
noteFreq = noteFreq / (DCD noteOctave)
Now we need to calculate how long to play each note. First, we read the value stored in the Durations DATA directive and store it in a variable named noteDuration.
READ Durations + index, noteDuration
In order to calculate the millisecond duration for each note, we’ll use the theoretical duration of a whole note as a base. In this case, we’ll say a whole note would last one second. Therefore, a half note would last 500 ms, a quarter note would last 250 ms, and an eighth note would last 125 ms. Since we set the values in the Durations DATA directive to the number in the denominator of the notes value, we just need to divide 1000 by the value in noteDuration.
noteDuration = 1000 / noteDuration
To finish, we need to re-calculate the note’s duration if it is a dotted note. Remember, we set dotted notes equal to 1 in the Dots DATA directive, so if we read a 1 from the Dots DATA directive, we need to increase that note’s duration by one-half its value. Or, to simplify matters, multiply the note’s duration by 1.5.
READ Dots + index, noteDot IF noteDot = 1 THEN noteDuration = noteDuration * 3 / 2
Then, we play the note for the specified duration through the piezospeaker, add one to the EEPROM index and repeat the process until the value in the Notes DATA directive is “Q”.
Links
[1] https://learn.parallax.com/sites/default/files/Files/Docs/Projects/SheetMusic/Sheet-Music-Piezospeaker.zip
[2] https://learn.parallax.com/project/playing-sheet-music-piezospeaker/lesson-sheet-music