Mikrofongesteuertes WS2812b-Projekt

Hallo zusammen,

ich suche Hilfe für mein erstes Arduino-Projekt.

Ich möchte mir für ein Musik-Festival eine Art tanztauglichen Rucksack basteln in dem ich meine Wasserflasche transportieren kann. Der Rucksack-Körper besteht aus einem PVC-Fallrohr (ca. 50cm hoch und 10cm Druchmesser). Daran befestige ich mit Kabelbindern einen alten Fahrradschlauch um 2 Schultergurte zu erhalten. Etwas unterhalb der Mitte kommt eine Gewindestange durch das Rohr, die die Flasche am Durchrutschen hindert.

Im unteren Teil des Rohrs ist dann noch genug Platz für eine Powerbank um etwas Dekobeleuchtung zu betreiben, die aussen an das Rohr kommen soll.
Als Gehäuse würde sich z.B. eine 250g-Kaffeedose anbieten, die formschlüssig in das PVC-Rohr passt.

Im Querschnitt sieht das in etwa so aus:

grafik

Die Deko-Beleuchtung besteht aus 2 WS2812B-Led-Streifen, die senkrecht an das Rohr kommen. Diese sollen auf die Musik reagieren.

Bei Youtube habe ich ein Tutorial gefunden, das ich nachbauen konnte und der dort verlinkte Code bietet ein paar schöne Effekte, wie die LEDs auf den Schall reagieren. Die Effekte lassen sich über einen Taster durchschalten.

So weit so gut. Ein paar Baustellen habe ich aber noch.

Die wichtigste zuerst ist ein Potentiometer das ich einbinden will um die Empfindlichkeit des Mikrofons zu steuern. Auf dem Mikrofonmodul ist zwar eines vorhanden, aber mitten auf dem Festival immer wieder einen feinen Schraubendreher auszupacken, das Gehäuse öffnen usw., erscheint mir nicht so wirklich praktikabel.
Darum brauche ich da eine zugänglichere Lösung :slight_smile:

Ich habe schon herausgefunden, dass das Poti-Signal an einen analogen Pin muss, den ich dann auslesen lassen kann, aber wie ich das im Code dann mit der Empfindlichkeit des Mikros verbinden kann übersteigt meine Kenntnisse schon.

Hier das Schaltbild

...und hier der Code


#include <Adafruit_NeoPixel.h>
#include <FastLED.h>
#include <math.h>
#include <SoftwareSerial.h>
#define N_PIXELS 14  // Number of pixels in strand
#define N_PIXELS_HALF (N_PIXELS / 2)
#define MIC_PIN A5           // Microphone is attached to this analog pin
#define LED_PIN 6            // NeoPixel LED strand is connected to this pin
#define SAMPLE_WINDOW 10     // Sample window for average level
#define PEAK_HANG 24         //Time of pause before peak dot falls
#define PEAK_FALL 20         //Rate of falling peak dot
#define PEAK_FALL2 8         //Rate of falling peak dot
#define INPUT_FLOOR 50       //Lower range of analogRead input
#define INPUT_CEILING 900    //Max range of analogRead input, the lower the value the more sensitive (1023 = max)300 (150)
#define DC_OFFSET 510        // DC offset in mic signal - if unusure, leave 0
#define NOISE 10             // Noise/hum/interference in mic signal
#define SAMPLES 60           // Length of buffer for dynamic level adjustment
#define TOP (N_PIXELS + 2)   // Allow dot to go slightly off scale
#define SPEED .20            // Amount to increment RGB color by each cycle
#define TOP2 (N_PIXELS + 1)  // Allow dot to go slightly off scale
#define LAST_PIXEL_OFFSET N_PIXELS - 1
#define PEAK_FALL_MILLIS 10  // Rate of peak falling dot
#define BG 0
#define LAST_PIXEL_OFFSET N_PIXELS - 1
#define BRIGHTNESS 10
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define COLOR_MIN 0
#define COLOR_MAX 255
#define DRAW_MAX 100
#define SEGMENTS 4            // Number of segments to carve amplitude bar into
#define COLOR_WAIT_CYCLES 10  // Loop cycles to wait between advancing pixel origin
#define qsubd(x, b) ((x > b) ? b : 0)
#define qsuba(x, b) ((x > b) ? x - b : 0)  // Analog Unsigned subtraction macro. if result <0, then => 0. By Andrew Tuline.
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))


struct CRGB leds[N_PIXELS];

Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);

static uint16_t dist;     // A random number for noise generator.
uint16_t scale = 30;  
```cpp

#include <Adafruit_NeoPixel.h>
#include <FastLED.h>
#include <math.h>
#include <SoftwareSerial.h>
#define N_PIXELS 14  // Number of pixels in strand
#define N_PIXELS_HALF (N_PIXELS / 2)
#define MIC_PIN A5  // Microphone is attached to this analog pin
#define blitzbutton_Pin 8
#define LED_PIN 6            // NeoPixel LED strand is connected to this pin
#define SAMPLE_WINDOW 10     // Sample window for average level
#define PEAK_HANG 24         //Time of pause before peak dot falls
#define PEAK_FALL 20         //Rate of falling peak dot
#define PEAK_FALL2 8         //Rate of falling peak dot
#define INPUT_FLOOR 50       //Lower range of analogRead input
#define INPUT_CEILING 900    //Max range of analogRead input, the lower the value the more sensitive (1023 = max)300 (150)
#define DC_OFFSET 510        // DC offset in mic signal - if unusure, leave 0
#define NOISE 10             // Noise/hum/interference in mic signal
#define SAMPLES 60           // Length of buffer for dynamic level adjustment
#define TOP (N_PIXELS + 2)   // Allow dot to go slightly off scale
#define SPEED .20            // Amount to increment RGB color by each cycle
#define TOP2 (N_PIXELS + 1)  // Allow dot to go slightly off scale
#define LAST_PIXEL_OFFSET N_PIXELS - 1
#define PEAK_FALL_MILLIS 10  // Rate of peak falling dot
#define BG 0
#define LAST_PIXEL_OFFSET N_PIXELS - 1
#define BRIGHTNESS 100
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define COLOR_MIN 0
#define COLOR_MAX 255
#define DRAW_MAX 100
#define SEGMENTS 4            // Number of segments to carve amplitude bar into
#define COLOR_WAIT_CYCLES 10  // Loop cycles to wait between advancing pixel origin
#define qsubd(x, b) ((x > b) ? b : 0)
#define qsuba(x, b) ((x > b) ? x - b : 0)  // Analog Unsigned subtraction macro. if result <0, then => 0. By Andrew Tuline.
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))


struct CRGB leds[N_PIXELS];

Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);

static uint16_t dist;     // A random number for noise generator.
uint16_t scale = 30;      // Wouldn't recommend changing this on the fly, or the animation will be really blocky.
uint8_t maxChanges = 48;  // Value for blending between palettes.

CRGBPalette16 currentPalette(OceanColors_p);
CRGBPalette16 targetPalette(CloudColors_p);

byte
  //  peak      = 0,      // Used for falling dot
  //  dotCount  = 0,      // Frame counter for delaying dot-falling speed
  volCount = 0;  // Frame counter for storing past volume data
int
  reading,
  vol[SAMPLES],   // Collection of prior volume samples
  lvl = 10,       // Current "dampened" audio level
  minLvlAvg = 0,  // For dynamic adjustment of graph low & high
  maxLvlAvg = 512;
float
  greenOffset = 30,
  blueOffset = 150;
// cycle variables

int CYCLE_MIN_MILLIS = 2;
int CYCLE_MAX_MILLIS = 1000;
int cycleMillis = 20;
bool paused = false;
long lastTime = 0;
bool boring = true;
bool gReverseDirection = false;
int myhue = 0;



unsigned int sample;

//Samples
#define NSAMPLES 64
unsigned int samplearray[NSAMPLES];
unsigned long samplesum = 0;
unsigned int sampleavg = 0;
int samplecount = 0;
//unsigned int sample = 0;
unsigned long oldtime = 0;
unsigned long newtime = 0;


byte peak = 16;         // Peak level of column; used for falling dots
byte dotCount = 0;      //Frame counter for peak dot
byte dotHangCount = 0;  //Frame counter for holding peak dot

const int buttonPin = 9;  // the number of the pushbutton pin
const int blitzbuttonPin = 8;

int buttonPushCounter = 0;  // counter for the number of button presses
int buttonState = 0;        // current state of the button
int lastButtonState = 0;
//---------------------------------------------------------------------------------------
//---------------------------------------- SETUP ----------------------------------------
//--------------------------------------------------------------------------------------

void setup() {

  analogReference(EXTERNAL);

  pinMode(buttonPin, INPUT);  //initialize the buttonPin as output
  digitalWrite(buttonPin, HIGH);
  pinMode(blitzbuttonPin, INPUT);
  digitalWrite(blitzbuttonPin, HIGH);

  // Serial.begin(9600);
  strip.begin();
  strip.show();  // all pixels to 'off'

  Serial.begin(57600);
  delay(3000);

  LEDS.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, N_PIXELS).setCorrection(TypicalLEDStrip);
  LEDS.setBrightness(BRIGHTNESS);
  dist = random16(12345);  // A semi-random number for our noise generator
}

float fscale(float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve) {

  float OriginalRange = 0;
  float NewRange = 0;
  float zeroRefCurVal = 0;
  float normalizedCurVal = 0;
  float rangedValue = 0;
  boolean invFlag = 0;

  // condition curve parameter
  // limit range

  if (curve > 10) curve = 10;
  if (curve < -10) curve = -10;

  curve = (curve * -.1);   // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output
  curve = pow(10, curve);  // convert linear scale into lograthimic exponent for other pow function


  // Check for out of range inputValues
  if (inputValue < originalMin) {
    inputValue = originalMin;
  }
  if (inputValue > originalMax) {
    inputValue = originalMax;
  }

  // Zero Refference the values
  OriginalRange = originalMax - originalMin;

  if (newEnd > newBegin) {
    NewRange = newEnd - newBegin;
  } else {
    NewRange = newBegin - newEnd;
    invFlag = 1;
  }

  zeroRefCurVal = inputValue - originalMin;
  normalizedCurVal = zeroRefCurVal / OriginalRange;  // normalize to 0 - 1 float


  // Check for originalMin > originalMax  - the math for all other cases i.e. negative numbers seems to work out fine
  if (originalMin > originalMax) {
    return 0;
  }

  if (invFlag == 0) {
    rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin;

  } else  // invert the ranges
  {
    rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange);
  }
  return rangedValue;
}

//---------------------------------------------------------------------------------------
//---------------------------------------- LOOP ----------------------------------------
//--------------------------------------------------------------------------------------

void loop() {

  //for mic
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;
  // end mic
  // read the pushbutton input pin:
  if (digitalRead(blitzbuttonPin) == LOW) {
    LEDS.setBrightness(100);
    FastLED.showColor(CRGB::White);
    FastLED.show();
  } else {
    LEDS.setBrightness(50);
    buttonState = digitalRead(buttonPin);
    // compare the buttonState to its previous state
    if (buttonState != lastButtonState) {
      // if the state has changed, increment the counter
      if (buttonState == HIGH) {
        // if the current state is HIGH then the button
        // wend from off to on:
        buttonPushCounter++;
        Serial.println("on");
        Serial.print("number of button pushes:  ");
        Serial.println(buttonPushCounter);
        if (buttonPushCounter == 10) {
          buttonPushCounter = 1;
        }
      } else {

        // if the current state is LOW then the button
        // wend from on to off:
        Serial.println("off");
      }
    }
    // save the current state as the last state,
    //for next time through the loop
    lastButtonState = buttonState;


    switch (buttonPushCounter) {

      case 1:
        buttonPushCounter == 1;
        {
          All2();  // wechselt die Funktion nach 30sek
          break;
        }

      case 2:
        buttonPushCounter == 2;
        {
          Effekt0();  // NORMAL
          break;
        }

      case 3:
        buttonPushCounter == 3;
        {
          Effekt1();  // Centre out
          break;
        }

      case 4:
        buttonPushCounter == 4;
        {
          Effekt2();  // Centre Inwards
          break;
        }

      case 5:
        buttonPushCounter == 5;
        {
          Effekt3();  // Normal Rainbow
          break;
        }

      case 6:
        buttonPushCounter == 6;
        {
          Effekt4();  // Centre rainbow
          break;
        }

      case 7:
        buttonPushCounter == 7;
        {
          Effekt5();  // Shooting Star
          break;
        }

      case 8:
        buttonPushCounter == 8;
        {
          Effekt6();  // Falling star
          break;
        }

      case 9:
        buttonPushCounter == 9;
        {
          Effekt7();  // Shatter
          break;
        }
    }
  }
}

// List of patterns to cycle through.  Each is defined as a separate function below.
typedef void (*SimplePatternList[])();
SimplePatternList qPatterns = { Effekt0, Effekt1, Effekt2, Effekt3, Effekt4, Effekt5, Effekt6, Effekt7 };
uint8_t qCurrentPatternNumber = 0;  // Index number of which pattern is current

void nextPattern2() {
  // add one to the current pattern number, and wrap around at the end
  qCurrentPatternNumber = (qCurrentPatternNumber + 1) % ARRAY_SIZE(qPatterns);
}
void All2() {
  // Call the current pattern function once, updating the 'leds' array
  qPatterns[qCurrentPatternNumber]();
  EVERY_N_SECONDS(30) {
    nextPattern2();
  }  // change patterns periodically
}


//---------------------------------------------------------------------------------------
//----------------------------------------  Effekt 0  ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt0() {

  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak) peak = height;  // Keep 'peak' dot at top


  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS; i++) {
    if (i >= height) strip.setPixelColor(i, 0, 0, 0);
    else strip.setPixelColor(i, Wheel(map(i, 0, strip.numPixels() - 1, 30, 150)));
  }


  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS - 1) strip.setPixelColor(peak, Wheel(map(peak, 0, strip.numPixels() - 1, 30, 150)));

  strip.show();  // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) {  //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }


  vol[volCount] = n;                        // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

// Input a value 0 to 255 to get a color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

//--------------------------------------------------------------------------------------
//---------------------------------------- Effekt 1 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt1() {

  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;



  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak) peak = height;  // Keep 'peak' dot at top


  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS_HALF; i++) {
    if (i >= height) {
      strip.setPixelColor(N_PIXELS_HALF - i - 1, 0, 0, 0);
      strip.setPixelColor(N_PIXELS_HALF + i, 0, 0, 0);
    } else {
      uint32_t color = Wheel(map(i, 0, N_PIXELS_HALF - 1, 30, 150));
      strip.setPixelColor(N_PIXELS_HALF - i - 1, color);
      strip.setPixelColor(N_PIXELS_HALF + i, color);
    }
  }

  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS_HALF - 1) {
    uint32_t color = Wheel(map(peak, 0, N_PIXELS_HALF - 1, 30, 150));
    strip.setPixelColor(N_PIXELS_HALF - peak - 1, color);
    strip.setPixelColor(N_PIXELS_HALF + peak, color);
  }

  strip.show();  // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) {  //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }



  vol[volCount] = n;                        // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

//---------------------------------------------------------------------------------------
//---------------------------------------- Effekt 2 ----------------------------------------
//--------------------------------------------------------------------------------------


void Effekt2() {
  unsigned long startMillis = millis();  // Start of sample window
  float peakToPeak = 0;                  // peak-to-peak level

  unsigned int signalMax = 0;
  unsigned int signalMin = 1023;
  unsigned int c, y;


  while (millis() - startMillis < SAMPLE_WINDOW) {
    sample = analogRead(MIC_PIN);
    if (sample < 1024) {
      if (sample > signalMax) {
        signalMax = sample;
      } else if (sample < signalMin) {
        signalMin = sample;
      }
    }
  }
  peakToPeak = signalMax - signalMin;

  // Serial.println(peakToPeak);



  for (int i = 0; i <= N_PIXELS_HALF - 1; i++) {
    uint32_t color = Wheel(map(i, 0, N_PIXELS_HALF - 1, 30, 150));
    strip.setPixelColor(N_PIXELS - i, color);
    strip.setPixelColor(0 + i, color);
  }


  c = fscale(INPUT_FLOOR, INPUT_CEILING, N_PIXELS_HALF, 0, peakToPeak, 2);

  if (c < peak) {
    peak = c;          // Keep dot on top
    dotHangCount = 0;  // make the dot hang before falling
  }
  if (c <= strip.numPixels()) {  // Fill partial column with off pixels
    drawLine(N_PIXELS_HALF, N_PIXELS_HALF - c, strip.Color(0, 0, 0));
    drawLine(N_PIXELS_HALF, N_PIXELS_HALF + c, strip.Color(0, 0, 0));
  }




  y = N_PIXELS_HALF - peak;
  uint32_t color1 = Wheel(map(y, 0, N_PIXELS_HALF - 1, 30, 150));
  strip.setPixelColor(y - 1, color1);
  //strip.setPixelColor(y-1,Wheel(map(y,0,N_PIXELS_HALF-1,30,150)));

  y = N_PIXELS_HALF + peak;
  strip.setPixelColor(y, color1);
  //strip.setPixelColor(y+1,Wheel(map(y,0,N_PIXELS_HALF+1,30,150)));

  strip.show();

  // Frame based peak dot animation
  if (dotHangCount > PEAK_HANG) {    //Peak pause length
    if (++dotCount >= PEAK_FALL2) {  //Fall rate
      peak++;
      dotCount = 0;
    }
  } else {
    dotHangCount++;
  }
}
//Used to draw a line between two points of a given color
void drawLine(uint8_t from, uint8_t to, uint32_t c) {
  uint8_t fromTemp;
  if (from > to) {
    fromTemp = from;
    from = to;
    to = fromTemp;
  }
  for (int i = from; i <= to; i++) {
    strip.setPixelColor(i, c);
  }
}
//---------------------------------------------------------------------------------------
//---------------------------------------- Effekt 3 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt3() {
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak) peak = height;  // Keep 'peak' dot at top

  greenOffset += SPEED;
  blueOffset += SPEED;
  if (greenOffset >= 255) greenOffset = 0;
  if (blueOffset >= 255) blueOffset = 0;

  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS; i++) {
    if (i >= height) {
      strip.setPixelColor(i, 0, 0, 0);
    } else {
      strip.setPixelColor(i, Wheel(
                               map(i, 0, strip.numPixels() - 1, (int)greenOffset, (int)blueOffset)));
    }
  }
  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS - 1) strip.setPixelColor(peak, Wheel(map(peak, 0, strip.numPixels() - 1, 30, 150)));

  strip.show();  // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) {  //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }
  strip.show();  // Update strip

  vol[volCount] = n;
  if (++volCount >= SAMPLES) {
    volCount = 0;
  }

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) {
      minLvl = vol[i];
    } else if (vol[i] > maxLvl) {
      maxLvl = vol[i];
    }
  }

  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) {
    maxLvl = minLvl + TOP;
  }
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

//---------------------------------------------------------------------------------------
//--------------------------------------- Effekt 4 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt4() {
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak) peak = height;  // Keep 'peak' dot at top
  greenOffset += SPEED;
  blueOffset += SPEED;
  if (greenOffset >= 255) greenOffset = 0;
  if (blueOffset >= 255) blueOffset = 0;

  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS_HALF; i++) {
    if (i >= height) {
      strip.setPixelColor(N_PIXELS_HALF - i - 1, 0, 0, 0);
      strip.setPixelColor(N_PIXELS_HALF + i, 0, 0, 0);
    } else {
      uint32_t color = Wheel(map(i, 0, N_PIXELS_HALF - 1, (int)greenOffset, (int)blueOffset));
      strip.setPixelColor(N_PIXELS_HALF - i - 1, color);
      strip.setPixelColor(N_PIXELS_HALF + i, color);
    }
  }

  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS_HALF - 1) {
    uint32_t color = Wheel(map(peak, 0, N_PIXELS_HALF - 1, 30, 150));
    strip.setPixelColor(N_PIXELS_HALF - peak - 1, color);
    strip.setPixelColor(N_PIXELS_HALF + peak, color);
  }

  strip.show();  // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) {  //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }


  vol[volCount] = n;                        // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

//---------------------------------------------------------------------------------------
//---------------------------------------- Effekt 5 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt5() {
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP2 * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP2) height = TOP2;
  if (height > peak) peak = height;  // Keep 'peak' dot at top


#ifdef CENTERED
  // Color pixels based on rainbow gradient
  for (i = 0; i < (N_PIXELS / 2); i++) {
    if (((N_PIXELS / 2) + i) >= height) {
      strip.setPixelColor(((N_PIXELS / 2) + i), 0, 0, 0);
      strip.setPixelColor(((N_PIXELS / 2) - i), 0, 0, 0);
    } else {
      strip.setPixelColor(((N_PIXELS / 2) + i), Wheel(map(((N_PIXELS / 2) + i), 0, strip.numPixels() - 1, 30, 150)));
      strip.setPixelColor(((N_PIXELS / 2) - i), Wheel(map(((N_PIXELS / 2) - i), 0, strip.numPixels() - 1, 30, 150)));
    }
  }

  // Draw peak dot
  if (peak > 0 && peak <= LAST_PIXEL_OFFSET) {
    strip.setPixelColor(((N_PIXELS / 2) + peak), 255, 255, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
    strip.setPixelColor(((N_PIXELS / 2) - peak), 255, 255, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
  }
#else
  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS; i++) {
    if (i >= height) {
      strip.setPixelColor(i, 0, 0, 0);
    } else {
      strip.setPixelColor(i, Wheel(map(i, 0, strip.numPixels() - 1, 30, 150)));
    }
  }

  // Draw peak dot
  if (peak > 0 && peak <= LAST_PIXEL_OFFSET) {
    strip.setPixelColor(peak, 255, 255, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
  }

#endif

  // Every few frames, make the peak pixel drop by 1:

  if (millis() - lastTime >= PEAK_FALL_MILLIS) {
    lastTime = millis();

    strip.show();  // Update strip

    //fall rate
    if (peak > 0) peak--;
  }

  vol[volCount] = n;                        // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP2) maxLvl = minLvl + TOP2;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

//---------------------------------------------------------------------------------------
//---------------------------------------- Effekt 6 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt6() {
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP2 * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP2) height = TOP2;
  if (height > peak) peak = height;  // Keep 'peak' dot at top


#ifdef CENTERED
  // Draw peak dot
  if (peak > 0 && peak <= LAST_PIXEL_OFFSET) {
    strip.setPixelColor(((N_PIXELS / 2) + peak), 255, 255, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
    strip.setPixelColor(((N_PIXELS / 2) - peak), 255, 255, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
  }
#else
  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS; i++) {
    if (i >= height) {
      strip.setPixelColor(i, 0, 0, 0);
    } else {
    }
  }

  // Draw peak dot
  if (peak > 0 && peak <= LAST_PIXEL_OFFSET) {
    strip.setPixelColor(peak, 0, 0, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
  }

#endif

  // Every few frames, make the peak pixel drop by 1:

  if (millis() - lastTime >= PEAK_FALL_MILLIS) {
    lastTime = millis();

    strip.show();  // Update strip

    //fall rate
    if (peak > 0) peak--;
  }

  vol[volCount] = n;                        // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP2) maxLvl = minLvl + TOP2;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

//---------------------------------------------------------------------------------------
//---------------------------------------- Effekt 7 ----------------------------------------
//--------------------------------------------------------------------------------------

//Effekt 7 variables
int
  origin = 0,
  color_wait_count = 0,
  scroll_color = COLOR_MIN,
  last_intensity = 0,
  intensity_max = 0,
  origin_at_flip = 0;
uint32_t
  draw[DRAW_MAX];
boolean
  growing = false,
  fall_from_left = true;

void Effekt7() {
  int intensity = calculateIntensity();
  updateOrigin(intensity);
  assignDrawValues(intensity);
  writeSegmented();
  updateGlobals();
}

int calculateIntensity() {
  int intensity;

  reading = analogRead(MIC_PIN);                         // Raw reading from mic
  reading = abs(reading - 512 - DC_OFFSET);              // Center on zero
  reading = (reading <= NOISE) ? 0 : (reading - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + reading) >> 3;                      // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  intensity = DRAW_MAX * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  return constrain(intensity, 0, DRAW_MAX - 1);
}

void updateOrigin(int intensity) {
  // detect peak change and save origin at curve vertex
  if (growing && intensity < last_intensity) {
    growing = false;
    intensity_max = last_intensity;
    fall_from_left = !fall_from_left;
    origin_at_flip = origin;
  } else if (intensity > last_intensity) {
    growing = true;
    origin_at_flip = origin;
  }
  last_intensity = intensity;

  // adjust origin if falling
  if (!growing) {
    if (fall_from_left) {
      origin = origin_at_flip + ((intensity_max - intensity) / 2);
    } else {
      origin = origin_at_flip - ((intensity_max - intensity) / 2);
    }
    // correct for origin out of bounds
    if (origin < 0) {
      origin = DRAW_MAX - abs(origin);
    } else if (origin > DRAW_MAX - 1) {
      origin = origin - DRAW_MAX - 1;
    }
  }
}

void assignDrawValues(int intensity) {
  // draw amplitue as 1/2 intensity both directions from origin
  int min_lit = origin - (intensity / 2);
  int max_lit = origin + (intensity / 2);
  if (min_lit < 0) {
    min_lit = min_lit + DRAW_MAX;
  }
  if (max_lit >= DRAW_MAX) {
    max_lit = max_lit - DRAW_MAX;
  }
  for (int i = 0; i < DRAW_MAX; i++) {
    // if i is within origin +/- 1/2 intensity
    if (
      (min_lit < max_lit && min_lit < i && i < max_lit)       // range is within bounds and i is within range
      || (min_lit > max_lit && (i > min_lit || i < max_lit))  // range wraps out of bounds and i is within that wrap
    ) {
      draw[i] = Wheel(scroll_color);
    } else {
      draw[i] = 0;
    }
  }
}

void writeSegmented() {
  int seg_len = N_PIXELS / SEGMENTS;

  for (int s = 0; s < SEGMENTS; s++) {
    for (int i = 0; i < seg_len; i++) {
      strip.setPixelColor(i + (s * seg_len), draw[map(i, 0, seg_len, 0, DRAW_MAX)]);
    }
  }
  strip.show();
}

uint32_t* segmentAndResize(uint32_t* draw) {
  int seg_len = N_PIXELS / SEGMENTS;

  uint32_t segmented[N_PIXELS];
  for (int s = 0; s < SEGMENTS; s++) {
    for (int i = 0; i < seg_len; i++) {
      segmented[i + (s * seg_len)] = draw[map(i, 0, seg_len, 0, DRAW_MAX)];
    }
  }

  return segmented;
}

void writeToStrip(uint32_t* draw) {
  for (int i = 0; i < N_PIXELS; i++) {
    strip.setPixelColor(i, draw[i]);
  }
  strip.show();
}

void updateGlobals() {
  uint16_t minLvl, maxLvl;

  //advance color wheel
  color_wait_count++;
  if (color_wait_count > COLOR_WAIT_CYCLES) {
    color_wait_count = 0;
    scroll_color++;
    if (scroll_color > COLOR_MAX) {
      scroll_color = COLOR_MIN;
    }
  }

  vol[volCount] = reading;                  // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (uint8_t i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < N_PIXELS) maxLvl = minLvl + N_PIXELS;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

liebe Grüße und :heart:lichen Dank im Voraus,
Fliederida


Edit: ButtonPin auf 13 gesetzt


Edit: Code angepasst


aktuellster Code am Ende des Threads

welchen der geschätzt 20 Konstanten/Variablen soll denn dein Potentiometer nun beeinflussen?

Ich dachte da an INPUT_CEILING, weil dort im Kommentar sensitive steht :slightly_smiling_face:

Oder habe ich da viel zu kompliziert gedacht hatte und so wäre die bessere Lösung?

Zur Schaltung.
Am Vin Pin muß eine Spannung zwischen 7V und 12V angeschlossen werden. Wenn Du Arduino mit 5V versorgen willst dann mußt Du diese am Pin 5V einspeisen. Achtung: Nicht gleichzeitig über 5V Pin und USB versorgen. Zum Programmieren die Powerpack absbziehen.

Die LEDstreifen kännen max 1,7A brauchen . Kann diese das Powerpack liefern?

Hast Du bedacht daß die Wasserflasche im Rohr ziemlich Lärm machen kann falls diese nur so herumschlägt?

Grüße Uwe

1 Like

Hallo,
Den Vorschlag den Du da selbst mit dem zusätzlichen Poti gemacht hast ist schon der einfachste und das sollte auch klappen.

1 Like

Hallo Uwe,

vielen Dank für den Hinweis mit dem Vin-Pin!
Ich habe das Schaltbild angepasst.

Die Ampere-Zahl habe ich im Blick und die Powerbank wird entsprechend dimensioniert. Das bringt mich gleich zu meiner nächsten Frage:

Um Strom zu sparen wollte ich die Helligkeit der LEDs reduzieren, im Code oben sieht man noch dass ich bei #define Brightness 10 eingegeben habe.
Das hat allerdings keine Veränderung gebracht.

Was ich gerne hätte wäre eine Leuchtkraft von 60% bei den schon im Code vorhandenen schallgesteuerten Effekten. Aber, das nehme ich jetzt mal vorweg, auch eine über einen zweiten Taster gesteuerte Blitz-Funktion, bei der die LED´s kurz in voller Helligkeit erstrahlen. (Daher mein Versuch das über Brightness zu regulieren und nicht etwa MaxAmps)

Das Herumschlagen der Flasche ist auch ein guter Punkt, um das etwas abzumildern kommt oben eine Pappröhre in das PVC-Rohr, in die die Flasche gerade so reinpasst, ich hoffe das dämpft genug. :slight_smile:

Hallo Rentner,

Danke das ist gut zu wissen, dann ist die Baustelle schon mal abgehakt. :slightly_smiling_face:

...bzw. kann es sein, dass sich die beiden Potis da in die Quere kommen und es besser wäre mir noch ein reines Mikrofonmodul ohne Poti zu besorgen?
Ich kenne diese Problematik bei Glühlampen-Dimmern.

Randnotiz:

buttonPin = 0

ist eine schlechte Idee.

Oh, ist Pin 13 eine bessere Idee? :smiley:

Kommt drauf an, ob der frei ist.
Du kannst für den Taster jeden freien, digitalen Pin verwenden.
Der Pin D0 ist ein serieller Pin, auf dem der USB-Chip hängt. Das könnte u.U. Probleme bringen.

1 Like

Ah, Danke für die Erläuterung.

Ich ändere das mal auf Pin 13

Ergänzung zu post #10, du kannst auch freie analoge Pins verwenden und dies als digital definieren.

Spezifizierung:
Ich rede von Arduinos mit ATmega328 Controller wie den UNO, NANO MINI. Auf anderen Controllern ist die Lage ähnlich aber auf anderen Pins.

Auch 13 ist nicht die beste Wahl weil dort eine LED angeschlossen ist ( LED "L") Diese blinkt einige male beim Einschalten.
An den Pins 11, 12 13 ist die Hardware SPI Schnittstelle angeschlossen. Diese braucht pro angeschlossenes Gerät noch ein Enable Pin. Diese sind standartmäßig 10 und oft auch noch 4.
Auch A5 ist nicht die beste Wahl da an A4 und A5 die Hardware I2C Schnittstelle hängt.
D0 ist nur die halbe Wahrheit weil die Hardware Serielle Schnittstelle die für die Komunikation und Programmierung über USB benötigt wird die Pins D0 und D1 verwendet.
Am besten ist man gewöhnt sich die jetzt genannten Pins am Anfang nicht zu nutzen und nutzt sie erst wenn alle anderen bereits verbaut sind bzw wenn man eine der beiden genannten Schnittstellen (I2C bzw SPI) verwenden will.
Fast alle Pins haben Mehrfachfunktionen. Wie die bereits genannten ist noch Interrupt auf D2 und D3 zu nennen. (Interrupt funktioniert auf allen Pins aber die Auswertung ist gegenüber den Pins D2 und D3 aufwendiger).
A0 bis A5 sind auch Digitale Ein/Ausgänge = D14 bis D19.
Es gibt noch andere Funktionen, die ich hier nicht nenne.

Da die WS2812 mittels PWM geregelt werden ist der Momentanverbrauch bis zu 100%. Der Mittelwert ist weniger.
Schwächere Farben kann man auch einfach durch proportionales Runterrechnen der R G B Werte erreichen. Also aus 255, 127 und 0 wird bei 50% zu127, 63, und 0 .

Powerpacks brauchen eine Mindestlast da sie ansonsten nac ca 30 Sekunden abschalten.
Das kannst Du erreichen, indem Du, falls alle WS längere Zeit ausgeschalten sind, etwa alle 20 Sekunden einige WS kurz einschaltest. Wie lange dieses Einschalten dauern muß mußt Du experimentell erarbeiten.

Du solltest irgend einen Taster vorsehen, der das Powerpack aus dem standby holt. Wie das genau zu realisieren ist hängt vom Powerpack ab. Ich hab zB eines das einen Bewegungssensor hat, mit dem man es einschaltet. Also nur kurz schütteln.

Grüße Uwe

1 Like

Vielen Dank Uwe,

da kann ich ´ne ganze Menge mitnehmen aus Deinem Beitrag!

Ich habe es mittlerweile geschafft einen zweiten Button mit in den Code aufzunehmen, der mir die gewünschte "Blitzfunktion" bietet und alle LEDs weiß leuchten lässt.

Beim ausprobieren kamen mir die LEDs dann doch etwas gedimmt vor und ich glaube das mit define Brightness hat doch funktioniert. Ich hab´s nur nicht bemerkt, weil ich es bei ständig blinken LEDs schwer einschätzen konnte und, der Gedanke kam mir auch erst jetzt, es eben ein 5V-Streifen ist (bei 12V wäre der Kontrast von 100 zu 10% ja deutlicher gewesen).

Was ich noch nicht geschafft habe ist, die Blitzfunktion mit voller Helligkeit und die anderen Effekte mit reduzierter Helligkeit auszustatten.
Kann ich das beim if Button2 Blitz --- else Effekte im Loop mitaufnehmen, wenn ich das define Brightness herausnehme? Oder muss diese Unterscheidung an eine andere Stelle?

Hier der aktuelle Code, die Buttons sind jetzt auf den Pins 8 & 9


#include <Adafruit_NeoPixel.h>
#include <FastLED.h>
#include <math.h>
#include <SoftwareSerial.h>
#define N_PIXELS 14  // Number of pixels in strand
#define N_PIXELS_HALF (N_PIXELS / 2)
#define MIC_PIN A5  // Microphone is attached to this analog pin
#define blitzbutton_Pin 8
#define LED_PIN 6            // NeoPixel LED strand is connected to this pin
#define SAMPLE_WINDOW 10     // Sample window for average level
#define PEAK_HANG 24         //Time of pause before peak dot falls
#define PEAK_FALL 20         //Rate of falling peak dot
#define PEAK_FALL2 8         //Rate of falling peak dot
#define INPUT_FLOOR 50       //Lower range of analogRead input
#define INPUT_CEILING 900    //Max range of analogRead input, the lower the value the more sensitive (1023 = max)300 (150)
#define DC_OFFSET 510        // DC offset in mic signal - if unusure, leave 0
#define NOISE 10             // Noise/hum/interference in mic signal
#define SAMPLES 60           // Length of buffer for dynamic level adjustment
#define TOP (N_PIXELS + 2)   // Allow dot to go slightly off scale
#define SPEED .20            // Amount to increment RGB color by each cycle
#define TOP2 (N_PIXELS + 1)  // Allow dot to go slightly off scale
#define LAST_PIXEL_OFFSET N_PIXELS - 1
#define PEAK_FALL_MILLIS 10  // Rate of peak falling dot
#define BG 0
#define LAST_PIXEL_OFFSET N_PIXELS - 1
#define BRIGHTNESS 100
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define COLOR_MIN 0
#define COLOR_MAX 255
#define DRAW_MAX 100
#define SEGMENTS 4            // Number of segments to carve amplitude bar into
#define COLOR_WAIT_CYCLES 10  // Loop cycles to wait between advancing pixel origin
#define qsubd(x, b) ((x > b) ? b : 0)
#define qsuba(x, b) ((x > b) ? x - b : 0)  // Analog Unsigned subtraction macro. if result <0, then => 0. By Andrew Tuline.
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))


struct CRGB leds[N_PIXELS];

Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);

static uint16_t dist;     // A random number for noise generator.
uint16_t scale = 30;      // Wouldn't recommend changing this on the fly, or the animation will be really blocky.
uint8_t maxChanges = 48;  // Value for blending between palettes.

CRGBPalette16 currentPalette(OceanColors_p);
CRGBPalette16 targetPalette(CloudColors_p);

byte
  //  peak      = 0,      // Used for falling dot
  //  dotCount  = 0,      // Frame counter for delaying dot-falling speed
  volCount = 0;  // Frame counter for storing past volume data
int
  reading,
  vol[SAMPLES],   // Collection of prior volume samples
  lvl = 10,       // Current "dampened" audio level
  minLvlAvg = 0,  // For dynamic adjustment of graph low & high
  maxLvlAvg = 512;
float
  greenOffset = 30,
  blueOffset = 150;
// cycle variables

int CYCLE_MIN_MILLIS = 2;
int CYCLE_MAX_MILLIS = 1000;
int cycleMillis = 20;
bool paused = false;
long lastTime = 0;
bool boring = true;
bool gReverseDirection = false;
int myhue = 0;



unsigned int sample;

//Samples
#define NSAMPLES 64
unsigned int samplearray[NSAMPLES];
unsigned long samplesum = 0;
unsigned int sampleavg = 0;
int samplecount = 0;
//unsigned int sample = 0;
unsigned long oldtime = 0;
unsigned long newtime = 0;



//Effekt 7 variables
int
  origin = 0,
  color_wait_count = 0,
  scroll_color = COLOR_MIN,
  last_intensity = 0,
  intensity_max = 0,
  origin_at_flip = 0;
uint32_t
  draw[DRAW_MAX];
boolean
  growing = false,
  fall_from_left = true;


byte peak = 16;  // Peak level of column; used for falling dots
                 //    unsigned int sample;

byte dotCount = 0;      //Frame counter for peak dot
byte dotHangCount = 0;  //Frame counter for holding peak dot

const int buttonPin = 9;  // the number of the pushbutton pin
const int blitzbuttonPin = 8;

int buttonPushCounter = 0;  // counter for the number of button presses
int buttonState = 0;        // current state of the button
int lastButtonState = 0;
//---------------------------------------------------------------------------------------
//---------------------------------------- SETUP ----------------------------------------
//--------------------------------------------------------------------------------------

void setup() {

  analogReference(EXTERNAL);

  pinMode(buttonPin, INPUT);  //initialize the buttonPin as output
  digitalWrite(buttonPin, HIGH);
  pinMode(blitzbuttonPin, INPUT);
  digitalWrite(blitzbuttonPin, HIGH);

  // Serial.begin(9600);
  strip.begin();
  strip.show();  // all pixels to 'off'

  Serial.begin(57600);
  delay(3000);

  LEDS.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, N_PIXELS).setCorrection(TypicalLEDStrip);
  LEDS.setBrightness(BRIGHTNESS);
  dist = random16(12345);  // A semi-random number for our noise generator
}

float fscale(float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve) {

  float OriginalRange = 0;
  float NewRange = 0;
  float zeroRefCurVal = 0;
  float normalizedCurVal = 0;
  float rangedValue = 0;
  boolean invFlag = 0;

  // condition curve parameter
  // limit range

  if (curve > 10) curve = 10;
  if (curve < -10) curve = -10;

  curve = (curve * -.1);   // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output
  curve = pow(10, curve);  // convert linear scale into lograthimic exponent for other pow function


  // Check for out of range inputValues
  if (inputValue < originalMin) {
    inputValue = originalMin;
  }
  if (inputValue > originalMax) {
    inputValue = originalMax;
  }

  // Zero Refference the values
  OriginalRange = originalMax - originalMin;

  if (newEnd > newBegin) {
    NewRange = newEnd - newBegin;
  } else {
    NewRange = newBegin - newEnd;
    invFlag = 1;
  }

  zeroRefCurVal = inputValue - originalMin;
  normalizedCurVal = zeroRefCurVal / OriginalRange;  // normalize to 0 - 1 float


  // Check for originalMin > originalMax  - the math for all other cases i.e. negative numbers seems to work out fine
  if (originalMin > originalMax) {
    return 0;
  }

  if (invFlag == 0) {
    rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin;

  } else  // invert the ranges
  {
    rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange);
  }
  return rangedValue;
}

//---------------------------------------------------------------------------------------
//---------------------------------------- LOOP ----------------------------------------
//--------------------------------------------------------------------------------------

void loop() {

  //for mic
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;
  // end mic
  // read the pushbutton input pin:
  if (digitalRead(blitzbuttonPin) == LOW) {
    FastLED.showColor(CRGB::White);
    FastLED.show();
  } else {
    buttonState = digitalRead(buttonPin);
    // compare the buttonState to its previous state
    if (buttonState != lastButtonState) {
      // if the state has changed, increment the counter
      if (buttonState == HIGH) {
        // if the current state is HIGH then the button
        // wend from off to on:
        buttonPushCounter++;
        Serial.println("on");
        Serial.print("number of button pushes:  ");
        Serial.println(buttonPushCounter);
        if (buttonPushCounter == 10) {
          buttonPushCounter = 1;
        }
      } else {
        // if the current state is LOW then the button
        // wend from on to off:
        Serial.println("off");
      }
    }
    // save the current state as the last state,
    //for next time through the loop
    lastButtonState = buttonState;


    switch (buttonPushCounter) {

      case 1:
        buttonPushCounter == 1;
        {
          All2();  // wechselt die Funktion nach 30sek
          break;
        }

      case 2:
        buttonPushCounter == 2;
        {
          Effekt0();  // NORMAL
          break;
        }

      case 3:
        buttonPushCounter == 3;
        {
          Effekt1();  // Centre out
          break;
        }

      case 4:
        buttonPushCounter == 4;
        {
          Effekt2();  // Centre Inwards
          break;
        }

      case 5:
        buttonPushCounter == 5;
        {
          Effekt3();  // Normal Rainbow
          break;
        }

      case 6:
        buttonPushCounter == 6;
        {
          Effekt4();  // Centre rainbow
          break;
        }

      case 7:
        buttonPushCounter == 7;
        {
          Effekt5();  // Shooting Star
          break;
        }

      case 8:
        buttonPushCounter == 8;
        {
          Effekt6();  // Falling star
          break;
        }

      case 9:
        buttonPushCounter == 9;
        {
          Effekt7();  // Shatter
          break;
        }
    }
  }
}

// List of patterns to cycle through.  Each is defined as a separate function below.
typedef void (*SimplePatternList[])();
SimplePatternList qPatterns = { Effekt0, Effekt1, Effekt2, Effekt3, Effekt4, Effekt5, Effekt6, Effekt7 };
uint8_t qCurrentPatternNumber = 0;  // Index number of which pattern is current

void nextPattern2() {
  // add one to the current pattern number, and wrap around at the end
  qCurrentPatternNumber = (qCurrentPatternNumber + 1) % ARRAY_SIZE(qPatterns);
}
void All2() {
  // Call the current pattern function once, updating the 'leds' array
  qPatterns[qCurrentPatternNumber]();
  EVERY_N_SECONDS(30) {
    nextPattern2();
  }  // change patterns periodically
}


//---------------------------------------------------------------------------------------
//----------------------------------------  Effekt 0  ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt0() {

  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak) peak = height;  // Keep 'peak' dot at top


  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS; i++) {
    if (i >= height) strip.setPixelColor(i, 0, 0, 0);
    else strip.setPixelColor(i, Wheel(map(i, 0, strip.numPixels() - 1, 30, 150)));
  }


  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS - 1) strip.setPixelColor(peak, Wheel(map(peak, 0, strip.numPixels() - 1, 30, 150)));

  strip.show();  // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) {  //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }


  vol[volCount] = n;                        // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

// Input a value 0 to 255 to get a color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

//--------------------------------------------------------------------------------------
//---------------------------------------- Effekt 1 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt1() {

  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;



  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak) peak = height;  // Keep 'peak' dot at top


  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS_HALF; i++) {
    if (i >= height) {
      strip.setPixelColor(N_PIXELS_HALF - i - 1, 0, 0, 0);
      strip.setPixelColor(N_PIXELS_HALF + i, 0, 0, 0);
    } else {
      uint32_t color = Wheel(map(i, 0, N_PIXELS_HALF - 1, 30, 150));
      strip.setPixelColor(N_PIXELS_HALF - i - 1, color);
      strip.setPixelColor(N_PIXELS_HALF + i, color);
    }
  }

  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS_HALF - 1) {
    uint32_t color = Wheel(map(peak, 0, N_PIXELS_HALF - 1, 30, 150));
    strip.setPixelColor(N_PIXELS_HALF - peak - 1, color);
    strip.setPixelColor(N_PIXELS_HALF + peak, color);
  }

  strip.show();  // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) {  //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }



  vol[volCount] = n;                        // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

//---------------------------------------------------------------------------------------
//---------------------------------------- Effekt 2 ----------------------------------------
//--------------------------------------------------------------------------------------


void Effekt2() {
  unsigned long startMillis = millis();  // Start of sample window
  float peakToPeak = 0;                  // peak-to-peak level

  unsigned int signalMax = 0;
  unsigned int signalMin = 1023;
  unsigned int c, y;


  while (millis() - startMillis < SAMPLE_WINDOW) {
    sample = analogRead(MIC_PIN);
    if (sample < 1024) {
      if (sample > signalMax) {
        signalMax = sample;
      } else if (sample < signalMin) {
        signalMin = sample;
      }
    }
  }
  peakToPeak = signalMax - signalMin;

  // Serial.println(peakToPeak);



  for (int i = 0; i <= N_PIXELS_HALF - 1; i++) {
    uint32_t color = Wheel(map(i, 0, N_PIXELS_HALF - 1, 30, 150));
    strip.setPixelColor(N_PIXELS - i, color);
    strip.setPixelColor(0 + i, color);
  }


  c = fscale(INPUT_FLOOR, INPUT_CEILING, N_PIXELS_HALF, 0, peakToPeak, 2);

  if (c < peak) {
    peak = c;          // Keep dot on top
    dotHangCount = 0;  // make the dot hang before falling
  }
  if (c <= strip.numPixels()) {  // Fill partial column with off pixels
    drawLine(N_PIXELS_HALF, N_PIXELS_HALF - c, strip.Color(0, 0, 0));
    drawLine(N_PIXELS_HALF, N_PIXELS_HALF + c, strip.Color(0, 0, 0));
  }




  y = N_PIXELS_HALF - peak;
  uint32_t color1 = Wheel(map(y, 0, N_PIXELS_HALF - 1, 30, 150));
  strip.setPixelColor(y - 1, color1);
  //strip.setPixelColor(y-1,Wheel(map(y,0,N_PIXELS_HALF-1,30,150)));

  y = N_PIXELS_HALF + peak;
  strip.setPixelColor(y, color1);
  //strip.setPixelColor(y+1,Wheel(map(y,0,N_PIXELS_HALF+1,30,150)));

  strip.show();

  // Frame based peak dot animation
  if (dotHangCount > PEAK_HANG) {    //Peak pause length
    if (++dotCount >= PEAK_FALL2) {  //Fall rate
      peak++;
      dotCount = 0;
    }
  } else {
    dotHangCount++;
  }
}
//Used to draw a line between two points of a given color
void drawLine(uint8_t from, uint8_t to, uint32_t c) {
  uint8_t fromTemp;
  if (from > to) {
    fromTemp = from;
    from = to;
    to = fromTemp;
  }
  for (int i = from; i <= to; i++) {
    strip.setPixelColor(i, c);
  }
}
//---------------------------------------------------------------------------------------
//---------------------------------------- Effekt 3 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt3() {
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak) peak = height;  // Keep 'peak' dot at top

  greenOffset += SPEED;
  blueOffset += SPEED;
  if (greenOffset >= 255) greenOffset = 0;
  if (blueOffset >= 255) blueOffset = 0;

  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS; i++) {
    if (i >= height) {
      strip.setPixelColor(i, 0, 0, 0);
    } else {
      strip.setPixelColor(i, Wheel(
                               map(i, 0, strip.numPixels() - 1, (int)greenOffset, (int)blueOffset)));
    }
  }
  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS - 1) strip.setPixelColor(peak, Wheel(map(peak, 0, strip.numPixels() - 1, 30, 150)));

  strip.show();  // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) {  //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }
  strip.show();  // Update strip

  vol[volCount] = n;
  if (++volCount >= SAMPLES) {
    volCount = 0;
  }

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) {
      minLvl = vol[i];
    } else if (vol[i] > maxLvl) {
      maxLvl = vol[i];
    }
  }

  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) {
    maxLvl = minLvl + TOP;
  }
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

//---------------------------------------------------------------------------------------
//--------------------------------------- Effekt 4 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt4() {
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP) height = TOP;
  if (height > peak) peak = height;  // Keep 'peak' dot at top
  greenOffset += SPEED;
  blueOffset += SPEED;
  if (greenOffset >= 255) greenOffset = 0;
  if (blueOffset >= 255) blueOffset = 0;

  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS_HALF; i++) {
    if (i >= height) {
      strip.setPixelColor(N_PIXELS_HALF - i - 1, 0, 0, 0);
      strip.setPixelColor(N_PIXELS_HALF + i, 0, 0, 0);
    } else {
      uint32_t color = Wheel(map(i, 0, N_PIXELS_HALF - 1, (int)greenOffset, (int)blueOffset));
      strip.setPixelColor(N_PIXELS_HALF - i - 1, color);
      strip.setPixelColor(N_PIXELS_HALF + i, color);
    }
  }

  // Draw peak dot
  if (peak > 0 && peak <= N_PIXELS_HALF - 1) {
    uint32_t color = Wheel(map(peak, 0, N_PIXELS_HALF - 1, 30, 150));
    strip.setPixelColor(N_PIXELS_HALF - peak - 1, color);
    strip.setPixelColor(N_PIXELS_HALF + peak, color);
  }

  strip.show();  // Update strip

  // Every few frames, make the peak pixel drop by 1:

  if (++dotCount >= PEAK_FALL) {  //fall rate

    if (peak > 0) peak--;
    dotCount = 0;
  }


  vol[volCount] = n;                        // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

//---------------------------------------------------------------------------------------
//---------------------------------------- Effekt 5 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt5() {
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP2 * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP2) height = TOP2;
  if (height > peak) peak = height;  // Keep 'peak' dot at top


#ifdef CENTERED
  // Color pixels based on rainbow gradient
  for (i = 0; i < (N_PIXELS / 2); i++) {
    if (((N_PIXELS / 2) + i) >= height) {
      strip.setPixelColor(((N_PIXELS / 2) + i), 0, 0, 0);
      strip.setPixelColor(((N_PIXELS / 2) - i), 0, 0, 0);
    } else {
      strip.setPixelColor(((N_PIXELS / 2) + i), Wheel(map(((N_PIXELS / 2) + i), 0, strip.numPixels() - 1, 30, 150)));
      strip.setPixelColor(((N_PIXELS / 2) - i), Wheel(map(((N_PIXELS / 2) - i), 0, strip.numPixels() - 1, 30, 150)));
    }
  }

  // Draw peak dot
  if (peak > 0 && peak <= LAST_PIXEL_OFFSET) {
    strip.setPixelColor(((N_PIXELS / 2) + peak), 255, 255, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
    strip.setPixelColor(((N_PIXELS / 2) - peak), 255, 255, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
  }
#else
  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS; i++) {
    if (i >= height) {
      strip.setPixelColor(i, 0, 0, 0);
    } else {
      strip.setPixelColor(i, Wheel(map(i, 0, strip.numPixels() - 1, 30, 150)));
    }
  }

  // Draw peak dot
  if (peak > 0 && peak <= LAST_PIXEL_OFFSET) {
    strip.setPixelColor(peak, 255, 255, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
  }

#endif

  // Every few frames, make the peak pixel drop by 1:

  if (millis() - lastTime >= PEAK_FALL_MILLIS) {
    lastTime = millis();

    strip.show();  // Update strip

    //fall rate
    if (peak > 0) peak--;
  }

  vol[volCount] = n;                        // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP2) maxLvl = minLvl + TOP2;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

//---------------------------------------------------------------------------------------
//---------------------------------------- Effekt 6 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt6() {
  uint8_t i;
  uint16_t minLvl, maxLvl;
  int n, height;

  n = analogRead(MIC_PIN);             // Raw reading from mic
  n = abs(n - 512 - DC_OFFSET);        // Center on zero
  n = (n <= NOISE) ? 0 : (n - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + n) >> 3;          // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  height = TOP2 * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  if (height < 0L) height = 0;  // Clip output
  else if (height > TOP2) height = TOP2;
  if (height > peak) peak = height;  // Keep 'peak' dot at top


#ifdef CENTERED
  // Draw peak dot
  if (peak > 0 && peak <= LAST_PIXEL_OFFSET) {
    strip.setPixelColor(((N_PIXELS / 2) + peak), 255, 255, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
    strip.setPixelColor(((N_PIXELS / 2) - peak), 255, 255, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
  }
#else
  // Color pixels based on rainbow gradient
  for (i = 0; i < N_PIXELS; i++) {
    if (i >= height) {
      strip.setPixelColor(i, 0, 0, 0);
    } else {
    }
  }

  // Draw peak dot
  if (peak > 0 && peak <= LAST_PIXEL_OFFSET) {
    strip.setPixelColor(peak, 0, 0, 255);  // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
  }

#endif

  // Every few frames, make the peak pixel drop by 1:

  if (millis() - lastTime >= PEAK_FALL_MILLIS) {
    lastTime = millis();

    strip.show();  // Update strip

    //fall rate
    if (peak > 0) peak--;
  }

  vol[volCount] = n;                        // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < TOP2) maxLvl = minLvl + TOP2;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

//---------------------------------------------------------------------------------------
//---------------------------------------- Effekt 7 ----------------------------------------
//--------------------------------------------------------------------------------------

void Effekt7() {
  int intensity = calculateIntensity();
  updateOrigin(intensity);
  assignDrawValues(intensity);
  writeSegmented();
  updateGlobals();
}

int calculateIntensity() {
  int intensity;

  reading = analogRead(MIC_PIN);                         // Raw reading from mic
  reading = abs(reading - 512 - DC_OFFSET);              // Center on zero
  reading = (reading <= NOISE) ? 0 : (reading - NOISE);  // Remove noise/hum
  lvl = ((lvl * 7) + reading) >> 3;                      // "Dampened" reading (else looks twitchy)

  // Calculate bar height based on dynamic min/max levels (fixed point):
  intensity = DRAW_MAX * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  return constrain(intensity, 0, DRAW_MAX - 1);
}

void updateOrigin(int intensity) {
  // detect peak change and save origin at curve vertex
  if (growing && intensity < last_intensity) {
    growing = false;
    intensity_max = last_intensity;
    fall_from_left = !fall_from_left;
    origin_at_flip = origin;
  } else if (intensity > last_intensity) {
    growing = true;
    origin_at_flip = origin;
  }
  last_intensity = intensity;

  // adjust origin if falling
  if (!growing) {
    if (fall_from_left) {
      origin = origin_at_flip + ((intensity_max - intensity) / 2);
    } else {
      origin = origin_at_flip - ((intensity_max - intensity) / 2);
    }
    // correct for origin out of bounds
    if (origin < 0) {
      origin = DRAW_MAX - abs(origin);
    } else if (origin > DRAW_MAX - 1) {
      origin = origin - DRAW_MAX - 1;
    }
  }
}

void assignDrawValues(int intensity) {
  // draw amplitue as 1/2 intensity both directions from origin
  int min_lit = origin - (intensity / 2);
  int max_lit = origin + (intensity / 2);
  if (min_lit < 0) {
    min_lit = min_lit + DRAW_MAX;
  }
  if (max_lit >= DRAW_MAX) {
    max_lit = max_lit - DRAW_MAX;
  }
  for (int i = 0; i < DRAW_MAX; i++) {
    // if i is within origin +/- 1/2 intensity
    if (
      (min_lit < max_lit && min_lit < i && i < max_lit)       // range is within bounds and i is within range
      || (min_lit > max_lit && (i > min_lit || i < max_lit))  // range wraps out of bounds and i is within that wrap
    ) {
      draw[i] = Wheel(scroll_color);
    } else {
      draw[i] = 0;
    }
  }
}

void writeSegmented() {
  int seg_len = N_PIXELS / SEGMENTS;

  for (int s = 0; s < SEGMENTS; s++) {
    for (int i = 0; i < seg_len; i++) {
      strip.setPixelColor(i + (s * seg_len), draw[map(i, 0, seg_len, 0, DRAW_MAX)]);
    }
  }
  strip.show();
}

uint32_t* segmentAndResize(uint32_t* draw) {
  int seg_len = N_PIXELS / SEGMENTS;

  uint32_t segmented[N_PIXELS];
  for (int s = 0; s < SEGMENTS; s++) {
    for (int i = 0; i < seg_len; i++) {
      segmented[i + (s * seg_len)] = draw[map(i, 0, seg_len, 0, DRAW_MAX)];
    }
  }

  return segmented;
}

void writeToStrip(uint32_t* draw) {
  for (int i = 0; i < N_PIXELS; i++) {
    strip.setPixelColor(i, draw[i]);
  }
  strip.show();
}

void updateGlobals() {
  uint16_t minLvl, maxLvl;

  //advance color wheel
  color_wait_count++;
  if (color_wait_count > COLOR_WAIT_CYCLES) {
    color_wait_count = 0;
    scroll_color++;
    if (scroll_color > COLOR_MAX) {
      scroll_color = COLOR_MIN;
    }
  }

  vol[volCount] = reading;                  // Save sample for dynamic leveling
  if (++volCount >= SAMPLES) volCount = 0;  // Advance/rollover sample counter

  // Get volume range of prior frames
  minLvl = maxLvl = vol[0];
  for (uint8_t i = 1; i < SAMPLES; i++) {
    if (vol[i] < minLvl) minLvl = vol[i];
    else if (vol[i] > maxLvl) maxLvl = vol[i];
  }
  // minLvl and maxLvl indicate the volume range over prior frames, used
  // for vertically scaling the output graph (so it looks interesting
  // regardless of volume level).  If they're too close together though
  // (e.g. at very low volume levels) the graph becomes super coarse
  // and 'jumpy'...so keep some minimum distance between them (this
  // also lets the graph go to zero when no sound is playing):
  if ((maxLvl - minLvl) < N_PIXELS) maxLvl = minLvl + N_PIXELS;
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;  // Dampen min/max levels
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  // (fake rolling average)
}

Der Einwand mit der Mindestlast für die Powerbank ist auch sehr gut. So eine mit Bewegungssensor wie Du sie hast, klingt für meine Zwecke geradezu ideal, da müsste ich nach einem Päuschen ja nur einmal hochspringen, um die wieder in Gang zu bringen :grinning:
Ich gucke mal ob ich da etwas passendes finde.

Die Powerbank mit Bewegungssnsor war mal eine Rabattaktion bei Amazon wobei die Aufwachfunktion nicht beschrieben war. (also Katze imsack gekauft) Wüßte jetzt nicht wo ich eine mit dieser Funktion finden könnte.

define Brightness definierst Du ja nur ein Ersetzen im Preprozessor. Die ware Funktion des Setzen der Helligkeit liegt irgendwo im Sketch. Genaugesagt im Setup:

LEDS.setBrightness(BRIGHTNESS);

Du kannst jederzeit die Helligkeit ändern, also vor dem "Blitz" auf 100% und danach wieder auf x %

Grüße Uwe

Ich habe zwar etwas gefunden, Beschleunigungssensor war das Stichwort, aber die ist mir zu teuer.

Meine Idee ist jetzt noch einen LED-Streifen etwas versteckter zu verbauen, der in kurzen Intervallen für die Mindestlast sorgt. Dazu habe ich einen Code geschrieben, in der Hoffnung die LEDs alle 20 Sekunden für 3 Sekunden angehen zu lassen, aber so ganz funktioniert das noch nicht. Sie gehen zwar alle 20 Sekunden an, aber nur für einen kurzen Moment.

#include <Adafruit_NeoPixel.h>
#include <FastLED.h>
#define N_PIXELS 14
#define LED2_PIN 7
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB

struct CRGB leds[N_PIXELS];
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED2_PIN, NEO_GRB + NEO_KHZ800);

long nullpunkt = 0;
long intervall = 20000;
long anschaltzeit = 3000;
void setup() {

  LEDS.addLeds<LED_TYPE, LED2_PIN, COLOR_ORDER>(leds, N_PIXELS).setCorrection(TypicalLEDStrip);
}

void loop() {

  if ((millis() - nullpunkt) > intervall) {
    nullpunkt = millis();
    FastLED.showColor(CRGB::White);
    FastLED.show();
  }
  if ((millis() > (nullpunkt + anschaltzeit))) {
    FastLED.showColor(CRGB::Black);
    FastLED.show();
  }
}

Vielleicht findet ja jemand den Fehler,
liebe Grüße, fliederida

merk dir in einer Variable ob der streifen ein oder ausgeschaltet ist.

ungetestet:

#include <Adafruit_NeoPixel.h> // wozu???
#include <FastLED.h>
#define N_PIXELS 14
#define LED2_PIN 7
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB

struct CRGB leds[N_PIXELS];
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED2_PIN, NEO_GRB + NEO_KHZ800);

unsigned long previousMillis = 0;
unsigned long intervall = 20000;
unsigned long anschaltzeit = 3000;
bool status = false; // ein oder aus
void setup() {

  LEDS.addLeds<LED_TYPE, LED2_PIN, COLOR_ORDER>(leds, N_PIXELS).setCorrection(TypicalLEDStrip);
}

void loop() {

  if (status == false && (millis() - previousMillis > intervall)) {
    previousMillis = millis();
    status = true;
    FastLED.showColor(CRGB::White);
    FastLED.show();
  }
  else if (status == true && (millis() - previousMillis > anschaltzeit)) {
    previousMillis = millis();
    status = false;
    FastLED.showColor(CRGB::Black);
    FastLED.show();
  }
}

OT: wozu bindest du jetzt die Adafruit und die FastLed ein? Mach alles mit einer Library.

1 Like

Danke für die Idee noiasca, leider bleibt das Ergebnis unverändert und die LEDs blinken nur ganz kurz auf.

Ich habe die beiden Bibliotheken eingebunden weil er mir ohne die Adafruit_Neopixel.h sagt

Compilation error: 'Adafruit_NeoPixel' does not name a type

und ich mit den FastLED.show-Befehlen schon etwas vertrauter bin und die einsetzen wollte.

Du vermischst die Nutzung beider Libs. Das fällt Dir auf die Füße. Ohne die Ada-Lib muss natürlich auch deren Konstruktor raus.

Gruß Tommy

Ok, verstehe ich :slight_smile:

Ist das dann der Konstruktor für die FastLED-Library

struct CRGB leds[N_PIXELS];

und sagt das gleiche wie

Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED2_PIN, NEO_GRB + NEO_KHZ800);

für die Neopixel?

Und mal angenommen ich würde den Code aus #1 auf nur eine der beiden Libraries bereinigen wollen. Gibt es für die IDE eine Methode mit der ich mir alles was sich auf eine bestimmte Library bezieht anzeigen lassen kann?