How to stop arduino in the middle of void loop

Hello, i have a sketch that play a sound from buzzer and lights up the led.
The code's like this:

#include <Tone.h>

Tone solo;
Tone bass;
Tone rythm;

const int buttonPin = 16;     // the number of the pushbutton pin
int buttonState = 0;         // variable for reading the pushbutton status

const int t = 650;  // quater note duration
const int tt = t*2;
const int t14 = round(t*1/4);
const int t24 = round(t*2/4);
const int t34 = round(t*3/4);

const int bassLedPin = 15;  // bass led signal pin (aka A1)
const int rythmLedPin = 17;  // rythm led signal pin (aka A3)
const int soloLedPin = 19;  // solo led signal pin (aka A5)

void wait(Tone t)
{
  while (t.isPlaying()) { }  
}

int bassLedState = random(120) < 80;
void switchBassLed()
{
  if (bassLedState == random(120) < 80)
    bassLedState = random(120) < 80;
  else
    bassLedState = random(120) < 80;
  digitalWrite(bassLedPin, random(120) < 80);
}

int rythmLedState = random(120) < 80;
void switchRythmLed()
{
  if (rythmLedState == random(120) < 80)
    rythmLedState = random(120) < 80;
  else
    rythmLedState = random(120) < 80;
  digitalWrite(rythmLedPin, random(120) < 80);
}

int soloLedState = random(120) < 80;
void switchSoloLed()
{
  if (soloLedState == random(120) < 80)
    soloLedState = random(120) < 80;
  else
    soloLedState = random(120) < 80;
  digitalWrite(soloLedPin, random(120) < 80);
}


void setup(void)
{ 
  // Switch ground reference
  pinMode(buttonPin, INPUT);
  
  pinMode(14, OUTPUT); // led ground pin (aka A0)
  pinMode(18, OUTPUT); // led ground pin (aka A4)
  pinMode(bassLedPin, OUTPUT);  // bass led signal pin
  pinMode(rythmLedPin, OUTPUT);  // rythm led signal pin
  pinMode(soloLedPin, OUTPUT);  // solo led signal pin

  pinMode(3, OUTPUT);  // solo buzzer ground pin
  pinMode(9, OUTPUT);  // rythm buzzer ground pin 

  solo.begin(6);  // solo buzzer signal pin
  bass.begin(0);  // bass buzzer signal pin
  rythm.begin(12);  // rythm buzzer signal pin

}



void loop(void)
{  buttonState = digitalRead(buttonPin);

if (buttonState == LOW){
solo.play(NOTE_D4, t34); switchSoloLed(); buttonState = digitalRead(buttonPin);
  wait(solo);
solo.play(NOTE_D4, t14); switchSoloLed();
  wait(solo);
bass.play(NOTE_D3, t); switchBassLed(); buttonState = digitalRead(buttonPin);
  rythm.play(NOTE_G4, t24); switchRythmLed();
        solo.play(NOTE_G4, t); switchSoloLed();
        wait(rythm);
  rythm.play(NOTE_B4, t14); switchRythmLed();
        wait(rythm);
  rythm.play(NOTE_D5, t14); switchRythmLed();
        wait(rythm); 
bass.play(NOTE_FS3, t); switchBassLed(); buttonState = digitalRead(buttonPin);
  rythm.play(NOTE_D5, t24); switchRythmLed();
        solo.play(NOTE_A4, t); switchSoloLed();
        wait(rythm);
        wait(rythm);
  rythm.play(NOTE_FS5, t14); switchRythmLed();
        wait(rythm);
  rythm.play(NOTE_A5, t14); switchRythmLed();
        wait(rythm);
else
        { digitalWrite(bassLedPin, LOW);
          digitalWrite(soloLedPin, LOW);
          digitalWrite(rythmLedPin, LOW);    
        buttonState = digitalRead(buttonPin);}
}

I want when the push button is pressed the buzzer stop plays a sound immediately, led off and the arduino do nothing until the arduino resetted. But when i tried push the button, the buzzer and the led stop when the buzzer finish the sound.
Can somebody help me with this?

Thanks

Well, don't wait until the tone has finished playing I guess?

void wait(Tone t)
{
  while (t.isPlaying()) { }  
}

Instead, check if the last tone has finished playing before enabling a new one.

LightuC:
Well, don't wait until the tone has finished playing I guess?

void wait(Tone t)

{
  while (t.isPlaying()) { } 
}



Instead, check if the last tone has finished playing before enabling a new one.

So i must add check button state in the "void wait" function?

Sorry I'm a newbie in this world

The trick is to keep loop() going. It should keep checking the inputs and making decisions thousands of times per second.

Most of those times the decision is not to change anything. But when a button becomes pressed or becomes released or the tune finished playing, then the output should change.

Currently after every call to play you call wait which will wait for the tone to finish playing. This stalls the arduino cpu, it is doing nothing else then waiting until the tone has finished playing. Because of this all the tones will finish playing, then it will reenter the loop and might find the button to be pressed and disables the led and tone (but they have finished playing anyways).

What you really should do (this involves a little more effort), is to queue up your tones. You can use the QueueArray library for that but your really should look into coding this yourself (also because most librarys use dynamic memory allocation, which should be avoided if possible).

Now if you have all the tones/notes or whatever queued up, in every iteration of the loop function you check the head of the queue for the tone to play. Then you check, if that tone has finished playing. If it has, you can remove it from the queue and start the next one. Now before you do all that you can check your button state and enable/disable the output pins accordingly

MorganS:
The trick is to keep loop() going. It should keep checking the inputs and making decisions thousands of times per second.

Most of those times the decision is not to change anything. But when a button becomes pressed or becomes released or the tune finished playing, then the output should change.

So i think i must add a function to check the input in every line right?

LightuC:
Currently after every call to play you call wait which will wait for the tone to finish playing. This stalls the arduino cpu, it is doing nothing else then waiting until the tone has finished playing. Because of this all the tones will finish playing, then it will reenter the loop and might find the button to be pressed and disables the led and tone (but they have finished playing anyways).

What you really should do (this involves a little more effort), is to queue up your tones. You can use the QueueArray library for that but your really should look into coding this yourself (also because most librarys use dynamic memory allocation, which should be avoided if possible).

Now if you have all the tones/notes or whatever queued up, in every iteration of the loop function you check the head of the queue for the tone to play. Then you check, if that tone has finished playing. If it has, you can remove it from the queue and start the next one. Now before you do all that you can check your button state and enable/disable the output pins accordingly

Wow its getting more complex. So i must use a QueueArray function? Is there any more simpler solution for that?

girifir:
So i think i must add a function to check the input in every line right?

No. If this is required you should reconsider your concept.

girifir:
Wow its getting more complex. So i must use a QueueArray function? Is there any more simpler solution for that?

You don't necessarily need to use a queue. Storing your tones in a simple array should also work. Your program might look something like this:

void loop()
{
    if (button is pressed)
    {
        disable tone
        disable led
        return
    }

    if (current tone has finished playing)
    {
        start next tone
    }
}

Here is the main loop from a very large Arduino program that took several years to write.

void loop() {
  checkInputs();
  doCalculations();
  setOutputs();
  doSerial();
}

Each of those functions is quite large but takes at most 2 milliseconds to run each time.