Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ee18f29
Showing
8 changed files
with
1,186 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// RGB Shades Audio Demo Code - REQUIRES MSGEQ7 AUDIO SENSOR | ||
// Copyright (c) 2015 macetech LLC | ||
// This software is provided under the MIT License (see license.txt) | ||
// Special credit to Mark Kriegsman for XY mapping code | ||
// | ||
// Use Version 3.0 or later https://github.com/FastLED/FastLED | ||
// ZIP file https://github.com/FastLED/FastLED/archive/master.zip | ||
// | ||
// Use Arduino IDE 1.0 or later | ||
// | ||
// If your RGB Shades were purchased before July 2015: | ||
// This version has the standard Arduino bootloader. R9 and R10 near the control buttons will be present. | ||
// Select the “Arduino Pro or Pro Mini” option. | ||
// Then, go back into the Tools menu and find the Processor option and select “ATmega328 (5V, 16MHz)”. | ||
// | ||
// If your RGB Shades were purchased after July 2015: | ||
// This version has the Optiboot bootloader. R9 and 10 near the control buttons will be missing. | ||
// Select the “Arduino Mini” option. | ||
// Then, go back into the Tools menu and find the Processor option and select “ATmega328”. | ||
// | ||
// [Press] the SW1 button to cycle through available effects | ||
// Effects will also automatically cycle at startup | ||
// [Press and hold] the SW1 button (one second) to switch between auto and manual mode | ||
// * Auto Mode (one blue blink): Effects automatically cycle over time | ||
// * Manual Mode (two red blinks): Effects must be selected manually with SW1 button | ||
// | ||
// [Press] the SW2 button to cycle through available brightness levels | ||
// [Press and hold] the SW2 button (one second) to reset brightness to startup value | ||
// | ||
// Brightness, selected effect, and auto-cycle are saved in EEPROM after a delay | ||
// The RGB Shades will automatically start up with the last-selected settings | ||
|
||
|
||
// RGB Shades data output to LEDs is on pin 5 | ||
#define LED_PIN 5 | ||
|
||
// RGB Shades color order (Green/Red/Blue) | ||
#define COLOR_ORDER GRB | ||
#define CHIPSET WS2811 | ||
|
||
// Global maximum brightness value, maximum 255 | ||
#define MAXBRIGHTNESS 72 | ||
#define STARTBRIGHTNESS 102 | ||
|
||
// Cycle time (milliseconds between pattern changes) | ||
#define cycleTime 15000 | ||
|
||
// Hue time (milliseconds between hue increments) | ||
#define hueTime 30 | ||
|
||
// Time after changing settings before settings are saved to EEPROM | ||
#define EEPROMDELAY 2000 | ||
|
||
// Include FastLED library and other useful files | ||
#include <FastLED.h> | ||
#include <EEPROM.h> | ||
#include "messages.h" | ||
#include "font.h" | ||
#include "XYmap.h" | ||
#include "utils.h" | ||
#include "audio.h" | ||
#include "effects.h" | ||
#include "buttons.h" | ||
|
||
|
||
// Runs one time at the start of the program (power up or reset) | ||
void setup() { | ||
|
||
// write FastLED configuration data | ||
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, LAST_VISIBLE_LED + 1);//.setCorrection(TypicalSMD5050); | ||
|
||
// set global brightness value | ||
FastLED.setBrightness( scale8(STARTBRIGHTNESS, MAXBRIGHTNESS) ); | ||
|
||
// configure input buttons | ||
pinMode(MODEBUTTON, INPUT_PULLUP); | ||
pinMode(BRIGHTNESSBUTTON, INPUT_PULLUP); | ||
pinMode(STROBEPIN, OUTPUT); | ||
pinMode(RESETPIN, OUTPUT); | ||
|
||
digitalWrite(RESETPIN, LOW); | ||
digitalWrite(STROBEPIN, HIGH); | ||
|
||
random16_add_entropy(analogRead(ANALOGPIN)); | ||
|
||
} | ||
|
||
// list of functions that will be displayed | ||
functionList effectList[] = {drawVU, | ||
RGBpulse, | ||
drawAnalyzer }; | ||
|
||
/* functionList effectList[] = {threeSine, | ||
threeDee, | ||
scrollTextZero, | ||
plasma, | ||
confetti, | ||
rider, | ||
scrollTextOne, | ||
glitter, | ||
slantBars, | ||
scrollTextTwo, | ||
colorFill, | ||
sideRain }; | ||
*/ | ||
|
||
const byte numEffects = (sizeof(effectList)/sizeof(effectList[0])); | ||
|
||
// Runs over and over until power off or reset | ||
void loop() | ||
{ | ||
currentMillis = millis(); // save the current timer value | ||
updateButtons(); // read, debounce, and process the buttons | ||
doButtons(); // perform actions based on button state | ||
checkEEPROM(); // update the EEPROM if necessary | ||
|
||
// analyze the audio input | ||
if (currentMillis - audioMillis > AUDIODELAY) { | ||
audioMillis = currentMillis; | ||
doAnalogs(); | ||
} | ||
|
||
// switch to a new effect every cycleTime milliseconds | ||
if (currentMillis - cycleMillis > cycleTime && autoCycle == true) { | ||
cycleMillis = currentMillis; | ||
if (++currentEffect >= numEffects) currentEffect = 0; // loop to start of effect list | ||
effectInit = false; // trigger effect initialization when new effect is selected | ||
} | ||
|
||
// increment the global hue value every hueTime milliseconds | ||
if (currentMillis - hueMillis > hueTime) { | ||
hueMillis = currentMillis; | ||
hueCycle(1); // increment the global hue value | ||
} | ||
|
||
// run the currently selected effect every effectDelay milliseconds | ||
if (currentMillis - effectMillis > effectDelay) { | ||
effectMillis = currentMillis; | ||
effectList[currentEffect](); // run the selected effect function | ||
random16_add_entropy(1); // make the random values a bit more random-ish | ||
} | ||
|
||
// run a fade effect too if the confetti effect is running | ||
if (effectList[currentEffect] == confetti) fadeAll(1); | ||
|
||
FastLED.show(); // send the contents of the led memory to the LEDs | ||
|
||
} | ||
|
||
|
||
|
||
|
||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Helper functions for a two-dimensional XY matrix of pixels. | ||
// Special credit to Mark Kriegsman | ||
// | ||
// 2014-10-18 - Special version for RGB Shades Kickstarter | ||
// https://www.kickstarter.com/projects/macetech/rgb-led-shades | ||
// 2014-10-18 - code version 2c (local table, holes are r/w), | ||
// by Mark Kriegsman | ||
// | ||
// This special 'XY' code lets you program the RGB Shades | ||
// as a plain 16x5 matrix. | ||
// | ||
// Writing to and reading from the 'holes' in the layout is | ||
// also allowed; holes retain their data, it's just not displayed. | ||
// | ||
// You can also test to see if you're on or off the layout | ||
// like this | ||
// if( XY(x,y) > LAST_VISIBLE_LED ) { ...off the layout...} | ||
// | ||
// X and Y bounds checking is also included, so it is safe | ||
// to just do this without checking x or y in your code: | ||
// leds[ XY(x,y) ] == CRGB::Red; | ||
// All out of bounds coordinates map to the first hidden pixel. | ||
// | ||
// XY(x,y) takes x and y coordinates and returns an LED index number, | ||
// for use like this: leds[ XY(x,y) ] == CRGB::Red; | ||
|
||
|
||
// Params for width and height | ||
const uint8_t kMatrixWidth = 16; | ||
const uint8_t kMatrixHeight = 5; | ||
|
||
// Pixel layout | ||
// | ||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
// +------------------------------------------------ | ||
// 0 | . 0 1 2 3 4 5 6 7 8 9 10 11 12 13 . | ||
// 1 | 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 | ||
// 2 | 30 31 32 33 34 35 36 . . 37 38 39 40 41 42 43 | ||
// 3 | 57 56 55 54 53 52 51 . . 50 49 48 47 46 45 44 | ||
// 4 | . 58 59 60 61 62 . . . . 63 64 65 66 67 . | ||
|
||
#define NUM_LEDS (kMatrixWidth * kMatrixHeight) | ||
CRGB leds[ NUM_LEDS ]; | ||
|
||
|
||
// This function will return the right 'led index number' for | ||
// a given set of X and Y coordinates on your RGB Shades. | ||
// This code, plus the supporting 80-byte table is much smaller | ||
// and much faster than trying to calculate the pixel ID with code. | ||
#define LAST_VISIBLE_LED 67 | ||
uint8_t XY( uint8_t x, uint8_t y) | ||
{ | ||
// any out of bounds address maps to the first hidden pixel | ||
if( (x >= kMatrixWidth) || (y >= kMatrixHeight) ) { | ||
return (LAST_VISIBLE_LED + 1); | ||
} | ||
|
||
const uint8_t ShadesTable[] = { | ||
68, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 69, | ||
29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, | ||
30, 31, 32, 33, 34, 35, 36, 70, 71, 37, 38, 39, 40, 41, 42, 43, | ||
57, 56, 55, 54, 53, 52, 51, 72, 73, 50, 49, 48, 47, 46, 45, 44, | ||
74, 58, 59, 60, 61, 62, 75, 76, 77, 78, 63, 64, 65, 66, 67, 79 | ||
}; | ||
|
||
uint8_t i = (y * kMatrixWidth) + x; | ||
uint8_t j = ShadesTable[i]; | ||
return j; | ||
} | ||
|
||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Interface with MSGEQ7 chip for audio analysis | ||
|
||
#define AUDIODELAY 4 | ||
|
||
// Pin definitions | ||
#define ANALOGPIN 3 | ||
#define STROBEPIN 8 | ||
#define RESETPIN 7 | ||
|
||
// Smooth/average settings | ||
#define SPECTRUMSMOOTH 0.07 | ||
#define PEAKDECAY 0.01 | ||
#define NOISEFLOOR 65 | ||
|
||
// AGC settings | ||
#define AGCSMOOTH 0.004 | ||
#define GAINUPPERLIMIT 8.0 | ||
#define GAINLOWERLIMIT 0.1 | ||
|
||
// Global variables | ||
unsigned int spectrumValue[7]; // holds raw adc values | ||
float spectrumDecay[7] = {0}; // holds time-averaged values | ||
float spectrumPeaks[7] = {0}; // holds peak values | ||
float audioAvg = 0.0; | ||
float gainAGC = 0.0; | ||
|
||
void doAnalogs() { | ||
|
||
static PROGMEM const byte spectrumFactors[7] = {10, 10, 11, 12, 13, 14, 16}; | ||
|
||
// reset MSGEQ7 to first frequency bin | ||
digitalWrite(RESETPIN, HIGH); | ||
delayMicroseconds(5); | ||
digitalWrite(RESETPIN, LOW); | ||
|
||
// store sum of values for AGC | ||
int analogsum = 0; | ||
|
||
// cycle through each MSGEQ7 bin and read the analog values | ||
for (int i = 0; i < 7; i++) { | ||
|
||
// set up the MSGEQ7 | ||
digitalWrite(STROBEPIN, LOW); | ||
delayMicroseconds(50); // to allow the output to settle | ||
|
||
// read the analog value | ||
spectrumValue[i] = analogRead(ANALOGPIN); | ||
digitalWrite(STROBEPIN, HIGH); | ||
|
||
if (i == 3) Serial.println(spectrumValue[i]); | ||
|
||
// noise floor filter | ||
if (spectrumValue[i] < NOISEFLOOR) { | ||
spectrumValue[i] = 0; | ||
} else { | ||
spectrumValue[i] -= NOISEFLOOR; | ||
} | ||
|
||
// apply correction factor per frequency bin | ||
spectrumValue[i] = (spectrumValue[i]*pgm_read_byte_near(spectrumFactors + i))/10; | ||
|
||
// prepare average for AGC | ||
analogsum += spectrumValue[i]; | ||
|
||
// apply current gain value | ||
spectrumValue[i] *= gainAGC; | ||
|
||
// process time-averaged values | ||
spectrumDecay[i] = (1.0 - SPECTRUMSMOOTH) * spectrumDecay[i] + SPECTRUMSMOOTH * spectrumValue[i]; | ||
|
||
// process peak values | ||
if (spectrumPeaks[i] < spectrumDecay[i]) spectrumPeaks[i] = spectrumDecay[i]; | ||
spectrumPeaks[i] = spectrumPeaks[i] * (1.0 - PEAKDECAY); | ||
} | ||
|
||
// Calculate audio levels for automatic gain | ||
audioAvg = (1.0 - AGCSMOOTH) * audioAvg + AGCSMOOTH * (analogsum / 7.0); | ||
|
||
// Calculate gain adjustment factor | ||
gainAGC = 250.0 / audioAvg; | ||
if (gainAGC > GAINUPPERLIMIT) gainAGC = GAINUPPERLIMIT; | ||
if (gainAGC < GAINLOWERLIMIT) gainAGC = GAINLOWERLIMIT; | ||
|
||
|
||
|
||
|
||
|
||
} | ||
|
||
// Attempt at beat detection | ||
byte beatTriggered = 0; | ||
#define beatLevel 20.0 | ||
#define beatDeadzone 30.0 | ||
#define beatDelay 50 | ||
float lastBeatVal = 0; | ||
byte beatDetect() { | ||
static float beatAvg = 0; | ||
static unsigned long lastBeatMillis; | ||
float specCombo = (spectrumDecay[0] + spectrumDecay[1]) / 2.0; | ||
beatAvg = (1.0 - AGCSMOOTH) * beatAvg + AGCSMOOTH * specCombo; | ||
|
||
if (lastBeatVal < beatAvg) lastBeatVal = beatAvg; | ||
if ((specCombo - beatAvg) > beatLevel && beatTriggered == 0 && currentMillis - lastBeatMillis > beatDelay) { | ||
beatTriggered = 1; | ||
lastBeatVal = specCombo; | ||
lastBeatMillis = currentMillis; | ||
return 1; | ||
} else if ((lastBeatVal - specCombo) > beatDeadzone) { | ||
beatTriggered = 0; | ||
return 0; | ||
} else { | ||
return 0; | ||
} | ||
|
||
} | ||
|
Oops, something went wrong.