/* * Code for Raphael Arar's Installation at SCMAH 2016-10-22 * Work in progress * Uses a spectrum shield to isolate 7 frequency bands stereo on audio input * This sketch expresses that data in a couple of ways. */ // Neopixels #include #define RING_COUNT 6 #define RING_LED_COUNT 24 #define NUM_LEDS (RING_COUNT * RING_LED_COUNT) #define LED_DATA_PIN 6 CRGB leds[NUM_LEDS]; // Spectrum shield pins #define STROBE 4 #define RESET 5 #define DC_One A0 #define DC_Two A1 #define BANDS 7 #define doPpv 0 #if doPpv #define ppvDelay delay(100); #define ppv(_t, _f) Serial.print(_t); Serial.println(_f); ppvDelay #define ppv3(_t, _f, _g) Serial.print(_t); Serial.print(_f); Serial.print(" "); Serial.println(_g); ppvDelay #else #define ppv(_t, _f) #define ppv3(_t, _f, _g) #endif int frequencyAmplitudesLeft[BANDS] = {0}; int frequencyAmplitudesRight[BANDS] = {0}; class Ring { public: int firstLed = -1; int ledCount = 0; int whichPattern; Ring(int firstLed, int ledCount); void setPixel1(int x, CHSV color); void setPixel(float x, CHSV color); void fade(int amt) { for(int i = 0; i < this->ledCount; i++) { leds[this->firstLed + i].nscale8(amt); } } void stepPattern() { switch(this->whichPattern % 3) { case 0: this->stepPattern0(); break; case 1: this->stepPattern1(); break; case 2: this->stepPattern2(); break; } } class P0Piece { public: float p0Current = 0; float p0Target = 0; int band0; int band1; int hueBase; int xBase; int ledCount; Ring *ring; void step() { // Lowest frequency this->p0Target = frequencyAmplitudesLeft[this->band0] * this->ledCount / 4 / 255; this->p0Current = migrate(this->p0Current, 3.8, this->p0Target); int hue = this->hueBase + frequencyAmplitudesLeft[this->band1] / 5; this->ring->setPixel(xBase + this->p0Current, CHSV(hue, 255,180)); } }; P0Piece p0Pieces[3]; void initPattern0() { // ppv("init: ", 2.2); for(int ix = 0; ix < 3; ix++) { P0Piece *pp = &p0Pieces[ix]; pp->band0 = random(0,7); pp->band1 = random(0,7); pp->hueBase = random(0,256); pp->xBase = ix * 8; pp->ring = this; pp->ledCount = this->ledCount; } } void stepPattern0() { for(int ix = 0; ix < 3; ix++) p0Pieces[ix].step(); this->fade(220); } int p1Level = 0; int p1Hue = 0; int p1HueBase = 0; int p1Band1 = 0; int p1Band2 = 1; void initPattern1() { this->p1Hue = random(0,255); this->p1HueBase = random(0,255); this->p1Band1 = random(0,BANDS); this->p1Band2 = random(0,BANDS); } void stepPattern1()//(int hue, int band1, int band2) { ppv3("p1 level", this->firstLed, this->p1Level); int newLevel = frequencyAmplitudesRight[this->p1Band1]; this->p1Level = migrateI(this->p1Level, 255, 90, newLevel); this->p1Hue = migrateI(this->p1Hue, 10, this->p1HueBase + frequencyAmplitudesLeft[this->p1Band2] / 9); CHSV c = CHSV(this->p1Hue, 255, this->p1Level); for(int ix = 0; ix < this->ledCount; ix++) { this->setPixel1(ix, c); c.hue++; c.saturation--; } } /* --------------------------- * Pattern '2' * Shows pairs of lamps, Left & Right for each frequency band. * Plain & Simple. */ int p2Hue; void initPattern2() { this->p2Hue = random(0,255); } void stepPattern2() { for(int ix = 0; ix < this->ledCount; ix++) this->setPixel1(ix, CHSV(0,0,0)); for(int ix = 0; ix < BANDS; ix++) { int k = ix * 3; this->setPixel1(k, CHSV(this->p2Hue, 255, frequencyAmplitudesLeft[ix])); this->setPixel1(k+1, CHSV(p2Hue, 255, frequencyAmplitudesRight[ix])); } this->p2Hue--; } }; Ring *rings[RING_COUNT] = {0}; // define a ring by its range of leds. Ring::Ring(int firstLed, int ledCount) { this->firstLed = firstLed; this->ledCount = ledCount; } // set integer pixel position within ring void Ring::setPixel1(int x, CHSV color) { // ppv3("::setPixel1() ", x, color.value); if(x < 0) x = 0; x = x % this->ledCount; leds[this->firstLed + x] = color; } // set faded "analog" led pixel position within ring void Ring::setPixel(float x, CHSV color) { CHSV color2 = color; float t = x - floor(x); color2.value *= t; color.value *= 1.0 - t; int xI = (int)floor(x); this->setPixel1(xI, color); this->setPixel1(xI + 1, color2); } #define FAKE_THE_FREQUENCIES 0 void initSpectrumShield() { pinMode(STROBE, OUTPUT); pinMode(RESET, OUTPUT); pinMode(DC_One, INPUT); pinMode(DC_Two, INPUT); digitalWrite(STROBE, HIGH); digitalWrite(RESET, HIGH); //Initialize Spectrum Analyzers digitalWrite(STROBE, LOW); delay(1); digitalWrite(RESET, HIGH); delay(1); digitalWrite(STROBE, HIGH); delay(1); digitalWrite(STROBE, LOW); delay(1); digitalWrite(RESET, LOW); } void setup() { // put your setup code here, to run once: Serial.begin(115200); Serial.print("hello"); FastLED.addLeds(leds,NUM_LEDS); LEDS.setBrightness(78); initSpectrumShield(); for(int ix = 0; ix < RING_COUNT; ix++) { rings[ix] = new Ring(ix * RING_LED_COUNT, RING_LED_COUNT); } } // scale spectrum shield input a nice amount. int analogReadAndPin(int pin) { int v = analogRead(pin); v = v * 2 / 9; if(v > 255) v = 255; return v; } void readFrequencies() { #if FAKE_THE_FREQUENCIES for(int ix = 0; ix < BANDS; ix++) { if(random(0,44) == 13) { frequencyAmplitudesLeft[ix] = random(128,255); frequencyAmplitudesRight[ix] = random(128,255); } else { frequencyAmplitudesLeft[ix] *= 0.85; frequencyAmplitudesRight[ix] *= 0.85; } } return; #endif // from https://learn.sparkfun.com/tutorials/spectrum-shield-hookup-guide // Read frequencies for each band for (int ix = 0; ix= 0 && x < NUM_LEDS) leds[xI] += color; xI++; if(xI >= 0 && x < NUM_LEDS) leds[xI] += color2; } static float migrate(float x, float amount, float towards) { float del = towards - x; if(abs(del) <= amount) x = towards; else if(del < 0) x -= amount; else x += amount; return x; } static int migrateI(int x, int amount, int towards) { int del = towards - x; if(abs(del) <= amount) x = towards; else if(del < 0) x -= amount; else x += amount; return x; } static int migrateI(int x, int amountUp, int amountDown, int towards) { int del = towards - x; if(del < 0) { if(-del < amountDown) x = towards; else x -= amountDown; } else { if(del < amountUp) x = towards; else x += amountUp; } return x; } #define PINTERVAL 250 unsigned long ticks = 0; int foreverDotHue = 0; void loop() { ticks++; leds[ticks % NUM_LEDS] += CHSV(foreverDotHue++,255,170); // moving red dot galore! int whichPattern = (ticks / 400) % 3; readFrequencies(); int t = ticks % PINTERVAL; if(t == 1) { // new patterns! // init everthing just in case. for(int ix = 0; ix < RING_COUNT; ix++) { rings[ix]->initPattern0(); rings[ix]->initPattern1(); rings[ix]->initPattern2(); } int patternA = random(0,3); int patternB = random(0,3); for(int ix = 0; ix < RING_COUNT; ix++) { rings[ix]->whichPattern = ix == 0 || ix == RING_COUNT - 1 ? patternA : patternB; } } for(int ix = 0; ix < RING_COUNT; ix++) { rings[ix]->stepPattern(); } FastLED.show(); delay(20); return; }