/ Glowing_Beehive_Hairdo_Wig / Glowing_Beehive_Hairdo_Wig.ino
Glowing_Beehive_Hairdo_Wig.ino
1 // SPDX-FileCopyrightText: 2017 Erin St Blaine for Adafruit Industries 2 // 3 // SPDX-License-Identifier: MIT 4 5 // Code by Erin St Blaine for Adafruit.com 6 // Full tutorial at https://learn.adafruit.com/glowing-beehive-hairdo-wig/ 7 8 #include <Adafruit_CircuitPlayground.h> // add this before the FastLED library to avoid issues 9 #include <FastLED.h> 10 11 #define LED_PIN 6 //led strand is soldered to pin 6 12 #define CP_PIN 17 //circuit playground's neopixels live on pin 17 13 #define NUM_LEDS 12 // number of LEDs in my strand 14 #define NUM_CP 10 // number of neopixels on the circuit playground 15 16 // I have purposefully mixed up the color order on the Neopixel strip to 17 // quickly and easily add color variety to this code -- This way the strip will always 18 // show a different color from the light pipe. 19 20 #define COLOR_ORDER GRB 21 #define COLOR_ORDER_STRIP RBG 22 23 uint8_t brightness = 255; //led strand brightness control 24 uint8_t cpbrightness = 255; //circuit playground brightness control 25 26 int STEPS = 25; //makes the rainbow colors more or less spread out 27 int NUM_MODES = 4; // change this number if you add or subtract modes 28 29 CRGB leds[NUM_LEDS]; //I've set up different arrays for the neopixel strand and the circuit playground 30 CRGB cp[NUM_CP]; // so that we can control the brightness separately 31 32 CRGBPalette16 currentPalette; 33 TBlendType currentBlending; 34 35 int ledMode = 0; //Initial mode 36 bool leftButtonPressed; 37 bool rightButtonPressed; 38 39 // SOUND REACTIVE SETUP -------------- 40 41 #define MIC_PIN A4 // Analog port for microphone 42 #define DC_OFFSET 0 // DC offset in mic signal - if unusure, leave 0 43 // I calculated this value by serialprintln lots of mic values 44 #define NOISE 200 // Noise/hum/interference in mic signal and increased value until it went quiet 45 #define SAMPLES 60 // Length of buffer for dynamic level adjustment 46 #define TOP (NUM_LEDS + 2) // Allow dot to go slightly off scale 47 #define PEAK_FALL 10 // Rate of peak falling dot 48 49 byte 50 peak = 0, // Used for falling dot 51 dotCount = 0, // Frame counter for delaying dot-falling speed 52 volCount = 0; // Frame counter for storing past volume data 53 int 54 vol[SAMPLES], // Collection of prior volume samples 55 lvl = 10, // Current audio level, change this number to adjust sensitivity 56 minLvlAvg = 0, // For dynamic adjustment of graph low & high 57 maxLvlAvg = 512; 58 59 60 // SETUP ------------------- 61 62 void setup() { 63 Serial.begin(57600); 64 CircuitPlayground.begin(); 65 FastLED.addLeds<WS2812B, LED_PIN, COLOR_ORDER_STRIP>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); 66 FastLED.addLeds<WS2812B, CP_PIN, COLOR_ORDER>(cp, 10).setCorrection( TypicalLEDStrip ); 67 currentBlending = LINEARBLEND; 68 set_max_power_in_volts_and_milliamps(5, 500); // FastLED 2.1 Power management set at 5V, 500mA 69 70 71 } 72 73 void loop() { 74 75 leftButtonPressed = CircuitPlayground.leftButton(); 76 rightButtonPressed = CircuitPlayground.rightButton(); 77 78 if (leftButtonPressed) { //left button cycles through modes 79 clearpixels(); 80 ledMode=ledMode+1; 81 delay(300); 82 if (ledMode > NUM_MODES){ 83 ledMode=0; 84 } 85 } 86 if (rightButtonPressed) { // right button turns all leds off 87 ledMode=99; 88 89 } 90 91 switch (ledMode) { 92 case 0: currentPalette = RainbowColors_p; rainbow(); break; 93 case 1: soundreactive(); break; 94 case 2: currentPalette = OceanColors_p; rainbow(); break; 95 case 3: currentPalette = LavaColors_p; rainbow(); break; 96 case 4: currentPalette = RainbowStripeColors_p; rainbow(); break; 97 case 99: clearpixels(); break; 98 99 } 100 } 101 102 void clearpixels() 103 { 104 CircuitPlayground.clearPixels(); 105 for (int i = 0; i < NUM_LEDS; i++) leds[i] = CRGB::Black; 106 for (int i = 0; i < NUM_CP; i++) cp[i] = CRGB::Black; 107 FastLED.show(); 108 } 109 110 void rainbow() 111 { 112 113 static uint8_t startIndex = 0; 114 startIndex = startIndex + 1; /* motion speed */ 115 116 FillLEDsFromPaletteColors( startIndex); 117 118 FastLED.show(); 119 FastLED.delay(20);} 120 121 //this bit is in every palette mode, needs to be in there just once 122 void FillLEDsFromPaletteColors( uint8_t colorIndex) 123 { 124 for (int i = 0; i < NUM_LEDS; i++) leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending); 125 for (int i = 0; i < NUM_CP; i++) cp[i] = ColorFromPalette( currentPalette, colorIndex, cpbrightness, currentBlending); 126 colorIndex += 25; 127 128 } 129 130 131 void soundreactive() { 132 133 uint8_t i; 134 uint16_t minLvl, maxLvl; 135 int n, height; 136 137 n = analogRead(MIC_PIN); // Raw reading from mic 138 n = abs(n - 512 - DC_OFFSET); // Center on zero 139 140 n = (n <= NOISE) ? 0 : (n - NOISE); // Remove noise/hum 141 lvl = ((lvl * 7) + n) >> 3; // "Dampened" reading (else looks twitchy) 142 143 // Calculate bar height based on dynamic min/max levels (fixed point): 144 height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg); 145 146 if (height < 0L) height = 0; // Clip output 147 else if (height > TOP) height = TOP; 148 if (height > peak) peak = height; // Keep 'peak' dot at top 149 150 151 // Color pixels based on rainbow gradient -- led strand 152 for (i=0; i<NUM_LEDS; i++) { 153 if (i >= height) leds[i].setRGB( 0, 0,0); 154 else leds[i] = CHSV(map(i,0,NUM_LEDS-1,0,255), 255, brightness); //constrain colors here by changing HSV values 155 } 156 157 // Draw peak dot -- led strand 158 if (peak > 0 && peak <= NUM_LEDS-1) leds[peak] = CHSV(map(peak,0,NUM_LEDS-1,0,255), 255, brightness); 159 160 // Color pixels based on rainbow gradient -- circuit playground 161 for (i=0; i<NUM_CP; i++) { 162 if (i >= height) cp[i].setRGB( 0, 0,0); 163 else cp[i] = CHSV(map(i,0,NUM_CP-1,0,255), 255, cpbrightness); //constrain colors here by changing HSV values 164 } 165 166 // Draw peak dot -- circuit playground 167 if (peak > 0 && peak <= NUM_CP-1) cp[peak] = CHSV(map(peak,0,NUM_LEDS-1,0,255), 255, cpbrightness); 168 169 // Every few frames, make the peak pixel drop by 1: 170 171 if (++dotCount >= PEAK_FALL) { // fall rate 172 if(peak > 0) peak--; 173 dotCount = 0; 174 } 175 176 vol[volCount] = n; // Save sample for dynamic leveling 177 if (++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter 178 179 // Get volume range of prior frames 180 minLvl = maxLvl = vol[0]; 181 for (i=1; i<SAMPLES; i++) { 182 if (vol[i] < minLvl) minLvl = vol[i]; 183 else if (vol[i] > maxLvl) maxLvl = vol[i]; 184 } 185 // minLvl and maxLvl indicate the volume range over prior frames, used 186 // for vertically scaling the output graph (so it looks interesting 187 // regardless of volume level). If they're too close together though 188 // (e.g. at very low volume levels) the graph becomes super coarse 189 // and 'jumpy'...so keep some minimum distance between them (this 190 // also lets the graph go to zero when no sound is playing): 191 if((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP; 192 minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels 193 maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average) 194 195 196 show_at_max_brightness_for_power(); // Power managed FastLED display 197 Serial.println(LEDS.getFPS()); 198 }