I want to make my Arduino to play several simple melodies, and also be able to skip a melody by pressing a button and go on with the next song. therefore I cannot use delay() because the code should constantly check if a button is pressed. So I wanted to use millis(), but dont't know how to implement it.
this is how song code looks like with delay():
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
//etc...
int tempo=144;
// change this to whichever pin you want to use
int buzzer = 11;
int melody[] = {
//Based on the arrangement at https://www.flutetunes.com/tunes.php?id=192
NOTE_E5, 4, NOTE_B4,8, NOTE_C5,8, NOTE_D5,4, NOTE_C5,8, NOTE_B4,8,
// etc...
};
// sizeof gives the number of bytes, each int value is composed of two bytes (16 bits)
// there are two values per note (pitch and duration), so for each note there are four bytes
int notes=sizeof(melody)/sizeof(melody[0])/2;
// this calculates the duration of a whole note in ms (60s/tempo)*4 beats
int wholenote = (60000 * 4) / tempo;
int divider = 0, noteDuration = 0;
void setup() {
// iterate over the notes of the melody.
// Remember, the array is twice the number of notes (notes + durations)
for (int thisNote = 0; thisNote < notes * 2; thisNote = thisNote + 2) {
// calculates the duration of each note
divider = melody[thisNote + 1];
if (divider > 0) {
// regular note, just proceed
noteDuration = (wholenote) / divider;
} else if (divider < 0) {
// dotted notes are represented with negative durations!!
noteDuration = (wholenote) / abs(divider);
noteDuration *= 1.5; // increases the duration in half for dotted notes
}
// we only play the note for 90% of the duration, leaving 10% as a pause
tone(buzzer, melody[thisNote], noteDuration*0.9);
// Wait for the specief duration before playing the next note.
delay(noteDuration);
// stop the waveform generation before the next note.
noTone(buzzer);
}
}
I found this code on internet but I don't know how to implement this in above code. when I try to, I get some kind of cursed sound.
unsigned long previousMillis = 0;
boolean outputTone = false;
if (millis() - previousMillis >= noteDuration) {
previousMillis = millis();
if (outputTone) {
noTone(buzzer);
outputTone==false;
} else {
tone(buzzer, melody[thisNote], noteDuration*0.9);
outputTone==true;
}
}
edit1: I tried this:
unsigned long previousMillis = millis();
int thisNote = 0;
while (thisNote < notes * 2) {
// calculates the duration of each note
divider = lied1[thisNote + 1];
if (divider > 0) {
// regular note, just proceed
noteDuration = (wholenote) / divider;
} else if (divider < 0) {
// dotted notes are represented with negative durations!!
noteDuration = (wholenote) / abs(divider);
noteDuration *= 1.5; // increases the duration in half for dotted notes
}
// play the note
tone(buzzer, melody[thisNote]);
check();//check if button is pressed, and if so, changes number to 2
if (number ==2){
thisNote=notes*2;
}
if ((millis() - previousMillis) >= noteDuration){
thisNote = thisNote + 2;
// stop the waveform generation before the next note.
noTone(buzzer);
}
}
but it doesn't work, and I don't really understand why
edit2: I changed something, this is probably the closest I have been to a working melody without "delay()". But it is extremely slow.
boolean outputTone = false;
unsigned long previousMillis = millis();
int thisNote = 0;
while (thisNote < notes * 2) {
// calculates the duration of each note
divider = lied1[thisNote + 1];
if (divider > 0) {
// regular note, just proceed
noteDuration = (wholenote) / divider;
} else if (divider < 0) {
// dotted notes are represented with negative durations!!
noteDuration = (wholenote) / abs(divider);
noteDuration *= 1.5; // increases the duration in half for dotted notes
}
if (millis() - previousMillis >= noteDuration) {
previousMillis = millis();
if (outputTone) {
noTone(buzzer);
outputTone==false;
} else {
tone(buzzer, melody[thisNote], noteDuration*0.9);
outputTone==true;
thisNote = thisNote + 2;
}
}
check(); //checks if button is pressed, and if so, changes number to 2.
if (number ==2){
thisNote=notes*2;
}
}