Chapter 7. Sound and Motion

Speakers generate sounds by vibrating.

You can generate those sound vibrations with the same PWM feature you used in Chapter 6 to adjust the intensity of LEDs. By changing the period and length of pulses, you can change the frequency of the sounds. And by using pulses that correspond to musical notes, you can play songs.

You can also use the length of pulses as a signal to a servo (motor), setting the servo to certain angular positions through specific pulse lengths.

Making Music

To play a song, you’ll need a speaker. For this example, use a common and inexpensive piezo speaker.

Wire up the piezo’s positive wire to pin D5 on your Netduino. Wire up the piezo’s negative (ground) wire to the GND pin on your Netduino. Figure 7-1 shows the connections.

Note

Some piezos have legs rather than wires. In most cases, one leg is longer than the other, and the long leg is positive. There may also be faint markings on the piezo indicating which is positive and which is negative. If in doubt, check your piezo’s instructions or datasheet for proper wiring.

Connecting the piezo

Figure 7-1. Connecting the piezo

Create a new Netduino project. Add the following code to the top of your Main routine:

// store the notes on the music scale and their associated pulse lengths
System.Collections.Hashtable scale = new System.Collections.Hashtable();1

// low octave
scale.Add("c", 1915u);2
scale.Add("d", 1700u);
scale.Add("e", 1519u);
scale.Add("f", 1432u);
scale.Add("g", 1275u);
scale.Add("a", 1136u);
scale.Add("b", 1014u);

// high octave
scale.Add("C", 956u);
scale.Add("D", 851u);
scale.Add("E", 758u);

// silence ("hold note")
scale.Add("h", 0u);
1

I’m introducing a new concept here called a Hashtable. A Hashtable is a collection of keys and values. The keys here are the notes, and the numbers are the pulse length values. Hashtables make it easy to look up values by specifying their keys. You’ll do this later by looking up notes and getting back their pulse length values.

2

The “u” after each value signifies that the values should be stored as unsigned integers (whole numbers). You could store this data in other ways, but this makes the sample simpler to understand later on.

Note

These note values are calculated by the equation 1 / (2 * toneFrequency). toneFrequency is the number of cycles per second for a specific note. You can extend this scale further if desired.

Next, specify the speed of the song. You’ll specify this in beats per minute, a common measurement for music.

int beatsPerMinute = 90;
int beatTimeInMilliseconds = 
  60000 / beatsPerMinute; // 60,000 milliseconds per minute
int pauseTimeInMilliseconds = (int)(beatTimeInMilliseconds * 0.1);

To calculate the beatTime (length of a beat) in milliseconds, divide 60,000 (the number of milliseconds in a minute) by the number of beats per minute.

And since you want a tiny bit of pause in between each note (so that the notes don’t all blur together), multiply the beat length by 10% to create a pause length. Later on, you’ll subtract 10% from the beat length and insert this pause instead, keeping a steady rhythm but making the song more pleasant.

Note

You casted the pause time to an integer value. Integers are positive or negative whole numbers. Since 0.1 (10%) is a fractional number and not a whole number, you need to do this explicitly. The programming language is smart and realizes that you might lose a little bit of accuracy by ending up with a few tenths of a number that can’t be stored in an integer. So it requires that you explicitly cast the product into an integer to show you know that you might lose some precision.

Now, define the song. This song involves animals on a farm and the sounds that they make:

// define the song (letter of note followed by length of note)
string song = "C1C1C1g1a1a1g2E1E1D1D1C2";

The song is defined as a series of notes (upper-case for higher octave, lower-case for lower octave) followed by the number of beats for each note. For the musicians’ reference, one beat is a quarter note in this instance and two beats is a half note, in 4/4 time.

Now that you have a musical scale and a song, you need a speaker to play them. You’ll add one here:

// define the speaker
PWM speaker = new PWM(Pins.GPIO_PIN_D5);

You’re all set to play the song. Create a loop that reads in each of the note/length entries in the song string, and then plays them by generating specific pulses for the piezo using PWM.

Create a loop:

// interpret and play the song
for (int i = 0;1 i < song.Length;2 i += 23)
{
    // song loop

}
1

The first part of the for statement, int i = 0, establishes the variable i as a position counter in the encoded song’s string.

2

The middle part of the statement, i < song.Length, repeats the loop until you’ve finished playing the song.

3

The third part of the statement, i += 2, moves the position forward by two places (the size of a note/length pair) each time through the loop.

Inside this loop, you’ll extract the musical notes and then play them. Inside the pair of curly braces, add the music interpreter/player code:

// extract each note and its length in beats
string note = song.Substring(i, 1);1
int beatCount = int.Parse(song.Substring(i + 1, 1));2
1

The first line reads the note out of the song string at the current position, i. Song.Subtring(i, 1) means “the string data starting at position i, length of 1 character.”

2

The second line reads the beat count of the song string. It reads the beat count at one position beyond the note. Then, it uses int.Parse() to translate this letter into an integer number that you can use. This is needed because you can’t do math with letters, and you’ll need to do a bit of math with the beat count shortly.

Now that you have the note, look up its duration:

// look up the note duration (in microseconds)
uint noteDuration = (uint)scale[note];

By passing in the letter (the variable note), you get back the noteDuration. Lookup is a powerful feature of C# that can be used for many purposes.

Whenever you retrieve a value from a collection (a Hashtable in this instance), you need to explicitly cast it since the programming language wants to be sure it knows what it’s getting.

Now, play the note:

// play the note for the desired number of beats
speaker.SetPulse(noteDuration * 2, noteDuration);
Thread.Sleep(
  beatTimeInMilliseconds * beatCount - pauseTimeInMilliseconds);

SetPulse is another PWM feature (in addition to SetDutyCycle, which you saw in Chapter 6). It sets a period of twice the noteDuration, followed by a duration of noteDuration. This will generate a pulse at the frequency required to sound the desired note.

You use Thread.Sleep to keep the note playing for the specified number of beats. You subtracted pauseTimeInMilliseconds from the note’s sounding time so that you can pause a tenth of a beat and make the music more pleasant.

Now that you’ve played the note, go ahead and insert that one-tenth beat pause:

// pause for 1/10th of a beat in between every note.
speaker.SetDutyCycle(0);
Thread.Sleep(pauseTimeInMilliseconds);

By setting the duty cycle to zero, you turn the piezo off momentarily. This creates the nice pause.

Finally, skip past the curly brace that ends the for loop and add one more line of code:

Thread.Sleep(Timeout.Infinite);

This will pause the program after playing the tune.

The final code should look like this:

public static void Main()
{
    // write your code here

    // store the notes on the music scale and their associated pulse lengths
    System.Collections.Hashtable scale = new System.Collections.Hashtable();

    // low octave
    scale.Add("c", 1915u);
    scale.Add("d", 1700u);
    scale.Add("e", 1519u);
    scale.Add("f", 1432u);
    scale.Add("g", 1275u);
    scale.Add("a", 1136u);
    scale.Add("b", 1014u);

    // high octave
    scale.Add("C", 956u);
    scale.Add("D", 851u);
    scale.Add("E", 758u);

    // silence ("hold note")
    scale.Add("h", 0u);

    int beatsPerMinute = 90;
    int beatTimeInMilliseconds = 
      60000 / beatsPerMinute; // 60,000 milliseconds per minute
      
    int pauseTimeInMilliseconds = (int)(beatTimeInMilliseconds * 0.1);

    // define the song (letter of note followed by length of note)
    string song = "C1C1C1g1a1a1g2E1E1D1D1C2";

    // define the speaker
    PWM speaker = new PWM(Pins.GPIO_PIN_D5);

    // interpret and play the song
    for (int i = 0; i < song.Length; i += 2)
    {        // extract each note and its length in beats
        string note = song.Substring(i, 1);
        int beatCount = int.Parse(song.Substring(i + 1, 1));

        // look up the note duration (in microseconds)
        uint noteDuration = (uint)scale[note];

        // play the note for the desired number of beats
        speaker.SetPulse(noteDuration * 2, noteDuration);
        Thread.Sleep(
          beatTimeInMilliseconds * beatCount - pauseTimeInMilliseconds);

        // pause for 1/10th of a beat in between every note.
        speaker.SetDutyCycle(0);
        Thread.Sleep(pauseTimeInMilliseconds);
    }

    Thread.Sleep(Timeout.Infinite);
}

Now, run your app. Sing along with the song if you’d like. Look up the full song online and add the rest if desired.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.168.8