Using elapsedMillis for multiple delays in tone() function

Hi! I'm doing a school project but I'm stuck on using Millis for multiple delays. I already checked the forums and BlinkWithoutDelay but still couldn't fix it. I just don't understand ;(

The reason why I'm using tone() instead of melody is, because for some kind of reason, I keep getting an error so I decided to play music by using tone(). I need to use millis because I want to rotate a servo at the same time and with delay that's not going to happen. This is my code so far and it all works except for the music part. What am I doing wrong here?

Thank you!

#include <elapsedMillis.h> 
elapsedMillis timeElapsed;//declare global if you don't want it reset every time loop runs
unsigned int interval1 = 100;
unsigned int interval2 = 150;
unsigned int interval3 = 200;
unsigned int interval4 = 300;
unsigned int interval5 = 550;
unsigned int interval6 = 575;

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards


// constants won't change. They're used here to set pin numbers:
const int buttonPin = D3;     // the number of the pushbutton pin
const int piezoPin =  D8;      // the number of the piezo

// variables will change:
int piezoState = LOW;
int buttonState;         // variable for reading the pushbutton status
int lastButtonState = LOW;   // the previous reading from the input pin

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
 // initialize the piezo pin as an output:
 pinMode(piezoPin, OUTPUT);
 // initialize the pushbutton pin as an input:
 pinMode(buttonPin, INPUT);

 myservo.attach(D5);  // attaches the servo on

 // set initial piezo state
 digitalWrite(piezoPin, piezoState);

 Serial.begin(115200);  
}

void loop() {
 // read the state of the pushbutton into a local value:
 int reading = digitalRead(buttonPin);

 int pos;

 // If the switch changed, due to noise or pressing:
 if (reading != lastButtonState) {
   // reset the debouncing timer
   lastDebounceTime = millis();
 }

 if ((millis() - lastDebounceTime) > debounceDelay) {
   // whatever the reading is at, it's been there for longer than the debounce
   // delay, so take it as the actual current state:

   // if the button state has changed:
   if (reading != buttonState) {
     buttonState = reading;

     // only play music if the new button state is HIGH
     if (buttonState == HIGH) {

       Serial.println(buttonState);

       for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
   // in steps of 1 degree
   myservo.write(pos);              // tell servo to go to position in variable 'pos'
   delay(15);                       // waits 15ms for the servo to reach the position
 }
 for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
   myservo.write(pos);              // tell servo to go to position in variable 'pos'
   delay(15);                       // waits 15ms for the servo to reach the position
 }
       
       // tones van https://gist.github.com/gskielian/6135641
       tone(piezoPin,660,100);
if (timeElapsed > interval2) {
 tone(piezoPin,660,100);
 timeElapsed = 0;
} if (timeElapsed > interval4) {
tone(piezoPin,660,100);
timeElapsed = 0;
} if (timeElapsed > interval2) {
tone(piezoPin,510,100);
timeElapsed = 0;
} if (timeElapsed > interval1) {
tone(piezoPin,660,100);
timeElapsed = 0;
} if (timeElapsed > interval4) {
tone(piezoPin,770,100);
timeElapsed = 0;
} if (timeElapsed > interval5) {
tone(piezoPin,380,100);
timeElapsed = 0;
} if (timeElapsed > interval6) {

tone(piezoPin,510,100);
timeElapsed = 0;
}
//delay(450);
//tone(piezoPin,380,100);
//delay(400);
//tone(piezoPin,320,100);
//delay(500);
//tone(piezoPin,440,100);
//delay(300);
//tone(piezoPin,480,80);
//delay(330);
//tone(piezoPin,450,100);
//delay(150);
//tone(piezoPin,430,100);
//delay(300);
//tone(piezoPin,380,100);
//delay(200);
//tone(piezoPin,660,80);
//delay(200);
//tone(piezoPin,760,50);
//delay(150);
//tone(piezoPin,860,100);
//delay(300);
//tone(piezoPin,700,80);
//delay(150);
//tone(piezoPin,760,50);
//delay(350);
//tone(piezoPin,660,80);
//delay(300);
//tone(piezoPin,520,80);
//delay(150);
//tone(piezoPin,580,80);
//delay(150);
//tone(piezoPin,480,80);
//delay(500);
//
//tone(piezoPin,510,100);
//delay(450);
//tone(piezoPin,380,100);
//delay(400);
//tone(piezoPin,320,100);
//delay(500);
//tone(piezoPin,440,100);
//delay(300);
//tone(piezoPin,480,80);
//delay(330);
//tone(piezoPin,450,100);
//delay(150);
//tone(piezoPin,430,100);
//delay(300);
//tone(piezoPin,380,100);
//delay(200);
//tone(piezoPin,660,80);
//delay(200);
//tone(piezoPin,760,50);
//delay(150);
//tone(piezoPin,860,100);
//delay(300);
//tone(piezoPin,700,80);
//delay(150);
//tone(piezoPin,760,50);
//delay(350);
//tone(piezoPin,660,80);
//delay(300);
//tone(piezoPin,520,80);
//delay(150);
//tone(piezoPin,580,80);
//delay(150);
//tone(piezoPin,480,80);
//delay(500);
//
//tone(piezoPin,500,100);
//delay(300);
//
//tone(piezoPin,760,100);
//delay(100);
//tone(piezoPin,720,100);
//delay(150);
//tone(piezoPin,680,100);
//delay(150);
//tone(piezoPin,620,150);
//delay(300);
//
//tone(piezoPin,650,150);
//delay(300);
//tone(piezoPin,380,100);
//delay(150);
//tone(piezoPin,430,100);
//delay(150);
//
//tone(piezoPin,500,100);
//delay(300);
//tone(piezoPin,430,100);
//delay(150);
//tone(piezoPin,500,100);
//delay(100);
//tone(piezoPin,570,100);
//delay(220);
//
//tone(piezoPin,500,100);
//delay(300);
//
//tone(piezoPin,760,100);
//delay(100);
//tone(piezoPin,720,100);
//delay(150);
//tone(piezoPin,680,100);
//delay(150);
//tone(piezoPin,620,150);
//delay(300);
//
//tone(piezoPin,650,200);
//delay(300);
//
//tone(piezoPin,1020,80);
//delay(300);
//tone(piezoPin,1020,80);
//delay(150);
//tone(piezoPin,1020,80);
//delay(300);
//
//tone(piezoPin,380,100);
//delay(300);
//tone(piezoPin,500,100);
//delay(300);
//
//tone(piezoPin,760,100);
//delay(100);
//tone(piezoPin,720,100);
//delay(150);
//tone(piezoPin,680,100);
//delay(150);
//tone(piezoPin,620,150);
//delay(300);
//
//tone(piezoPin,650,150);
//delay(300);
//tone(piezoPin,380,100);
//delay(150);
//tone(piezoPin,430,100);
//delay(150);
//
//tone(piezoPin,500,100);
//delay(300);
//tone(piezoPin,430,100);
//delay(150);
//tone(piezoPin,500,100);
//delay(100);
//tone(piezoPin,570,100);
//delay(420);
//
//tone(piezoPin,585,100);
//delay(450);
//
//tone(piezoPin,550,100);
//delay(420);
//
//tone(piezoPin,500,100);
//delay(360);
     }
   }
 }
 
 // set the LED:
 digitalWrite(piezoPin, piezoState);

 // save the reading. Next time through the loop, it'll be the lastButtonState:
 lastButtonState = reading;
}

What is it You can't fix? Please explain what actualy happends and how You want it to be.

The piezo buzzer doesn't play the tone, everything else works. So when you press the button the servo rotates but the piezo should start playing a tone as well but doesn't. I'm trying to apply Millis so that both can run at the same time but it doesn't work.

      for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees

// in steps of 1 degree
  myservo.write(pos);              // tell servo to go to position in variable 'pos'
  delay(15);                       // waits 15ms for the servo to reach the position
}
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
  myservo.write(pos);              // tell servo to go to position in variable 'pos'
  delay(15);                       // waits 15ms for the servo to reach the position
}

Apart from the poor indenting (use auto-format; it is very good) this piece of code will totally lock up your Arduino and make it unresponsive while the servo moves. Is that what you want?

unsigned int interval1 = 100;

unsigned int interval2 = 150;
unsigned int interval3 = 200;
unsigned int interval4 = 300;
unsigned int interval5 = 550;
unsigned int interval6 = 575;

Any time you have numbers in your variable names you should consider using arrays. Read the Ardiino reference on arrays.

if (timeElapsed > interval2) {

tone(piezoPin,660,100);
timeElapsed = 0;
}

Since you reset the timeElapsed back to zero, how will it ever get bigger than the first interval? It would* always cylcle.from 0 to 150.

*"Would" because you put all of that code inside the if statement which detected that the button changed. After it changed once, when elapsed time was zero, then you never go back into this section to check any other elapsed time.

That would be easier to see if you used auto-format.

More to come...

Thank you for the feedback! My coding is indeed messy, didn't know about the auto formatting option so that's good to know now. I also read the references so I'm using an array instead.

I've changed the ifs to an == statement now so that the timeElapsed can still be set back to 0. When this happens I can still use separate if's right and not nest them or? However I tried both and it is still not working. At least my code looks more readable now.

#include <elapsedMillis.h>
elapsedMillis timeElapsed;//declare global if you don't want it reset every time loop runs
unsigned int myArray[6] = {100, 150, 200, 300, 550, 575};

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards


// constants won't change. They're used here to set pin numbers:
const int buttonPin = D3;     // the number of the pushbutton pin
const int piezoPin =  D8;      // the number of the piezo

// variables will change:
int piezoState = LOW;
int buttonState;         // variable for reading the pushbutton status
int lastButtonState = LOW;   // the previous reading from the input pin

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  // initialize the piezo pin as an output:
  pinMode(piezoPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);

  myservo.attach(D5);  // attaches the servo on

  // set initial piezo state
  digitalWrite(piezoPin, piezoState);

  Serial.begin(115200);
}

void loop() {
  // read the state of the pushbutton into a local value:
  int reading = digitalRead(buttonPin);

  int pos;

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only play music if the new button state is HIGH
      if (buttonState == HIGH) {

        Serial.println(buttonState);

        for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
          // in steps of 1 degree
          myservo.write(pos);              // tell servo to go to position in variable 'pos'
          delay(15);                       // waits 15ms for the servo to reach the position
        }
        for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
          myservo.write(pos);              // tell servo to go to position in variable 'pos'
          delay(15);                       // waits 15ms for the servo to reach the position
        }

        //tones van https://gist.github.com/gskielian/6135641
        tone(piezoPin, 660, 100);
        if (timeElapsed == myArray[2]) {
          tone(piezoPin, 660, 100);
          timeElapsed = 0;
        }
        if (timeElapsed == myArray[4]) {
          tone(piezoPin, 660, 100);
          timeElapsed = 0;
        }
        if (timeElapsed == myArray[2]) {
          tone(piezoPin, 510, 100);
          timeElapsed = 0;
        }
        if (timeElapsed == myArray[2]) {
          tone(piezoPin, 510, 100);
          timeElapsed = 0;
        } if (timeElapsed == myArray[1]) {
          tone(piezoPin, 660, 100);
          timeElapsed = 0;
        } if (timeElapsed == myArray[4]) {
          tone(piezoPin, 770, 100);
          timeElapsed = 0;
        } if (timeElapsed == myArray[5]) {
          tone(piezoPin, 380, 100);
          timeElapsed = 0;
        } if (timeElapsed == myArray[6]) {
          tone(piezoPin, 510, 100);
          timeElapsed = 0;
        }

        //delay(450);
        //tone(piezoPin,380,100);
        //delay(400);
        //tone(piezoPin,320,100);
        //delay(500);
        //tone(piezoPin,440,100);
        //delay(300);
        //tone(piezoPin,480,80);
        //delay(330);
        //tone(piezoPin,450,100);
        //delay(150);
        //tone(piezoPin,430,100);
        //delay(300);
        //tone(piezoPin,380,100);
        //delay(200);
        //tone(piezoPin,660,80);
        //delay(200);
        //tone(piezoPin,760,50);
        //delay(150);
        //tone(piezoPin,860,100);
        //delay(300);
        //tone(piezoPin,700,80);
        //delay(150);
        //tone(piezoPin,760,50);
        //delay(350);
        //tone(piezoPin,660,80);
        //delay(300);
        //tone(piezoPin,520,80);
        //delay(150);
        //tone(piezoPin,580,80);
        //delay(150);
        //tone(piezoPin,480,80);
        //delay(500);
        //
        //tone(piezoPin,510,100);
        //delay(450);
        //tone(piezoPin,380,100);
        //delay(400);
        //tone(piezoPin,320,100);
        //delay(500);
        //tone(piezoPin,440,100);
        //delay(300);
        //tone(piezoPin,480,80);
        //delay(330);
        //tone(piezoPin,450,100);
        //delay(150);
        //tone(piezoPin,430,100);
        //delay(300);
        //tone(piezoPin,380,100);
        //delay(200);
        //tone(piezoPin,660,80);
        //delay(200);
        //tone(piezoPin,760,50);
        //delay(150);
        //tone(piezoPin,860,100);
        //delay(300);
        //tone(piezoPin,700,80);
        //delay(150);
        //tone(piezoPin,760,50);
        //delay(350);
        //tone(piezoPin,660,80);
        //delay(300);
        //tone(piezoPin,520,80);
        //delay(150);
        //tone(piezoPin,580,80);
        //delay(150);
        //tone(piezoPin,480,80);
        //delay(500);
        //
        //tone(piezoPin,500,100);
        //delay(300);
        //
        //tone(piezoPin,760,100);
        //delay(100);
        //tone(piezoPin,720,100);
        //delay(150);
        //tone(piezoPin,680,100);
        //delay(150);
        //tone(piezoPin,620,150);
        //delay(300);
        //
        //tone(piezoPin,650,150);
        //delay(300);
        //tone(piezoPin,380,100);
        //delay(150);
        //tone(piezoPin,430,100);
        //delay(150);
        //
        //tone(piezoPin,500,100);
        //delay(300);
        //tone(piezoPin,430,100);
        //delay(150);
        //tone(piezoPin,500,100);
        //delay(100);
        //tone(piezoPin,570,100);
        //delay(220);
        //
        //tone(piezoPin,500,100);
        //delay(300);
        //
        //tone(piezoPin,760,100);
        //delay(100);
        //tone(piezoPin,720,100);
        //delay(150);
        //tone(piezoPin,680,100);
        //delay(150);
        //tone(piezoPin,620,150);
        //delay(300);
        //
        //tone(piezoPin,650,200);
        //delay(300);
        //
        //tone(piezoPin,1020,80);
        //delay(300);
        //tone(piezoPin,1020,80);
        //delay(150);
        //tone(piezoPin,1020,80);
        //delay(300);
        //
        //tone(piezoPin,380,100);
        //delay(300);
        //tone(piezoPin,500,100);
        //delay(300);
        //
        //tone(piezoPin,760,100);
        //delay(100);
        //tone(piezoPin,720,100);
        //delay(150);
        //tone(piezoPin,680,100);
        //delay(150);
        //tone(piezoPin,620,150);
        //delay(300);
        //
        //tone(piezoPin,650,150);
        //delay(300);
        //tone(piezoPin,380,100);
        //delay(150);
        //tone(piezoPin,430,100);
        //delay(150);
        //
        //tone(piezoPin,500,100);
        //delay(300);
        //tone(piezoPin,430,100);
        //delay(150);
        //tone(piezoPin,500,100);
        //delay(100);
        //tone(piezoPin,570,100);
        //delay(420);
        //
        //tone(piezoPin,585,100);
        //delay(450);
        //
        //tone(piezoPin,550,100);
        //delay(420);
        //
        //tone(piezoPin,500,100);
        //delay(360);
      }
    }
  }

  // set the LED:
  digitalWrite(piezoPin, piezoState);

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}

Dealing with time == is not always safe. Use >= or <= instead.

The way to fix this is to learn about a concept called "state machine." Basically the state machine remembers where it is up to so it knows where to go next. Your program is going to end up with 3 state machines in it, maybe more.

You already have the button debounce working. That is a state machine. Let's work through it, discovering what states it has.

int buttonState;         
int lastButtonState = LOW;   
unsigned long lastDebounceTime = 0;  
unsigned long debounceDelay = 50;   

void loop() {
 int reading = digitalRead(buttonPin);
 if (reading != lastButtonState) {
   lastDebounceTime = millis();
 }

 if ((millis() - lastDebounceTime) > debounceDelay) {
   if (reading != buttonState) {
     buttonState = reading;
     if (buttonState == HIGH) {
       doSomething();
     }
   }
 }
 lastButtonState = reading;
}

Now you need a blank sheet of paper and a pen or pencil. Seriously. This diagram we are about to draw cannot be drawn on the computer screen. We are working backwards to make a state diagram from the code. Usually you would draw the state diagram first and then write the code. We will do that for the servo next but I want to get this diagram-drawing process first.

"State" here is memory. What does this snippet of code remember about what happened before? Look at the global variables: buttonState and lastButtonState. You also have time: very important. The first state to draw on the paper is the "Not Pressed" state when both the globals are LOW. Write that in the middle of the blank page and draw a box around it.

States are going to be boxes in this diagram. The next important concept is the state transitions. What will cause it to leave one box and move to another one? The state transitions will be drawn as arrows between the boxes. Each arrow will have a note next to it describing what happened to make it leave that state.

Obviously pressing the button is going to leave the "Not Pressed" state and move to a "Pressed" state. Reading through the code, the temporary variable reading is HIGH, the timer gets reset and the lastButtonState is set to HIGH. buttonState is still LOW at this point. So draw that in a box on your page and draw the arrow with a little note next to it saying "button pressed".

loop() will repeat thousands of times per second. This is a simple one so maybe hundreds of thousands of times per second. It reads the digital input, compares it to lastButtonState and checks the time. Let's assume this is a regular button push and it is held down for long enough. After 50 milliseconds, we have another state transition. Draw an arrow leading out of this box and label it "50ms" or whatever makes sense to you. The new state needs a name: let's call it "Held Down". In this state, both lastButtonState and buttonState are HIGH.

This is also when we doSomething(). Notice that this is inside the if (reading != buttonState) block. We only do something on the transition. While we remain in the state with the button held down, we don't do anything except the normal job of loop() reading the input and comparing that to its state variables.

The next transition is when the button is released. lastButtonState will go to LOW but buttonState doesn't immediately change. So this is a different state to the starting state. Draw another box and name it "Released". This also has a 50ms timer, which is the transition that will take us back to the initial "Not Pressed" state. The code you have doesn't do anything special on that transition.

Now we have all the main states on the page. We are missing some transitions. We didn't think about what happens if there are button bounces. In the Pressed state, what happens if the button is released before 50ms and lastButtonState goes LOW? That matches the NotPressed state, both state variables are LOW.

There is also a transition from Released back to Held Down, if the button contact is broken for less than 50ms.

I think that completes the state diagram for the button drbouncer: 4 states and 6 transition arrows. It seems kind of complex for just a button that does one action but real physical buttons require that complexity.

Your next state machines are more complex but when you have boxes and arrows on the page, it should look pretty simple. I'll put that in another post.

Railroader:
Dealing with time == is not always safe. Use >= or <= instead.

True.

Worse, it still has the same problem. How can it reach 200 without passing through 150?

myArray[] is a silly name. What does this actually contain? Note durations? Then call it noteDurations[]. The note values or pitches will go into an array too.

Ok. Two state machines to go. The music one is slightly simpler so I will guide you through that. For now, remove the servo code so there is absolutely no delay() anywhere in loop().

So what states does the music state machine have? It can be playing music or it can be not-playing while it waits for the button to be pressed. So draw 2 state boxes on a fresh sheet of paper and two transitions: button-pressed and music-finished.

Are we done? Not quite. Inside the Playing state, we need to keep track of which note we are playing and how long we have been playing it. That way we will know when to transition to playing the next note. Sounds like a state machine yet?

There must be a variable to keep track of what note we are on. Maybe call it melodyPosition. Then you can write something like...

if(playing) {
    if(timeElapsed > noteDuration[melodyPosition]) {
    melodyPosition++;
    timeElapsed=0;
    tone(piezoPin, noteValue[melodyPosition]);
  }
}

Forehead-slappingly simple isn't it? There is no longer any problems with counting up to 200 because we only compare the timer with the current duration we are waiting for.

So why the long post about drawing diagrams? Well this simple code does have two problems. First, what starts the first note (at melodyPosition 0)? And what stops the last note playing and sets the playing variable to false? It is those transition arrows that do the real "actions" of the state machine.

Do you want to have a go at this yourself?

The servo state machine can be completed after the music is working. Or before. While all the code is balled up in loop() the different state variables mean that the state macines can work independently. loop() loops thousands of times per second so it can do one transition for one state machine less than a millisecond after it serviced a different state machine.

The servo seems to just extend and retract. Once again there will be a Wait state like the music machine has Not Playing. Wait, Extend, Retract seems pretty simple. As soon as it has finished extending it retracts right away without waiting for anything. Or should it wait for the music to finish? Maybe it starts retracting after melodyPosition 17 has played? You can do what you want.

Within the extension and retraction there are 180 little states. But the delays are all the same so you don't need arrays. You just need to keep your own timer variable for this purpose.

This is a good time to learn about enum and switch-case. Instead of remembering that state 3 is the wait-before-retract state, you can give the states names and the compiler can check that you got the names right.

enum ServoStates {Wait, Extend, Retract} servoState;

switch(servoState) {
  case Wait:
     if(servoStartCommand) {
       servoState = Extend;
       pos=ServoRetractedPosition;
       servoTimer=millis();
       myservo.write(pos);
     }
     break;
  case Extend:
    if(millis() - servoTimer > servoExtendInterval) {
      servoTimer = millis();
      pos++;
      if(pos >= ServoMaxExtendPosition) {
        servoState = Retract;
      } else {
        myservo.write(pos);
      }
    }
    break;
  case Retract:
    if(millis() - servoTimer > servoExtendInterval) {
      servoTimer = millis();
      pos--;
      if(pos <= ServoRetractedPosition) {
        servoState = Wait;
        servoStartCommand = false;
      } else {
        myservo.write(pos);
      }
    }
    break;
}

You may notice that I wrapped this inside another state machine. servoStartCommand is another state machine. It is a global variable which remembers something so that is what makes it a state variable. It simplifies communication between the main loop and this little snippet.

You can see that when a start is requested, there are a lot of little things to set up to begin the servo movement. It gets very messy if your button debouncer is doing that. So this snippet could be put into its own function, maybe even into a library. The main loop only needs to know how to command a start; it doesn't need to know how the servo works internally.

The main loop can also watch that variable to find out when the servo finishes. It doesn't need to know how the internal states of extend and retract work. Maybe that variable going to false starts a state transition for another state machine.

You can add other commands and other state transitions. Maybe there is an emergency-stop or a idiot-pressed-the-button-during-a-song-so-we-have-to-restart?

Thanks for the detailed explanation! I have drawn the drawings, I think I get it more now but it's still confusing since I have never coded before. But I tried to apply it in my own code and this is what I have now. I have these new arrays:

unsigned int noteDuration[6] = {100, 150, 200, 300, 550, 575};
unsigned int toneFrequency[8] = {660, 660, 660, 510, 660, 770, 380, 510};
unsigned int toneDuration[8] = {100, 100, 100, 100, 100, 100, 100, 100};

As for when to start the first note isn't adding an int melodyPosition = 0; not enough? For when the music is finished I saw noTone() in the examples so I don't know if that is a way to stop the music from playing on a pin? I also didn't know where to declare the state (playing) in my code and what I should put in it.. I'm sorry I'm really a noob and beginner in this :frowning: Thank you so much for helping!!

void loop() {
  // read the state of the pushbutton into a local value:
  int reading = digitalRead(buttonPin);

//  int pos;

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only play music if the new button state is HIGH
      if (buttonState == HIGH) {

        Serial.println(buttonState);

        int melodyPosition = 0;

        if(playing) {
          if(timeElapsed > noteDuration[melodyPosition]) {
            melodyPosition++;
            timeElapsed=0;
            tone(piezoPin, toneFrequency[melodyPosition], toneDuration[melodyPosition]);

            noTone(piezoPin);
          }
        }
    }
  }

  // set the LED:
  digitalWrite(piezoPin, piezoState);

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}