Developing in C for the ATmega328P: Function - tone()

6 minute read

Where I describe the function - tone() as well as noTone() and how to play music on the Uno.

Introduction

Using the function tone() allows us to play musical notes via the Uno and a speaker. Using tone() is more difficult than understanding the command. It requires having a understanding of music, songs and melodies to use tone() to its fullest.

We are also somewhat spoiled in this era of polyphonic speakers, that is speakers which are able to play multiple notes at once. The Uno and a simple cone speaker is only capable of playing a single tone, which limits the melodies and fidelity of the music played.

Commands

The commands for creating music are simple; tone(), for playing a note, noTone(), for specifically stopping a note and delay() for adding a pause between notes:

  • tone(pin, note, duration) plays a note on a specific pin for a specified duration, pin can be any one of the digital pins from 0-13, note is a musical note, described in the section Constants below and duration is the length of the note and also has some constants provided as well. There is a limit on the length of a note as a duration must be less than 65535 milliseconds or approximately 1 minute. If you call tone() with a note of 0, it is the same as calling noTone(), however, it will last for a duration.

  • noTone(pin) turns off the note being played on a pin. It doesn’t have to be called, as when duration is exceeded, the note stops playing as well. If you want to play different pitches on multiple pins, you need to call noTone() on one pin before calling tone() on the next pin.

  • delay(milliseconds) is the same delay used before, it is mentioned here to remind you that you can use it to delay notes if desired.

Constants

As notes which aren’t pleasing to the ear, don’t make for good music, its best to call tone() using the musical constants. The constants are specifically designed to play a frequency which corresponds to a musical note. There are also standard durations, which correspond to the durations used in music, such as Whole note, Half note, Quarter note, Eighth note and Sixteenth note.

  • Notes take on the form NOTE_ln or NOTE_lSn, with the S indicating a sharp note. For example, you can have both NOTE_A2 or NOTE_AS2, however, neither B nor E have sharp notes. You may view the exact names by the Library file Library/tone.h. The note names also follow the same nomenclature used by Arduino Tone Library or this library, arduino-songs.

  • Duration take on the names used in music as in whole, half, quarter or if using a dotted version d_whole, d_half, d_quarter. There is also a dn version which is d1 for whole, d2 for half and so on. Either version works and they can be mixed in desired. Please note, this form of duration is different than some examples such as this library, arduino-songs.

Examples

The best way to understand how to make music on the Uno is to play around. In examples there are two simple programs, durationtest is linear and is helpful to understand the process of playing notes, changing the duration etc. The second program is melody and shows you how to setup a melody in program memory to be played as an array. Once you understand how the music is played, via durationtest, I recommend you use melody as your method of exploring tones and tunes.

durationtest

There is a little ditty called “Shave and Haircut”, which is sometimes delivered via percussion (knocking on a door), however, it does make a nice test. Here is the program in its entirety. Along with loading the program on the Uno, you need to attach a speaker positive (red) wire to a pin, its black (ground) wire to a resistor and the resistor to ground. An even better solution is to use a potentiometer as the resistor, which provides a simple volume mechanism. (See image below.)

Uno, potentiometer and speaker

Uno, potentiometer and speaker

Large Version to see detail

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// durationTest() - very simple linear test to demonstrate playing a melody
// requires a speaker to hear the melody on the pin
// connect positive speaker wire to pin 8
// connect negative speaker wire to center pin of potentiometer
// connect either remaining lead of potentiometer to GND

#include "tone.h"
#include "delay.h"

int main (void)
{
    const uint8_t musicPin = 8;

    tone(musicPin, NOTE_C4, quarter);
    delay(d16);

    tone(musicPin, NOTE_G3, eighth);
    delay(d16);

    tone(musicPin, NOTE_G3, eighth);
    delay(d16);

    tone(musicPin, NOTE_A3, quarter);
    delay(d8);

    tone(musicPin, NOTE_G3, quarter);
    delay(d8);

    tone(musicPin, 0, quarter);
    delay(d8);

    tone(musicPin, NOTE_B3, d_quarter);
    delay(d8);

    tone(musicPin, NOTE_C4, d_quarter);
    delay(d8);

    return 0;
}

melody_array

It is desirable to be able to play notes from program memory, this allows you to add songs and play them back individually using an array. While helpful, it is also an intermediate step to using Flash memory or PROGMEM for storing songs.

In this example, we’ll use the “Happy Birthday” song and the melody from arduino-songs. In our tone() function, we take a slightly different approach to defining a duration of a note. As described above, we want to use the musical definitions, so replace all “2” values with half, “4” with quarter, etc. If the number is negative (a dotted note), add a “d_” to the value, so that “-2” becomes d_half and “-4” is d_quarter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// melody_array - plays a melody from an array
// requires a speaker to hear the melody on the pin
// connect positive speaker wire to pin
// connect negative speaker wire center pin of pot
// connect either remaining lead of pot to GND
// Uses songs from: https://github.com/robsoncouto/arduino-songs
// Replace all 2,4,8,16 values with half, quarter, eighth or sixteenth, respectively
// Replace all negative values with a "d_" and the note, as in "-2" == "d_half"

#include <stdlib.h>
#include "delay.h"
#include "tone.h"

int main() {

    uint8_t musicPin = 8;

    // notes in the melody:
    int melody[] = 
    {
      NOTE_C4,quarter, NOTE_C4,eighth, 
      NOTE_D4,d_quarter, NOTE_C4,d_quarter, NOTE_F4,d_quarter,
      NOTE_E4,d_half, NOTE_C4,quarter, NOTE_C4,eighth, 
      NOTE_D4,d_quarter, NOTE_C4,d_quarter, NOTE_G4,d_quarter,
      NOTE_F4,d_half, NOTE_C4,quarter, NOTE_C4,eighth,

      NOTE_C5,d_quarter, NOTE_A4,d_quarter, NOTE_F4,d_quarter, 
      NOTE_E4,d_quarter, NOTE_D4,d_quarter, NOTE_AS4,quarter, NOTE_AS4,eighth,
      NOTE_A4,d_quarter, NOTE_F4,d_quarter, NOTE_G4,d_quarter,
      NOTE_F4,d_half,
    };

    // iterate over the notes of the melody:
    for (int thisNote = 0; thisNote < sizeof(melody)/sizeof(melody[0]); thisNote += 2) 
    {
      tone(musicPin, melody[thisNote], melody[thisNote+1]);
      // to distinguish the notes, set a minimum time between them.
      // in this case, divide the notes duration by 4
      int pauseBetweenNotes = (melody[thisNote+1] >> 2);
      delay(pauseBetweenNotes);
    }
}

Sources

Here is a list of information which might prove valuable if you wish to explore music on the Uno in greater depth:

Comments powered by Talkyard.