Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Dawn Dupriest
Published © CC BY

NeoPixel Musical Ugly Christmas Sweater

Every year I make an ugly Christmas sweater with wearable electronics. I decided to add an MP3 player this year. I have no regrets!

IntermediateFull instructions provided8 hours1,043

Things used in this project

Hardware components

Lilypad MP3 Board
SparkFun Lilypad MP3 Board
×1
Flora RGB Neopixel LEDs- Pack of 4
Adafruit Flora RGB Neopixel LEDs- Pack of 4
×4
Lilypad Arduino USB
SparkFun Lilypad Arduino USB
×1
Speaker: 0.25W, 8 ohms
Speaker: 0.25W, 8 ohms
×2
SparkFun Conductive Thread
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Fritzing Diagram

I didn't have a fritzing model for the LilyPad MP3, so just pretend it's there. :) Neopixel fritzing files are here. https://github.com/adafruit/Fritzing-Library/tree/master/parts

Code

Sweater_Mariah_Wham

Arduino
Based on the sample Neopixel library. Thanks to Adafruit! Works nice.
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN 11

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

int bpm = 150;
int msperbeat = (int)(60000 / bpm);
int pixelsinorder[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 11, 10, 9, 15, 14, 13};



void setup() {
  // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket
  #if defined (__AVR_ATtiny85__)
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif
  // End of trinket special code


  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  
}

void loop() {

 while((digitalRead(5) == HIGH) && (digitalRead(6) == HIGH))
  ;

 if(digitalRead(6) == LOW) // WHAM
 {
  bpm = 112;
  msperbeat = (int)(60000 / bpm);
  delay(1000);
  
 theaterChaseDuration(strip.Color(0, 127, 0), 50, msperbeat * 4); // Green
 theaterChaseRainbowDuration(50,msperbeat * 4);
 theaterChaseDuration(strip.Color(127, 0, 0), 50, msperbeat * 4); // red
 theaterChaseRainbowDuration(50,msperbeat * 4);
 theaterChaseDuration(strip.Color(127,0,127),200, msperbeat * 4);
 theaterChaseDuration(strip.Color(0,127,127),200, msperbeat * 4);
 rainbowDuration(50, msperbeat * 4);
 // last christmas
 colorWipeDurationMini(strip.Color(127,127,127),0,15,msperbeat * 4);
 colorMiniStrip(strip.Color(0,127,0), 0, 5, (int)(msperbeat * 3 / 2));
  colorMiniStrip(strip.Color(0,127,0), 9, 12,(int)(msperbeat * 3 / 2));
  // I gave you my heart
  colorMiniStrip(strip.Color(0,0,127), 6, 8, msperbeat);
  colorMiniStrip(strip.Color(127,0,0), 0, 15, msperbeat);
  colorMiniStrip(strip.Color(0,0,0), 0, 15, msperbeat);
  colorMiniStrip(strip.Color(127,0,0), 0, 15, msperbeat);
  colorMiniStrip(strip.Color(0,0,0), 0, 15, msperbeat);
  // but the very next day
  colorWipeDurationMini(strip.Color(127,127,0),0, 5, msperbeat * 4);
  // you gave it away
  theaterChaseMiniDuration(strip.Color(0,0,127), 6,8, 150, msperbeat * 2);
  theaterChaseMiniDuration(strip.Color(0,0,127), 13,15,150,  msperbeat * 2);
  // this year
  brightenMiniDuration(1, 0, 15, msperbeat * 4);
  // to save me from tears
  theaterChaseMiniDuration(strip.Color(127,127,127), 6,8, 50, msperbeat * 2);
  theaterChaseMiniDuration(strip.Color(127,127,127), 13,15,50,  msperbeat * 2);
  // I'll give it to someone special
  brightenMiniDuration(4, 0, 5, msperbeat * 4);
  brightenMiniDuration(3, 6, 15, msperbeat * 4);

  // last christmas
 colorMiniStrip(strip.Color(0,127,0), 0, 5, (int)(msperbeat * 3 / 2));
  colorMiniStrip(strip.Color(0,127,0), 9, 12,(int)(msperbeat * 3 / 2));
  // I gave you my heart
  colorMiniStrip(strip.Color(0,0,127), 6, 8, msperbeat);
  colorMiniStrip(strip.Color(127,0,0), 0, 15, msperbeat);
  colorMiniStrip(strip.Color(0,0,0), 0, 15, msperbeat);
  colorMiniStrip(strip.Color(127,0,0), 0, 15, msperbeat);
  colorMiniStrip(strip.Color(0,0,0), 0, 15, msperbeat);
  // but the very next day
  colorWipeDurationMini(strip.Color(127,127,0),0, 5, msperbeat * 4);
  // you gave it away
  theaterChaseMiniDuration(strip.Color(0,0,127), 6,8, 150, msperbeat * 2);
  theaterChaseMiniDuration(strip.Color(0,0,127), 13,15,150,  msperbeat * 2);
  // this year
  brightenMiniDuration(1, 0, 15, msperbeat * 4);
  // to save me from tears
  theaterChaseMiniDuration(strip.Color(127,127,127), 6,8, 50, msperbeat * 2);
  theaterChaseMiniDuration(strip.Color(127,127,127), 13,15,50,  msperbeat * 2);
  // I'll give it to someone special
  brightenMiniDuration(4, 0, 5, msperbeat * 4);
  brightenMiniDuration(3, 6, 15, msperbeat * 4);
 
 colorWipe(strip.Color(0,0,0),10);
 }

 else  // mariah carey
 {
  bpm = 60;
  msperbeat = 60000 / bpm;
  //delay(500);
  colorWipeDurationMini(strip.Color(255,0,0),0, 15, msperbeat * 6);
  theaterChaseRainbowDuration(50,msperbeat * 6);
  colorWipeDurationMini(strip.Color(0,127,0),13, 15, msperbeat*2);
  colorWipeDurationMini(strip.Color(127,0,0),6, 8, msperbeat*2);
  colorWipe(strip.Color(0,0,0),50);
  
  colorWipeDurationMini(strip.Color(127,127,127),0, 5, msperbeat);
  colorWipeDurationMini(strip.Color(127,127,127),9, 12, msperbeat);
  theaterChaseRainbowDuration(50,msperbeat * 3);
  colorMiniStrip(strip.Color(0,0,127), 0, 5, msperbeat / 2);
  colorMiniStrip(strip.Color(0,0,127), 9, 12, msperbeat / 2);
  colorMiniStrip(strip.Color(0,0,127), 6, 8, msperbeat / 2);
  colorMiniStrip(strip.Color(0,0,127), 13, 15, msperbeat / 2);
  theaterChaseMiniDuration(strip.Color(127,127,127), 6,8, 50, msperbeat);
  theaterChaseMiniDuration(strip.Color(127,127,127), 13,15,50,  msperbeat);
  theaterChaseRainbowDuration(50,msperbeat * 2);
  colorWipeDurationMini(strip.Color(0,255,0),0, 15, msperbeat * 4);
  theaterChaseDuration(strip.Color(127,0,127), 200, msperbeat * 4);
  rainbowDuration(50, msperbeat * 4);
  theaterChaseMiniDuration(strip.Color(127,127,0),9,12, 100, msperbeat * 3);
  colorWipeDurationMini(strip.Color(127,127,127), 0,5, msperbeat * 4);
  rainbowDuration(50, msperbeat * 4);
  colorWipe(strip.Color(0,0,0),15);
  delay(400);
  for(int h = 0; h < 3; h++)
  {
  colorMiniStrip(strip.Color(127,127,127), 0, 15, msperbeat / 10);
  colorMiniStrip(strip.Color(0,0,0), 0, 15, msperbeat / 10);
  colorMiniStrip(strip.Color(127,127,127), 0, 15, msperbeat / 10 * 2);
  colorMiniStrip(strip.Color(0,0,0), 0, 15, msperbeat / 10);
  }
  colorMiniStrip(strip.Color(127,127,127), 0, 15, msperbeat / 10*2);
  colorMiniStrip(strip.Color(0,0,0), 0, 15, msperbeat / 10);

  // Just about perfect introduction
  // now for the main verse
  bpm = 75;
  msperbeat = (int)(60000 / bpm);

  brightenMiniDuration(3, 0, 15, msperbeat * 4);
  theaterChaseMiniDuration(strip.Color(127,127,127),0,15,100,msperbeat * 4);
  brightenMiniDuration(1, 0, 15, msperbeat * 4);
  theaterChaseMiniDuration(strip.Color(127,127,127),0,15,100,msperbeat * 4);
  colorMiniStrip(strip.Color(0,127,0),6,8,msperbeat);
  colorMiniStrip(strip.Color(0,127,0),13,15,msperbeat);
  colorMiniStrip(strip.Color(0,0,0),6,8,msperbeat);
  colorMiniStrip(strip.Color(0,0,0),13,15,msperbeat);
  colorMiniStrip(strip.Color(0,127,0),0,5,msperbeat);
  colorMiniStrip(strip.Color(0,127,0),9,12,msperbeat);
  colorMiniStrip(strip.Color(0,0,0),0,5,msperbeat);
  colorMiniStrip(strip.Color(0,0,0),9,12,msperbeat);
  colorMiniStrip(strip.Color(127,0,0),6,8,msperbeat);
  colorMiniStrip(strip.Color(127,0,0),13,15,msperbeat);
  colorMiniStrip(strip.Color(0,0,0),6,8,msperbeat);
  colorMiniStrip(strip.Color(0,0,0),13,15,msperbeat);
  colorMiniStrip(strip.Color(127,0,0),0,5,msperbeat);
  colorMiniStrip(strip.Color(127,0,0),9,12,msperbeat);
  colorMiniStrip(strip.Color(0,0,0),0,5,msperbeat);
  colorMiniStrip(strip.Color(0,0,0),9,12,msperbeat);

  theaterChaseMiniDuration(strip.Color(0,0,127),0,5,50,msperbeat);
  theaterChaseMiniDuration(strip.Color(0,0,127),9,12,50,msperbeat);
  theaterChaseMiniDuration(strip.Color(127,0,127),6,8,50,msperbeat);
  theaterChaseMiniDuration(strip.Color(127,0,127),13,15,50,msperbeat);
  colorWipeDurationMini(strip.Color(127,0,0),0, 15, msperbeat * 2);
  colorWipeDurationMini(strip.Color(0,127,0),0, 15, msperbeat * 2);
  colorWipeDurationMini(strip.Color(0,127,127),0, 15, msperbeat * 2);
  colorWipeDurationMini(strip.Color(127,127,127),0, 15, msperbeat * 4);
  rainbowDuration(50, msperbeat * 6);

  for(int h = 0; h < 3; h++)
  {
  colorMiniStrip(strip.Color(127,127,127), 0, 15, msperbeat / 10);
  colorMiniStrip(strip.Color(0,0,0), 0, 15, msperbeat / 10);
  colorMiniStrip(strip.Color(127,127,127), 0, 15, msperbeat / 10 * 2);
  colorMiniStrip(strip.Color(0,0,0), 0, 15, msperbeat / 10);
  }
  colorMiniStrip(strip.Color(127,127,127), 0, 15, msperbeat / 10*2);
  colorMiniStrip(strip.Color(0,0,0), 0, 15, msperbeat / 10);
  
 }

   
   
}

// some example procedures
 // Some example procedures showing how to display to the pixels:
//  colorWipe(strip.Color(255, 0, 0), 50); // Red
 // colorWipe(strip.Color(0, 255, 0), 50); // Green
  //colorWipe(strip.Color(0, 0, 255), 50); // Blue
//colorWipe(strip.Color(0, 0, 0, 255), 50); // White RGBW
  // Send a theater pixel chase in...
  //theaterChase(strip.Color(127, 127, 127), 50); // White
  //theaterChase(strip.Color(127, 0, 0), 50); // Red
  //theaterChase(strip.Color(0, 0, 127), 50); // Blue

  //theaterChaseDuration(strip.Color(127, 0, 0), 50, 2000); // Red
  //theaterChaseDuration(strip.Color(0, 0, 127), 50, 5000); // Blue

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void colorWipeDurationMini(uint32_t c, int lowlight, int highlight, int duration) {
  int numlights = highlight - lowlight + 1;
  int durationperlight = duration / numlights;

  if(numlights == 16)
  {
    for(int i = 0; i <= 15; i++)
    {
      strip.setPixelColor(pixelsinorder[i],c);
      strip.show();
      delay(durationperlight);
    }
  }
  else{
    for(int i=lowlight; i<=highlight; i++) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(durationperlight);
    }
  }
}



void colorMiniStrip(uint32_t c, int lowlight, int highlight, int duration)
{
  int numlights = highlight - lowlight;
  int durationperlight = duration / numlights;
  for(int i=lowlight; i<=highlight; i++) {
    strip.setPixelColor(i, c);
  }
  strip.show();
  delay(duration);
  
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

void rainbowDuration(uint8_t wait, int duration) {
  uint16_t i, j;
  int totaltime = 0;
  while(totaltime < duration)
  {
  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
    totaltime += wait;
    if(totaltime >= duration)
    {
      return;
    }
  }
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

//Theatre-style crawling lights.
void theaterChaseDuration(uint32_t c, uint8_t wait, int duration) {
  int j = 0;
  int q = 0;
  uint16_t i = 0;
  int totaltime = 0;
  int lightnum;
  while(totaltime < duration)
  {
      for (uint16_t i=0; i <= 15; i=i+3) {
        lightnum = i+q;
        if(lightnum > 15)
        {
          lightnum = lightnum - 15 - 1;
        }
        strip.setPixelColor(pixelsinorder[lightnum], c);    //turn every third pixel on
      }
      strip.show();

      delay(wait);
      totaltime += wait;

      for (uint16_t i=0; i <= 15; i=i+3) {
        lightnum = i+q;
        if(lightnum > 15)
        {
          lightnum = lightnum - 15 - 1;
        }
        strip.setPixelColor(pixelsinorder[lightnum], 0);        //turn every third pixel off
      }

    q++;
    if(q >= 3)
      q = 0;
  }
  // when time is up turn lights off
  for(uint16_t i = 0; i < strip.numPixels(); i++)
  {
    strip.setPixelColor(i,0);
  }
  strip.show();
}


void theaterChaseMiniDuration(uint32_t c, int lowlight, int highlight, uint8_t wait, int duration) {
  int j = 0;
  int q = 0;
  uint16_t i = 0;
  int totaltime = 0;
  while(totaltime < duration)
  {
      int lightnum;
      for (int i=lowlight; i <= highlight; i=i+3) {
        lightnum = i+q;
        if(lightnum > highlight)
        {
          lightnum = lightnum - highlight - 1 + lowlight;
        }
        strip.setPixelColor(lightnum, c);    //turn every third pixel on
      }
      strip.show();

      delay(wait);
      totaltime += wait;

      for (uint16_t i=lowlight; i <= highlight; i=i+3) {
        lightnum = i+q;
        if(lightnum > highlight)
        {
          lightnum = lightnum - highlight - 1 + lowlight;
        }
        strip.setPixelColor(lightnum, 0);        //turn every third pixel off
      }

    q++;
    if(q >= 3)
      q = 0;
  }
  // when time is up turn lights off
  for(uint16_t i = 0; i < strip.numPixels(); i++)
  {
    strip.setPixelColor(i,0);
  }
  strip.show();
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbowDuration(uint8_t wait, int duration) {
  int totaltime = 0;
  int lightnum;
  while(totaltime < duration)
  {
  for (int j=0; j < 256; j = j + 10) {     // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i <= 15; i=i+3) {
        lightnum = i+q;
        if(lightnum > 15)
        {
          lightnum = lightnum - 15 - 1;
        }
        strip.setPixelColor(pixelsinorder[lightnum], Wheel( (i+j) % 255));    //turn every third pixel on
      }
      strip.show();

      delay(wait);
      for (uint16_t i=0; i <= 15; i=i+3) {
         lightnum = i+q;
        if(lightnum > 15)
        {
          lightnum = lightnum - 15 - 1;
        }
        strip.setPixelColor(pixelsinorder[lightnum], 0);        //turn every third pixel off
      }
      
      totaltime += wait;
      if(totaltime >= duration)
      {
        for(uint16_t m = 0; m < strip.numPixels(); m++)
          strip.setPixelColor(m,0);
        strip.show();
        delay(10);
        return;
      }

      
    }
  }
  
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}


// brightens a strip of pixels over a duration
// assumes duration is over like 1000
// first parameter is 1 if red, 2 if green, 3 if blue, 4 if white
void brightenMiniDuration(int hue, int lowlight, int highlight, int duration)
{
  duration = duration - 127; // need to shorten, there are delays in here
  int mspershade = (int)(duration / 128);
  if(duration < 256)
    mspershade = 2;
  if(duration < 128)
     mspershade = 1;

  int totaltime = 0;
  uint32_t c;
  int i = 0;
  
  
  while(totaltime < duration)
  {
    if(hue == 1)
        c =strip.Color(i, 0, 0);
    else if (hue == 2)
        c = strip.Color(0,i,0);
    else if (hue == 3)
        c = strip.Color(0,0,i);
    else
        c = strip.Color(i,i,i);
    for(int index = lowlight; index <= highlight; index++)
    {    
      strip.setPixelColor(index, c);
    }
    strip.show();
    i+= 1;
    delay(mspershade);
    totaltime += mspershade;
  }
  return;
  
}

Credits

Dawn Dupriest

Dawn Dupriest

4 projects • 5 followers
Middle School Computer Science teacher, Feminist, Maker. 2012 Poudre School District Teacher of the Year. 2016 Allen Distinguished Educator.
Thanks to Mark Schreiber.

Comments