Need to shrink my code from 6662 to 6012 bytes

I'm sure this has to be possible ... just not for me, tho.

This is my latest version of my script:

#include <Adafruit_NeoPixel.h>

#define PIN        5    // output pin Neopixel is attached to

#define NUMPIXELS   19    // number of neopixels in "strip"

#define delayval    20    // timing delay in milliseconds

#define ranMin      100   //minimum time for random intervall
#define ranMax      150   //maximum time for random intervall

#define anipause    100   //time between animation steps
#define anistep     6   //animation stepsize

#define ranTwinkleMin 1000  //minimum time for random intervall
#define ranTwinleMax  2500  //maximum time for random intervall
#define twinkleTime   20    //length of twinkle

#define colorStep   10    //change color this much each step

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int LEDColor[7][4]={{127,127,0,0},{127,127,0,0},{127,127,0,0},{127,127,0,0},{127,127,0,0},{127,127,0,0},{127,127,0,0}}; //LED block see above
int LED8Color[]={127,127,0,0};  //LED   2
int LED9Color[]={127,127,0,0};  //LED   4
int LED10Color[]={127,127,0,0}; //LED   6
int LED11Color[]={127,127,0,0}; //LED   8
int LED12Color[]={127,127,0,0}; //LED   10
int LED13Color[]={127,127,0,0}; //LED   12


unsigned long nextMillis[]={0,0,0,0,0,0,0};
int ranpau[7]={0,0,0,0,0,0,0};

int animation=0; // for breath animation, value in degrees for cos function
unsigned long nextAni=millis()+anipause;;
unsigned long nextTwinkle=millis()+random(ranTwinkleMin, ranTwinleMax);
bool twinkleStep=false;
int twinkleLED; // defines which LED should twinkle

void setup() {
  // Initialize the NeoPixel library.
  pixels.begin();

  for (int i=0; i <= 7 ; i++) // set random intervalls for all in LED block
  {
    ranpau[i]=random(ranMin, ranMax);
  }
}

void loop() {
  for (int i=0; i < 7 ; i++) // loop through LED block and see if one is to be updated
  {
    if (millis()>=nextMillis[i]){ //has LED i an event upcomming?
      nextMillis[i]=millis()+ranpau[i]; //update time for next change ?? maybe put this at end?
      switch (i) {
        case 0: // first set of LEDs
          pixels.setPixelColor(0, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          pixels.setPixelColor(12, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          break;
        case 1: // second set of LEDs ... you get the gist
          pixels.setPixelColor(2, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          pixels.setPixelColor(13, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          break;
        case 2:
          pixels.setPixelColor(4, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          pixels.setPixelColor(14, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          break;
        case 3:
          pixels.setPixelColor(6, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          pixels.setPixelColor(15, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          break;
        case 4:
          pixels.setPixelColor(8, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          pixels.setPixelColor(16, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          break;
        case 5:
          pixels.setPixelColor(10, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          pixels.setPixelColor(17, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          break;
        case 6:
          pixels.setPixelColor(18, pixels.Color(breath(LEDColor[i][0]),breath(LEDColor[i][1]),breath(LEDColor[i][2])));
          break;
        default: // nothing here! go home, could use this to catch error.
          break;
      }
      colorRotation(i,LEDColor[i][0],LEDColor[i][1],LEDColor[i][2],LEDColor[i][3]); // update to next color in animation for next call
      pixels.show(); //fun part
    }
  }
  
  if (millis()>=nextAni){ // update breath animation
    animation=animation+anistep;
    nextAni=millis()+anipause;
  }
  
  if (millis()>=nextTwinkle){
  if (!twinkleStep){
    twinkleStep = true ;
    nextTwinkle=millis()+twinkleTime;
    twinkle();
  } else {
    nextTwinkle=millis()+random(ranTwinkleMin, ranTwinleMax);
    twinkleStep=false;
    switch (twinkleLED){
      case 0:
      case 12:
        pixels.setPixelColor(0, pixels.Color(breath(LEDColor[0][0]),breath(LEDColor[0][1]),breath(LEDColor[0][2])));
        pixels.setPixelColor(12, pixels.Color(breath(LEDColor[0][0]),breath(LEDColor[0][1]),breath(LEDColor[0][2])));
        break;
      case 2:
      case 13:
        pixels.setPixelColor(2, pixels.Color(breath(LEDColor[1][0]),breath(LEDColor[1][1]),breath(LEDColor[1][2])));
        pixels.setPixelColor(13, pixels.Color(breath(LEDColor[1][0]),breath(LEDColor[1][1]),breath(LEDColor[1][2])));
        break;
      case 4:
      case 14:
        pixels.setPixelColor(4, pixels.Color(breath(LEDColor[2][0]),breath(LEDColor[2][1]),breath(LEDColor[2][2])));
        pixels.setPixelColor(14, pixels.Color(breath(LEDColor[2][0]),breath(LEDColor[2][1]),breath(LEDColor[2][2])));
        break;
      case 6:
      case 15:
        pixels.setPixelColor(6, pixels.Color(breath(LEDColor[3][0]),breath(LEDColor[3][1]),breath(LEDColor[3][2])));
        pixels.setPixelColor(15, pixels.Color(breath(LEDColor[3][0]),breath(LEDColor[3][1]),breath(LEDColor[3][2])));
        break;
      case 8:
      case 16:
        pixels.setPixelColor(8, pixels.Color(breath(LEDColor[4][0]),breath(LEDColor[4][1]),breath(LEDColor[4][2])));
        pixels.setPixelColor(16, pixels.Color(breath(LEDColor[4][0]),breath(LEDColor[4][1]),breath(LEDColor[4][2])));
        break;
      case 10:
      case 17:
        pixels.setPixelColor(10, pixels.Color(breath(LEDColor[5][0]),breath(LEDColor[5][1]),breath(LEDColor[5][2])));
        pixels.setPixelColor(17, pixels.Color(breath(LEDColor[5][0]),breath(LEDColor[5][1]),breath(LEDColor[5][2])));
        break;
      case 18:
        pixels.setPixelColor(18, pixels.Color(breath(LEDColor[6][0]),breath(LEDColor[6][1]),breath(LEDColor[6][2])));
        break;
    }
    pixels.show();
  }
  }
}

int breath(int colorin){ // changes brighness depending on animation step
  int colorout= colorin * ((cos(((animation%360)/180*M_PI))+1.5)/2.5);
  return colorout;
}

void twinkle(){
  twinkleLED = random(0,NUMPIXELS); // get a random pixel
  pixels.setPixelColor(twinkleLED, pixels.Color(255,255,0)); // make it bright yellow
  pixels.show(); // show it
}

void colorRotation(int LED,int RredColor,int RgreenColor,int RblueColor,int circ){ // cycles through all vcolors
  switch (circ) { // circ defines at which point the color cycle is.
    case 0: //green
        if (RgreenColor <= 254) {
              RredColor=RredColor-colorStep;
            RgreenColor=RgreenColor+colorStep;
          if (RredColor<0) {RredColor=0;}
          if (RgreenColor>255) {RgreenColor=255;}
        }
      else {
            circ++;
        }
        break;
    case 1: //blue
      if (RblueColor <= 254) {
          RgreenColor=RgreenColor-colorStep;
          RblueColor=RblueColor+colorStep;
          if (RgreenColor<0) {RgreenColor=0;}
          if (RblueColor>255) {RblueColor=255;}
      }
      else {
            circ++;
        }
      break;
    case 2: //red
      if (RredColor <= 254) {
          RblueColor=RblueColor-colorStep;
          RredColor=RredColor+colorStep;
          if (RblueColor<0) {RblueColor=0;}
          if (RredColor>255) {RredColor=255;}
      }
      else {
            circ=0;
        }
      break;
    default:
      circ=0;
      break;
  }
  // update colors:
  LEDColor[LED][0]= RredColor;
  LEDColor[LED][1]= RgreenColor;
  LEDColor[LED][2]= RblueColor;
  LEDColor[LED][3]= circ;
}

Problem: Sketch uses 6662 bytes (110%) of program storage space. Maximum is 6012 bytes.

for (int i=0; i <= 7 ; i++) Oops. This is getting tedious.

Got it down to 6594 bytes by moving pixels.show() to end of main loop and remove it everywhere else.

You'd make a RAM saving and probably a flash saving by using more appropriate data types.

There is enough ram left ... rom is what is full ... I try to squeeze it into a digispark

-> Global variables use 153 bytes of dynamic memory.

Unless I have no clue what you are talking of. (C is still black magic for me)

umm ... if I cut out my breathing animation It reduces the usage to 4272 bytes ...

(C is still black magic for me)

It seems to be - this must be the third time I've posted the same correction

Most of your "int" declarations could easaly be changed to "byte" and thus saving some space.

Maybe it helps a little to make your ledColor variables byte instead of int. Can't test now.but I suspect that it will not only help for ram size but also for the code size.

nextTwinkle=millis()+random(ranTwinkleMin, ranTwinleMax);

This is a method that will cause you problems and this approach is present multiple places in the code.

OK, ... I clearly have no clue ... or even less. @ All thanks for the tip.
Reduced it to 6506 bytes program storage and 118 bytes of dynamic memory.
Still 494 bytes to go.

Danois90:
[...]This is a method that will cause you problems and this approach is present multiple places in the code.

Thought it was pretty smart. Tend to be wrong, tho. Can you tell me why it is bad, and what bad side effects it causes?
I want to learn

Is your breath function working correctly? I'm getting odd answers with (animation%360) / 180 being done as integer math before converting it to float for the rest of the calculation.

int breath(int colorin){ // changes brighness depending on animation step
  int colorout= colorin * ((cos(((animation%360)/180*M_PI))+1.5)/2.5);
  return colorout;
}

Anyway, do away with the floats and cos() function entirely, try substituting this for the breath() function, I know it looks very large, but it reduces code size by keeping all the math as integer.

int breath(int colorin) { // changes brighness depending on animation step
  static const byte cosine[360] PROGMEM = {
    128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 126, 126, 126,
    126, 125, 125, 125, 124, 124, 124, 123, 123, 123, 122, 122, 122, 121, 121, 120,
    120, 119, 119, 118, 118, 117, 117, 116, 116, 115, 114, 114, 113, 113, 112, 111,
    111, 110, 109, 109, 108, 107, 106, 106, 105, 104, 103, 103, 102, 101, 100, 100,
    99, 98, 97, 96, 95, 95, 94, 93, 92, 91, 90, 90, 89, 88, 87, 86,
    85, 84, 83, 83, 82, 81, 80, 79, 78, 77, 76, 75, 75, 74, 73, 72,
    71, 70, 69, 68, 67, 67, 66, 65, 64, 63, 62, 61, 60, 60, 59, 58,
    57, 56, 55, 55, 54, 53, 52, 51, 51, 50, 49, 48, 48, 47, 46, 45,
    45, 44, 43, 43, 42, 41, 41, 40, 39, 39, 38, 38, 37, 37, 36, 35,
    35, 34, 34, 33, 33, 32, 32, 32, 31, 31, 30, 30, 30, 29, 29, 29,
    28, 28, 28, 27, 27, 27, 27, 26, 26, 26, 26, 26, 26, 25, 25, 25,
    25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26,
    26, 26, 27, 27, 27, 27, 28, 28, 28, 29, 29, 29, 30, 30, 30, 31,
    31, 32, 32, 32, 33, 33, 34, 34, 35, 35, 36, 37, 37, 38, 38, 39,
    39, 40, 41, 41, 42, 43, 43, 44, 45, 45, 46, 47, 48, 48, 49, 50,
    51, 51, 52, 53, 54, 55, 55, 56, 57, 58, 59, 60, 60, 61, 62, 63,
    64, 65, 66, 67, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77,
    78, 79, 80, 81, 82, 83, 83, 84, 85, 86, 87, 88, 89, 90, 90, 91,
    92, 93, 94, 95, 95, 96, 97, 98, 99, 100, 100, 101, 102, 103, 103, 104,
    105, 106, 106, 107, 108, 109, 109, 110, 111, 111, 112, 113, 113, 114, 114, 115,
    116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 122, 123,
    123, 123, 124, 124, 124, 125, 125, 125, 126, 126, 126, 126, 126, 127, 127, 127,
    127, 127, 127, 127, 127, 127, 127, 127
  };

  //int colorout = colorin * ((cos(((animation % 360) / 180 * M_PI)) + 1.5) / 2.5);
  int colorout = (colorin * pgm_read_byte(&cosine[animation % 360])) / 128;
  return colorout;
}
This would probably work just as well, since the cosine function is symmetrical:
int breath(int colorin) { // changes brighness depending on animation step
  static const byte cosine[180] PROGMEM = {
    128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 126, 126, 126, 126, 125,
    125, 125, 124, 124, 124, 123, 123, 123, 122, 122, 122, 121, 121, 120, 120, 119, 119, 118,
    118, 117, 117, 116, 116, 115, 114, 114, 113, 113, 112, 111, 111, 110, 109, 109, 108, 107,
    106, 106, 105, 104, 103, 103, 102, 101, 100, 100,  99,  98,  97,  96,  95,  95,  94,  93,
    92,   91,  90,  90,  89,  88,  87,  86,  85,  84,  83,  83,  82,  81,  80,  79,  78,  77,
    76,   75,  75,  74,  73,  72,  71,  70,  69,  68,  67,  67,  66,  65,  64,  63,  62,  61,
    60,   60,  59,  58,  57,  56,  55,  55,  54,  53,  52,  51,  51,  50,  49,  48,  48,  47,
    46,   45,  45,  44,  43,  43,  42,  41,  41,  40,  39,  39,  38,  38,  37,  37,  36,  35,
    35,   34,  34,  33,  33,  32,  32,  32,  31,  31,  30,  30,  30,  29,  29,  29,  28,  28,
    28,   27,  27,  27,  27,  26,  26,  26,  26,  26,  26,  25,  25,  25,  25,  25,  25,  25
  };
  //int colorout = colorin * ((cos(((animation % 360) / 180 * M_PI)) + 1.5) / 2.5);
  int lookup = animation % 360;
  if (lookup > 179) {
    lookup = 359 - lookup;
  }
  int colorout = (colorin * pgm_read_byte(&cosine[lookup])) / 128;
  return colorout;
}

Something else I noticed what will save you a bit of memory. You are incrementing animation in steps of 6 (the value of anistep), then later on using animation modulo 360 to keep the value within the range of 0 - 359. It takes less code to check the value of animation after you increment it, and adjust it to remain within the desired range. This also prevents a problem you will eventually run into, when the value of animation exceeds 32767 and suddenly appears as a negative number. You can then eliminate the use of modulo, saving around 90 bytes of program memory.

  if (millis() >= nextAni) { // update breath animation
    animation = animation + anistep;
    if (animation >= 360){         //if animation is 360 or more, reduce it by 360 to keep it within 0 - 359
      animation = animation - 360; //basically the same as animation = animation % 360,
    }                              //but we know animation is never going much over 359
    nextAni = millis() + anipause;
  }

david_2018:
Is your breath function working correctly? I'm getting odd answers with (animation%360) / 180 being done as integer math before converting it to float for the rest of the calculation.
[...]

... Now you stoked my insecurities, cause I thought it was ... although it was hard to tell in the simulation alone
Since I think I cut the comments in my upload here the full documented one with my thoughts behind it.

int breath(int colorin){ // changes brighness depending on animation step
  /*
 int colorout = // make color out an int number
 colorin * ((cos(( // multiply original color value by the cosinus of
 (animation%360) // modulo of the animation value, so that only value of less than 360 appear
 /180*M_PI)) // turn degrees value into radiant
 +1.5) // raise amplitude of cos value at 1.5 so values only between 0.5 and 2.5 appear
 /2.5); // cap value to 1 // remap values
  */
  int colorout= colorin * ((cos(((animation%360)/180*M_PI))+1.5)/2.5);
  return colorout;
}

... I did run a serial debug output on the simulation ... you are right. That thing is totally broken. The output is only 1 or 0.2 ... so much for an animation ...

david_2018:
Something else I noticed what will save you a bit of memory. You are incrementing animation in steps of 6 (the value of anistep), then later on using animation modulo 360 to keep the value within the range of 0 - 359. It takes less code to check the value of animation after you increment it, and adjust it to remain within the desired range. This also prevents a problem you will eventually run into, when the value of animation exceeds 32767 and suddenly appears as a negative number. You can then eliminate the use of modulo, saving around 90 bytes of program memory.

I did that originally so that I can freely vary the step size to adjust the speed of the animation without taxing the processor too much.

Edit: Thanks!
Converting my calculation to your static reduced it to 5326 bytes. The only thing that frustrates me, is that I never would came up with this solution. ... And I want to be able to.

Getting rid of the modulo got it down to 5234 bytes.

Although as I learned from earlier in this thread I used byte instead of int.

Hmm ... 774 bytes ... almost enough to use untouched 6 pixels ...(just kidding, I won't even try to try that)

Is it for a ATmega8 ?
You can try a different bootloader. With optiboot, there is 7680 bytes of flash memory for the sketch. If you do use that, you have to make a new board in the "boards.txt" file.

You use one line with floating point. If you don't use floating point and the Neopixel library does not use it, then the floating point library does not have to be linked in.
That is why the optimization by david_2018 is a very good proposal.

Everywhere you use millis(), you use it in the wrong way. Do not compare millis() with a a value and do not add something to a millis-related-value.

Koepel:
Is it for a ATmega8 ?

No a Tiny85 ...(digispark clone ... would have loved to buy a genuine one ...but they don't produce them anymore)
Edit: It WAS a ATTiny85 ... now it's trash (turns out the enamel wire had a bad coating on it ... which I wanted to use So the wires don't show up ... well at least it was a nice firework [the wires burned rather nicely when they did shorted out])

There is enough ram left ... rom is what is full ... I try to squeeze it into a digispark

Since the AVR is an 8bit CPU, it takes twice as many instruction (in general) to do something to an Int as it does to do the same thing to a byte. In addition to the extra RAM usage.