This is an example of using the tone() function on an Arduino Nano. In the same way, you can apply it to other Arduinos and similar boards.
Two buttons are used: one starts the music, and the second returns the melody to its original tone (fourth octave). A 10k potentiometer controls the octave of the melody across the 7 octaves of a piano, raising or lowering the pitch. Each octave is made up of 12 notes, including sustained tones.

Four LEDs are included to show relative note changes with light.
I don't use the pitches.h file; instead, I use the MIDI note sequence (p), starting with the root note A4 (440 Hz). Mathematically, each note can be represented perfectly as an exponential multiple of the note A4, using the following equation:
f = 2 ^ ((p - 69) / 12) x 440 Hz
By means of the MeSderM matrix [X][3], where X is the total number of notes (depends on the melody), I declare the note number, the note duration factor, and the LED that will light up on that note.
In this case, and in most melodies, there are parts that repeat. I have created a melodyY(int RepX, int iniX, int endX) function that plays a part of the notes (range: from iniX to endX) the required number of times (RepX).
In the loop(), the melody is played once button 1 is pressed. During playback, it checks the value of the potentiometer to determine the playing tone of each note. If button 2 is pressed at any time, it returns to the original tone.
Likewise, if the melody ends, pressing button 2 will return the melody to its original pitch, and the loop will play the melody if button 1 is pressed again.
Finally, by means of a serial monitor, you can view the frequency of each note and the change that occurs when moving the potentiometer throughout its range.
The code is not optimized; it is possible to improve it, so in the future, I will publish a version 2.
The melody used is as follows: Marvel Spiderman Theme (c).
Additionally, I have made the same example in TinkerCAD (with Arduino Micro), which you can copy and modify the code to taste.
EXPANDED TECHNICAL DETAILS
Digital Audio Synthesis
This project turns the compact Arduino Nano into a monophonic musical instrument.
- Square Wave Generation: Utilizes the
tone()function to generate PWM square waves at specific frequencies corresponding to musical notes (e.g., A4 = 440Hz, C5 = 523Hz). - Pitch Accuracy: The code calculates frequencies mathematically from MIDI note numbers, ensuring accurate pitch based on the standard A4 = 440 Hz reference.
Hardware Output
- Piezo vs. Speaker: The project can drive a high-impedance Piezo Buzzer directly from the digital pin. For a better sound with a small 8-ohm speaker, a safety 100Ω resistor in series is recommended to limit current.
- Melody Playing: The sequence-handler in the
melodyY()function manages note duration and the pauses between notes, allowing the Nano to play pre-programmed songs.
Reference Links:
Code:
const int LED_GRN = 8;
const int LED_RED = 6;
const int LED_BLE = 4;
const int LED_YLW = 2;
const int BUZZER = 13;
const int BTN1 = 5;
const int BTN2 = 3;
const int POT = A0;
const int MeSderM[] [3] = {{60 ,6, LED_GRN}, {63 ,8, LED_RED}, {67 ,2, LED_BLE}, {66 ,6, LED_BLE}, {63 ,8, LED_RED}, {60 ,2, LED_GRN}, {60 ,6, LED_GRN}, {63 ,8, LED_RED}, {67 ,6, LED_BLE}, {68 ,8, LED_YLW}, {67 ,8, LED_YLW}, {66 ,6, LED_BLE}, {63 ,6, LED_RED}, {60 ,2, LED_GRN}, {65 ,6, LED_RED}, {68 ,8, LED_BLE}, {72 ,2, LED_YLW}, {71 ,6, LED_YLW}, {68 ,8, LED_BLE}, {65 ,2, LED_RED}, {60 ,6, LED_GRN}, {63 ,8, LED_BLE}, {67 ,2, LED_YLW}, {66 ,6, LED_BLE}, {63 ,8, LED_RED}, {60 ,2, LED_GRN}, {68 ,6, LED_YLW}, {67 ,1, LED_BLE}, {67 ,8, LED_BLE}, {65 ,8, LED_RED}, {63 ,8, LED_GRN}, {65 ,8, LED_RED}, {63 ,8, LED_GRN}, {60 ,1, LED_GRN}, {67 ,6, LED_RED}, {68 ,8, LED_BLE}, {70 ,2, LED_YLW}, {68 ,6, LED_YLW}, {67 ,2, LED_BLE}, {65 ,6, LED_RED}, {63 ,8, LED_GRN}, {65 ,2, LED_RED}, {63 ,6, LED_GRN}, {62 ,8, LED_RED}, {63 ,2, LED_GRN}, {67 ,6, LED_RED}, {68 ,8, LED_BLE}, {70 ,2, LED_YLW}, {68 ,6, LED_YLW}, {67 ,2, LED_BLE}, {65 ,6, LED_RED}, {63 ,8, LED_GRN}, {65 ,2, LED_RED}, {63 ,6, LED_GRN}, {65 ,8, LED_RED}, {67 ,1, LED_BLE}, {67 ,8, LED_BLE}, {65 ,8, LED_RED}, {63 ,8, LED_GRN}, {65 ,8, LED_RED}, {63 ,8, LED_GRN}, {60 ,1, LED_GRN}, {67 ,6, LED_BLE}, {65 ,6, LED_RED}, {63 ,8, LED_GRN}, {65 ,6, LED_RED}, {67 ,6, LED_BLE}, {74 ,1, LED_YLW}};
const int LEDS[] = {LED_GRN, LED_RED, LED_BLE, LED_YLW};
int PotV = 0;
int AntO = 0;
int OctX = 0;
void Btn2Read(){
if (digitalRead(BTN2)==HIGH){
OctX=0;
}
}
void melodyY(int RepX, int iniX, int endX) {
for (int RepI = 0; RepI < RepX; RepI++) {
for (int thisNote = iniX; thisNote < endX; thisNote++) {
PotV = map(analogRead(POT), 0, 1023, -3, 4);
if (AntO != PotV){
AntO = PotV;
OctX = PotV;
}
Btn2Read();
int noteDuration = 1000 / MeSderM[thisNote][1];
digitalWrite(MeSderM[thisNote][2], HIGH);
float NteX = MeSderM[thisNote][0]+OctX*12-69;
NteX = pow(2, NteX/12)*440;
String str1 = "Eighth: " + String(4+OctX) + "; Freq: " + String(NteX,3);
Serial.println(str1);
tone(BUZZER, NteX, noteDuration);
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes*2/3);
Btn2Read();
digitalWrite(MeSderM[thisNote][2], LOW);
delay(pauseBetweenNotes/3);
Btn2Read();
noTone(BUZZER);
}
}
}
void setup() {
Serial.begin(9600);
for(int i=0; i<4; i++){
pinMode(LEDS[i], OUTPUT);
digitalWrite(LEDS[i], LOW);
}
pinMode(BTN1, INPUT);
pinMode(BTN2, INPUT);
}
void loop() {
if (digitalRead(BTN1)==HIGH)
{
melodyY(2,0,34);
melodyY(1,34,56);
melodyY(1,0,34);
melodyY(1,56,68);
}
Btn2Read();
}