Single Button Press limited by multiple conditions

Plan:

Single button press could activate something

There are several conditions ( maybe 10, like ‘be on home page’)

If all 3 required conditions are met → something can happen w/button press

If all 3 required conditions are not met → something else happens w/button press

Problem:
My current program works fine, but I am finding that with 10 conditions, all the if’s, ||'s, else’s, my program looks sloppy and verbose. If I write these conditions into switch case, I am still seeing similar verbose patterns.

Is there an alternative such as using a 2D array? I did search for other options…

Thx for any pointers

Here is my button press section out of my main loop (only a part of the main loop)

  //====== MAIN BUTTON CONTROL======

  plasmaButtonState = digitalRead(PLASMABUTTON);


  if ((plasmaButtonState == HIGH) && (currentPage == '0' ) && (currentMillis - startMillis < plasmaButtonTimer) && (turboVolumeRange > 0)) {
    if  (currentMillis - startMillis < plasmaBurnerTimer) {
      if (humState == 0) {
        humState = 1;
      }

      digitalWrite (READYLED, HIGH);
      digitalWrite (CHARGINGLED, LOW);
      neopixelShow();
      lastPlasmaButtonState = 1;

      if (selectLED == '0' ) {
        if (musicPlayer.stopped()) {
          musicPlayer.softReset();
          musicPlayer.startPlayingFile("RASMA.WAV"); // making new sound files
          Serial.println("RASMA.WAV");
        }
      }
      if (selectLED == '1' ) {
        if (musicPlayer.stopped()) {
          musicPlayer.softReset();
          musicPlayer.startPlayingFile("BLASMA.WAV");
          Serial.println("BLASMA.WAV");
        }
      }
      if (selectLED == '2' ) {
        if (musicPlayer.stopped()) {
          musicPlayer.softReset();
          musicPlayer.startPlayingFile("GRASMA.WAV");
          Serial.println("GRASMA.WAV");
        }
      }
      if (selectLED == '3' ) {
        if (musicPlayer.stopped()) {
          musicPlayer.softReset();
          musicPlayer.startPlayingFile("SPASMA.WAV");
          Serial.println("SPASMA.WAV");
        }
      }
    }
  }


  else  {
    startMillis = currentMillis;

    if ((selectLED != '0') || (selectLED != '1') || (selectLED != '2') || (selectLED != '3')) {
      if ((plasmaButtonState == LOW) && (currentPage == '0' ) && (humState == 1) || (turboVolumeRange == 0))  {
        digitalWrite (READYLED, LOW);
        digitalWrite (CHARGINGLED, HIGH);
      }
    }

    if ((selectLED == '0') || (selectLED == '1') || (selectLED == '2') || (selectLED == '3')) {
      if ((plasmaButtonState == LOW) && (currentPage == '0' ) && (humState == 1) || (turboVolumeRange > 0))  {
        digitalWrite (READYLED, HIGH);
        digitalWrite (CHARGINGLED, LOW);
      }
    }

    if  ((currentPage != '0' ) && (currentPage != '3')) {
      //digitalWrite (READYLED, LOW);
      digitalWrite (CHARGINGLED, HIGH);
    }


    if ((selectLED == '0') || (selectLED == '1') || (selectLED == '2') || (selectLED == '3')) {
      if ((plasmaButtonState == LOW) && (currentPage == '0' ) && (humState == 1))  {
        if (plasmaButtonState != lastPlasmaButtonState) {
          colorWipe(strip.Color (0 , 0, 0), 10);
          musicPlayer.stopPlaying();
          humState = 0;
          //Serial.print("humState  ");
          //Serial.println(humState);

          if ((musicPlayer.stopped()) && (humState == 0)) {
            musicPlayer.softReset();
            musicPlayer.startPlayingFile("SHUTDWN.WAV"); //SHUTDOWN.WAV is 1.3sec long
            digitalWrite (CHARGINGLED, HIGH);
            digitalWrite (READYLED, LOW);
            Serial.println("SHUTDWN.WAV");
            delay(1500);// needed or else the call to play HUM.WAV will be missed
          }

          if ((musicPlayer.stopped()) && (humState == 0)) {
            digitalWrite (READYLED, HIGH);
            digitalWrite (CHARGINGLED, LOW);
            playBackground();

          }
        }
      }
    }
  }
}

Sections like this, where a value just selects one of several options, could use an array:

      if (selectLED == '0' ) {
        if (musicPlayer.stopped()) {
          musicPlayer.softReset();
          musicPlayer.startPlayingFile("RASMA.WAV"); // making new sound files
          Serial.println("RASMA.WAV");
        }
      }
      if (selectLED == '1' ) {
        if (musicPlayer.stopped()) {
          musicPlayer.softReset();
          musicPlayer.startPlayingFile("BLASMA.WAV");
          Serial.println("BLASMA.WAV");
        }
      }
      if (selectLED == '2' ) {
        if (musicPlayer.stopped()) {
          musicPlayer.softReset();
          musicPlayer.startPlayingFile("GRASMA.WAV");
          Serial.println("GRASMA.WAV");
        }
      }
      if (selectLED == '3' ) {
        if (musicPlayer.stopped()) {
          musicPlayer.softReset();
          musicPlayer.startPlayingFile("SPASMA.WAV");
          Serial.println("SPASMA.WAV");
        }
      }
    }

All four ‘if’ statements can be reduced into one:

const char * WavNames[] = {"RASMA.WAV", "BLASMA.WAV", "GRASMA.WAV",  "SPASMA.WAV"};


    if (selectLED >= '0' && selectLED <= '3' ) 
    {
      if (musicPlayer.stopped()) 
      {
          musicPlayer.softReset();
          musicPlayer.startPlayingFile(WavNames[selectLED - '0']);
          Serial.println(WavNames[selectLED - '0']);
      }

    }

A couple of thoughts…

  1. You could implement this as a state machine. Draw a state diagram and figure out how you transition from one state to the next…

  2. You can put some of those tests in a function. For example, you test selectedLED a lot. If that test was a function, your if() statements would be shorted and probably more clear. For example

if ( checkLEDs() ) {...}

bool checkLEDs() {
  return (selectLED == '0') || (selectLED == '1') || (selectLED == '2') || (selectLED == '3'));
}
  1. You can also break your if() condidtions into multiple lines which adds readability
if (  (plasmaButtonState == HIGH) &&                             // comment about button
      (currentPage == '0' ) &&                                          // comment about page
      (currentMillis - startMillis < plasmaButtonTimer) &&    // elapsed time check
      (turboVolumeRange > 0)                                          // volume
   ) {

Also, this code

if ((selectLED != '0') || (selectLED != '1') || (selectLED != '2') || (selectLED != '3'))

will always be TRUE. Testing for NOT something usually is used it conjuntion with AND (&&) not OR (||).

Slightly different :wink:

You can use an array; the song you want to play can be indexed by selectedLed - ‘0’.

Place this above setup().

char songs[][13] =
{
  "RASMA.WAV",
  "BLASMA.WAV",
};

And an example loop()

void loop()
{
  // check if selectedLED is inside the number of songs
  if (selectLED >= '0' && (selectedLED - '0') < sizeof(songs) / sizeof(songs[0]))
  {
    if (musicPlayer.stopped())
    {
      musicPlayer.softReset();
      musicPlayer.startPlayingFile(songs[selectedLED - '0'); // making new sound files
      Serial.println(songs[selectedLED - '0'));
    }
  }
}

blh64:
A couple of thoughts....

  1. You could implement this as a state machine. Draw a state diagram and figure out how you transition from one state to the next..

This seems to be a good fit for a state machine. It solves exactly the kind of problem you're experiencing.

THX!! everyone for the info. I will try to write out some new code using your suggestions.