Skip to content

Arduino - Tone Library

Arduino - Modern Sound Generation with tone()

Section titled “Arduino - Modern Sound Generation with tone()”

This chapter explores how to generate sounds and melodies using the Arduino’s built-in tone() function. The tone() function can produce a square-wave of a specified frequency on any digital pin. It’s a fantastic way to add auditory feedback to your projects, from simple beeps to complex musical tunes. You can connect the output pin to a piezo buzzer or a small speaker to hear the sound.

Safety Warning: The signal from an Arduino pin is a 5V (or 3.3V) square wave. Do not connect it directly to standard audio inputs like a sound card or amplifier, as this high voltage can cause permanent damage. If you need to interface with audio equipment, use a voltage divider circuit and a coupling capacitor to safely lower the voltage and remove the DC offset.

To complete this tutorial, you will need:

  • 1 × Arduino UNO board (or any other Arduino board)
  • 1 × Piezo Buzzer or an 8-ohm Speaker
  • 1 × 100-ohm Resistor (for current limiting with the speaker)
  • Jumper wires

The circuit is straightforward. We will connect the sound-producing component to digital pin 8.

Using a Piezo Buzzer:

Connect the positive leg (often longer) to Arduino’s digital pin 8. Connect the negative leg to the Arduino’s GND.

Using an 8-ohm Speaker:

Connect one terminal of the speaker to the Arduino’s digital pin 8 through a 100-ohm resistor. Connect the other terminal to the Arduino’s GND. The resistor protects the Arduino pin from drawing too much current.

Here is a text-based representation of the circuit:

Arduino Component
GND ---------------- (-) Piezo Buzzer / Speaker Terminal 2
PIN 8 -------------- (+) Piezo Buzzer / (Resistor) -> Speaker Terminal 1

The original tutorial used a separate pitches.h file. While this works, modern C++ practices allow us to define these constants cleanly within our main sketch, making it self-contained. We will also use modern techniques to make our code more robust and efficient.

Open the Arduino IDE, create a new sketch (File > New), and paste the following code.

/*
* Modern Melody Player
*
* This sketch plays a simple melody using the tone() function.
* It demonstrates efficient memory usage with PROGMEM and robust array handling.
*/
// Include the PROGMEM header for memory optimization
#include <avr/pgmspace.h>
// --- Note Definitions ---
// These are frequencies in Hertz (Hz)
#define NOTE_C4 262
#define NOTE_G3 196
#define NOTE_A3 220
#define NOTE_B3 247
#define NOTE_C5 523
#define REST 0 // A rest/pause
// --- Pin Configuration ---
const int buzzerPin = 8;
// --- Melody and Durations ---
// PROGMEM stores this data in Flash memory, saving precious RAM.
const int melody[] PROGMEM = {
NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, REST, NOTE_B3, NOTE_C4
};
// Note durations: 4 = quarter note, 8 = eighth note, etc.
const int noteDurations[] PROGMEM = {
4, 8, 8, 4, 4, 4, 4, 4
};
void setup() {
// No setup needed for tone(), but good practice to set pin mode.
pinMode(buzzerPin, OUTPUT);
// Get the total number of notes in the melody.
// Using sizeof() makes the code adaptable to melodies of any length.
int numNotes = sizeof(melody) / sizeof(melody[0]);
// Iterate over the notes of the melody
for (int thisNote = 0; thisNote < numNotes; thisNote++) {
// The tempo (e.g., a quarter note is 1000ms long)
int tempo = 1000;
// Read the note duration from PROGMEM
int durationType = pgm_read_word_near(&noteDurations[thisNote]);
int noteDuration = tempo / durationType;
// Read the note frequency from PROGMEM
int frequency = pgm_read_word_near(&melody[thisNote]);
// Play the note using tone(pin, frequency, duration)
tone(buzzerPin, frequency, noteDuration);
// To allow the note to finish and add a brief pause between notes,
// we calculate a pause. A 30% pause often sounds good.
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// Stop the tone to ensure it doesn't overlap with the next one.
noTone(buzzerPin);
}
}
void loop() {
// The melody plays once in setup(). The loop is empty.
// You could add code here to replay the melody on a button press.
}

tone(pin, frequency, duration): This is the core function. It generates a square wave of a specific frequency (in Hz) on a pin for a given duration (in milliseconds). The duration is optional; if omitted, the tone plays until you call noTone(pin).

PROGMEM: This is a crucial feature for memory-constrained devices like the Arduino Uno. It tells the compiler to store the melody and noteDurations arrays in the larger Flash program memory instead of the very limited SRAM (RAM). This leaves more RAM available for your variables and other runtime needs, preventing crashes in larger programs.

sizeof(melody) / sizeof(melody[0]): This is the standard, robust C++ way to calculate the number of elements in an array. It’s better than hard-coding a number (like 8) because if you add or remove notes from the melody array, this calculation updates automatically, preventing bugs.

  • No Sound? Check your wiring. Is the buzzer/speaker connected to the correct pin (8) and GND? If using a speaker, did you include the resistor?
  • Distorted Sound? The small speaker might be rattling. Ensure it’s secure. Piezo buzzers often produce a cleaner, albeit more ‘digital’, sound.
  • Going Further: Try creating your own melodies by changing the notes and durations. You could add a button to the loop() function to trigger the melody on demand. Or, connect a potentiometer to an analog pin and use its reading to control the tempo of the music.

Once you upload the sketch, the Arduino will immediately play the pre-programmed melody through the connected buzzer or speaker. The melody will play once, and then the program will sit idle in the loop() function.