Sunday, February 22, 2015

Steampunk Light Dress Part 6: Getting the LED Out

Just merged the musicbox code with my main code, tweaked the LED's to allow for any byte to be passed to the Shift Register LED's, and added a fading feature for the RGB LED's.

Please see references to LEDShiftRegister and RGBColor class.

/*

Steampunk Light Dress Program V 1.0B
Beau Bureau, 2015
Released to Public Domain

NOTES:
1st pot controls MAIN SETTING.  The color code is WHITE.
2nd pot controls SENSITIVITY to sound.  The color code is BLUE
3rd pot controls COLOR SPEED transition.  The color code is RED

*/

#include <LED.h>
#include <ShiftRegister.h>
#include <RGBColor.h>

int passer=5;


RGBColor * color;
RGBColor * color2;
RGBColor * colorDark;
Led * c2;
Led * c1;

byte binPin1=7;
byte binPin2=12;
byte binPin4=13;


byte dataPin = 2;              // The Serial Data Pin to the Shift Register
byte latchPin = 8;             // The Latch Pin to the Shift Register
byte clockPin = 4;             // The Clock Pin to the Shift Register

// Analog inputs
int firstPot=A5;
int soundPin=A0;
int thirdPot=A1;
int secondPot=A2;
byte potSet=0;

// Music Vars
double currMult=0.5;
byte shiftSpeed=0;
byte trackVector=0;
byte RGBPeakHit=10;
bool colorsPicked=false;

ShiftRegister * sr=new ShiftRegister(clockPin,latchPin,dataPin,16,2);
void setup()

{

  c1=new Led(3,5,6);
  c2=new Led(9,10,11);
  colorDark=new RGBColor(0,0,0);
  color=new RGBColor();
  color2=new RGBColor();
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  // Sets the binary pins that will tell us which setting we're on.
    pinMode(binPin1,OUTPUT);
    pinMode(binPin2,OUTPUT);
    pinMode(binPin4,OUTPUT);
 
    pinMode(dataPin, OUTPUT);    // Configure Digital Pins
 
    pinMode(latchPin, OUTPUT);
 
    pinMode(clockPin, OUTPUT);
 
    Serial.begin(9600);
}
void loop()
{

  //deChase(*sr,50000);
  //sparkle(*sr,500000);
   //doSomething();
  // pingPong(*sr,5000,true);
  do {
    ReadPot(false);
    //chase(*sr,50000);
   //sparkle(*sr,1,true);
   //RGBFlash(*c1,*c2,passer);
  } while (true);


}
// Music Functions
//TODO: Make MusicBox only go for X time.
void musicBox(Led &led1, Led &led2, bool timed)
{
  int target=30000;
  int count=0;
  do {
  // Bytes for the shift register
  byte SRPulse[]={B00000000,B00011000,B00111100,B01111110,B11111111};
  // we prepopulate our ranks
  byte Rank4[]={255,200,175,150,100};
  byte Rank3[]={200,150,100,75,50};
  byte Rank2[]={150,100,75,50,25};
  byte Rank1[]={125,75,50,25,10};
  // The second potentiometer assigns the rank from 0 to 4.  THe higher the setting, the more sensitive the reading.
  byte rank=map(analogRead(secondPot),0,1024,0,4);
  // determines the shift speed mod from the third potentiometer.  The higher the setting, the more impact the music will have on the colors.
  byte spMod=map(analogRead(thirdPot),0,1024,rank+1, rank+2*2);
// If we've detected enough peaks, start shifting colors.
  if (RGBPeakHit>=10)
  {
    // If a new color hasn't been picked, pick new colors.
    if (!colorsPicked)
    {
      color->SetRandom();
      color2->setColors(color->Compliment());
      colorsPicked=true;

    }
    // Shift colors per iteration until they match.  The pot settings impact how quickly the colors shift.
    bool match1=matchColors(led1,*color,30+shiftSpeed*spMod);
    bool match2=matchColors(led2,*color2,30+shiftSpeed*spMod);

    if (match1&&match2)
    {
      RGBPeakHit=0;
      colorsPicked=false;
    }
  }

  // collect the local sound value
  byte val=collectAnalogAVG(50);
  Serial.println(val);
  clearLed(led1);
  clearLed(led2);

  // add the value to the track total
  if (val>Rank4[rank])
  {
    RGBPeakHit=RGBPeakHit+5;
    trackVector=4;
    shiftSpeed=10;
  }
  else if (val>Rank3[rank])
  {
     RGBPeakHit=RGBPeakHit+3;
    trackVector=3;
    shiftSpeed=5;
  }
  else if (val>Rank2[rank])
  {
    RGBPeakHit=RGBPeakHit+2;
    trackVector=2;
  }
  else if (val>Rank1[rank])
  {
    RGBPeakHit=RGBPeakHit+1;
    trackVector=1;
  }
  else
  {
    trackVector=0;
  }
  // Check if settings are the same
       if (CheckPot()) {}
      else {
        return;
      }
  fireLed(led1);
  fireLed(led2);
  fireLEDs(SRPulse[trackVector]);
  delay(2);
  count++;
  // IF we're timed AND out of time... return.
  if (timed==true&&count>target)
  {
    return;
  }
  }
  while (true);
}

  byte collectAnalogAVG(byte sampleWindow)
{
   unsigned long startMillis= millis();  // Start of sample window
   byte peakToPeak = 0;   // peak-to-peak level
   byte sample=0;
   byte signalMax = 0;
   byte signalMin = 255;

   // collect data for 50 mS
   while (millis() - startMillis < sampleWindow)
   {
      sample = map(analogRead(soundPin),0,1024,0,255);
   
      if (sample < 255)  // toss out spurious readings
      {
         if (sample > signalMax)
         {
            signalMax = sample;  // save just the max levels
         }
         else if (sample < signalMin)
         {
            signalMin = sample;  // save just the min levels
         }
      }
   }
   return signalMax - signalMin;  // max - min = peak-peak amplitude
}

  // TODO: Invent fading and defading.


// Random SR Settings
void FireRandomSR()
{
  int target=50000;
  int count=0;
  fireLEDs(0);
switch (random(1,6))
{
  case 1:
  FireRandomRGB();
  chase(*sr,50000);
  break;
  case 2:
  FireRandomRGB();
  deChase(*sr,50000);
  break;
  case 3:
  FireRandomRGB();
  pingPong(*sr,50000,true);
  break;
  case 4:
  FireRandomRGB();
  pingPong(*sr,50000,false);
  break;
  case 5:
  do {
  sparkle(*sr,1,true);
  RGBFlash(*c1,*c2,passer);
  count++;
  } while (count<target&&CheckPot());
  break;
  case 6:
  musicBox(*c1,*c2,true);
 break;


}
}


// Random RGB Settings

void FireRandomRGB()
{
  // Fires off a random RGB Function
   switch(random(1,4))
   {
     case 1:
     // Flash the RGB's
       RGBFlash(*c1,*c2,100);
       break;
      case 2:
      // Fade to the same color
        color->SetRandom();
        shiftTogether(*c1, *c2, *color, random(10,50));
        break;
      case 3:
      // Fade to complimentary colors
        color->SetRandom();
        shiftCompliments(*c1,*c2, *color,30);
        break;
      case 4:
      // Fade the LEDs and relight them i numbers of times
      for (int i=0; i<random(2,4);i++)
      {
        byte inc=random(5,60);
        FadeLEDs(*c1,*c2, inc);
        // Pause.  If it's been returned by checkpot, return to the calling function
        for (int i=0; i<random(500,2000);i++)
        {
        if (CheckPot()==false)
        {
          return;
        }
        delay(1);
        }
        color->SetRandom();
        shiftCompliments(*c1,*c2, *color,inc);
        // Pause. If it's been returned by checkpot, return to the calling function
            for (int i=0; i<random(500,2000);i++)
        {
        if (CheckPot()==false)
        {
          return;
        }
        delay(1);
        }
      }
        break;
   }
}

// POT SETTINGS AND ADJUSTMENTS AREA
bool CheckPot()
{
  if (PotSetting()==potSet) return true;
  else {
    Serial.println("Dial reading:");
    Serial.println(PotSetting());
    fireLEDs(0);
    return false;
  }
}

void SetBinLights()
{
      // set the binary display pins low to overwrite
    digitalWrite(binPin1,LOW);
    digitalWrite(binPin2,LOW);
    digitalWrite(binPin4,LOW);

     Serial.print("PotSet:");
     Serial.println(potSet);
   // Fire the binary lights in the control panel to show what setting we're currently on
  switch(PotSetting())
  {
      case 1:
        digitalWrite(binPin1,HIGH);
        break;
      case 2:
        digitalWrite(binPin2,HIGH);
        break;
      case 3:
         digitalWrite(binPin2,HIGH);
         digitalWrite(binPin1,HIGH);
         break;
      case 4:
         digitalWrite(binPin4,HIGH);
         break;
       case 5:
         digitalWrite(binPin4,HIGH);
         digitalWrite(binPin1,HIGH);
         break;
       case 6:
         digitalWrite(binPin4,HIGH);
         digitalWrite(binPin2,HIGH);
         break;
       case 7:
         digitalWrite(binPin4,HIGH);
         digitalWrite(binPin2,HIGH);
         digitalWrite(binPin1, HIGH);
         break;  
  }

}


void ReadPot(bool rand)
{
  potSet=PotSetting();
  SetBinLights();

  Serial.println(potSet);
  switch(potSet)
  {
    case 1:
    Serial.println("PingPong.");
        fireLEDs(0);
        FireRandomRGB();
        pingPong(*sr,50000,true);
        fireLEDs(0);
        FireRandomRGB();
        pingPong(*sr,50000,false);
      break;
    case 2:
      Serial.println("Chasing.");
        fireLEDs(0);
        FireRandomRGB();
        chase(*sr,50000);
        fireLEDs(0);
        FireRandomRGB();
        deChase(*sr,50000);      
      break;
      case 3:
        Serial.println("RGB Sparkle");
        sparkle(*sr,1,true);
        RGBFlash(*c1,*c2,passer);      
      break;
      case 4:
      // TURN TO RANDOM
        Serial.println("Random");
        FireRandomSR();
        break;
      case 5:
        Serial.println("Music");
        musicBox(*c1,*c2, false);
        break;
  }
}

byte PotSetting()
{
  int r=analogRead(firstPot);
  if (r>960)
  {
    return 5;
  }
  else if (r>720)
  {
    return 4;
  }
  else if (r>480)
  {
    return 3;
  }
  else if (r>240)
  {
  return 2;
  }
  else {
    return 1;
  }

}

// RGB Functions
//Fade the LED's to black
void FadeLEDs(Led &led1, Led &led2, byte inc)
{
  bool halt=false;
  if (((led1.Red()!=0)&&(led1.Blue()!=0)&&(led1.Green()!=0))&&((led2.Red()!=0)&&(led2.Blue()!=0)&&(led2.Green()!=0)))
  {
    do {
    if (matchColors(led1,*colorDark)==true&&matchColors(led2,*colorDark)==true)
    {
      halt=true;
    }
    else delay(inc);
    } while (halt=false);
  }
}

// Flash the RGB's times amount of times.
void RGBFlash (Led &led1, Led &led2, int times)
{
    Serial.print("Times:");
    Serial.println(times);
    int count=0;
    do {
      color->SetRandom();
      color2->SetRandom();
 
      led1.SetRGB(color->Red(),color->Green(),color->Blue());
      led2.SetRGB(color2->Red(),color2->Green(),color2->Blue());
   
     fireLed(led1);
     fireLed(led2);

    // Verify the pot setting has remained the same.  Otherwise return to the calling function.
      if (CheckPot()) {}
      else {
        return;
      }
   
      delay(random(30,100));  
   
      if (CheckPot()==false)
     {
       return;
     }
         
      count++;
   
    } while (count<times);

}

void shiftTogether (Led &led1, Led &led2, RGBColor color, byte pause)
{
  bool halt=false;
   do {
   if (matchColors(led1,color)==true&&matchColors(led2,color)==true)
    {
      halt=true;
    }
 
     fireLed(led1);
     fireLed(led2);
   
        // Verify the pot setting has remained the same.  Otherwise return to the calling function.
      if (CheckPot()) {}
      else {
        return;
      }
   
      if (CheckPot()==false)
     {
       return;
     }
   
     delay(pause);
   
  } while(halt==false);
}

void shiftCompliments(Led &led1, Led &led2, RGBColor color, byte pause)
{
  RGBColor * color2=new RGBColor(color.ID(),true);
  bool halt=false;
  do {
    if (matchColors(led1,color)==true&&matchColors(led2,*color2)==true)
    {
      halt=true;
    }
   
     fireLed(led1);
     fireLed(led2);
   
        // Verify the pot setting has remained the same.  Otherwise return to the calling function.
      if (CheckPot()) {}
      else {
        return;
      }
   
   
     delay(pause);
   
     if (CheckPot()==false)
     {
       return;
     }
   
  } while(halt==false);

}

bool matchColors(Led &led,RGBColor &color)
{
  bool r=0;
  bool g=0;
  bool b=0;

  if (led.Blue()==color.Blue())
  {
    b=1;
  }
  else {
    if (led.Blue()>color.Blue()) led.SetBlue(led.Blue()-1);
    else led.SetBlue(led.Blue()+1);
  }


  if (led.Red()==color.Red())
  {
    r=1;
  }
  else {
    if (led.Red()>color.Red()) led.SetRed(led.Red()-1);
    else led.SetRed(led.Red()+1);
  }


  if (led.Green()==color.Green())
  {
    g=1;
  }
  else {
    if (led.Green()>color.Green()) led.SetGreen(led.Green()-1);
    else led.SetGreen(led.Green()+1);
  }

  if (r==1)
  {
    if (g==1) {
      if (b==1) {
    return true;
      }
    }
  }

  return false;

}

void shiftColors(Led &led, RGBColor color, int pause)
{

bool halt=0;

  do {
      // fade to black until colors match
    if (matchColors(led,color)==true)
    {
      halt=true;
    }
   
     fireLed(led);
   
     delay(pause);
   
     if (CheckPot()==false)
     {
       return;
     }
   
  } while(halt==false);


}


void fadeLed(Led led, int pause)
{
  // Create a color of 0,0,0 (black)
  RGBColor * color=new RGBColor(0,0,0);
  bool halt=false;
    do {
      // fade to black until colors match
    if (matchColors(led,*color)==true)
    {
      halt=true;
    }
   
     fireLed(led);
   
     delay(pause);
   
     if (CheckPot()==false)
     {
       return;
     }
   
  } while(halt==false);

}

void fireLed(Led led)
{
  if (led.IsRGB())
  {
    /*
    Serial.print(led.RPin());
    Serial.print(":");
    Serial.print(led.Red());
    Serial.print(led.Green());
    Serial.println(led.Blue());
    */
    analogWrite(led.RPin(),led.Red());
    analogWrite(led.GPin(),led.Green());
    analogWrite(led.BPin(),led.Blue());
  }
}



// Parameters include the shift register, the amount of ms this will run, an array of breakpoints and the size of this array.
void pingPong(ShiftRegister &r, long time, bool goBack)
{
 int pause=150;
  long count=0;
  int i=0;
  byte steps=6;
  if (goBack==false) steps=4;

  int rdmCount=random(0,800);

  byte Pins[]={
    B00011000,
    B00100100,
    B01000010,
    B10000001,
    B01000010,
    B00100100,
  };

    do {

    for (int index=0;index<steps;index++)
    {
        if (i>=rdmCount)
        {
          pause=pause*.75;
          rdmCount=random(0,800);
          i=0;
        }
        // if pause is lower than 30, reset pause to a random number between 100 and 300
        if (pause<30) pause=random(100,300);
        i++;
        digitalWrite(latchPin,LOW);
        shiftOut(dataPin,clockPin,MSBFIRST,Pins[index]);
        shiftOut(dataPin,clockPin,MSBFIRST,Pins[index]);   // Send the data byte 2
        digitalWrite(latchPin, HIGH);
        delay(pause);
     
        if (CheckPot()==false)
     {
       return;
     }
     
        count=count+pause;
    }
  }   while(count<time);
}
/*
void sparkle(ShiftRegister &r, long time, bool sparkMode)
{
  byte inPause=0;
  int outPause=0;
  long count=0;
  do {
    inPause=random(10,150);
    outPause=random(100,1000);
    r.ClearPins();
    byte numPins=random(1,3);
    for (int i=0;i<numPins;i++)
    {
    int pin=random(1,r.NoPins()-1);
    r.ActivatePin(pin);
    }
     fireLED(r);
     r.ClearPins();
     delay(inPause);
     fireLEDs(0);
     // If we're in the sparkle mode, do passing.
     if (sparkMode)
     {
      passer=outPause/40;
     }
     else {
     delay(outPause);
     }
     count=count+inPause+outPause;
  } while(count<time);
}
*/

void sparkle(ShiftRegister &r, long time, bool sparkleMode)
{
  byte inPause=0;
  int outPause=0;
  long count=0;
  do {
 
    inPause=random(10,100);
    outPause=random(100,1500);
    r.ClearPins();
    byte numPins=random(1,3);
    for (int i=0;i<numPins;i++)
    {
    int pin=random(1,r.NoPins());
    r.ActivatePin(pin);
    }
     fireLED(r);
     r.ClearPins();
     delay(inPause);
     fireLEDs(0);
     if (sparkleMode)
     {
       byte div=random(30,50);
       passer=outPause/div;
     }
     else {
     delay(outPause);
     }
   
     if (CheckPot()==false)
     {
       return;
     }
   
     count=count+inPause+outPause;
  } while(count<time);
}

void chase(ShiftRegister &r, long time)
{
  int pause=200;
  long count=0;
  do {
  for (int i=0; i<r.NoPins();i++) {
      // Clear the pins
      r.ClearPins();
      // get the boolean pin number for i
      r.ActivatePin(i);
      // turn the pins on
      fireLED(*sr);
      delay(pause);
      count=count+pause;
 
     if (CheckPot()==false)
     {
       return;
     }
   
     }
 
  } while (count<time);
  }
/*
void doSomething()
{
  byte pins[]={B10000001,
B01000010,
B00101000,
B00010000,
B00101000,
B00100100,
B01000010};
  do {
  for (int i=0;i<7;i++)
  {
    fireLEDs(pins[i]);
    delay(300);
  }

  } while (true);
}
*/

void deChase(ShiftRegister &r, long time)
{
  int pause=200;
  long count=0;
  do {
  for (int i=r.NoPins()-1; i>=0;i--) {
      // Clear the pins
      r.ClearPins();
      // get the boolean pin number for i
      r.ActivatePin(i);
      // turn the pins on
      fireLED(*sr);
      delay(pause);
      count=count+pause;
   
     }
     if (CheckPot()==false)
     {
       return;
     }
  } while (count<time);
  }

void checker(ShiftRegister &r, long time)
{
  byte pause=random(20,50);
  byte countDown=random(50,200);
  long count=0;
  do {
      // Clear the pins
      r.ClearPins();
        // fire even pins
      for (int i=1;i<r.NoPins();i++)
      {
        if (i%2==0) r.ActivatePin(i);
      }
      fireLED(r);
      delay(pause);
       // fire even pins
       r.ClearPins();
      for (int i=1;i<r.NoPins();i++)
      {
        if (i%2!=0) r.ActivatePin(i);
      }
      fireLED(r);
      delay(pause);
      count=count+(pause*2);
      countDown--;
      if (countDown<=0)
      {
      pause--;
      if (pause<20) pause=random(30,50);
      countDown=random(0,200);
  }
     if (CheckPot()==false)
     {
       return;
     }
  } while (count<time);

}


    void fireLEDs(int data)
  {
        digitalWrite(latchPin,LOW);
        shiftOut(dataPin,clockPin,MSBFIRST,data);
        shiftOut(dataPin,clockPin,MSBFIRST,data);   // Send the data byte 2
        digitalWrite(latchPin, HIGH);

  }

 // clear an RGB led
  void clearLed(Led led)
{
 
 
    analogWrite(led.RPin(),0);
    analogWrite(led.GPin(),0);
    analogWrite(led.BPin(),0);

}

bool matchColors(Led &led,RGBColor &color, byte inc)
{
  bool r=0;
  bool g=0;
  bool b=0;

  if (led.Blue()==color.Blue())
  {
    b=1;
  }
  else {
    if (led.Blue()-inc>color.Blue()) led.SetBlue(led.Blue()-inc);
    else if (led.Blue()+inc<color.Blue())  led.SetBlue(led.Blue()+inc);
    else led.SetBlue(color.Blue());
   
  }


  if (led.Red()==color.Red())
  {
    r=1;
  }
  else {
    if (led.Red()-inc>color.Red()) led.SetRed(led.Red()-inc);
    else if (led.Red()+inc<color.Red())  led.SetRed(led.Red()+inc);
    else led.SetRed(color.Red());
   
  }


  if (led.Green()==color.Green())
  {
    g=1;
  }
  else {
    if (led.Green()-inc>color.Green()) led.SetGreen(led.Green()-inc);
    else if (led.Green()+inc<color.Green())  led.SetGreen(led.Green()+inc);
    else led.SetGreen(color.Green());
   
  }

  if (r==1)
  {
    if (g==1) {
      if (b==1) {
    return true;
      }
    }
  }

  return false;

}


    void fireLED(ShiftRegister &r)
  {
   
     
        digitalWrite(r.LatchPin(),LOW);
       // for (byte i=0; i<r.NoRegs();i++)
        //{
          // if the current register is active, fire its pins
           // Serial.println(i);
            shiftOut(r.DataPin(),r.ClockPin(),MSBFIRST,r.ShiftNum(0));
            shiftOut(r.DataPin(),r.ClockPin(),MSBFIRST,r.ShiftNum(1));
       
        //}
         digitalWrite(r.LatchPin(), HIGH);
  }
  /*void fireLED(ShiftRegister &r)
  {
     
        digitalWrite(r.LatchPin(),LOW);
        Serial.println(r.ShiftNum(0));
        for (byte i=0; i<r.NoRegs();i++)
        {
          // if the current register is active, fire its pins
            Serial.print("Firing register: ");
            Serial.println(i);
            shiftOut(r.DataPin(),r.ClockPin(),MSBFIRST,r.ShiftNum(i));
       
        }
         digitalWrite(r.LatchPin(), HIGH);
  }

Wednesday, February 18, 2015

Victorian Steampunk Light Dress - Graphic Equalizer Function

Got the base function working with a shift register and two RGB LED's.

 Pinout is:

  • Datapin: 2 ->SR1(14)
  • Latchpin: 8->SR1(4)
  • Clockpin: 4 ->SR1(11)
  • SR1&2(16,10)->+5V
  • SR1&2(8) ->GND
  • SR1&2(13)->GND
  • SR1&2(15,1-7) LED's
  • SR1(9)->SR2(14)
  • SR1(4)->SR2(4)
  • SR1(11)->SR2(11)
  • Sound sensor VCC-5V
  • Sound Sensor GND->GND
  • Sound Sensor Out-> Analog 0
  • in/out 3 -> RGB1 Red pin
  • RGB1 GND->GND
  • in/out 5 -> RGB1 Green Pin
  • in/out 6 ->RGB1 Blue Pin
  • in/out 9 -> RGB2 Red pin
  • RGB2 GND->GND
  • in/out 10 -> RGB2 Green Pin
  • in/out 11 ->RGB2 Blue Pin

(photos to come)

Code below.  Please see references to LED, ShiftRegister and RGBColor class.

#include <LED.h>
#include <ShiftRegister.h>
#include <RGBColor.h>
// DO NOT COPY
RGBColor * color;
RGBColor * color2;
Led * c2;
Led * c1;
byte dataPin = 2;              // The Serial Data Pin to the Shift Register
byte latchPin = 8;             // The Latch Pin to the Shift Register
byte clockPin = 4;

ShiftRegister * sr=new ShiftRegister(clockPin,latchPin,dataPin,16,2);

// END DO NOT COPY

// Tracking SR variabes
byte trackVector=0;
byte oldTrackAvg=0;
byte trackCount=0;
int trackTotal=0;
byte newTrackAvg=0;
//Standard SR Variables
int soundPin=A0;
byte mus_peak=0;
int mus_peakAdj=0;
byte mus_avg=0;
int mus_colorCount=5000;
long mus_count=0;
long mus_total=0;


void setup()
{
  c1=new Led(3,5,6);
  c2=new Led(9,10,11);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  
  pinMode(dataPin, OUTPUT);    // Configure Digital Pins
    
  pinMode(latchPin, OUTPUT);
    
  pinMode(clockPin, OUTPUT);  
  
  color=new RGBColor();
  color2=new RGBColor();
  Serial.begin(9600);
}

void loop()
{
  //Serial.println(analogRead(soundPin));
  //delay(40);
  musicBox(*c1,*c2);

}


void musicBox(Led &led1, Led &led2)
{
  // Bytes for the shift register
  byte SRPulse[]={B00000000,B00011000,B00111100,B01111110,B11111111};
// Turn off the Shift Register pins and LEDS


  // set the color
    // increment the music color count
  mus_colorCount=mus_colorCount+1;
  
  if (mus_colorCount>=5000)
  {
    color->SetRandom();
    color2->setColors(color->Compliment());
    mus_colorCount=0;

    
  }
  
  // collect the local sound value
  byte val=collectAnalogAVG(2);
  clearLed(led1);
  clearLed(led2);
  // add the value to the track total
  trackTotal=trackTotal+val;
  trackCount=trackCount+1;
  if (trackCount>=10)
  {
    oldTrackAvg=newTrackAvg;
    newTrackAvg=trackTotal/trackCount;
    int trackDifferent=newTrackAvg-oldTrackAvg;
    if (trackDifferent<0)
    {
      Serial.print(trackVector);
      // if we've picked up less noise, decrement the vector.
      if (trackVector>=1) trackVector=trackVector-1;
      Serial.print("=");
      Serial.print(trackVector);
    }
    else if (trackDifferent==0)
    {
      // if the sound value has not changed, trackvector should stay the same.
    }
    else if (trackDifferent>100)
    {
      // if the difference is great, increment by 2.
      if (trackVector<=2)  trackVector=trackVector+2;
      else if (trackVector<=3) trackVector=trackVector+1;
    }
    else {
    
      if (trackVector<=3) trackVector=trackVector+1;
    }
    Serial.print("=");
      Serial.println(trackVector);
    // reset SR tracking
    trackTotal=0;
    trackCount=0;
  }
  

  // if the current value is above the average...
  // TODO: Add an array of bytes that go from 0 up to to 255 in steps of 30.  If the sound goes up, pulse up every 2 (add counter.)  If it goes down, pulse down every 30.
  // weight the value against the peak
  if (val>mus_avg)
  {
  double perc=map(val,0,mus_peak,12,100)*.01;
  led1.SetRGB(color->Red()*perc,color->Green()*perc,color->Blue()*perc);
  led2.SetRGB(color2->Red()*perc,color2->Green()*perc,color2->Blue()*perc);
  fireLed(led1);
  fireLed(led2);
  
  delay(15);
  }
  fireLEDs(SRPulse[trackVector]);
}

byte SRNum(double perc)
{
  if (perc>.9)
  {
    return 255;
  }
  else if (perc>.7)
  {
    return 85;
  }
  else if (perc>.5)
  {
    return 68;
  }
  else {
    return 0;
  }
}

byte collectAnalogAVG(byte times)


  
  int total=0;
  for (int i=0;i<times;i++)
  {
    //total=total+map(analogRead(pin),0,500,0,255);
    byte val=map(analogRead(soundPin),0,255,0,255);
    // add it to the total
    mus_total+=val;
    // increment the count
    mus_count=mus_count+1;
    // calculate the average
    mus_avg=mus_total/mus_count;
    // If we've hit a musical peak
    if (val>=mus_peak)
    {
    trackCount=trackCount+5;
    mus_peak=val;
    // increment the color count; it goes up faster with loud noise!
    mus_colorCount=mus_colorCount+500;
    mus_peakAdj=0;
    // return right away!
    return mus_peak;
    }
    else {
    // increment the adjustment
    mus_peakAdj=mus_peakAdj+1;
    if (mus_peakAdj>=10000)
    {
      // if we've gone lower a hundred times, reduce the peak.
      mus_peak=mus_peak*.9;
      mus_peakAdj=0;
    }
    }
    total=total+val;
    delay(2);
    
  }
  return total/times;
}

void SRFireDiv(ShiftRegister &r, byte div)
{
     for (int i=0;i<r.NoPins();i++)
      {
        if (i%div==0) r.ActivatePin(i);
      }
      fireLED(r);
}
void clearLed(Led led)
{
    
    
    analogWrite(led.RPin(),0);
    analogWrite(led.GPin(),0);
    analogWrite(led.BPin(),0);
  
}

// STOP DO NOT COPY



void fireLed(Led led)
{
    
    
    analogWrite(led.RPin(),led.Red());
    analogWrite(led.GPin(),led.Green());
    analogWrite(led.BPin(),led.Blue());
  
}

    void fireLEDs(int data)
  {
        digitalWrite(latchPin,LOW);
        shiftOut(dataPin,clockPin,MSBFIRST,data);  
        shiftOut(dataPin,clockPin,MSBFIRST,data);   // Send the data byte 2
        digitalWrite(latchPin, HIGH);

  }
    void fireLED(ShiftRegister &r)
  {
     
       
        digitalWrite(r.LatchPin(),LOW);
       // for (byte i=0; i<r.NoRegs();i++)
        //{
          // if the current register is active, fire its pins
           // Serial.println(i);
            shiftOut(r.DataPin(),r.ClockPin(),MSBFIRST,r.ShiftNum(0));
            shiftOut(r.DataPin(),r.ClockPin(),MSBFIRST,r.ShiftNum(1));
          
        //}
         digitalWrite(r.LatchPin(), HIGH);
  }