Last active
September 26, 2017 18:11
-
-
Save jwhendy/c252ad78c4f6cefeeee82e85a24cb300 to your computer and use it in GitHub Desktop.
Code used to run some fun animations/routines on a 16x16 WS2812 LED matrix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Based on SpectrumAnalyzerBasic by Paul Stoffregen included in the Teensy Audio Library | |
* Modified by Jason Coon for the SmartMatrix Library | |
* Requires Teensyduino 1.20 or higher and the Teensy Audio Library | |
* Also requires FastLED 3.1 or higher | |
* If you are having trouble compiling, see | |
* the troubleshooting instructions here: | |
* https://github.com/pixelmatix/SmartMatrix/#external-libraries | |
* | |
* actual code found: | |
* https://raw.githubusercontent.com/pixelmatix/SmartMatrix/master/examples/SpectrumAnalyzer/SpectrumAnalyzer.ino | |
* | |
* Requires the following libraries: | |
* Teensy Audio Library: https://github.com/PaulStoffregen/Audio | |
* SerialFlash Library (a dependency of the Teensy Audio Library): https://github.com/PaulStoffregen/SerialFlash | |
* FastLED v3.1 or higher: https://github.com/FastLED/FastLED/releases | |
* | |
* Uses line in on pin A2. For more information, and a recommended analog input circuit, see: http://www.pjrc.com/teensy/gui/?info=AudioInputAnalog | |
* | |
* You can change the pin used for ADC with the ADC_INPUT_PIN definition below. | |
* There are no dedicated ADC pins brought out on the SmartMatrix Shield, | |
* but even if you've used all the pins on the SmartMatrix expansion header, | |
* you can use solder pins directly to the Teensy to use A14/DAC, A11, or A10 | |
* | |
* This SmartMatrix example uses just the background layer | |
*/ | |
// all these libraries are required for the Teensy Audio Library | |
#define FASTLED_ALLOW_INTERRUPTS 0 | |
#include <Audio.h> | |
#include <Wire.h> | |
#include <SPI.h> | |
#include <SD.h> | |
#include <FastLED.h> | |
#include <RotaryEncoder.h> | |
#define DATA_PIN 22 | |
#define LED_TYPE WS2812B | |
#define COLOR_ORDER GRB | |
#define NUM_LEDS 256 | |
CRGB leds[NUM_LEDS]; | |
// adxl device for wire.h | |
#define DEVICE (0x53) | |
#define ADC_INPUT_PIN A2 | |
// adxl setup | |
byte _buff[6]; | |
char POWER_CTL = 0x2D; //Power Control Register | |
char DATA_FORMAT = 0x31; | |
char DATAX0 = 0x32; //X-Axis Data 0 | |
char DATAX1 = 0x33; //X-Axis Data 1 | |
char DATAY0 = 0x34; //Y-Axis Data 0 | |
char DATAY1 = 0x35; //Y-Axis Data 1 | |
char DATAZ0 = 0x36; //Z-Axis Data 0 | |
char DATAZ1 = 0x37; //Z-Axis Data 1 | |
uint8_t howManyBytesToRead = 6; | |
AudioInputAnalog input(ADC_INPUT_PIN); | |
AudioAnalyzeFFT256 fft; | |
AudioConnection audioConnection(input, 0, fft, 0); | |
int mode_aud = 0; | |
int mode_main = 0; | |
int16_t x_raw = 0; | |
int16_t y_raw = 0; | |
int16_t z_raw = 0; | |
int x_off = -129; | |
int y_off = 25; | |
int z_off = 1742; | |
int x_rng = 595; | |
int y_rng = 583; | |
int z_rng = 522; | |
float acc_x; float acc_y; float acc_z; | |
long now = millis(); | |
float cx = 7; | |
float cy = 8; | |
float x = 0; | |
float y = 0; | |
float rad = 0; | |
int hue = 0; | |
int delta = 3; | |
int bright = 255; | |
int sat = 255; | |
int fill = 0; | |
long pulse = 0; | |
long running = 0; | |
//int x = 0; | |
//int y = 0; | |
RotaryEncoder enc_y(12, 11); | |
RotaryEncoder enc_x(15, 14); | |
int pin_enc_x = 10; | |
int pin_enc_y = 17; | |
// The scale sets how much sound is needed in each frequency range to | |
// show all 16 bars. Higher numbers are more sensitive. | |
float scale = 3000.0; | |
// An array to hold the 16 frequency bands | |
float level[16]; | |
// This array holds the current max seen. We can't know ahead of time | |
// how big the signal will be, so this increases it per channel | |
// so that the max-seen-so-far corresponds to lighting all 16 pixels | |
int cur_max[16]; | |
int cur_min[16]; | |
void setup() | |
{ | |
Serial.begin(9600); | |
pinMode(A9, INPUT); | |
pinMode(pin_enc_x, INPUT_PULLUP); | |
pinMode(pin_enc_y, INPUT_PULLUP); | |
// join i2c bus (address optional for master) | |
Wire.begin(); | |
// Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register. | |
// think 0x00 = 2g, 00x1 = 4g, 00x2 = 8g, and 00x3 = 16g | |
writeTo(DATA_FORMAT, 0x0B); | |
//Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register. | |
writeTo(POWER_CTL, 0x08); | |
// Initialize Matrix | |
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS); | |
FastLED.setBrightness(200); | |
// Audio requires memory to work. | |
AudioMemory(12); | |
// initialize our maximums to some guess (10) | |
// from watching serial, the actual values looks to be ~30ish | |
for(int i = 0; i < 16; i++) { cur_max[i] = 0; } | |
for(int i = 0; i < 16; i++) { cur_min[i] = 0; } | |
FastLED.clear(); | |
FastLED.show(); | |
} | |
void loop() | |
{ | |
now = millis(); | |
int set = 0; | |
while((digitalRead(pin_enc_x) == LOW) & (digitalRead(pin_enc_y) == LOW)) | |
{ | |
if((millis() - now > 2000) & (set == 0)) | |
{ | |
FastLED.clear(); | |
FastLED.show(); | |
mode_main = mode_main + 1; | |
if(mode_main > 2) { mode_main = 0; } | |
set = 1; | |
} | |
} | |
if ((fft.available()) & (mode_main == 0)) | |
{ | |
// read the 128 FFT frequencies into 16 levels | |
// music is heard in octaves, but the FFT data | |
// is linear, so for the higher octaves, read | |
// many FFT bins together. | |
// I'm skipping the first two bins, as they seem to be unusable | |
// they start out at zero, but then climb and don't come back down | |
// even after sound input stops | |
level[0] = fft.read(1); | |
level[1] = fft.read(2); | |
level[2] = fft.read(3); | |
level[3] = fft.read(4); | |
level[4] = fft.read(5, 7); | |
level[5] = fft.read(7, 8); | |
level[6] = fft.read(9, 12); | |
level[7] = fft.read(13, 18); | |
level[8] = fft.read(19, 24); | |
level[9] = fft.read(25, 31); | |
level[10] = fft.read(32, 41); | |
level[11] = fft.read(42, 52); | |
level[12] = fft.read(53, 65); | |
level[13] = fft.read(66, 82); | |
level[14] = fft.read(83, 103); | |
level[15] = fft.read(104, 127); | |
for (int i = 0; i < 16; i++) | |
{ | |
if(cur_max[i] < (level[i] * scale)) { cur_max[i] = level[i] * scale; } | |
cur_min[i] = (cur_max[i] / 25) + 1; | |
} | |
switch(mode_aud) | |
{ | |
case 0: | |
color_per_band(); | |
break; | |
case 1: | |
rainbow_bands(); | |
break; | |
case 2: | |
rainbow_bands_cycle(); | |
break; | |
case 3: | |
wild(); | |
break; | |
case 4: | |
wild_split(); | |
break; | |
case 5: | |
rainbow_bands_split(); | |
break; | |
case 6: | |
rainbow_bands_cycle_split(); | |
break; | |
case 7: | |
color_per_band_split(); | |
break; | |
} | |
EVERY_N_MILLISECONDS(10) { fadeToBlackBy(leds, 256, 25); } | |
EVERY_N_MILLISECONDS(5000) | |
{ | |
for (int i = 0; i < 16; i++) | |
{ | |
cur_max[i] = int(cur_max[i] * 0.98); | |
} | |
} // every_n | |
EVERY_N_MILLISECONDS(10000) | |
{ | |
mode_aud = mode_aud + 1; | |
if(mode_aud > 7) { mode_aud = 0; } | |
} | |
} // if() | |
if(mode_main == 1) | |
{ | |
enc_x.tick(); | |
enc_y.tick(); | |
x = enc_x.getPosition(); | |
y = enc_y.getPosition(); | |
hue = beatsin8(12, 0, 150); | |
EVERY_N_MILLISECONDS(20) { fadeToBlackBy(leds, NUM_LEDS, 1); } | |
leds[(int(x)*16) + int(y)] = CHSV(hue, 255, 100); | |
FastLED.show(); | |
} | |
if(mode_main == 2) | |
{ | |
EVERY_N_MILLISECONDS(50) | |
{ | |
//read the acceleration data from the ADXL345 | |
readFrom(DATAX0, howManyBytesToRead, _buff); | |
x_raw = (((int)_buff[1]) << 8) | _buff[0]; | |
y_raw = (((int)_buff[3]) << 8) | _buff[2]; | |
z_raw = (((int)_buff[5]) << 8) | _buff[4]; | |
acc_x = (x_raw - x_off) * (2.0/x_rng); | |
acc_y = (y_raw - y_off) * (2.0/y_rng); | |
acc_z = (z_raw - z_off) * (2.0/z_rng); | |
now = millis(); | |
} | |
cx = constrain(cx - acc_y, 2, 13); | |
cy = constrain(cy - acc_x, 2, 13); | |
EVERY_N_MILLISECONDS(10) { fadeToBlackBy(leds, 256, 10); } | |
for(int i = 0; i < 16; i++) | |
{ | |
for(int j = 0; j < 16; j++) | |
{ | |
x = abs(i - cx); | |
y = abs(j - cy); | |
hue = beatsin8(10, 0, 255); | |
rad = sq(x) + sq(y); | |
if(rad <= 8) | |
{ | |
//hue = constrain(map(rad, 0, 5, hue, hue + 120), hue, hue + 220); | |
hue = map(rad, 0, 8, hue, hue + 120); | |
leds[(i*16) + j] = CHSV(hue, 255, 255); | |
} | |
} | |
} | |
FastLED.show(); | |
} | |
} // loop() | |
void color_per_band() | |
{ | |
for (int i = 0; i < 16; i++) | |
{ | |
fill = constrain(map(level[i] * scale, cur_min[i], int(cur_max[i]), 0, 16), 0, 16); | |
// this will give you a distinct color per bar cycling through the rainbow | |
fill_solid(leds + (i*16) + (16 - fill), fill, CHSV(i*220/16, 255, 255)); | |
} // for() | |
FastLED.show(); | |
} | |
void rainbow_bands() | |
{ | |
delta = 12; | |
for (int i = 0; i < 16; i++) | |
{ | |
fill = constrain(map(level[i] * scale, cur_min[i], int(cur_max[i]), 0, 16), 0, 16); | |
// this will provide a changing rainbow continuous across all bars | |
// rainbow always starts blue, goes to red | |
// fill_rainbow(leds + (i*16), fill, 160, -(160 / 16)); | |
fill_rainbow(leds + ((i*16) + (16 - fill)), fill, 140 + (delta*fill), -delta); | |
} // for() | |
FastLED.show(); | |
} | |
void rainbow_bands_cycle() | |
{ | |
delta = 12; | |
for (int i = 0; i < 16; i++) | |
{ | |
fill = constrain(map(level[i] * scale, cur_min[i], int(cur_max[i]), 0, 16), 0, 16); | |
// like the above, but start color constantly changes | |
fill_rainbow(leds + ((i*16) + (16 - fill)), fill, hue + (delta*fill), -delta); | |
EVERY_N_MILLISECONDS(10) { hue = hue + 1; } | |
} // for() | |
FastLED.show(); | |
} | |
void wild() | |
{ | |
for (int i = 0; i < 16; i++) | |
{ | |
fill = constrain(map(level[i] * scale, cur_min[i], int(cur_max[i]), 0, 16), 0, 16); | |
// like the first one (solid color per band), but rotates teh colors | |
fill_solid(leds + ((i*16) + (16 - fill)), fill, CHSV(hue + (i*220/16), 255, 255)); | |
EVERY_N_MILLISECONDS(3) { hue = hue + 5; } | |
} // for() | |
FastLED.show(); | |
} | |
void wild_split() | |
{ | |
for (int i = 0; i < 16; i++) | |
{ | |
fill = constrain(map(level[i] * scale, cur_min[i], int(cur_max[i]), 0, 16), 0, 16); | |
// like first fill_solid, but bars rotate through colors | |
int filly = int(fill / 2); | |
fill_solid(leds + (i*16), filly, CHSV(hue + (i*220/16), 255, 255)); | |
fill_solid(leds + (i*16) + (16-filly), filly, CHSV(hue - (i*220/16), 255, 255)); | |
EVERY_N_MILLISECONDS(3) { hue = hue + 5; } | |
} // for() | |
FastLED.show(); | |
} | |
void color_per_band_split() | |
{ | |
for (int i = 0; i < 16; i++) | |
{ | |
fill = constrain(map(level[i] * scale, cur_min[i], int(cur_max[i]), 0, 16), 0, 16); | |
// this will give you a distinct color per bar cycling through the rainbow | |
int filly = int(fill / 2); | |
fill_solid(leds + (i*16), filly, CHSV(i*220/16, 255, 255)); | |
fill_solid(leds + (i*16) + (16 - filly), filly, CHSV(i*220/16, 255, 255)); | |
} // for() | |
FastLED.show(); | |
} | |
void rainbow_bands_split() | |
{ | |
delta = 25; | |
for (int i = 0; i < 16; i++) | |
{ | |
fill = constrain(map(level[i] * scale, cur_min[i], int(cur_max[i]), 0, 16), 0, 16); | |
// this will provide a changing rainbow continuous across all bars | |
// rainbow always starts blue, goes to red | |
// fill_rainbow(leds + (i*16), fill, 160, -(160 / 16)); | |
int filly = int(fill / 2); | |
fill_rainbow(leds + (i*16) + (16 - filly), filly, 160 + (-delta*(filly-1)), delta); | |
fill_rainbow(leds + (i*16), filly, 160, -delta); | |
} // for() | |
FastLED.show(); | |
} | |
void rainbow_bands_cycle_split() | |
{ | |
delta = 12; | |
for (int i = 0; i < 16; i++) | |
{ | |
fill = constrain(map(level[i] * scale, cur_min[i], int(cur_max[i]), 0, 16), 0, 16); | |
// like the above, but start color constantly changes | |
int filly = int(fill / 2); | |
fill_rainbow(leds + (i*16) + (16 - filly), filly, hue + (-delta*(filly-1)), delta); | |
fill_rainbow(leds + (i*16), filly, hue, -delta); | |
//fill_rainbow(leds + ((i*16) + (16 - fill)), fill, hue + (delta*fill), -delta); | |
EVERY_N_MILLISECONDS(10) { hue = hue + 1; } | |
} // for() | |
FastLED.show(); | |
} | |
void writeTo(byte address, byte val) { | |
Wire.beginTransmission(DEVICE); // start transmission to device | |
Wire.write(address); // send register address | |
Wire.write(val); // send value to write | |
Wire.endTransmission(); // end transmission | |
} | |
// Reads num bytes starting from address register on device in to _buff array | |
void readFrom(byte address, int num, byte _buff[]) { | |
Wire.beginTransmission(DEVICE); // start transmission to device | |
Wire.write(address); // sends address to read from | |
Wire.endTransmission(); // end transmission | |
Wire.beginTransmission(DEVICE); // start transmission to device | |
Wire.requestFrom(DEVICE, num); // request 6 bytes from device | |
int i = 0; | |
while (Wire.available()) // device may send less than requested (abnormal) | |
{ | |
_buff[i] = Wire.read(); // receive a byte | |
i++; | |
} | |
Wire.endTransmission(); // end transmission | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment