Optimising repetitive code

I've been using lots of repetitive statements to change the colour of some LEDs in time with audio cues from MP3 playback, and am looking for any ways these sections could be cut down.

I'm working with an Uno, a Sparkfun MP3 Player shield (latest version: SparkFun MP3 Player Shield - DEV-12660 - SparkFun Electronics), and an RN-XV attached via a Ciseco Active XBee breakout board. I've got a string of 10 RGB LED pixels incorporating 6803 chips (http://www.earthshineelectronics.com/105-15mm-rgb-led-pixel.html) attached to the board. Everything is working very nicely, but my sketch is seriously pushing up against the size limitations!

Relevant related routine, iterates over LED string and changes colour of each in turn:

void colorWipe(uint16_t c, uint8_t wait) {
  int i;
  for (i=0; i < strip.numPixels(); i++) { // numPixels=10
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

My original code looks like:

  delay(2200);
  colorWipe(Color(63,0,0),50); 
  delay(300);
  colorWipe(Color(0,63,0),50);
  delay(300);
  colorWipe(Color(0,0,63),50);
  delay(200);
  colorWipe(Color(63,0,0),50); 
  delay(700);
  colorWipe(Color(0,63,0),50); 
  delay(300);
  colorWipe(Color(0,0,63),50); 
  delay(200);
  colorWipe(Color(63,0,0),50);  
  delay(200);
  colorWipe(Color(0,63,0),50); 
  delay(700);
  colorWipe(Color(0,0,63),50); 
  delay(300);
  colorWipe(Color(63,0,0),50);
  delay(200);
  colorWipe(Color(0,63,0),50);
  delay(100);
  colorWipe(Color(0,0,63),50); 
  delay(700);

...and I've cut this back to:

  int delays[] = {2200,300,300,200,700,300,200,200,700,300,200,100,700};
  unsigned int pColors[] = {Color(63,0,0),Color(0,63,0),Color(0,0,63)};
  byte loopCount = 0;
  
  for(byte i=0;i<13;i++)
  {
     delay(delays[i]);
     colorWipe(pColors[loopCount],50);
     if(loopCount<2)
       loopCount++;
     else
       loopCount=0;
  }

The integer array in my revised code is a killer and, I suspect, not ideal. Are there any suggestions for improvements?

colorWipe(pColors[loopCount],50);
     if(loopCount<2)
       loopCount++;
     else
       loopCount=0;

shorter:

colorWipe(pColors[i % 3],50);

Everything is working very nicely, but my sketch is seriously pushing up against the size limitations!

Which size limitations?

At the risk of being redundant, snippets-are-us is down the road a ways. Here, we need to see all of your code. Your arrays are not that large. They do not appear to be what is causing you to push up against the size limitations (whichever ones they are).

My sketch does half a dozen other things, and is apparently too characterful to be split across two posts. I'm more than happy to post it in sections if you think it'll produce a better response. Current functionality covers:

Get time from RN-XV module sync'd to NTP server
Play different MP3 samples on hour, quarter hour, half hour, three quarter hour
Run different (brief) LED routines to sync with MP3 samples as above
IR remote interrupt starts weather retrieval:
Get Yahoo weather API RSS for local area
Parse returned feed for 1 or 2 digit weather code
Play appropriate MP3 sample to give spoken word version of weather
Run different (brief) LED routine corresponding to one of 5 weather types

It's a large sketch, and I'm running something like 100 bytes short. I think I can pull that back from the six or seven routines I have which are similar to the above - I'm using separate but similar routines as the timing of each MP3 sample is veeeeerry slightly different, and requires individual delay values.

Section 1:

//IRRemote stuff
//IR Remote library
#include <IRremote.h>
int RECV_PIN = A0;
IRrecv irrecv(RECV_PIN);
decode_results results;

#include <string.h>

#include <WiFlyHQ.h>
#include <SoftwareSerial.h>
SoftwareSerial wifiSerial(A1,A2);

WiFly wifly;

/* Change these to match your WiFi network */
const char mySSID[] = "[redacted]";
const char myPassword[] = "[redacted]";

const char site[] = "weather.yahooapis.com";
//String inString; // string for incoming serial data

//MP3Shield stuff
#include <SPI.h>
//Add the SdFat Libraries
#include <SdFat.h>
#include <SdFatUtil.h> 

//and the MP3 Shield Library
#include <SFEMP3Shield.h>

//create and name the library object
SFEMP3Shield MP3player;
byte result;

#include <TimerOne.h>
#include "LPD6803.h"

// Choose which 2 pins you will use for output.
// Can be any valid output pins.
int dataPin = A4;  
int clockPin = A5;

// Timer 1 is also used by the strip to send pixel clocks

// Set the first variable to the NUMBER of pixels. 20 = 20 pixels in a row
LPD6803 strip = LPD6803(10, dataPin, clockPin);

void setup() {
  Serial.begin(9600);

  wifiSerial.begin(9600);
  if (!wifly.begin(&wifiSerial, &Serial)) {
    ;
  }

  /* Join wifi network if not already associated */
  if (!wifly.isAssociated()) {
    /* Setup the WiFly to connect to a wifi network */
    wifly.setSSID(mySSID);
    wifly.setPassphrase(myPassword);
    wifly.enableDHCP();
    wifly.join();
    wifly.setDeviceID("WWC");
  }

  wifly.setTimeAddress("193.47.164.28");
  wifly.setTimezone(23);  
  wifly.setTimeEnable(2); 
  wifly.save();

  // The Arduino needs to clock out the data to the pixels
  // this happens in interrupt timer 1, we can change how often
  // to call the interrupt. setting CPUmax to 100 will take nearly all all the
  // time to do the pixel updates and a nicer/faster display, 
  // especially with strands of over 100 dots.
  // (Note that the max is 'pessimistic', its probably 10% or 20% less in reality)

  strip.setCPUmax(50);  // start with 50% CPU usage. up this if the strand flickers or is slow

  // Start up the LED counter
  strip.begin();
  // Update the strip, to start they are all 'off'
  strip.show();

  result = MP3player.begin();
  if(result != 0) {
    ;
  }

  irrecv.enableIRIn(); // Start the receiver
}

//time (mins) MP3 sample last played
char lastPlayed[] = "-1"; 
//current clock mins
char currentMinute[3];
//current clock hours
char currentHour[3];
//for wifly.getTime()
char buf[9];
//holds return from wifly.getTime()
char *strTime;
//MP3 shield track name - tracks held on SD card
char trackName[] = "track000.mp3";
//2 digit Yahoo weather API code
char wCode[] = "xx";

Section 2:

void loop()
{
  colorWipe(Color(0,0,0), 50);

  //If [1] pressed on remote, pause clock,
  //retrieve Yahoo weather RSS, parse for 
  //weather code, play audio sample, run lights
  if (irrecv.decode(&results)) {
    if(results.value == 0xFF30CF)
    {
      connectAndRead(); //connect to the server and read the output
      
      //track000 - track014 are used for clock chimes
      byte trackNum = atoi(wCode) + 15;
      itoa(trackNum, wCode, 10);            

      trackName[6] = wCode[0];
      trackName[7] = wCode[1];
      MP3player.playMP3(trackName);
      
      //Large, extremely gimpy selection routine for selecting
      //LED routine based on weather code. Weather code table at:
      //http://developer.yahoo.com/weather/#codes
      if((trackNum-15 < 5) ||
         ((trackNum-15 > 36) && (trackNum-15 < 40)))
      {
        stormLights; 
      }
      else if((trackNum-15 == 5) ||
             (trackNum-15 == 6) ||
             ((trackNum-15 > 7) && (trackNum-15 < 13)) ||
             (trackNum-15 == 17) ||
             (trackNum-15 == 35) ||
             (trackNum-15 == 40) ||
             (trackNum-15 == 45) ||
             (trackNum-15 == 47))
      {
        rainLights();         
      }
      else if((trackNum-15 == 7) ||
              ((trackNum-15 > 12) && (trackNum-15 < 17)) ||
              (trackNum-15 == 18) ||
              (trackNum-15 == 25) ||
              ((trackNum-15 > 40) && (trackNum-15 < 44)) ||              
              (trackNum-15 == 46))
      {
        snowLights();
      }
      else if((trackNum-15 == 19) ||
              (trackNum-15 == 21) ||
              (trackNum-15 == 22) ||
              (trackNum-15 == 32) ||
              (trackNum-15 == 34) ||
              (trackNum-15 == 36))
      {
        sunLights();
      }        
      else if((trackNum-15 == 20) ||
              (trackNum-15 == 23) ||
              (trackNum-15 == 24) ||
              ((trackNum-15 > 25) && (trackNum-15 < 31)) ||
              (trackNum-15 == 44))
      {
        cloudLights();
      }
      else
      {
        nightLights();
      }  

      //Reset LEDs, wait 3 secs before next possible
      //weather request
      colorWipe(Color(0,0,0), 50);
      delay(3000);
    }
    irrecv.resume();
  }

  else
  {
    //Clock stuff
    
    //check if MP3player is already playing back
    result = MP3player.isPlaying();
    
    //if not playing
    if(result == 0)
    { 
      //Get time from RN-XV
      strTime = wifly.getTime(buf,sizeof(buf)); 

      Serial.println(strTime);

      currentMinute[0] = strTime[3];
      currentMinute[1] = strTime[4];
      currentMinute[2] = '\0';
      
      //figure out what hour it is, translate
      //24 hour clock value to one of 12 MP3 track names
      if((currentMinute[0] == '0') && (currentMinute[1] == '0'))
      {
        if((currentMinute[0] != lastPlayed[0]) || (currentMinute[1] != lastPlayed[1]))
        {
          currentHour[0] = strTime[0];
          currentHour[1] = strTime[1];
          currentHour[2] = '\0';

          if(atoi(currentHour) < 12)
          {
            trackName[6] = currentHour[0];
            trackName[7] = currentHour[1]; 
          }
          else if((atoi(currentHour) >= 12) && (atoi(currentHour) <20))
          {
            trackName[6] = currentHour[0] - 1;
            trackName[7] = currentHour[1] - 2; 
          }
          else if((atoi(currentHour) >= 20) && (atoi(currentHour) <22))
          {
            trackName[6] = currentHour[0] - 2;
            trackName[7] = currentHour[1] + 8; 
          }
          else if((atoi(currentHour) >= 21) && (atoi(currentHour) <24))
          {
            trackName[6] = currentHour[0] - 1;
            trackName[7] = currentHour[1] - 2; 
          }

          lastPlayed[0] = currentMinute[0];
          lastPlayed[1] = currentMinute[1];
          
          MP3player.playMP3(trackName);
          //TODO: Implement hour chimes/LED routine
          threeQuarterHourLights();
        }
      }
      //Quarter hour chime
      else if((currentMinute[0] == '1') && (currentMinute[1] == '5'))
      {
        if((currentMinute[0] != lastPlayed[0]) || (currentMinute[1] != lastPlayed[1]))
        {
          lastPlayed[0] = currentMinute[0];
          lastPlayed[1] = currentMinute[1];

          trackName[6] = '1';
          trackName[7] = '3';

          MP3player.playMP3(trackName);
          quarterLights();
        }
      }
      //Half hour chime
      else if((currentMinute[0] == '3') && (currentMinute[1] == '0'))
      {
        if((currentMinute[0] != lastPlayed[0]) || (currentMinute[1] != lastPlayed[1]))
        {
          lastPlayed[0] = currentMinute[0];
          lastPlayed[1] = currentMinute[1];

          trackName[6] = '1';
          trackName[7] = '2';

          MP3player.playMP3(trackName);
          halfLights();
        }
      }
      //Three quarter hour chime
      else if((currentMinute[0] == '4') && (currentMinute[1] == '5'))
      {
        if((currentMinute[0] != lastPlayed[0]) || (currentMinute[1] != lastPlayed[1]))
        {
          lastPlayed[0] = currentMinute[0];
          lastPlayed[1] = currentMinute[1];

          trackName[6] = '1';
          trackName[7] = '4';

          MP3player.playMP3(trackName);
          threeQuarterLights();
        }
      }
    } 
    //Wait 1 sec between clock updates
    delay(1000);
  }
}

Section 3:

//WEATHER STUFF

void connectAndRead(){
  //connect to the server
  if (wifly.isConnected()) {
    wifly.close();
  }
  //RN-XV GET request
  if (wifly.open(site, 80)) {
    wifly.println("GET http://weather.yahooapis.com/forecastrss?w=26376587 HTTP/1.0");
    wifly.println();

    //Connected - Read the page
    char inString[7];
    inString[6] = '\0';
    byte charCount = 0;
    boolean recordOn = false;
    
    //While weather code prefix 'code="' not reached
    while(strcmp(inString,"code=\"") != 0)
    {
      //Read char from RN-XV
      if(wifiSerial.available())
      {
        char c = wifly.read();
        
        //If first letter of 'code="', start recording
        if(c == 'c')
        {
          recordOn = true;       
        }
        
        //Record for 6 chars
        if((recordOn == true) && (charCount < 6))
        {
          inString[charCount] = c;
          charCount++; 
        }
        //If more than 6 chars, not 'code="', so reset count
        else if((recordOn == true) && (charCount >= 6))
        {
          charCount = 0; 
          for(byte i=0;i<11;i++)
          {
            inString[i] = '\0';
          }
        }

        if(Serial.available())
        {
          wifiSerial.write(Serial.read()); 
        }
      }
    }

    //Rinse and repeat above to pick up weather code - next 1 or 2 digits
    //after 'code="'
    char code[] = "\0\0\0"; // string for incoming serial data
    byte codeCount = 0;
    boolean codeRecordOn = false;

    while(codeCount < 2)
    {
      if(wifiSerial.available())
      {

        char c = wifly.read();

        if(c != '"')
        {
          code[codeCount] = c; 
        }

        if(Serial.available())
        {
          wifiSerial.write(Serial.read()); 
        }
        codeCount++;
      }
    }
    //Set global wCode to retrieved code
    for(byte i=0;i<2;i++)
    {
      wCode[i] = code[i];
    }
  } 
}

(Last) Section 4:

//LED STUFF
unsigned int Color(byte r, byte g, byte b)
{
  return( ((unsigned int)g & 0x1F )<<10 | ((unsigned int)b & 0x1F)<<5 | (unsigned int)r & 0x1F);
}

void colorWipe(uint16_t c, uint8_t wait) {
  int i;
  for (i=0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void quarterLights()
{
  delay(2000);
  colorWipe(Color(63,0,0),50); 
  delay(400);
  colorWipe(Color(0,0,63),50);
  delay(400);
  colorWipe(Color(0,63,0),50);
  delay(350);
  colorWipe(Color(63,0,0),50); 
  delay(2000);
}

void halfLights()
{  
  delay(2200);
  colorWipe(Color(63,0,0),50); 
  delay(300);
  colorWipe(Color(0,63,0),50);
  delay(300);
  colorWipe(Color(0,0,63),50);
  delay(200);
  colorWipe(Color(63,0,0),50); 
  delay(700);
  colorWipe(Color(0,63,0),50); 
  delay(300);
  colorWipe(Color(0,0,63),50); 
  delay(200);
  colorWipe(Color(63,0,0),50);  
  delay(200);
  colorWipe(Color(0,63,0),50); 
  delay(1800);
}

int interval = 1000;
unsigned int pColors[] = {Color(63,0,0),Color(0,63,0),Color(0,0,63)};

void threeQuarterLights()
{ 
  int delays[] = {2200,300,300,200,700,300,200,200,700,300,200,100,700};
  unsigned int pColors[] = {Color(63,0,0),Color(0,63,0),Color(0,0,63)};
  byte loopCount = 0;
  
  for(byte i=0;i<13;i++)
  {
     delay(delays[i]);
     colorWipe(pColors[loopCount],50);
     if(loopCount<2)
       loopCount++;
     else
       loopCount=0;
  }
}

/* TODO - Find enough sketch space to fit this in, implement
/* hour chimes properly
void hourLights(byte b)
{
  //threeQuarterLights();
  
  int delays[] = {2200,300,300,200,700,300,200,200,700,300,200,100,700};
  unsigned int pColors[] = {Color(63,0,0),Color(0,63,0),Color(0,0,63)};
  byte loopCount = 0;
  
  for(byte i=0;i<13;i++)
  {
     delay(delays[i]);
     colorWipe(pColors[loopCount],50);
     
     if(loopCount<2)
       loopCount++;
     else
       loopCount=0;
  }
  /*
  delay(2200);
  colorWipe(Color(63,0,0),50); 
  delay(300);
  colorWipe(Color(0,63,0),50);
  delay(300);
  colorWipe(Color(0,0,63),50);
  delay(200);
  colorWipe(Color(63,0,0),50); 
  delay(700);
  colorWipe(Color(0,63,0),50); 
  delay(300);
  colorWipe(Color(0,0,63),50); 
  delay(200);
  colorWipe(Color(63,0,0),50);  
  delay(200);
  colorWipe(Color(0,63,0),50); 
  delay(700);
  colorWipe(Color(0,0,63),50); 
  delay(300);
  colorWipe(Color(63,0,0),50);
  delay(200);
  colorWipe(Color(0,63,0),50);
  delay(100);
  colorWipe(Color(0,0,63),50); 
  delay(700);
  
  for(byte j=0;j<b;j++)
  {     
     colorWipe(Color(0,0,63),50);
     delay(300);
  }
}
*/

void rainLights()
{
  for(byte j=0;j<10;j++)
  {
    for(byte i=0;i<10;i++)
    {
      strip.setPixelColor(i, Color(random(17,25),63,20));
      strip.show();
      delay(50);
    }
  }
}

void sunLights()
{
  for(byte j=0;j<10;j++)
  {
    for(byte i=0;i<10;i++)
    {
      strip.setPixelColor(i, Color(random(58,63),0,random(55,63)));
      strip.show();
      delay(50);
    }
  }
}

void snowLights()
{
  for(byte j=0;j<10;j++)
  {
    for(byte i=0;i<10;i++)
    {
      strip.setPixelColor(i, Color(random(60,63),59,random(60,63)));
      strip.show();
      delay(50);
    }
  }
}

void stormLights()
{
  for(byte j=0;j<10;j++)
  {
    for(byte i=0;i<10;i++)
    {
      strip.setPixelColor(i, Color(random(50,55),random(50,55),10));
      strip.show();
      delay(50);
      strip.setPixelColor(i+2, Color(random(50,55),random(50,55),10));
      strip.show();
      delay(50);
      strip.setPixelColor(i, Color(63,63,63));
    }
  }
}

void cloudLights()
{
  for(byte j=0;j<10;j++)
  {
    for(byte i=0;i<10;i++)
    {
      strip.setPixelColor(i, Color(random(10,15),random(10,15),10));
      strip.show();
      delay(50);
    }
  }
}

void nightLights()
{
  for(byte j=0;j<10;j++)
  {
    for(byte i=0;i<10;i++)
    {
      strip.setPixelColor(i, Color(random(45,50),random(45,50),0));
      strip.show();
      delay(50);
    }
  } 
}