Arduino + Piezo Speaker = Super Mario!

by Tiago Gala

Some time ago I decided to put my Arduino into the music business! I had this piezoelectric buzzer lying around and it was time to give it a trial run so I googled around and found this in the Arduino Forum and decided to give it a go, but the code on the website had a kind of “dirty” look so I rewrote it bearing optimization and code-size in mind. Next follows the Fritzing layout, video and code:

Arduino + piezo

//Definição dos periodos para cada nota (*0.0000001)
#define C    1911
#define C1    1804
#define D    1703
#define Eb    1607
#define E    1517
#define F    1432
#define F1    1352
#define G    1276
#define Ab    1204
#define A    1136
#define Bb    1073
#define B    1012
#define c       955
#define c1      902
#define d       851
#define eb      803
#define e       758
#define f       716
#define f1      676
#define g       638
#define ab      602
#define a       568
#define bb      536
#define b       506

#define p       0  //pausa

int speaker = 6;    //porta do arduino
long vel = 20000;

void setup() {
    pinMode(speaker, OUTPUT);
    delay(2000);
}

int melod[] = {e, e, e, c, e, g, G, c, G, E, A, B, Bb, A, G, e, g, a, f, g, e, c, d, B, c};
int ritmo[] = {6, 12, 12, 6, 12, 24, 24, 18, 18, 18, 12, 12, 6, 12, 8, 8, 8, 12, 6, 12, 12, 6, 6, 6, 12};

void loop() {
    for (int i=0; i<42; i++) {
        int tom = melod[i];
        int tempo = ritmo[i];

        long tvalue = tempo * vel;

        tocar(tom, tvalue);

        delayMicroseconds(1000); //pausa entre notas!
    }
    delay(1000);
}

void tocar(int tom, long tempo_value) {
     long tempo_gasto = 0;
     while (tempo_gasto < tempo_value) {
        digitalWrite(speaker, HIGH);
        delayMicroseconds(tom / 2);

        digitalWrite(speaker, LOW);
        delayMicroseconds(tom/2);

        tempo_gasto += tom;
    }
}

Basically what’s being done is to output a HIGH signal half of the note’s period (the inverse of frequency) and then a LOW for the same amount of time, thus creating a square wave with the note’s corresponding frequency (it’s called PWM – Pulse Width Modulation, if the HIGH and LOW times are the same, it’s said that the duty-cycle is 50%), this HIGH/LOW cycle repeats until the time calculated for that note to be heard is over. At the end of each sound there is a gap of 1000 µseconds (1 milisecond) to make two notes distinguishable if they happen to have the same frequency. Note periods are defined in the anglo-saxonic notation to simplify and standardize note entering. Note duration isn’t related to the relative value of each note (as it would be expected in true musical notation:  quarter = 4, a sixteenth = 16) but instead to the duration of the note in µseconds according to the formula: time_µseconds = value * note_span, so if value is 20 000, a note with a note_span = 12 has a duration of 20 000 * 12 = 240 000 µseconds.

In the mean time I already transcribed a few kind of well known songs into this notation, to hear them you just need to swap it’s array name for the equivalent melod[] and ritmo[]:

int peergynt_m[] = {G, E, D, C, D, E, G, E, D, C, D, E, D, E,G, E, G, A, E, A, G, E, D, C};
int peergynt_r[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16};

int smoke_m[] = {E, G, A, E, G, Bb, A, E, G, A, G, E};
int smoke_r[] = {12, 12, 18, 12, 12, 6, 18, 12, 12, 18, 12, 24};

int natal_m[] = {G, A, G, E, G, A, G, E, c, c, A, B, B, G, A, G, A, c, B, A, G, A, G, E};
int natal_r[] = {12, 4, 8, 16, 12, 4, 8, 16, 12, 4, 16, 12, 4, 16, 12, 4, 8, 8, 8, 8, 12, 4, 8, 16};

int LTS_m[] = {Bb, G, G, Bb, G, G, Bb, ;G, G, Bb, G, G, Bb, G, C, G, Bb, G, G, Bb, G, G, Bb, G, G, Bb, G, G, Bb, G, F, D, F, D, G, F, D, C, Bb, G, Bb, C, C1, C, Bb, F, D, Bb, G, F, D, C, Bb, D, C, Bb, G} ;
int LTS_r[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};

As a final note, I’m sorry but the name of some variables in the code is in Portuguese, it’s old code and I don’t feel like going through it and risk adding bugs. You might have to tweak vel variable to get the correct speed for your song. As a challenge, try to find what songs I have written in this last part of the code! As a bigger challenge, write your own pieces of awesome PWM music and share them with everyone =)