From 7400d18c0dfebf861a3024292f6d49071e888bf3 Mon Sep 17 00:00:00 2001 From: Thomas Schmid Date: Sat, 18 Jun 2022 23:02:27 +0200 Subject: [PATCH] updates from labor Signed-off-by: Thomas Schmid --- arduino_zauberstab/arduino_zauberstab.ino | 2 +- firmware/sound_wave/sound_wave.ino | 163 ----------------- firmware/temp/alex_beat_detect.cpp | 204 ---------------------- firmware/temp/beat_detect.cpp | 44 ++--- 4 files changed, 23 insertions(+), 390 deletions(-) delete mode 100644 firmware/sound_wave/sound_wave.ino delete mode 100644 firmware/temp/alex_beat_detect.cpp diff --git a/arduino_zauberstab/arduino_zauberstab.ino b/arduino_zauberstab/arduino_zauberstab.ino index 85a6973..41f3001 100644 --- a/arduino_zauberstab/arduino_zauberstab.ino +++ b/arduino_zauberstab/arduino_zauberstab.ino @@ -4,7 +4,7 @@ //lichterkette: PWM 2 //mikrofon: A1 #define LED_PIN 2 -#define NUM_LEDS 240 +#define NUM_LEDS 144 #define SAMPLING_FREQUENCY_BP 40 // number of energy chunks per second diff --git a/firmware/sound_wave/sound_wave.ino b/firmware/sound_wave/sound_wave.ino deleted file mode 100644 index 09d0a37..0000000 --- a/firmware/sound_wave/sound_wave.ino +++ /dev/null @@ -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 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(leds, NUM_LEDS); // Use this for WS2812B -// LEDS.addLeds(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() - - diff --git a/firmware/temp/alex_beat_detect.cpp b/firmware/temp/alex_beat_detect.cpp deleted file mode 100644 index 1e8806b..0000000 --- a/firmware/temp/alex_beat_detect.cpp +++ /dev/null @@ -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; - } - } - } -} - diff --git a/firmware/temp/beat_detect.cpp b/firmware/temp/beat_detect.cpp index b47b0ab..a4f75ec 100644 --- a/firmware/temp/beat_detect.cpp +++ b/firmware/temp/beat_detect.cpp @@ -1,4 +1,5 @@ #include "zauberstab.h" +#include #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 @@ -33,11 +34,13 @@ static float u1[n_BP]; static float u2[n_BP]; static float y[n_BP]; static float y_fil[n_BP]; +static float y_fil_avg; +static float transience = 0; static float angle; static float angle2; -static double energy_fil = 800.; +//static double energy_fil = 800.; static float pos_target = 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 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; } 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) { - 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); + //energy_fil += (energy - energy_fil) * 0.01; + y_fil_avg = 0; 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]; @@ -114,7 +112,9 @@ void loop() yy2[i] = yy1[i]; yy1[i] = y[i]; 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.); @@ -150,20 +150,20 @@ void loop() pos_target_filtered = pos_target; } - // Serial.print(y_fil[active]); - // Serial.print(","); - // Serial.println(y[active]); - 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++) { - int brightness = get_value(i, pos_target_filtered); - if (brightness >= 1) { - brightness = 10; - } - //leds[i].setRGB(brightness, brightness, brightness); - leds[i].setHSV(160, (rounds == 6) ? 0xFF : 0, brightness); + leds[i].g = int(get_value(i, pos_target_filtered)*transience); + leds[i].r = int(get_value(i, pos_target_filtered+2)*transience); + leds[i].b = int(get_value(i, pos_target_filtered-2)*transience); + + //leds[i].setRGB(brightness_red, brightness_green, brightness_blue); + //leds[i].setHSV(160, (rounds == 6) ? 0xFF : 0, brightness); } FastLED.show(); } @@ -193,7 +193,7 @@ void loop() rounds = 0; candidate = argmax; } - if (rounds > 6) + if (rounds > 3) { rounds = 0; active = candidate;