Mills-based buzzer music

I am woriking on a project where I need to contoll a buzzer to play music without using the delay(); command. I am using mills to do this. I have two libraries, one for the diffrent notes, and one for all the songs. When I upload and run the program it compiles but no sound is made. I have quadruple checked my hardware so I am shure this must be a software issue. Can somebody tell me what I have done wrong?

const int buzzerPin =     3;

int timeMS = 0;
int bcMusic = 0;

void setup() {
  pinMode(buzzerPin, OUTPUT);
}

int thisNote = 0; 
bool cooldown = 0;
int timerMax  = 0;

void playMelody(int melody[], int ND[]) {

  if ((thisNote < (sizeof(melody))) && (cooldown == 0)) {

    cooldown = 1;
    int noteDuration = ND[thisNote] * 500;

    tone(buzzerPin, melody[thisNote], 500);

    timerMax = (500 * 1.30) + timeMS;
    thisNote++;
  }
  if (timeMS >= timerMax) {
    cooldown = 0;
    if (thisNote > (sizeof(melody))){thisNote = 0;}
  }
}

void loop() {
  // put your main code here, to run repeatedly:

  timeMS = millis();  
  bcMusic = 1;
  playMelody(menueTheme, menueThemeND);
//menueTheme & menueThemeND (ND= note durations) are int lists defined in a seperate document
  
}
//

:+1: for using code tags!

Where are these defined?

Did you simply run 1 tone to your buzzer?
Only if that works, you can rule out hardware issues...

Timers should be unsigned int...
Or better: unsigned long int.

This will not properly rollover...
Use subtraction instead of addition...

if (curTime - lastTime > period)

Yes I have sucsessfully ran the tone command with a single tone. and here are the definitions:

int menueTheme[] = {
  NOTE_F3, 0, NOTE_C4, 0, NOTE_F3, 0, NOTE_G3, NOTE_A3, NOTE_B3, 0, NOTE_F4, NOTE_E4, NOTE_D4, 0, NOTE_C3, NOTE_D3, NOTE_E3, 0, NOTE_F4, 0, NOTE_F4, 0, NOTE_C3, 0, NOTE_F3, 0, NOTE_D3, 0, NOTE_C3
};

int menueThemeND[] = {
  0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5


#define NOTE_C3  131
#define NOTE_D3  147
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_G3  196
#define NOTE_A3  220
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_D4  294
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_G4  392
#define NOTE_A4  440
#define NOTE_B4  494
};


do I need to define curTime lastTime & period? in that case what format?

unsigned long int, is it written like this?

unsigned long int timeMS = 0;

void loop(){
   timeMS = millis();
}

Yes!

How you name those variable is up to you. But all should be unsigned long int

0.5 does not fit in an int. It will be rounded downward... to 0.

...

do I use float instead?

That would be able to hold the value 0.5....
You could also normalize the whole lot to integer numbers. That would save you 3 bytes per array element....

sounds good, Thanks for all the help I finally got it to work!!! (now to normalize to integer)
You are the best!

Great!

Tip for integer math:
Multiply first, then divide...

void playMelody(int melody[], int ND[]) {

  if ((thisNote < (sizeof(melody))) && (cooldown == 0)) {

This will not work like you think it will. It's stupid, but C++ treats unsized array types like this as pointers. sizeof(melody) will always be sizeof(int*), which I think is 2 on an Uno. You either need to explicitly pass the size of the array into the function or test for a special terminating value that you place at the end (like the null terminator in C-style strings).

timerMax = (500 * 1.30) + timeMS;

This math is going to introduce a constant dead time in between notes of 650 ms. Over half a second of silence in between every note. That's probably not what you wanted. More than likely, you want the silence to be a proportional amount to the note length, so this will need to rearrangement.

if ((thisNote < (sizeof(melody))) && (cooldown == 0)) {

    if (thisNote > (sizeof(melody))){thisNote = 0;}

What do you think will happen when thisNote is equal to sizeof(melody)?

The best way to do math is to make the computer do the match for you. You can make it do that for Just like you used #define for note frequency, you can use it for note durations as well.

Suppose 16th notes are the fastest you need. Here's how you can normalize things to an integer.

#define DOT(x) ((x) + ((x)/2))

#define NOTE_SIXTEENTH 1
#define NOTE_EIGTH (NOTE_SIXTEENTH*2)
#define NOTE_QUARTER (NOTE_EIGTH*2)
#define NOTE_HALF (NOTE_QUARTER*2)
#define NOTE_WHOLE (NOTE_HALF*2)

Note how you don't need to explicitly write the length of all the different notes, you can just reference them as double the previous one. The base case (Sixteenth = 1) is the only one you need to explicitly define, and everything else gets calculated off of that. The compiler will do that math for you to calculate that a whole note is 16 units long. You can even use a macro to DOT them for that extra 1.5 duration, like DOT(NOTE_QUARTER).

So each note is defined by how many 16th notes it is long. How long should a 16th note be played? Again, make the computer calculate it for you!

int bpm = whatever
unsigned long durationUnit = (60000UL / bpm / NOTE_QUARTER);

A good programmer is studiously lazy. Don't do work that you can make the computer do for you.

thank you so much! this is so much better! I like your quote btw "A good programer is studiously lazy." - Jiggy-Ninja, 2025