1

I was hoping anyone could help me with my problem.

I am trying to play a sequence of tones without using delay. So I am relying on millis(). However I have not been successful yet and after reading multiple tutorials about using millis(), I could not find one that covers sequencies of events. What I am trying to do is the following:

  • Play a tone1 for 1 s
  • After 1 second (duration which tone 1 is played) play tone 2
  • After 1 second (duration which tone 2 is played) play tone 3
  • After 1 second (duration which tone 3 is played) play tone 4

With the current code I have, everything seems to be played at the same time and not really considering my IF statements.

Code:

#include "pitches.h"

int notes[]={
NOTE_B1,
NOTE_C2,
NOTE_CS2,
NOTE_D2,
NOTE_DS2,
NOTE_E2,
NOTE_F2,
NOTE_FS2,
NOTE_G2,
NOTE_GS2,
NOTE_A2,
NOTE_AS2,
NOTE_B2, 
NOTE_C3, 
NOTE_CS3,
NOTE_D3, 
NOTE_DS3,
NOTE_E3, 
NOTE_F3,
NOTE_FS3,
NOTE_G3, 
NOTE_GS3, 
NOTE_A3,  
NOTE_AS3, 
NOTE_B3,  
NOTE_C4,  
NOTE_CS4, 
NOTE_D4,  
NOTE_DS4, 
NOTE_E4,  
NOTE_F4,  
NOTE_FS4, 
NOTE_G4,  
NOTE_GS4, 
NOTE_A4,  
NOTE_AS4, 
NOTE_B4,  
NOTE_C5,  
NOTE_CS5, 
NOTE_D5,  
NOTE_DS5, 
NOTE_E5,  
NOTE_F5,  
NOTE_FS5, 
NOTE_G5,  
NOTE_GS5, 
NOTE_A5,  
NOTE_AS5, 
NOTE_B5,  
NOTE_C6,  
NOTE_CS6, 
NOTE_D6,  
NOTE_DS6, 
NOTE_E6,  
NOTE_F6,  
NOTE_FS6, 
NOTE_G6,  
NOTE_GS6, 
NOTE_A6,  
NOTE_AS6, 
NOTE_B6,  
NOTE_C7,  
NOTE_CS7, 
NOTE_D7,  
NOTE_DS7, 
NOTE_E7,  
NOTE_F7,  
NOTE_FS7, 
NOTE_G7,  
NOTE_GS7, 
NOTE_A7,  
NOTE_AS7, 
NOTE_B7,  
NOTE_C8, 
NOTE_CS8,
NOTE_D8,  
NOTE_DS8
};

int speakerPin = 3;

 #define N_BUTTONS 8


int button_pins[N_BUTTONS] = {6, 7, 8, 9, 10, 11, 12, 13}; // Putting button_pins into an array

int Pitches[N_BUTTONS] = {0}; // Define array to hold the pitch. Setting it to 0.

long Durations[N_BUTTONS]; // Define array to hold the duration of the note. Setting it to 500.

unsigned long startMillis;
unsigned long startMillis_2;
unsigned long startMillis_3;
unsigned long startMillis_4;
unsigned long currentMillis;
unsigned long period = 1000;



void setup() {

Serial.begin(9600);

for(int pin : button_pins) pinMode(pin, INPUT); // Define the input pins for button_pins

startMillis = millis();

}



void loop() {

for (int button=0; button<N_BUTTONS ; button++){
  if(digitalRead(button_pins[button])){
    Pitches[button] = analogRead(A0)/13;   // As we have 77 pitches we divide the max Potentiometer value by 77. This equals 13.
    Durations[button] = analogRead(A1)*4;
   }
  }
////////////////////OUTPUT CODE////////////////////Sound generation code /////////////////////////////////

unsigned long currentMillis = millis(); // Gets the current time

if (currentMillis - startMillis >= period)  // Start event after 1 second
  {  
  tone(speakerPin, notes[Pitches[0]], period); 
  Serial.print("pitch1= ");
  Serial.println(Pitches[0]);
  Serial.print("duration1= ");
  Serial.println(period);
  Serial.print("millis = ");
  Serial.println(currentMillis);
  startMillis_2 = currentMillis;   // Saves the current time into the variable
  Serial.print("startMillis_2 = ");
  Serial.println(startMillis_2);
  }


if (currentMillis - startMillis_2 >= period) 
  {
  tone(speakerPin, notes[Pitches[1]], period); 
  Serial.print("pitch2= ");
  Serial.println(Pitches[1]);
  Serial.print("duration2= ");
  Serial.println(period);
  startMillis_3 = currentMillis;
  Serial.print("millis = ");
  Serial.println(currentMillis);
  Serial.print("startMillis_3 = ");
  Serial.println(startMillis_3);
  }


if (currentMillis - startMillis_3>= period) 
  {
  tone(speakerPin, notes[Pitches[2]], period); 
  Serial.print("pitch3= ");
  Serial.println(Pitches[2]);
  Serial.print("duration3= ");
  Serial.println(period);
  startMillis_4 = currentMillis;
  Serial.print("millis = ");
  Serial.println(currentMillis);
  Serial.print("startMillis_4 = ");
  Serial.println(startMillis_4);
  }

unsigned long startMillis_4;

if (currentMillis - startMillis_4 >= period) 
  {
  tone(speakerPin, notes[Pitches[3]], period); 
  Serial.print("pitch4= ");
  Serial.println(Pitches[3]);
  Serial.print("duration4= ");
  Serial.println(period);
  startMillis = currentMillis;
  Serial.print("millis = ");
  Serial.println(currentMillis);
  Serial.print("startMillis = ");
  Serial.println(startMillis);
  }

}

I have managed to get my code running on delay. It is working but I am very limited on what I can accomplish if I want more. I have read through all answers and comments but was still unable to get a millis() solution since my main problem was how to get tone 2 started and so on. I can get the first tone to play on a loop and correct intervals, but I am not understanding how to trigger the start of tone 2. Here is my code with delay. If anyone has can guide me to use millis() specially to trigger the start the tone 2, it would be very helpful.

EDIT. New Code:

#include "pitches.h"

int notes[]={
0,  
NOTE_B1,
NOTE_C2,
NOTE_CS2,
NOTE_D2,
NOTE_DS2,
NOTE_E2,
NOTE_F2,
NOTE_FS2,
NOTE_G2,
NOTE_GS2,
NOTE_A2,
NOTE_AS2,
NOTE_B2, 
NOTE_C3, 
NOTE_CS3,
NOTE_D3, 
NOTE_DS3,
NOTE_E3, 
NOTE_F3,
NOTE_FS3,
NOTE_G3, 
NOTE_GS3, 
NOTE_A3,  
NOTE_AS3, 
NOTE_B3,  
NOTE_C4,  
NOTE_CS4, 
NOTE_D4,  
NOTE_DS4, 
NOTE_E4,  
NOTE_F4,  
NOTE_FS4, 
NOTE_G4,  
NOTE_GS4, 
NOTE_A4,  
NOTE_AS4, 
NOTE_B4,  
NOTE_C5,  
NOTE_CS5, 
NOTE_D5,  
NOTE_DS5, 
NOTE_E5,  
NOTE_F5,  
NOTE_FS5, 
NOTE_G5,  
NOTE_GS5, 
NOTE_A5,  
NOTE_AS5, 
NOTE_B5,  
NOTE_C6,  
NOTE_CS6, 
NOTE_D6,  
NOTE_DS6, 
NOTE_E6,  
NOTE_F6,  
NOTE_FS6, 
NOTE_G6,  
NOTE_GS6, 
NOTE_A6,  
NOTE_AS6, 
NOTE_B6,  
NOTE_C7,  
NOTE_CS7, 
NOTE_D7,  
NOTE_DS7, 
NOTE_E7,  
NOTE_F7,  
NOTE_FS7, 
NOTE_G7,  
NOTE_GS7, 
NOTE_A7,  
NOTE_AS7, 
NOTE_B7,  
NOTE_C8, 
NOTE_CS8,
NOTE_D8,  
NOTE_DS8
};

int speakerPin = 3;

#define N_BUTTONS 8

// Input variables definitions

int button_pins[N_BUTTONS] = {6, 7, 8, 9, 10, 11, 12, 13}; // Putting button_pins into an array

int Pitches[N_BUTTONS] = {0}; // Define array to hold the pitch. Setting it to 0.

long Durations[N_BUTTONS]; // Define array to hold the duration of the note. Setting it to 500.


void setup() {

Serial.begin(9600);

for(int pin : button_pins) pinMode(pin, INPUT); // Define the input pins for button_pins


}

void loop() {
int tempo = analogRead(A2);
for (int button=0; button<N_BUTTONS ; button++){
  if(digitalRead(button_pins[button])){
    Pitches[button] = analogRead(A0)/13;   // As we have 78 pitches we divide the max Potentiometer value by 77. This equals 13.
    Durations[button] = (analogRead(A1)*4) + tempo;
   }
  }
////////////////////OUTPUT CODE////////////////////Sound generation code /////////////////////////////////
  for (int button=0; button <N_BUTTONS ; button++){
  tone(speakerPin, notes[Pitches[button]], Durations[button]);
  delay(tempo);
  Serial.print("Pitch");
  Serial.print(button);
  Serial.print(" = ");
  Serial.println(Pitches[button]);
  Serial.print("Duration");
  Serial.print(button);
  Serial.print(" = ");
  Serial.println(Durations[button]);
  Serial.println(tempo);
  }
}
4
  • take a close look at the if statements
    – jsotola
    Feb 15, 2020 at 18:40
  • your description of sequence of events is convoluted ... it is simply Play a tone1 for 1 s, Play a tone2 for 1 s, Play a tone3 for 1 s, Play a tone4 for 1 s
    – jsotola
    Feb 15, 2020 at 18:44
  • I am still very new at this. It would be easier to explain what I want like this: Play tone1 for 1s, after finishing playing start play tone 2 for 1s.... and so on. I still don't fully know how to use if statements.
    – Sushyoshi
    Feb 16, 2020 at 17:00
  • the if statement is fairly simple ... look at the expression inside the brackets () ... if that expresdion is true, then execute the commands that are inside the curly braces {}
    – jsotola
    Feb 16, 2020 at 18:09

2 Answers 2

1

You are overcomplicating the program. There is no point in remembering when each of the notes started. You just have to remember:

  • what note is currently playing
  • when you started playing this note

Then the logic of loop() becomes simply: “if we are done with the current note, then start playing the next one.” In code:

Edit: Changed the code to include your button-scanning loop.

int current_button;
uint32_t note_started;

void loop() {
    // Adjust the notes on button presses.
    for (int button = 0; button < N_BUTTONS; button++) {
        if (digitalRead(button_pins[button])) {
            // As we have 78 pitches we divide the max Potentiometer
            // value by 77. This equals 13.
            Pitches[button] = analogRead(A0)/13;
            Durations[button] = analogRead(A1)*4;
        }
    }

    // Are we done with the current note?
    uint32_t now = millis();
    int tempo = analogRead(A2);
    if (now - note_started >= Durations[current_button] + tempo) {

        // Then move to the next note.
        ++current_button;

        // Finished the tune?
        if (current_button == N_BUTTONS) {
            current_button = 0;  // then restart from the beginning
        }

        // Play the note.
        tone(speakerPin,
                Pitches[current_button], Durations[current_button]);

        // Take note of when this started.
        note_started = now;
    }
}
2
  • Thank you for your comment. I have taken some time to understand your code but I cannot understand how to adapt to my code. My pitches array is a variable dependent on a button and potentiometer. Each pitch played is selected my user input. Note duration also is an input variable with potentiometer and button. Take a look at my code below. I have provided the one using delays. Thank you.
    – Sushyoshi
    Feb 16, 2020 at 16:57
  • Thank you. Your code works as intended. although I would need to adjust some things like how to control the tempo, but overall this is a great solution.
    – Sushyoshi
    Mar 1, 2020 at 17:48
0

Your code falls through (skips over) the first “if” statement in the output code because its time period has not yet passed.

It then starts to use startMillis_2, which is not yet initialized (and may be any value), in the next “if”.

Initialization of startMillis_2 only happens inside the first “if” statement but that code has not yet been executed.

The same goes for startMillis_3 and 4.

But I think there’s something more fundamentally wrong with your code. You execute all “if” statements inside of a loop that is continuously repeated. There is no sequence. You have to make sure that tone 2 can only be started after tone 1, etcetera.

1
  • That is the point I am not able. How to make sure tone 2 only starts after tone1 finishes. I can achieve this goal with delay, but I will be very limited on my code. Right now my code is doing exactly what I wanted except the delays interfere with my potentiometers inputs. I have updated my code on my post.
    – Sushyoshi
    Feb 16, 2020 at 16:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.