2

Is there a method to play a Melody with Tone() without using the delay() function?

tone(8, melody[thisNote], noteDuration);
int pauseBetweenNotes = noteDuration;
**delay(pauseBetweenNotes);**
1
  • 2
    Yes. The same method as is used in the BlinkWithoutDelay example sketch.
    – Majenko
    Oct 31, 2015 at 12:14

3 Answers 3

4

As others have noted, this can be done using the same method as used in the standard 'BlinkWithoutDelay' example sketch, and combining that with a state-machine type approach. In a simple state machine you'd assume you can be in one of two states: outputting a tone, and not outputting a tone.

Applying these ideas to your code snippet above:

// BEFORE SETUP
const int tonePin = 8;
unsigned long previousMillis = 0;
const long interval = pauseBetweenNotes;
const long interval = noteDuration;
boolean outputTone = false;                // Records current state


// IN LOOP
unsigned long currentMillis = millis();

if (outputTone) {
// We are currently outputting a tone
// Check if it's been long enough and turn off if so
    if (currentMillis - previousMillis >= noteDuration) {
        previousMillis = currentMillis;
        noTone(tonePin);
        outputTone = false;
    }
} else {
// We are currently in a pause
// Check if it's been long enough and turn on if so
    if (currentMillis - previousMillis >= pauseBetweenNotes) {
        previousMillis = currentMillis;
        tone(tonePin, melody[thisNote]);
        outputTone = true;
    }
}
0
1

Adding a bit to kabdulla's great example, to be able to use a MelodyArray

// declaring variables
const int tonePin = 10;
unsigned long previousMillis = 0;
const long pauseBetweenNotes = 250;   // interval between notes (ms)
const long noteDuration = 400;        // (ms)
boolean outputTone = false;                // Records current state
const int MelodyLength = 2;
const int Melody[MelodyLength] = {880, 698};
int MelodyIndex = 0;
unsigned long currentMillis;



void setup() {
}

void loop() {
  currentMillis = millis();
  PlayMelody();
}

void PlayMelody() {
  if (outputTone) {
    // We are currently outputting a tone
    // Check if it's been long enough and turn off if so
    if (currentMillis - previousMillis >= noteDuration) {
      previousMillis = currentMillis;
      noTone(tonePin);
      outputTone = false;
    }
  } else {
    // We are currently in a pause
    // Check if it's been long enough and turn on if so
    if (currentMillis - previousMillis >= pauseBetweenNotes) {
      previousMillis = currentMillis;
      tone(tonePin, Melody[MelodyIndex]);
      outputTone = true;
      //Update to play the next tone, next time
      MelodyIndex = MelodyIndex + 1;
      if (MelodyIndex >= MelodyLength) {
        MelodyIndex = 0;
      }
    }
  }
}
1

this is a minimal modification of the basic Arduino toneMelody example to a non-blocking version

#include "pitches.h"

// notes in the melody:
int melody[] = {
  NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  4, 8, 8, 4, 4, 4, 4, 4
};

unsigned long previousMillis = 0;
unsigned long pauseBetweenNotes;
int thisNote;

void setup() {
}

void loop() {

  // iterate over the notes of the melody:
  unsigned long currentMillis = millis();
  if (thisNote < 8 && currentMillis - previousMillis >= pauseBetweenNotes) {
    previousMillis = currentMillis;

    // to calculate the note duration, take one second divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000 / noteDurations[thisNote];
    tone(8, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    pauseBetweenNotes = noteDuration * 1.30;
    
    thisNote++;
  }
}

Your Answer

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

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