updates from labor

Signed-off-by: Thomas Schmid <tom@binary-kitchen.de>
This commit is contained in:
Thomas 2022-06-18 23:02:27 +02:00
parent 543a2588a3
commit 7400d18c0d
4 changed files with 23 additions and 390 deletions

View File

@ -4,7 +4,7 @@
//lichterkette: PWM 2 //lichterkette: PWM 2
//mikrofon: A1 //mikrofon: A1
#define LED_PIN 2 #define LED_PIN 2
#define NUM_LEDS 240 #define NUM_LEDS 144
#define SAMPLING_FREQUENCY_BP 40 // number of energy chunks per second #define SAMPLING_FREQUENCY_BP 40 // number of energy chunks per second

View File

@ -1,163 +0,0 @@
/* 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()

View File

@ -1,204 +0,0 @@
#include "zauberstab.h"
#include "app.h"
#define SAMPLING_FREQUENCY_BP 40 // number of energy chunks per second
#define SAMPLING_FREQUENCY_CONTROL 1 // check number of times per second if the current band pass is the best one
#define Q 20. // quality factor of band pass filters
#define PI 3.1415926535897932384626433832795
#define n_BP 30 //number of band pass filters
static unsigned long sampling_period_bp = 1000000L / SAMPLING_FREQUENCY_BP;
static unsigned long sampling_period_control = 1000000L / SAMPLING_FREQUENCY_CONTROL;
static double energy = 0;
static unsigned long last_us_bp = 0L;
static unsigned long last_us_control = 0L;
static float a0[n_BP];
static float a1[n_BP];
static float a2[n_BP];
static float b0[n_BP];
//static float b1[n_BP];
static float b2[n_BP];
static float a[n_BP];
static float w0[n_BP];
static float yy1[n_BP];
static float yy2[n_BP];
static float yy3[n_BP];
static float yy4[n_BP];
static float yy5[n_BP];
static float yy6[n_BP];
static float u1[n_BP];
static float u2[n_BP];
static float y[n_BP];
static float y_fil[n_BP];
static float angle;
static float angle2;
static double energy_fil = 800.;
static float pos_target = NUM_LEDS / 2;
static float pos_target_filtered = NUM_LEDS / 2;
static float microphone_offset = 675;
static long initial_time;
static int active = 15;
static int candidate = 15;
static int rounds = 0;
static int get_value(int pos, float pos0)
{
if (abs(pos0 - pos) > 20)
{
return 0;
}
else
{
return (40 - abs(pos0 - pos) * 2);
}
}
static void set_filter()
{
for (int i = 0; i < n_BP; i++)
{
float frequency = 1.75 + i * (2.4 - 1.75) / n_BP;
w0[i] = 2. * PI * frequency / SAMPLING_FREQUENCY_BP;
a[i] = sin(w0[i] / (2. * Q));
b0[i] = a[i];
//b1[i] = 0;
b2[i] = -a[i];
a0[i] = 1. + a[i];
a1[i] = -2. * cos(w0[i]);
a2[i] = 1. - a[i];
}
}
static void abeat_setup()
{
zauberstab_init();
Serial.begin(115200);
set_filter();
initial_time = micros();
}
static void abeat_loop()
{
int sample = int(analogRead(MIC_PIN) - microphone_offset);
energy += abs(sample) * abs(sample);
if (micros() - last_us_bp > sampling_period_bp)
{
Serial.println(sample);
microphone_offset += (analogRead(MIC_PIN) - microphone_offset) * 0.001;
//Serial.println(microphone_offset);
last_us_bp += sampling_period_bp;
energy_fil += (energy - energy_fil) * 0.01;
//Serial.println(energy);
for (int i = 0; i < n_BP; i++)
{
y[i] = (b0[i] / a0[i]) * energy + 0. + (b2[i] / a0[i]) * u2[i] - (a1[i] / a0[i]) * yy1[i] - (a2[i] / a0[i]) * yy2[i];
u2[i] = u1[i];
u1[i] = energy;
yy6[i] = yy5[i];
yy5[i] = yy4[i];
yy4[i] = yy3[i];
yy3[i] = yy2[i];
yy2[i] = yy1[i];
yy1[i] = y[i];
y_fil[i] += (abs(y[i]) - y_fil[i]) * 0.005; //linie der scheitelpunkte
}
float delays = constrain(SAMPLING_FREQUENCY_BP * 0.25 / (1.75 + active * (2.4 - 1.75) / n_BP), 4., 6.);
float delayed = 0;
if (delays > 5)
{
delayed = yy5[active] * (1 - delays + 5) + yy6[active] * (delays - 5);
}
else
{
delayed = yy4[active] * (1 - delays + 4) + yy5[active] * (delays - 4);
}
angle = atan2(delayed, y[active]);
if (PI < abs(angle - angle2) && abs(angle - angle2) < 3 * PI)
{
angle2 = angle + 2 * PI;
}
else
{
angle2 = angle;
}
pos_target = map(angle2, -PI, 3 * PI, -0.3 * NUM_LEDS, NUM_LEDS * 1.5);
if (pos_target > pos_target_filtered)
{
pos_target_filtered += (pos_target - pos_target_filtered) * 0.35;
}
else
{
pos_target_filtered = pos_target;
}
// Serial.print(y_fil[active]);
// Serial.print(",");
// Serial.println(y[active]);
energy = 0;
for (int i = 0; i < NUM_LEDS; i++)
{
int brightness = get_value(i, pos_target_filtered);
//leds[i].setRGB(brightness, brightness, brightness);
//leds[i].setHSV(160, (rounds == 6) ? 0xFF : 0, brightness);
leds[i] = CRGB::White;
}
FastLED.show();
}
if (micros() - last_us_control > sampling_period_control)
{
last_us_control += sampling_period_control;
int argmax = -1;
float valuemax = 0;
for (int i = 0; i < n_BP; i++)
{
if (y_fil[i] > valuemax)
{
valuemax = y_fil[i];
argmax = i;
}
}
if (argmax > -1)
{
if (argmax == candidate)
{
rounds++;
}
else
{
rounds = 0;
candidate = argmax;
}
if (rounds > 6)
{
rounds = 0;
active = candidate;
}
}
}
}

View File

@ -1,4 +1,5 @@
#include "zauberstab.h" #include "zauberstab.h"
#include <algorithm>
#define SAMPLING_FREQUENCY_BP 40 // number of energy chunks per second #define SAMPLING_FREQUENCY_BP 40 // number of energy chunks per second
#define SAMPLING_FREQUENCY_CONTROL 1 // check number of times per second if the current band pass is the best one #define SAMPLING_FREQUENCY_CONTROL 1 // check number of times per second if the current band pass is the best one
@ -33,11 +34,13 @@ static float u1[n_BP];
static float u2[n_BP]; static float u2[n_BP];
static float y[n_BP]; static float y[n_BP];
static float y_fil[n_BP]; static float y_fil[n_BP];
static float y_fil_avg;
static float transience = 0;
static float angle; static float angle;
static float angle2; static float angle2;
static double energy_fil = 800.; //static double energy_fil = 800.;
static float pos_target = NUM_LEDS / 2; static float pos_target = NUM_LEDS / 2;
static float pos_target_filtered = NUM_LEDS / 2; static float pos_target_filtered = NUM_LEDS / 2;
@ -49,15 +52,15 @@ static int active = 15;
static int candidate = 15; static int candidate = 15;
static int rounds = 0; static int rounds = 0;
static int get_value(int pos, float pos0) static float get_value(int pos, float pos0)
{ {
if (abs(pos0 - pos) > 20) if (abs(pos0 - pos) > 5)
{ {
return 0; return 0;
} }
else else
{ {
return (40 - abs(pos0 - pos) * 2); return (40 - abs(pos0 - pos) * 8);
} }
} }
@ -92,16 +95,11 @@ void loop()
if (micros() - last_us_bp > sampling_period_bp) if (micros() - last_us_bp > sampling_period_bp)
{ {
Serial.println(sample); Serial.println(sample);
microphone_offset += (analogRead(MIC_PIN) - microphone_offset) * 0.001; microphone_offset += (analogRead(MIC_PIN) - microphone_offset) * 0.001;
//Serial.println(microphone_offset);
last_us_bp += sampling_period_bp; last_us_bp += sampling_period_bp;
energy_fil += (energy - energy_fil) * 0.01; //energy_fil += (energy - energy_fil) * 0.01;
//Serial.println(energy); y_fil_avg = 0;
for (int i = 0; i < n_BP; i++) for (int i = 0; i < n_BP; i++)
{ {
y[i] = (b0[i] / a0[i]) * energy + 0. + (b2[i] / a0[i]) * u2[i] - (a1[i] / a0[i]) * yy1[i] - (a2[i] / a0[i]) * yy2[i]; y[i] = (b0[i] / a0[i]) * energy + 0. + (b2[i] / a0[i]) * u2[i] - (a1[i] / a0[i]) * yy1[i] - (a2[i] / a0[i]) * yy2[i];
@ -114,7 +112,9 @@ void loop()
yy2[i] = yy1[i]; yy2[i] = yy1[i];
yy1[i] = y[i]; yy1[i] = y[i];
y_fil[i] += (abs(y[i]) - y_fil[i]) * 0.005; //linie der scheitelpunkte y_fil[i] += (abs(y[i]) - y_fil[i]) * 0.005; //linie der scheitelpunkte
y_fil_avg += y_fil[i];
} }
y_fil_avg /= n_BP;
float delays = constrain(SAMPLING_FREQUENCY_BP * 0.25 / (1.75 + active * (2.4 - 1.75) / n_BP), 4., 6.); float delays = constrain(SAMPLING_FREQUENCY_BP * 0.25 / (1.75 + active * (2.4 - 1.75) / n_BP), 4., 6.);
@ -150,20 +150,20 @@ void loop()
pos_target_filtered = pos_target; pos_target_filtered = pos_target;
} }
// Serial.print(y_fil[active]);
// Serial.print(",");
// Serial.println(y[active]);
energy = 0; energy = 0;
transience += ((y_fil[active]/y_fil_avg-1.6) - transience)*0.02;
transience = max(transience, 0.0f);
transience = min(transience, 1.0f);
for (int i = 0; i < NUM_LEDS; i++) for (int i = 0; i < NUM_LEDS; i++)
{ {
int brightness = get_value(i, pos_target_filtered); leds[i].g = int(get_value(i, pos_target_filtered)*transience);
if (brightness >= 1) { leds[i].r = int(get_value(i, pos_target_filtered+2)*transience);
brightness = 10; leds[i].b = int(get_value(i, pos_target_filtered-2)*transience);
}
//leds[i].setRGB(brightness, brightness, brightness); //leds[i].setRGB(brightness_red, brightness_green, brightness_blue);
leds[i].setHSV(160, (rounds == 6) ? 0xFF : 0, brightness); //leds[i].setHSV(160, (rounds == 6) ? 0xFF : 0, brightness);
} }
FastLED.show(); FastLED.show();
} }
@ -193,7 +193,7 @@ void loop()
rounds = 0; rounds = 0;
candidate = argmax; candidate = argmax;
} }
if (rounds > 6) if (rounds > 3)
{ {
rounds = 0; rounds = 0;
active = candidate; active = candidate;