Skip to main content
+ button scanning.
Source Link
Edgar Bonet
  • 45.2k
  • 4
  • 42
  • 81

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.

#includeint "pitches.h"current_button;
uint32_t note_started;
const
void uint8_tloop() speaker_pin{
 = 3;
const int note_count// =Adjust 4;the notes on button presses.
const    for (int pitches[note_count]button = {0; NOTE_B1,button NOTE_C2,< NOTE_CS2,N_BUTTONS; NOTE_D2button++) };{
const int note_duration = 1000;
    if (digitalRead(button_pins[button])) {
int current_note = note_count;         // whatAs notewe ishave currently78 playingpitches we divide the max Potentiometer
uint32_t note_started;           // whenvalue theby note77. startedThis playing
equals 13.
void setup           Pitches[button] = analogRead(A0){}
/13;
void loop() {
    uint32_t now     Durations[button] = millisanalogRead(A1);*4;
        }
    }

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

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

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

        // Play the note.
        tone(speaker_pinspeakerPin, 
 pitches[current_note]               Pitches[current_button], Durations[current_button]);

        // Take note of when this started.
        note_started = now;
    }
}

Note that tune() is called with no duration parameter: the note is going to be overridden by the next one anyway. You could add a duration shorter than note_duration if you want to have a small silence between consecutive notes.

You could also have different durations for different notes: store the durations in an array, then replace note_duration by duration[current_note].

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:

#include "pitches.h"

const uint8_t speaker_pin = 3;
const int note_count = 4;
const int pitches[note_count] = { NOTE_B1, NOTE_C2, NOTE_CS2, NOTE_D2 };
const int note_duration = 1000;

int current_note = note_count;  // what note is currently playing
uint32_t note_started;          // when the note started playing

void setup(){}

void loop() {
    uint32_t now = millis();

    // Are we done with the current note?
    if (now - note_started >= note_duration) {

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

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

        // Play the note.
        tone(speaker_pin, pitches[current_note]);

        // Take note of when this started.
        note_started = now;
    }
}

Note that tune() is called with no duration parameter: the note is going to be overridden by the next one anyway. You could add a duration shorter than note_duration if you want to have a small silence between consecutive notes.

You could also have different durations for different notes: store the durations in an array, then replace note_duration by duration[current_note].

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;
    }
}
Source Link
Edgar Bonet
  • 45.2k
  • 4
  • 42
  • 81

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:

#include "pitches.h"

const uint8_t speaker_pin = 3;
const int note_count = 4;
const int pitches[note_count] = { NOTE_B1, NOTE_C2, NOTE_CS2, NOTE_D2 };
const int note_duration = 1000;

int current_note = note_count;  // what note is currently playing
uint32_t note_started;          // when the note started playing

void setup(){}

void loop() {
    uint32_t now = millis();

    // Are we done with the current note?
    if (now - note_started >= note_duration) {

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

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

        // Play the note.
        tone(speaker_pin, pitches[current_note]);

        // Take note of when this started.
        note_started = now;
    }
}

Note that tune() is called with no duration parameter: the note is going to be overridden by the next one anyway. You could add a duration shorter than note_duration if you want to have a small silence between consecutive notes.

You could also have different durations for different notes: store the durations in an array, then replace note_duration by duration[current_note].