Created
April 5, 2018 19:20
-
-
Save caitlinsdad/e71f00bb4677f6906da3591810b08797 to your computer and use it in GitHub Desktop.
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
/* | |
LED VU meter for Circuit Playground | |
This is a port of the Adafruit Amplitie project to Circuit Playground. | |
Based on code for the adjustable sensitivity version of amplitie from: | |
https://learn.adafruit.com/led-ampli-tie/the-code | |
Hardware requirements: | |
- Circuit Playground | |
Software requirements: | |
- Adafruit Circuit Playground library | |
Written by Adafruit Industries. Distributed under the BSD license. | |
This paragraph must be included in any redistribution. | |
fscale function: | |
Floating Point Autoscale Function V0.1 | |
Written by Paul Badger 2007 | |
Modified from code by Greg Shakar | |
*/ | |
#include <Adafruit_CircuitPlayground.h> | |
#include <Wire.h> | |
#include <SPI.h> | |
#include <math.h> | |
#include <Adafruit_NeoPixel.h> | |
#define PIN 6 | |
#define pixelcount 29 | |
#define delayval 20 | |
#define brightval 40 | |
#define kickoff 2000 | |
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(pixelcount, PIN, NEO_GRB + NEO_KHZ800); | |
#define MIC_PIN A4 // Microphone is attached to this analog pin (A4 for circuit playground) | |
#define SAMPLE_WINDOW 10 // Sample window for average level | |
#define PEAK_HANG 24 // Time of pause before peak dot falls | |
#define PEAK_FALL 4 // Rate of falling peak dot | |
#define INPUT_FLOOR 10 // Lower range of analogRead input | |
#define INPUT_CEILING 180 // Max range of analogRead input, the lower the value the more sensitive (1023 = max) | |
byte peak = 16; // Peak level of column; used for falling dots | |
byte Cpeak = 16; | |
unsigned int sample; | |
byte dotCount = 0; //Frame counter for peak dot | |
byte dotHangCount = 0; //Frame counter for holding peak dot | |
byte CdotCount = 0; //Frame counter for peak dot | |
byte CdotHangCount = 0; //Frame counter for holding peak dot | |
float fscale(float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve); | |
// ============================================= | |
void setup() | |
{ | |
CircuitPlayground.begin(); | |
Serial.begin(9600); | |
pixels.begin(); // This initializes the NeoPixel library. | |
pixels.setBrightness(brightval); | |
// +++++++++++++++++++++++++ | |
// just stuff to show that the strips are working on startup... | |
int pos = 0, dir = 1; // Position, direction of "eye" | |
for(int r=0;r<pixelcount*4;r++){ | |
int j; | |
// Draw 5 pixels centered on pos. setPixelColor() will clip any | |
// pixels off the ends of the strip, we don't need to watch for that. | |
pixels.setPixelColor(pos - 2, 0x100000); // Dark red | |
pixels.setPixelColor(pos - 1, 0x800000); // Medium red | |
pixels.setPixelColor(pos , 0xFF3000); // Center pixel is brightest | |
pixels.setPixelColor(pos + 1, 0x800000); // Medium red | |
pixels.setPixelColor(pos + 2, 0x100000); // Dark red | |
pixels.show(); | |
delay(30); | |
// Rather than being sneaky and erasing just the tail pixel, | |
// it's easier to erase it all and draw a new one next time. | |
for(j=-2; j<= 2; j++) pixels.setPixelColor(pos+j, 0); | |
// Bounce off ends of strip | |
pos += dir; | |
if(pos < 0) { | |
pos = 1; | |
dir = -dir; | |
} else if(pos >= pixels.numPixels()) { | |
pos = pixels.numPixels() - 2; | |
dir = -dir; | |
} | |
} | |
// +++++++++++++++++++++++++ | |
CircuitPlayground.playTone(392, 300); | |
delay(40); | |
CircuitPlayground.playTone(659, 300); | |
delay(40); | |
CircuitPlayground.playTone(523, 600); | |
delay(70); | |
colorWipe(pixels.Color(0, 0, 0), 10); // purple | |
theaterChase(CircuitPlayground.strip.Color(255, 0, 100), 50); // | |
theaterChase(CircuitPlayground.strip.Color(0, 0, 0), 0); // | |
colorWipe(pixels.Color(255, 0, 100), 50); // purple | |
theaterChase(CircuitPlayground.strip.Color(255, 0, 100), 50); // | |
theaterChase(CircuitPlayground.strip.Color(0, 0, 0), 0); // | |
delay(kickoff); | |
// ============================================= | |
} | |
void loop() | |
{ | |
//int numPixels = CircuitPlayground.strip.numPixels(); | |
int xnumPixels = 60; | |
int xxnumPixels = 10; | |
unsigned long startMillis= millis(); // Start of sample window | |
float peakToPeak = 0; // peak-to-peak level | |
unsigned int signalMax = 0; | |
unsigned int signalMin = 1023; | |
unsigned int c, y, Cc, Cy; | |
// collect data for length of sample window (in mS) | |
while (millis() - startMillis < SAMPLE_WINDOW) | |
{ | |
sample = analogRead(MIC_PIN); | |
if (sample < 1024) // 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 | |
} | |
} | |
} | |
peakToPeak = signalMax - signalMin; // max - min = peak-peak amplitude | |
//Serial.println(peakToPeak); | |
//Fill the strip with rainbow gradient | |
for (int g=0;g<=xxnumPixels-1;g++){ | |
CircuitPlayground.strip.setPixelColor(g,Wheel(map(g,0,xnumPixels-1,30,150))); | |
} | |
for (int i=0;i<=xnumPixels-1;i++){ | |
pixels.setPixelColor(i,Wheel(map(i,0,xnumPixels-1,30,150))); | |
} | |
//Scale the input logarithmically instead of linearly | |
c = fscale(INPUT_FLOOR, INPUT_CEILING, xnumPixels, 0, peakToPeak, 2); | |
Cc = fscale(INPUT_FLOOR, INPUT_CEILING, xxnumPixels, 0, peakToPeak, 2); | |
// Turn off pixels that are below volume threshold. | |
if(c < peak) { | |
peak = c; // Keep dot on top | |
dotHangCount = 0; // make the dot hang before falling | |
} | |
if (c <= xnumPixels) { // Fill partial column with off pixels | |
drawLine(xnumPixels, xnumPixels-c, CircuitPlayground.strip.Color(0, 0, 0)); | |
} | |
if(Cc < Cpeak) { | |
Cpeak = Cc; // Keep dot on top | |
CdotHangCount = 0; // make the dot hang before falling | |
} | |
if (Cc <= xxnumPixels) { // Fill partial column with off pixels | |
CdrawLine(xxnumPixels, xxnumPixels-Cc, CircuitPlayground.strip.Color(0, 0, 0)); | |
} | |
// Set the peak dot to match the rainbow gradient | |
y = xnumPixels - peak; | |
Cy = xxnumPixels - Cpeak; | |
Serial.println(y); | |
CircuitPlayground.strip.setPixelColor(Cy-1,Wheel(map(Cy,0,xxnumPixels-1,30,150))); | |
CircuitPlayground.strip.show(); | |
pixels.setPixelColor(y-1,Wheel(map(y,0,xnumPixels-1,30,150))); | |
pixels.show(); | |
delay(10); | |
// Frame based peak dot animation | |
if(dotHangCount > PEAK_HANG) { //Peak pause length | |
if(++dotCount >= PEAK_FALL) { //Fall rate | |
peak++; | |
dotCount = 0; | |
} | |
} | |
else { | |
dotHangCount++; | |
} | |
if(CdotHangCount > PEAK_HANG) { //Peak pause length | |
if(++CdotCount >= PEAK_FALL) { //Fall rate | |
Cpeak++; | |
CdotCount = 0; | |
} | |
} | |
else { | |
CdotHangCount++; | |
} | |
} | |
//Used to draw a line between two points of a given color | |
void drawLine(uint8_t from, uint8_t to, uint32_t c) { | |
uint8_t fromTemp; | |
if (from > to) { | |
fromTemp = from; | |
from = to; | |
to = fromTemp; | |
} | |
for(int i=from; i<=to; i++){ | |
// CircuitPlayground.strip.setPixelColor(i, c); | |
pixels.setPixelColor(i, c); | |
} | |
} | |
void CdrawLine(uint8_t from, uint8_t to, uint32_t c) { | |
uint8_t fromTemp; | |
if (from > to) { | |
fromTemp = from; | |
from = to; | |
to = fromTemp; | |
} | |
for(int i=from; i<=to; i++){ | |
CircuitPlayground.strip.setPixelColor(i, c); | |
} | |
} | |
float fscale( float originalMin, float originalMax, float newBegin, float | |
newEnd, float inputValue, float curve){ | |
float OriginalRange = 0; | |
float NewRange = 0; | |
float zeroRefCurVal = 0; | |
float normalizedCurVal = 0; | |
float rangedValue = 0; | |
boolean invFlag = 0; | |
// condition curve parameter | |
// limit range | |
if (curve > 10) curve = 10; | |
if (curve < -10) curve = -10; | |
curve = (curve * -.1) ; // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output | |
curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function | |
/* | |
Serial.println(curve * 100, DEC); // multply by 100 to preserve resolution | |
Serial.println(); | |
*/ | |
// Check for out of range inputValues | |
if (inputValue < originalMin) { | |
inputValue = originalMin; | |
} | |
if (inputValue > originalMax) { | |
inputValue = originalMax; | |
} | |
// Zero Refference the values | |
OriginalRange = originalMax - originalMin; | |
if (newEnd > newBegin){ | |
NewRange = newEnd - newBegin; | |
} | |
else | |
{ | |
NewRange = newBegin - newEnd; | |
invFlag = 1; | |
} | |
zeroRefCurVal = inputValue - originalMin; | |
normalizedCurVal = zeroRefCurVal / OriginalRange; // normalize to 0 - 1 float | |
// Check for originalMin > originalMax - the math for all other cases i.e. negative numbers seems to work out fine | |
if (originalMin > originalMax ) { | |
return 0; | |
} | |
if (invFlag == 0){ | |
rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin; | |
} | |
else // invert the ranges | |
{ | |
rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange); | |
} | |
return rangedValue; | |
} | |
// 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) { | |
if(WheelPos < 85) { | |
return CircuitPlayground.strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); | |
} | |
else if(WheelPos < 170) { | |
WheelPos -= 85; | |
return CircuitPlayground.strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); | |
} | |
else { | |
WheelPos -= 170; | |
return CircuitPlayground.strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); | |
} | |
} | |
// Fill the dots one after the other with a color | |
void colorWipe(uint32_t c, uint8_t wait) { | |
for(uint16_t i=0; i<pixels.numPixels(); i++) { | |
pixels.setPixelColor(i, c); | |
pixels.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 < CircuitPlayground.strip.numPixels(); i=i+3) { | |
CircuitPlayground.strip.setPixelColor(i+q, c); //turn every third pixel on | |
} | |
CircuitPlayground.strip.show(); | |
delay(wait); | |
for (uint16_t i=0; i < CircuitPlayground.strip.numPixels(); i=i+3) { | |
CircuitPlayground.strip.setPixelColor(i+q, 0); //turn every third pixel off | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment