Loop code inside Switch Case

I recognize that other people have asked similar questions to this, but have been unable to find help closely related enough to my particular issue.

I'm using an Arduino Mega to control a set of WS2812 LEDs (similar to Adafruit's Neopixels) via MIDI messages using a SparkFun MIDI Shield.

Depending on which MIDI NoteOn message the arduino receives, a different case is called which in turn either sets the LEDs to a certain color OR calls a function.

The problem is that with the MIDI Library, the switch-case statement is not in the void loop(); function, so the light functions requiring loop behavior (sparkle, chase, etc) do not behave properly. I would prefer to not have to rewrite all of the light functions to accommodate this.

Is there a way to loop the code inside each case until another case is called?

I'm relatively new to Arduino so please excuse me if this is too simple a question.

Attached is my code, I can simplify it if it will make the problem easier to see/solve.

Thanks,
Alex

Christmas_2015_Beta_2.ino (15.3 KB)

You can put a for loop or a while loop in there, but that would block the rest of your program. Best to refactor this entirely so that the cases just set a variable that lets the loop function know what to do. You could have a variable called whatToDo and each case could set it to a different value. Then loop could have another switch / case that looks at that variable and takes the appropriate action.

Thanks Delta_G! I'm going to go work on that now and see what I can come up with. I'll post my code in a bit.
Thanks a bunch.

It's all working great now!
Thanks again Delta_G.

I've attached the updated code.
(I tried using a for loop to list the cases and whatToDo variables in the MyNoteOnFunction but couldn't get it to work, so for now they're just listed out)

Here's the important part:

#include <MIDI.h>  // Add Midi Library
#include <FastLED.h> //include LED library

#define NUM_STRIPS 2
#define NUM_LEDS_DOWNSTAIRS 400
#define NUM_LEDS_UPSTAIRS 276
#define NUM_LEDS NUM_LEDS_UPSTAIRS+NUM_LEDS_DOWNSTAIRS
#define DATA_PIN_DOWNSTAIRS 8
#define DATA_PIN_UPSTAIRS 7
#define LED_TYPE WS2811
#define COLOR_ORDER BRG
#define MASTER_BRIGHTNESS 255
#define FRAMES_PER_SECOND 120
#define STARTING_BRIGHTNESS 64
#define FADE_IN_SPEED 32
#define FADE_OUT_SPEED 20
#define DENSITY 255

MIDI_CREATE_DEFAULT_INSTANCE();

int whatToDo;

CRGB leds[NUM_LEDS];

void setup() {
  MIDI.begin(1); //initialize the MIDI library
  MIDI.setHandleNoteOn(MyNoteOnFunction); // This command tells the MIDI Library
  // the function you want to call when a NoteOn command is received.
  FastLED.addLeds<LED_TYPE, DATA_PIN_DOWNSTAIRS, COLOR_ORDER>(leds, 0, NUM_LEDS_DOWNSTAIRS); //for correct LED strips
  FastLED.addLeds<LED_TYPE, DATA_PIN_UPSTAIRS, COLOR_ORDER>(leds, NUM_LEDS_DOWNSTAIRS, NUM_LEDS_UPSTAIRS);
  setupStripedPalette( CRGB::Red, CRGB::Red, CHSV(20, 200, 255), CHSV(20, 200, 255), CRGB::Green, CRGB::Green);
  //above is palette for redGreenWhiteChaser
}

void loop()
{
  MIDI.read(); // Continuously check if Midi data has been received.
  sequenceChooser();
}

void MyNoteOnFunction(byte channel, byte number, byte value)
{
  switch (number)
  {
          case 0: whatToDo = 0;
          break;
          case 1: whatToDo = 1;
          break;
          case 2: whatToDo = 2;
          break;
          case 3: whatToDo = 3;
          break;
          case 4: whatToDo = 4;
          break;
          case 5: whatToDo = 5;
          break;
          case 6: whatToDo = 6;
          break;
          case 7: whatToDo = 7;
          break;
          case 8: whatToDo = 8;
          break;
          case 9: whatToDo = 9;
          break;
          case 10: whatToDo = 10;
          break;
          case 11: whatToDo = 11;
          break;
          case 12: whatToDo = 12;
          break;
          case 13: whatToDo = 13;
          break;
          case 14: whatToDo = 14;
          break;
          case 15: whatToDo = 15;
          break;
          case 16: whatToDo = 16;
          break;
          case 17: whatToDo = 17;
          break;
          case 18: whatToDo = 18;
          break;
          case 19: whatToDo = 19;
          break;
          case 20: whatToDo = 20;
          break;
          case 21: whatToDo = 21;
          break;
          case 22: whatToDo = 22;
          break;
          case 23: whatToDo = 23;
          break;
          case 24: whatToDo = 24;
          break;
          case 25: whatToDo = 25;
          break;
          case 26: whatToDo = 26;
          break;
          case 27: whatToDo = 27;
          break;
          case 28: whatToDo = 28;
          break;
          case 29: whatToDo = 29;
          break;
          case 30: whatToDo = 30;
          break;
          case 31: whatToDo = 31;
          break;
          case 32: whatToDo = 32;
          break;
          case 33: whatToDo = 33;
          break;
          case 34: whatToDo = 34;
          break;
          case 35: whatToDo = 35;
          break;
          case 36: whatToDo = 36;
          break;
          case 37: whatToDo = 37;
          break;
          case 38: whatToDo = 38;
          break;
          case 39: whatToDo = 39;
          break;
          case 40: whatToDo = 40;
          break;
  }
}

void sequenceChooser()
{
  switch (whatToDo)
  {
    case 0:
      fill_solid(leds, NUM_LEDS, CRGB::Black);
      FastLED.show();
      break;
    case 1:
      fill_solid(leds, NUM_LEDS, CRGB::Red);
      FastLED.show();
      break;
    case 2:
      fill_solid(leds, NUM_LEDS, CRGB::Green);
      FastLED.show();
      break;
    case 3:
      fill_solid(leds, NUM_LEDS, CRGB::Blue);
      FastLED.show();
      break;
    case 4:
      fill_solid(leds, NUM_LEDS, CRGB::Orange);
      FastLED.show();
      break;
    case 5:
      fill_solid(leds, NUM_LEDS, CRGB::Cyan);
      FastLED.show();
      break;
    case 6:
      fill_solid(leds, NUM_LEDS, CRGB::Purple);
      FastLED.show();
      break;
    case 7:
      fill_solid(leds, NUM_LEDS, CRGB::White);
      FastLED.show();
      break;
    case 8:
      fill_solid(leds, NUM_LEDS, CHSV(20, 200, 255));
      FastLED.show();
      break;
    case 9:

      break;
    case 10:

      break;

    case 11:

      break;
    case 12:
      FastLED.setBrightness(150); //use to dim existing scene
      break;
    case 13:
      fill_solid(leds, NUM_LEDS, CRGB(100, 0, 255));
      FastLED.show();
      break;
    case 14:

      break;
    case 15:

      break;
    case 16:

      break;
    case 17:

      break;
    case 18:

      break;
    case 19:
      break;
    case 20:
      rainbow();
      break;
    case 21:
      rainbowWithGlitter();
      FastLED.show();
      break;
    case 22:
      confetti();
      FastLED.show();
      break;
    case 23:
      bpm();
      FastLED.show();
      break;
    case 24:
      juggle();
      FastLED.show();
      break;
    case 25:
      sinelon();
      FastLED.show();
      break;
    case 26:
      chooseColorPalette();
      colortwinkles();
      FastLED.show();
      break;
    case 27:
      redGreenWhiteChaser();
      FastLED.show();
      break;
    case 28:
      snowColorPalette();
      colortwinkles();
      FastLED.show();
      break;
    case 29:
      rgwPalette();
      colortwinkles();
      FastLED.show();
      break;
    case 30:
      blueWhitePalette();
      colortwinkles();
      FastLED.show();
      break;
    case 31:
      Sparkle();
      FastLED.show();
      break;
    case 32:
      hotSpotsBlue();
      FastLED.show();
      break;
    case 33:
      poinsettiasRed();
      FastLED.show();
      break;
    case 34:
      fill_solid(leds, NUM_LEDS, CRGB::Black);
      poinsettiasPoles();
      FastLED.show();
      break;
    case 35:
      angelsBlue();
      FastLED.show();
      break;
    case 36:
      classicChristmas();
      FastLED.show();
      break;
    case 37:
      fill_solid(leds, NUM_LEDS, CRGB::Black);
      poleAngelRotatingHue();
      FastLED.show();
      break;
  }
}

Christmas_2015_Beta_3.ino (17 KB)

You could have this in MyNoteOnFunction instead of a switch case if they're all going to be the same number:

whatToDo = number;

:disappointed_relieved:
Oh. Hahaha.
Thanks for taking the time to write that, especially considering how obvious it was.
Thanks!
Alex

I am having a slight problem now. Not sure if I'll be able to solve it.
Now that I have something other than "MIDI.read();" in the void loop, my arduino is missing some of the incoming MIDI messages, particularly while another function is running. I have eliminated all uses of "delay" and am still having the problem.

Is there any other way to have a function run on a loop until another case is called?

Right now the code in the loop looks like this:

void loop()
{
  MIDI.read(); // Continuously check if MIDI data has been received.
  sequenceChooser(); //choose light sequence
}

where "sequenceChooser();" references a switch case that chooses which lighting function to call, and "MIDI.read()" assigns the incoming note number to the variable "whatToDo".

As an example, I'd like to have the following function "loop" until another case is called via MIDI note number:

void Sparkle()
{
  unsigned long currentMillis = millis();

  int Pixel = random(NUM_LEDS);

  if (pixelState == LOW)
  {
    leds[Pixel] = CRGB::White;
    pixelState = HIGH;
    FastLED.show();
    if (currentMillis - previousMillis >= interval)
    {
      previousMillis = currentMillis;
      leds[Pixel] = CRGB::Black;
      pixelState = LOW;
      FastLED.show();
    }
    else
    {
      leds[Pixel] = CRGB::White;
      pixelState = HIGH;
      FastLED.show();
    }
  }
}

Any help would be much appreciated.

You don't want any function to loop. That means that particular function is doing its thing and all the rest of your code isn't running. You want to keep calling that function over and over and over again letting it take its next step if it is time to do so or doing nothing if it isn't. You keep calling that same function again and again until you want to change to calling a different function.

Post up the whole code like it is now and we'll see if we can't figure out the best way to do that.

You might have eliminated the delay function but you still have blocking code in that effects loop. You can put the MIDI.read call in multiple places you know and use flags to exit your effects code prematurely.

Okay, attached is the code the way it is now.

I'm using the MIDI MyNoteOnFunction to directly call the "static" light scenes and write the "whatToDo" variable for function "sequenceChooser" switch-case (for the functions that need to run in the loop).

I didn't think about putting the MIDI.read(); in multiple places. Hmm. Maybe I could put it in the functions that get called via the sequenceChooser function?

The functions I'm most concerned about are the "Sparkle" function, "redWhiteGreenChaser" function, and the "colortwinkles" function. I don't use very many of the other ones in my show at the moment, so even if I could get it working reliably with just these 3 and the solid colors, this would be a drastic improvement.

Thanks again for all of your guys help, it is very much appreciated.

Sorry I couldn't post the code directly; apparently it exceeds the length limit.

Christmas_2015_Beta_3.ino (15.5 KB)

Okay, everything seems to be working great now.

There is probably a more elegant way to achieve what I am doing but having all these extra MIDI.read(); calls seems to do the trick.

Thanks for your guys' help.

Alex

Attached is my latest code. Maybe later I'll post a picture of the final effect. :slight_smile:

Christmas_2015_Beta_3.ino (15.7 KB)