Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-Blocking Code #33

Open
tahunus opened this issue May 13, 2023 · 1 comment
Open

Non-Blocking Code #33

tahunus opened this issue May 13, 2023 · 1 comment

Comments

@tahunus
Copy link

tahunus commented May 13, 2023

Amazing work! Kudos!

I made some changes to your code to make it non-blocking: instead of delay statements for each note and program logic waiting for the song to end, my changes allow for program execution while the tunes are being played.

Also I added a flag that can stop tune playback before it ends (for example if program logic requires it).

I also added the option to have up to 10 tunes selectable either by user input or by program logic.

Thanks!

Note: I don't know how to upload programs into a reported issue other than presenting the full code using markup language, so I renamed the NonBlockingTunes.INO and the tunes.h files to .TXT so that they could be copied here.

NonBlockingTunes.txt
tunes.txt

@tahunus
Copy link
Author

tahunus commented May 13, 2023

Perhaps adding the code files here can assist in a visual tour.

const byte buzzPin = 12;
const byte buzzChan = 0; 
#include "tunes.h"

int tempo, notes, wholenote, divider, thisNote, noteDuration;
byte activeTune;
bool tuneIsOn, noteIsOn;
ulong elapsedNote;

void defineTunes() { 
  switch (activeTune) {
    case 0: tempo = 190; notes = sizeof(superMarioShort) / sizeof(superMarioShort[0]) / 2;    break;
    case 1: tempo = 170; notes = sizeof(darthVaderShort) / sizeof(darthVaderShort[0]) / 2;    break;
    case 2: tempo = 170; notes = sizeof(pinkPantherShort) / sizeof(pinkPantherShort[0]) / 2;  break;
    case 3: tempo = 190; notes = sizeof(superMarioFull) / sizeof(superMarioFull[0]) / 2;      break;
    case 4: tempo = 170; notes = sizeof(darthVaderFull) / sizeof(darthVaderFull[0]) / 2;      break;
    case 5: tempo = 170; notes = sizeof(pinkPantherFull) / sizeof(pinkPantherFull[0]) / 2;    break;
    case 6: tempo = 140; notes = sizeof(happybirthday) / sizeof(happybirthday[0]) / 2;        break;
    case 7: tempo = 114; notes = sizeof(odetojoy) / sizeof(odetojoy[0]) / 2;                  break;
    case 8: tempo = 122; notes = sizeof(lionsleeps) / sizeof(lionsleeps[0]) / 2;              break;
    case 9: tempo =  76; notes = sizeof(brahmslullaby) / sizeof(brahmslullaby[0]) / 2;        break;
  }
  wholenote = (60000 * 4) / tempo; //calculate the duration of a whole note in ms
  thisNote = 0;
  tuneIsOn = true;
  noteIsOn = false;
}

void chkOnTunes() {
  if (thisNote < notes * 2) { //  for (int thisNote = 0; thisNote < notes * 2; thisNote = thisNote + 2) {
    if (!noteIsOn) { // calculates the duration of each note
      switch (activeTune) {   //array is twice the number of notes (notes + durations)
        case 0: divider = superMarioShort[thisNote + 1];  break;
        case 1: divider = darthVaderShort[thisNote + 1];  break;
        case 2: divider = pinkPantherShort[thisNote + 1]; break;
        case 3: divider = superMarioFull[thisNote + 1];   break;
        case 4: divider = darthVaderFull[thisNote + 1];   break;
        case 5: divider = pinkPantherFull[thisNote + 1];  break;
        case 6: divider = happybirthday[thisNote + 1];    break;
        case 7: divider = odetojoy[thisNote + 1];         break;
        case 8: divider = lionsleeps[thisNote + 1];       break;
        case 9: divider = brahmslullaby[thisNote +1];     break;
      }
      if (divider > 0) noteDuration = (wholenote) / divider; // regular note, just proceed
      else if (divider < 0) { // dotted notes are represented with negative durations
          noteDuration = (wholenote) / abs(divider);
          noteDuration *= 1.5; // increases the duration in half for dotted notes
        }
      noteIsOn = true;
      elapsedNote = 0;
    } //end of calculation of note duration
    if (elapsedNote == 0) { //start to play note
      switch (activeTune) { 
        case 0: ledcWriteTone(buzzChan,superMarioShort[thisNote]);  break;
        case 1: ledcWriteTone(buzzChan,darthVaderShort[thisNote]);  break;
        case 2: ledcWriteTone(buzzChan,pinkPantherShort[thisNote]); break;
        case 3: ledcWriteTone(buzzChan,superMarioFull[thisNote]);   break;
        case 4: ledcWriteTone(buzzChan,darthVaderFull[thisNote]);   break;
        case 5: ledcWriteTone(buzzChan,pinkPantherFull[thisNote]);  break;
        case 6: ledcWriteTone(buzzChan,happybirthday[thisNote]);    break;
        case 7: ledcWriteTone(buzzChan,odetojoy[thisNote]);         break;
        case 8: ledcWriteTone(buzzChan,lionsleeps[thisNote]);       break;
        case 9: ledcWriteTone(buzzChan,brahmslullaby[thisNote]);    break;
      }
      elapsedNote = millis();
    }else{ // Wait for the specified duration before playing the next note
      if (millis() - elapsedNote >= noteDuration) { 
        ledcWriteTone(buzzChan,0); // stop the waveform generation before the next note
        noteIsOn = false;
        thisNote += 2;
      }
    }
  }else // tune has ended because thisNote > notes * 2
    tuneIsOn = false; 
}

void setup() //------------------------------------------------------------------SETUP
{
  pinMode(buzzPin, OUTPUT); 
  ledcSetup(buzzChan, 10000, 12); 
  ledcAttachPin(buzzPin, buzzChan);
  tuneIsOn = true; //flag to start or stop playback. To be used in program logic in loop()
  activeTune = 4; //number of Tune to play. Can be defined by user input or as program logic
  defineTunes();
}

void loop() //--------------------------------------------------------------------LOOP
{
  if (tuneIsOn) chkOnTunes();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant