WS2812B Musikgesteuert

Hallo,

ich bin seit einiger Zeit dabei, digitale LED-Streifen musikgesteuert zu programmieren. Dazu verwende ich einen Arduino Mega 2560 mit einem AZDelivery Max9814 Microphone.

Leider fehlt mir hier noch der "Feinschliff" im vergleich zu fertig gekauften Controllern.

Folgenden Code habe ich bisher (im Moment nur 1 Muster, mehrere sollen demnächst folgen):

#include <Adafruit_NeoPixel.h>
#include <FastLED.h>





#define Anzahl_LEDS 60
#define Anzahl_LEDS_Halb (Anzahl_LEDS/2)
#define Datenpin_Arduino 7
#define Helligkeit 100 //Maximal 255
#define MIC_PIN 0
#define DC_OFFSET -300 //-250
#define UMBEGUNGSGERAEUSCHE 50 //20
#define Puffer   10 //Puffer für Dynamische Anpassung
#define Segmente 1
#define TOP (Anzahl_LEDS/Segmente )
#define Fallrate_Peak 5 //Rate of falling peak dot
#define SPEED 0.2      // Regenbogen Verlauf Geschwindigkeit 


CRGB leds[Anzahl_LEDS];
Adafruit_NeoPixel strip = Adafruit_NeoPixel(Anzahl_LEDS, Datenpin_Arduino, NEO_GRB + NEO_KHZ800);


int minLvlAvg = 0;
int maxLvlAvg = 512; 
int lvl = 10; 
int vol[Puffer];
int height;
int Maximaler_Peak;

byte peak = 16;
byte dotCount = 2;
byte volCount = 2;

float greenOffset = 30; //30
float blueOffset = 150; //150


void setup() {
  Serial.begin(9600);
  FastLED.addLeds<NEOPIXEL, Datenpin_Arduino >(leds, Anzahl_LEDS);
  LEDS.setBrightness(Helligkeit);
  strip.setBrightness(Helligkeit);
  strip.begin();
  }



void loop() {
  Muster_01();
}


//-----------------------------------------------------------------------


void Peak_Auslesen(){
  int i;
  int n;
  uint16_t minLvl;
  uint16_t maxLvl;
  
  n   = analogRead(MIC_PIN);
  n   = abs(n - 512 - DC_OFFSET);
  n   = (n <= UMBEGUNGSGERAEUSCHE) ? 0 : (n - UMBEGUNGSGERAEUSCHE);
  
  if(n > Maximaler_Peak) Maximaler_Peak = n;
  
  lvl = ((lvl * 7) + n) >> 3; 
  
  vol[volCount] = n;
  if(++volCount >= Puffer) volCount = 0;
  
  minLvl = maxLvl = vol[0];

  for(i=1; i<Puffer; i++) {
    if(vol[i] < minLvl)      minLvl = vol[i];
    else if(vol[i] > maxLvl) maxLvl = vol[i];
  }
  
  
  //if((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;

  if((maxLvl - minLvl) < TOP) maxLvl = TOP;
  
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  
  
  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);

  Serial.println(height);

  if(height < 0L)       height = 0; 
  else if(height > TOP) height = TOP;
  if(height > peak)     peak   = height;

  if(++dotCount >= Fallrate_Peak) {
   if(peak > 0) peak--;
    dotCount = 0;
  } 


}



void Muster_01(){
  int dot;
  int i;
  
  Peak_Auslesen();

  for(i=0; i<Anzahl_LEDS; i++) {
    if(i >= height)               leds[i].setRGB( 0, 0, 0);
    else leds[i].setRGB( 255, 0, 0);
  }
    if(peak > 0 && peak <= Anzahl_LEDS-1) leds[peak].setRGB( 0, 255, 0);
  FastLED.show();
}

  

Grundsätzlich möchte ich das ganze Lautstärkeunabhängig gestalten, da ja die Lautstärke der Lieder immer variiert und bei Partys auch gerne mal die Lautstärke verändert wird.

Gibt es hierzu ein paar hilfreiche Tipps/Verbesserungsvorschläge?

Grüße

Ja, du schließt dein Projekt nicht an ein Mikrofon an, sondern am Line-Ausgang deiner Anlage. Und mit einem zusätzlichen Dynamikkompressor wird auch der Rest automatisch ausgeregelt.

Oke Danke.
Ich würde aber gerne bei der Microphone-Lösung bleiben, da ich hier flexibler bin bezüglich Ort und Anlagentyp. Viele sind ja mittels Bluetooth verbunden, da kann ich nur das Microphone nutzen.

Bei zwei Bibliotheken ist eine zu viel :slightly_smiling_face:

Danke, ich benötige späte beide, da ich mehrere Muster mittels Zufall durchwechseln möchte :wink:

Mir geht es im ersten Schritt erst einmal um die Korrekte Erkennung des Peaks und der Skalierung auf die Lautstärke. Das funktioniert noch nicht ganz.

Bitte schreibe mir, wenn das tatsächlich funktionieren sollte, denn dann hätte ich was gelernt :thinking:

Ich halte die Wahrscheinlichkeit für gering.

Gruß Tommy

Dann brauchst du einen Dynamikkompressor, der den Unterschied komplett ausgleicht.

Wie muss ich mir das Vorstellen?

Hier gibt es die passende Beschreibung dazu.
Und hier eine passende Schaltung.

Danke, ich glaube aber das wird mir zu komplex. Da werde ich wohl wieder auf einen Poti zurückgehen, mit dem ich die Empfindlichkeit per Hand einstellen kann.

Wie kann ich so etwas umsetzen?

Wie meinst du das ?
Mit dem Dynamikkompressor oder Poti ?

In beiden Fällen kommt es sehr auf deine restliche Schaltung an, die wir nicht kennen.

Meine Schaltung sieht so aus:

Über einen Poti kann ich ja dann entsprechend Werte verarbeiten. Nur wie passe ich den Code hier so an, dass ich die Empfindlichkeit über einen Wert regeln kann? Meine idee war jetzt, eine Variable (Empfindlichkeit) einzubauen:

#define Anzahl_LEDS 60
#define Anzahl_LEDS_Halb (Anzahl_LEDS/2)
#define Datenpin_Arduino 7
#define Helligkeit 100 //Maximal 255
#define MIC_PIN 0
#define DC_OFFSET -250 //-250
#define UMBEGUNGSGERAEUSCHE 20 //20
#define Puffer   50 //Puffer für Dynamische Anpassung
#define Segmente 1
#define TOP (Anzahl_LEDS/Segmente)
#define Fallrate_Peak 10 //Rate of falling peak dot
#define SPEED 0.2      // Regenbogen Verlauf Geschwindigkeit 
#define Empfindlichkeit 20;


CRGB leds[Anzahl_LEDS];
Adafruit_NeoPixel strip = Adafruit_NeoPixel(Anzahl_LEDS, Datenpin_Arduino, NEO_GRB + NEO_KHZ800);


int minLvlAvg = 0;
int maxLvlAvg = 512; 
int lvl = 10; 
int vol[Puffer];
int height;
int Maximaler_Peak;



byte peak = 16;
byte dotCount = 2;
byte volCount = 2;

float greenOffset = 30; //30
float blueOffset = 150; //150


void setup() {
  Serial.begin(9600);
  FastLED.addLeds<NEOPIXEL, Datenpin_Arduino >(leds, Anzahl_LEDS);
  LEDS.setBrightness(Helligkeit);
  strip.setBrightness(Helligkeit);
  strip.begin();
  }



void loop() {
  Muster_01();

  
}


//-----------------------------------------------------------------------


void Peak_Auslesen(){
  int i;
  int n;
  uint16_t minLvl;
  uint16_t maxLvl;
  
  n   = analogRead(MIC_PIN);
  n   = abs(n - 512 - DC_OFFSET);
  n = n - Empfindlichkeit;
  n   = (n <= UMBEGUNGSGERAEUSCHE) ? 0 : (n - UMBEGUNGSGERAEUSCHE);

  if(n > Maximaler_Peak) Maximaler_Peak = n;
  
  lvl = ((lvl * 7) + n) >> 3; 

  maxLvlAvg = TOP;
  if(lvl > TOP) lvl = TOP;

  height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);
  
  if(height < 0L)       height = 0; 
  else if(height > TOP) height = TOP;
  if(height > peak)     peak   = height;

  if(++dotCount >= Fallrate_Peak) {
   if(peak > 0) peak--;
    dotCount = 0;
  } 

  vol[volCount] = n;
  volCount = ++volCount % Puffer;
  if(++volCount >= Puffer) volCount = 0;

  minLvl = maxLvl = vol[0];

  for(i=1; i<Puffer; i++) {
    if(vol[i] < minLvl)      minLvl = vol[i];
    else if(vol[i] > maxLvl) maxLvl = vol[i];
  }
  
  if((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
  
  minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6;
  maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;  
  
}

Das verstehe ich nicht.
Welches Poti meinst du ?

Du kannst aber den Wert der Variablen auswerten, die mit Daten vom analogen Pin gespeist wird. Ich bin da aber nicht sicher, ob das mit deinem Soundsensor funktioniert. Zeige doch mal einen Link zum Sensor.

Damit meinte ich, das mit dem Poti bekomme ich hin, ist aber aktuell nich nicht integriert.

Ich weiß eben nur noch nicht, wie ich einen Wert in den vorhandenen Code bekomme, damit ich die Empfindlichkeit regeln kann.

Hier wäre das Micro:

https://www.az-delivery.de/products/max9814-mikrofon?utm_source=google&utm_medium=cpc&utm_campaign=DSA&utm_term=&gclid=Cj0KCQiA2ZCOBhDiARIsAMRfv9LyhT3WBTIfL0cjdmZ1WOTsk-lngvoysGPh3Po6xHN1941HKI73uWUaAlKEEALw_wcB

Du kannst doch den Wert des analogen Eingangs am seriellen Monitor anzeigen lassen. Dann hast du Werte, die du auch zur weiteren Verarbeitung auswerten kannst.

n = analogRead(MIC_PIN);
Serial.println(n);

Z.B, so.

Vielen Dank, das habe ich bereits gemacht. Mir fehlt der Zusammenhang, diesen Wert in den Code zu integrieren. Das bekomme ich nicht hin…

Wenn ich dich richtig verstehe, hast du das doch schon in deinem obigen Sketch verwendet.
Nur musst du evtl. deine Auswertung anpassen.

Ich bekomme es nicht hin, die Empfindlichkeit mit einem Parameter zu steuern…

Die Lösung mit dem Dynamikkompressor wäre vermutlich sinnvoller oder?
Wie kann ich das in meine Schaltung integrieren? Mit dem o.g. link kann ich leider nicht viel anfangen.

Der Arduino auch nicht. Die abgegebene Audioausgangsspannung ist mit 50mV viel zu gering.