forked from buddhabrot/fusion-zauberstab
164 lines
7.0 KiB
C++
164 lines
7.0 KiB
C++
|
|
/* sound_wave
|
|
*
|
|
* By: Andrew Tuline
|
|
*
|
|
* Date: February, 2017
|
|
*
|
|
* Basic code to read from the Sparkfun INMP401 microphone, and create waves based on sampled input. This does NOT include sensitivity adjustment.
|
|
*
|
|
* My hardware setup:
|
|
*
|
|
* Arduino Nano & Addressable LED strips
|
|
* - Powered by USB power bank
|
|
* - APA102 or WS2812 data connected to pin 12.
|
|
* - APA102 clock connected to pin 11.
|
|
* - 5V on APA102 or WS2812 connected to 5V on Nano (good for short strips).
|
|
* - Gnd to Gnd on Nano.
|
|
*
|
|
*
|
|
* Sparkfun MEMS microphone
|
|
* - Vcc on microphone is connected to 3.3V on Nano.
|
|
* - AREF on Nano connected to 3.3V on Nano.
|
|
* - Mic out connected to A5.
|
|
* - Gnd to Gnd on Nano.
|
|
*
|
|
* 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"
|
|
|
|
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 sampleAgc, multAgc;
|
|
uint8_t targetAgc = 60; // This is our setPoint at 20% of max for the adjusted output.
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
struct CRGB leds[NUM_LEDS]; // Initialize our LED array.
|
|
|
|
int max_bright = 255;
|
|
|
|
CRGBPalette16 currentPalette = OceanColors_p;
|
|
CRGBPalette16 targetPalette = OceanColors_p;
|
|
TBlendType currentBlending = LINEARBLEND; // NOBLEND or LINEARBLEND
|
|
|
|
|
|
|
|
void setup() {
|
|
//analogReference(EXTERNAL); // 3.3V reference for analog input.
|
|
|
|
Serial.begin(115200); // Initialize serial port for debugging.
|
|
delay(1000); // Soft startup to ease the flow of electrons.
|
|
|
|
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); // FastLED Power management set at 5V, 500mA.
|
|
|
|
} // 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)>>2; // 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 agcAvg() { // A simple averaging multiplier to automatically adjust sound sensitivity.
|
|
|
|
multAgc = (sampleAvg < 1) ? targetAgc : targetAgc / sampleAvg; // Make the multiplier so that sampleAvg * multiplier = setpoint
|
|
sampleAgc = sample * multAgc;
|
|
if (sampleAgc > 255) sampleAgc = 255;
|
|
|
|
//------------ Oscilloscope output ---------------------------
|
|
Serial.print(targetAgc); Serial.print(" ");
|
|
Serial.print(multAgc); Serial.print(" ");
|
|
Serial.print(sampleAgc); Serial.print(" ");
|
|
|
|
Serial.print(micLev); Serial.print(" ");
|
|
Serial.print(sample); Serial.println(" ");
|
|
// Serial.print(sampleAvg); Serial.print(" ");
|
|
// Serial.print(samplePeak); Serial.print(" "); samplePeak = 0;
|
|
// Serial.print(100); Serial.print(" ");
|
|
// Serial.print(0); Serial.print(" ");
|
|
// Serial.println(" ");
|
|
|
|
} // agcAvg()
|
|
|
|
|
|
|
|
void sndwave() {
|
|
|
|
leds[NUM_LEDS/2] = ColorFromPalette(currentPalette, sampleAgc, sampleAgc, currentBlending); // Put the sample into the center
|
|
|
|
for (int i = NUM_LEDS - 1; i > NUM_LEDS/2; i--) { //move to the left // Copy to the left, and let the fade do the rest.
|
|
leds[i] = leds[i - 1];
|
|
}
|
|
|
|
for (int i = 0; i < NUM_LEDS/2; i++) { // move to the right // Copy to the right, and let the fade to the rest.
|
|
leds[i] = leds[i + 1];
|
|
}
|
|
|
|
} // sndwave()
|
|
|
|
|
|
void loop() {
|
|
|
|
|
|
EVERY_N_SECONDS(5) { // Change the palette every 5 seconds.
|
|
for (int i = 0; i < 16; i++) {
|
|
targetPalette[i] = CHSV(random8(), 255, 255);
|
|
}
|
|
}
|
|
|
|
EVERY_N_MILLISECONDS(100) { // AWESOME palette blending capability once they do change.
|
|
uint8_t maxChanges = 24;
|
|
nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges);
|
|
}
|
|
|
|
|
|
EVERY_N_MILLIS_I(thistimer,20) { // For fun, let's make the animation have a variable rate.
|
|
uint8_t timeval = beatsin8(10,20,50); // Use a sinewave for the line below. Could also use peak/beat detection.
|
|
thistimer.setPeriod(timeval); // Allows you to change how often this routine runs.
|
|
fadeToBlackBy(leds, NUM_LEDS, 16); // 1 = slow, 255 = fast fade. Depending on the faderate, the LED's further away will fade out.
|
|
getSample();
|
|
agcAvg();
|
|
sndwave();
|
|
}
|
|
|
|
FastLED.show();
|
|
|
|
} // loop()
|
|
|
|
|