fusion-zauberstab/firmware/sound_ripple/sound_ripple.cpp

126 lines
5.2 KiB
C++

/* soundmems_ripple
*
* By: Andrew Tuline
*
* Date: August, 2015
*
* Updated: January, 2020
*
* Create a ripple from a calculated peak from a sampled microphone
*
* Note: If you are using a microphone powered by the 3.3V signal, such as the Sparkfun MEMS microphone, then connect 3.3V to the AREF pin.
*
*/
//#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266.
#include <FastLED.h> // FastLED library.
#include "zauberstab.h"
// Fixed definitions cannot change on the fly.
#define LED_DT LED_PIN // Data pin to connect to the strip.
#define LED_CK 11 // Clock pin for WS2801 or APA102.
#define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102.
#define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit.
uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'.
int sample; // Current sample.
float sampleAvg = 0; // Smoothed Average.
float micLev = 0; // Used to convert returned value to have '0' as minimum.
uint8_t maxVol = 11; // Reasonable value for constant volume for 'peak detector', as it won't always trigger.
bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag.
int max_bright = 255;
CRGB leds[NUM_LEDS];
// Ripple variables
uint8_t colour; // Ripple colour is randomized.
int center = 0; // Center of the current ripple.
int step = -1; // -1 is the initializing step.
uint8_t myfade = 255; // Starting brightness.
#define maxsteps 16 // Case statement wouldn't allow a variable.
void setup() {
//analogReference(EXTERNAL); // 3.3V reference for analog input.
Serial.begin(115200);
LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS); // Use this for WS2812B
// LEDS.addLeds<LED_TYPE, LED_DT, LED_CK, COLOR_ORDER>(leds, NUM_LEDS); // Use this for WS2801 or APA102
FastLED.setBrightness(max_bright);
//FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);
} // setup()
void getSample() {
int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed.
static long peakTime;
micIn = analogRead(MIC_PIN); // Poor man's analog Read.
micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering.
micIn -= micLev; // Let's center it to 0 now.
micIn = abs(micIn); // And get the absolute value of each sample.
sample = (micIn <= squelch) ? 0 : (sample + micIn) / 2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample.
sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples.
if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value.
samplePeak = 1; // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger.
peakTime=millis();
}
} // getSample()
void ripple() {
if (samplePeak == 1) {step = -1; samplePeak = 0; } // If we have a peak, let's reset our ripple.
fadeToBlackBy(leds, NUM_LEDS, 64); // 8 bit, 1 = slow, 255 = fast
switch (step) {
case -1: // Initialize ripple variables.
center = random(NUM_LEDS);
colour = random8(); // More peaks/s = higher the hue colour.
step = 0;
break;
case 0:
leds[center] = CHSV(colour, 255, 255); // Display the first pixel of the ripple.
step ++;
break;
case maxsteps: // At the end of the ripples.
// step = -1;
break;
default: // Middle of the ripples.
leds[(center + step + NUM_LEDS) % NUM_LEDS] += CHSV(colour, 255, myfade/step*2); // Simple wrap.
leds[(center - step + NUM_LEDS) % NUM_LEDS] += CHSV(colour, 255, myfade/step*2);
step ++; // Next step.
break;
} // switch step
} // ripple()
void loop() {
getSample();
EVERY_N_MILLISECONDS(20) {
ripple();
}
FastLED.show();
} // loop()