Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
macegr committed Dec 8, 2015
0 parents commit ee18f29
Show file tree
Hide file tree
Showing 8 changed files with 1,186 additions and 0 deletions.
153 changes: 153 additions & 0 deletions RGBShadesAudio.ino
@@ -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

}





71 changes: 71 additions & 0 deletions XYmap.h
@@ -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;
}


116 changes: 116 additions & 0 deletions audio.h
@@ -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;
}

}

0 comments on commit ee18f29

Please sign in to comment.