I've just started coding for my Arduino in earnest today, and I needed to get back up to speed on C, and learn how to play sounds on the props I'm building, so I decided to take the Tone() example, and expand upon it to make it easier to input tunes.
I based my function loosely on how the Play() command on the Commodore 128 worked, because it's easy to find monophonic ringtones in formats similar to this, you don't have to keep track of the notes and durations in two seperate arrays, and it's a lot less typing to input notes.
I also added the ability to play tones with vibrato so they sound more pleasant.
The code is currently set to output to pin 16. (A2) You'll have to change the contant in two places in the Vibrato function to use a different pin.
Also, it requires pitches.h from the tone()/playmelody example.
Anyway, the code is free to use however you please. Enjoy!
#include "pitches.h"
int bpm = 300;
int octave = 3;
int duration = 4;
// Format:
// O5 = Set octave to 5.
// 4#A = A sharp quarter note in octave last selected.
// Spaces may be omitted, and you need only specify the note duration when it changes.
char song1[] = "O5 8G 8G 4B 4G 4A 4F 1R 8G 8G 8G 8G 4F 4G 2R 4R 8G 8G 4B 4G 4A 4F 1R 8G 8G 8G 8G 4F 4A 4G";
char song2[] = "O58GG4BGAF1R8GGGG4FG2R4R8GG4BGAF1R8GGGG4FAG"; // Same as above!
void setup() {
play(song1);
}
void loop() {
}
void play(char *song) {
int n = 0;
int playnote = false;
int sharp = false;
int frequency;
while (song[n]) {
switch (song[n]) {
case ' ':
break;
case 'O':
n++;
if (song[n]) { octave = song[n] - 48; }
break;
case '8': duration = 8; break;
case '4': duration = 4; break;
case '2': duration = 2; break;
case '1': duration = 1; break;
case '#': sharp = true; break;
case 'A':
playnote = true;
frequency = NOTE_A4;
if (sharp == true) { frequency = NOTE_AS4; }
break;
case 'B':
playnote = true;
frequency = NOTE_B4;
break;
case 'C':
playnote = true;
frequency = NOTE_C4;
if (sharp == true) { frequency = NOTE_CS4; }
break;
case 'D':
playnote = true;
frequency = NOTE_D4;
if (sharp == true) { frequency = NOTE_DS4; }
break;
case 'E':
playnote = true;
frequency = NOTE_E4;
break;
case 'F':
playnote = true;
frequency = NOTE_F4;
if (sharp == true) { frequency = NOTE_FS4; }
break;
case 'G':
playnote = true;
frequency = NOTE_G4;
if (sharp == true) { frequency = NOTE_GS4; }
break;
case 'R':
playnote = true;
frequency = 0;
break;
}
if (playnote == true) {
frequency = float(frequency) * pow(2, octave-4);
// If you don't wish to use vibrato(), comment it out, and uncomment the following lines:
/*
int wholenote = 4000.0 / (bpm/60.0);
tone(16, frequency, wholenote/duration);
delay (wholenote / duration);
*/
vibrato(frequency, duration);
playnote = false;
sharp = false;
}
n++;
}
}
// This function plays a note while rapidly switching between two octaves.
void vibrato(int frequency, int duration) {
int wholenote = 4000.0 / (bpm/60.0);
int i;
int v;
int time;
switch (duration) {
case 8:
v = 2;
break;
case 4:
v = 4;
break;
case 2:
v = 8;
break;
case 1:
v = 16;
break;
}
time = (wholenote/duration) / v;
for (int i = 0; i < v; i++) {
switch (i % 2) {
case 0:
tone(16, frequency/2, time);
delay(time);
break;
case 1:
tone(16, frequency, time);
delay(time);
break;
}
}
delay((wholenote/duration) * 0.3); // Pause between notes.
}