[Solved] Sound responsive code crashing at certain "else if" sound level

Hey all,

Trying to get my code up and running for my festival structure, but ran into an odd issue. When my sound levels get to 6 or higher the arduino (Mega 2560) starts to freeze/lockup for a moment. Could someone look over my code and see if there is something that jumps out at them. I have some unused animations at the bottom of my code for future potential modifications if I can get this to work. It works great at sound levels 5 and below.

void loop()
{
  //open void loop
  //first run the sound sampling
  unsigned long startMillis = millis(); // Start of sample window
  unsigned int peakToPeak = 0;   // peak-to-peak level

  unsigned int signalMax = 0;
  unsigned int signalMin = 1024;

  // collect data for 50 mS
  while (millis() - startMillis < sampleWindow)
  {
    //open while loop
    sample = analogRead(0);
    if (sample < 1024)  // toss out spurious readings
    {
      //open 1st if loop in while
      if (sample > signalMax)
      {
        //open 2nd if
        signalMax = sample;  // save just the max levels
      }//close 2nd if
      else if (sample < signalMin)
      {
        //open 3rd if
        signalMin = sample;  // save just the min levels
      }//close 3rd if
    }//close 1st if
  }//close while loop
  peakToPeak = signalMax - signalMin;  // max - min = peak-peak amplitude
  double volts = (peakToPeak * 3.3) / 1024;  // convert to volts

//section below maps the signal from the microphone on to 12 options for LED effects. Potentiometer alows for sound level sensitivity adjustment.
  float pot = (float)analogRead(4);
  int sound = 0;

  if (pot <= 100)
  {
  sound = (volts * 1);
  }
  else if (pot <= 200)
  {
  sound = (volts * 2);
  }
  else if (pot <= 300)
  {
  sound = (volts * 3);
  }
  else if (pot <= 400)
  {
  sound = (volts * 4);
  }
  else if (pot <= 500)
  {
  sound = (volts * 5);
  }
  else if (pot <= 600)
  {
  sound = (volts * 6);
  }
  else if (pot <= 700)
  {
  sound = (volts * 7);
  }
  else if (pot <= 800)
  {
  sound = (volts * 8);
  }
  else if (pot <= 900)
  {
  sound = (volts * 9);
  }
  else if (pot <= 1200)
  {
  sound = (volts * 10);
  }

  //int soundLevel = map(sound, 1, 10, 0, 11);
  int soundLevel = 6;

  Serial.print("The soundLevel is ");
  Serial.println(sound);
  Serial.println(soundLevel);

  int blankPixels = 1;

  int leftStart = 0;
  int leftLength = (NUM_LEDS / 3);

  int midStart = leftStart + leftLength + blankPixels;
  int midLength = (NUM_LEDS / 3) - blankPixels + 3;


  int rightStart = midStart + midLength + blankPixels;
  int rightLength = NUM_LEDS - rightStart - blankPixels + 3;

  if (soundLevel == 0 || soundLevel == -1)
  {
    //open if 0. When there is silence a rainbow pattern runs

     drawRainbow( leftStart, NUM_LEDS );
     EVERY_N_MILLISECONDS( 5 ) { gHue--; } // slowly cycle the "base color" through the rainbow

  }//close if 0 statement


  if (soundLevel == 1)
  {
    //open level 1 if statement which contains another rainbow cycle for low end

     drawRainbow( leftStart, NUM_LEDS );
     EVERY_N_MILLISECONDS( 1 ) { gHue--; } // slowly cycle the "base color" through the rainbow
  }//close if 1 statement
    [color=red]
 Removed levels 2-4 due to character limit[/color]


  else if (soundLevel == 5)
  {
    //open if sound level 5

    int level5Color = random(1, 5);

    if (level5Color == 1) //run red
    {
      //open option 1
      FastLED.clear();
      gHue = 48;
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );

    }//close option 1 red

    else if (level5Color == 2) //run green
    {
      //open option 2
      FastLED.clear();
      gHue = random(48,56);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );

    }//close option 2 green

    else if (level5Color == 3) //run blue
    {
      //open option 3
      FastLED.clear();
      gHue = random(56,64);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );
    }//close option 3 blue

    else if (level5Color == 4) //run yellow
    {
      //open option 4
      FastLED.clear();
      gHue = random(64,72);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );

    }//close yellow

    else if (level5Color == 5)
    {
      //open option 5
      FastLED.clear();
      gHue = random(48,72);
      theaterChase( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );

    }//close option 5

  }//close level 5


  else if (soundLevel == 6)
  {
    //open if soundlevel 6

    int level6Color = random(1, 5);

    if (level6Color == 1) //run red
    {
      //open option 1
      FastLED.clear();
      gHue = random(72,80);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );

    }//close option 1red

    else if (level6Color == 2) //run green
    {
      //open option 2
      FastLED.clear();
      gHue = random(80,88);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );
    }//close option 2 green

    else if (level6Color == 3) //run blue
    {
      //open option 3
      FastLED.clear();
      gHue = random(88,96);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );
    }//close option 3 blue

    else if (level6Color == 4) //run yellow
    {
      //open option 4
      FastLED.clear();
      gHue = random(96,104);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );
    }//close yellow

    else if (level6Color == 5)
    {
      //open option 5
      FastLED.clear();
      gHue = random(72,104);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      theaterChase( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );
    }//close option 5

  }//close if sound level 6

[color=red]*Removed levels 7-11 for character limit*[/color]

}//close void loop()

If anyone has a suggestion on additional ways to troubleshoot this I would love to hear that too.

Another_Beat_Try.ino (30.3 KB)

Hi,
Welcome to the forum.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Can you explain fully what your code is supposed to do?

Thanks.. Tom.. :slight_smile:

Many of us do not have the time or patience to download large sketches and look through and correct a large amount of code.

Please show us a down sized version of your sketch that still exhibits the same problems you are experiencing.
Since this is your sketch, you should be able to identify irrelevant lines of code and delete those lines.

Also, adding good comments to your code can make things infinitely easier for us to understand what your intentions are in the sketch.
Remember, formatting your sketch using or helps us to help you.

Pretty simple circuit so I hope a picture is sufficient. The output of the mic has a 100 mF capacitor on the output to the arduino.

The code takes samples of the of the microphone sound levels. I use a 10k potentiometer to adjust the sensitivity of the mic output. I then map the sound levels to a value of 1 to 11. Those lead to my sound level cases. Each level having a unique color hue that is output to an LED strip. It creates a sound response to the level of the music to look cool.

Here is a link to an example of the lower sound level response. https://www.instagram.com/p/BycEAoSgNEO/?utm_source=ig_web_copy_link

This works fine all the way through sound level 5. Once I set it manually to 6 it starts to crash even if I reduce my LED count.

Larryd,

Unfortunately I am not sure what line of code is the issue. The sound level 6 is the same basic code as sound level 5 with only a higher starting hue as I shift through the pattern. I am unsure if I am asking too much of the hardware to go through so many if statements when I am sampling the mic at around 20hz.

The commenting could be better and I intend to clean it up, but I am reaching a deadline and was hoping someone more experienced might be able to see a glaring flaw.

Try a adding a 10k resistor across the capacitor to see what happens.

sample = analogRead(0);
The above line of code can be commented out and then add the line below:
sample = 512; // this can be used to freeze a reading to 1/2 scale etc.
Use this technique in trouble shooting.

The capacitor between the mic module and the analogue pin makes things worse.
The analogue pin now doesn't have a DC reference, and signal could be clipping against "VCC +0.6volt" or "ground -0.6volt", resulting in unreliable peak/peak levels.

To get constant and max A/D values from this Adafruit MAX9814 module do this:

  1. Connect the mic output directly to the analogue input (no cap).

  2. Add this line to setup().

analogReference(INTERNAL2V56); // Mega only

The pot may now become a problem.
Best to power it from the 3.3volt pin instead of the 5volt pin.
Max pot level is now already reached at about 75%.
If that's a problem, then you must adjust the pot A/D value in the code.
Leo..

Hey Larry,

In the code I posted I actually took the Mic/Potentiometer out of the loop by manually setting my code via the following:

int soundLevel = 5;

So regardless of what the Mic is reading or the potentiometer is set to it should execute my:

 else if (soundLevel == 5)
  {
    //open if sound level 5

    int level5Color = random(1, 5);

    if (level5Color == 1) //run red
    {
      //open option 1
      FastLED.clear();
      gHue = 48;
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );

    }//close option 1 red

    else if (level5Color == 2) //run green
    {
      //open option 2
      FastLED.clear();
      gHue = random(48,56);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );

    }//close option 2 green

    else if (level5Color == 3) //run blue
    {
      //open option 3
      FastLED.clear();
      gHue = random(56,64);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );
    }//close option 3 blue

    else if (level5Color == 4) //run yellow
    {
      //open option 4
      FastLED.clear();
      gHue = random(64,72);
      setAll( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );

    }//close yellow

    else if (level5Color == 5)
    {
      //open option 5
      FastLED.clear();
      gHue = random(48,72);
      theaterChase( leftStart, leftLength, gHue ); 
      gHue += 60;
      setAll( midStart, midLength, gHue );
      gHue += 60;
      setAll( rightStart, rightLength, gHue );
    }//close option 5

  }//close level 5

So I have been manually testing each sound level and anything beyond 5 starts to crash on me. Thats why I was wondering if I was asking too much of my controller. But in thinking about it, I have a simple hue case at soundLevel 11 that worked. My thought is that it may be due to me adding to my existing hue levels and having some math issues?

uint16_t gHue = 0;//so I can have my code go over 255 in value

...

 else if (soundLevel == 11)

  {
    //open if sound Level 11
     drawRainbow( leftStart, NUM_LEDS );
     EVERY_N_MILLISECONDS( 1 ) { gHue--; } // slowly cycle the "base color" through the rainbow

  }//close if sound level 11

I know that its a crash/hang up as my serial monitor shows this when it is glitching out:

"The soundLe⸮The soundLev⸮T"

vs a functioning
"The soundLevel is 0
11
The soundLevel is 0
11"

Your calculations for dividing the LED strip into left, middle, and right segments are incorrect, resulting in addressing LEDs 0 to 218 in a strip of 216.

Reading analog input A4 into a float variable also seems meaningless, what you are using it for will easily work as an integer. The entire section where you are using the A4 input could be problematic for a few reasons, one being that volts can be as great as 3.3, making sound potentially as great as 33, which can give some unexpected results with the subsequent map function.

 float pot = (float)analogRead(4);
  int sound = 0;
  if (pot <= 100) {
    sound = (volts * 1);
  } else if (pot <= 200) {
    sound = (volts * 2);
  } else if (pot <= 300) {
    sound = (volts * 3);
  } else if (pot <= 400) {
    sound = (volts * 4);
  } else if (pot <= 500) {
    sound = (volts * 5);
  } else if (pot <= 600) {
    sound = (volts * 6);
  } else if (pot <= 700) {
    sound = (volts * 7);
  } else if (pot <= 800) {
    sound = (volts * 8);
  } else if (pot <= 900) {
    sound = (volts * 9);
  } else if (pot <= 1200) {
    sound = (volts * 10);
  }
  //int soundLevel = map(sound, 1, 10, 0, 11);
  int soundLevel = 6;

Thank you for your comments David. I changed my pot to an integer and I am not too concerned about out of range mappings as the potentiometer is there to help me get it into a fun range of color outputs.

I am 99% sure I am asking too much of my little Mega. I set my soundLevel to 7 and it became non responsive. I then manually chose my level 7 color and it started working. If I added extra theaterChase calls (i.e. on all three segments) it would then go back to glitchy behavior. And I just now realized my random function was set to exlude my last color case which typically housed my theaterChase calls.

Any suggestions on how I can streamline the code to free up more soundLevel cases? With a bunch of if statements, is it still doing all the random math even if the case isnt executed?

Have a look at your theaterChase function, you are exceeding the bounds of the LED strip, particularly in the latter part.

Don't have time tonight to look at it anymore.

Don’t convert pot A/D to voltage (you’re not building a voltmeter).
I would read the A/D value of the pot, and map it directly to 1-6 (or whatever is needed).
Then use ‘switch case’ on that mapped number to select the presets (instead of all the if else).
Leo…

That was it David. Thank you. Totally missed that. Its working so much better now.

Sorry for all the ignorance on the issues here guys. Thank you everyone for your assistance.

Something to play with.
Partially tested.
Leo…

const byte micPin = A0;
const byte potPin = A4; // pot connected to A4, 3.3volt, and ground
int rawValue, potValue;
int minValue, maxValue, ppValue;
int soundValue;
byte selected;

void setup() {
  Serial.begin(115200);
  analogReference(INTERNAL2V56); // Mega only
}

void loop() {
  minValue = 1023;
  maxValue = 0; // reset values
  rawValue = analogRead(micPin); // one dummy read to prevent possible pot<>mic cross-talk, just in case..
  for (int i = 0; i < 500; i++) { // 500 readings is about 20ms
    rawValue = analogRead(micPin);
    if (rawValue > maxValue) maxValue = rawValue;
    if (rawValue < minValue) minValue = rawValue;
  }
  ppValue = maxValue - minValue;
  potValue = analogRead(potPin) >> 6; // reduce to about 12 gain levels
  soundValue = ppValue * potValue;
  selected = constrain((soundValue >> 8), 1, 12);

  // prints and delay, remove after testing
  Serial.print("\nPeak/Peak A/D value: ");
  Serial.println(ppValue);
  Serial.print("Pot value: ");
  Serial.println(potValue);
  Serial.print("Sound value: ");
  Serial.println(soundValue);
  Serial.print("Selected: ");
  Serial.println(selected);
  delay(500);
}