Audio Spektrum Analyse mit Arduino, RGB-LED und MSGEQ7

GKMsound

GKMsound

Systemimmun
Ich habe vor eine LED Audio Spektrum Anzeige zu bauen.
Mit dem programmieren von Arduino habe ich kaum Erfahrung.
Im Netz gibt es einige Projekte allerdings nur selten ausführlich erklärt, das Beste was ich bisher finden konnte ist wohl RGB Matrix Audio Visualizer with Arduino.
Allerdings hätte ich das ganze gerne mit 2 x 7 Bändern für links/rechts so etwa wie hier.
Oder :

https://youtu.be/CgeB-qr2Kf0?t=127


Etwas komplexer wird es bei 14 Bändern was sehr beeindruckend aussieht:

https://youtu.be/Zg-GyNWBf1Y?t=101


Wichtig ist mir Übersteuerung / Clipping im jeweiligen Band sichtbar zu machen.
Außerdem soll das ganze auch der Beleuchtung dienen.

Ich habe ein 5m WS2812 LED Band, einen Arduino Nano und 2 MSGEQ7 Chips.
Eingeplanter Platz für die fertige Anzeige ist maximal 50 cm x 18 cm und so flach wie möglich.

Ich bin mir noch nicht ganz sicher wie ich das Ganze angehen möchte.
Auf jeden Fall sollte es 7 Bänder für links und auch rechts anzeigen, Übersteuerung muss sichtbar werden und als einstellbare Beleuchtung dienen.

Habt ihr so etwas schon realisiert? Für Tipps und Anregungen bin ich offen.
 
Sowas in etwa?

Ich hab das in einem FPGA realisiert: es gibt jeweils 1x Low-pass-Filter (32 Taps MAC FIR), Fenster-Funktion ("Von-Hann"), 1024-Taps FFT, Peak-Detection und Averaging pro Stereo-Kanal. Für die Anzeige gibt es verschiedene Optionen zum Zusammenfassen der Ergebnisse der 1024 Taps. Sinnvoll ist ein logarithmisches Zusammenfassen von benachbarten Bins. Das Video ist aus der Entwicklungszeit. Hier kann man noch nicht die Ergebnisse der zwei Kanäle erkennen, Peak-Anzeige ist jedoch schon drin (die roten Dots oben). Es gibt noch ein längeres Video mit dem finalen Stand, da sieht man dann noch die verschiedenen Kanäle in verschiedenen Farben. Das Video ist für das Forum aber zu groß, muß mal schauen wo ich das hochlade.
Falls du Detailfragen hast, gerne her damit.

Grüße,
Dirk
 

Anhänge

  • WG3P0307.mp4
    33,8 MB
Nachtrag: Habe das größere spätere Video beim großen Videohoster hochgeladen:

RGB-LED-Matrix Spektrum-Analyzer

Man sieht die kanalabhängigen Farben (hellblau/türkis für beide Kanäle, blau oder grün wenn das Signal exklusiv auf einem Kanal stärker ist, orange wenn das Signal beim Top-Wert auf beiden Kanälen gleich groß ist, rot für Peaks über dem aktuell eingestellten darstellbaren Bereich). Die Amplitudenskalierung erfolgt "schleichend" über eine gleitende Mittelwertbildung. Die Amplitudenachse (y-Achse) ist annähernd logarithmisch. Die FFT hat 1024 Taps, Samplefrequenz ist 44100 Hz, Breite eines Taps ist ~43 Hz, verwendet werden die Ergebnisse der ersten 448 Taps (0 ... ca. 19kHz). Für die Darstellung der Frequenzen auf der x-Achse werden die Taps (empirisch logarithmisch) zusammengefasst: anfangend mit einem Tap pro Spalte (ganz links: 43 Hz) bis zu 30 Taps pro Spalte (ganz rechts: alles >17 kHz).
Darstellungsmodus, Reaktionsgeschwindigkeit ("Zappeligkeit"), Nachleuchtzeit sind einstellbar. Im Video schalte ich bei den Zeitindexes ca. 2:00 und 3:00 den Darstellungsmodus um.
 
Zuletzt bearbeitet:
Ich hab das in einem FPGA realisiert:
Sieht super aus, was ein FPGA ist habe ich eben kurz überflogen....
Aber vielleicht hast du noch ein Bild von der Schaltung damit man eine Vorstellung bekommt.
Die technische Realisierung war sicher nicht ohne, von der Programierung mal ganz abgesehen.

Ich denke ganz so genau brauche ich es jetzt nicht. Ich würde gerne bei den MSGEQ7 mit Arduino bleiben.
 
Anbei ein Ausschnitt aus dem Blockschaltbild des FPGAs mit dem Signalpfad. Die Displayansteuerung (z.B. mit dem Nachleuchten der Dots) wird vom "RGBDisplayController" (am unteren Bildrand) erledigt. Konfiguration der Parameter, Einstellung der Skalierung und Zusammenfassung der Taps werden per Software gemacht und sind hier nicht dargestellt.

Das Prinzip ist ja im Wesentlichen das selbe, egal ob man es per FPGA oder per Software realisiert: du brauchst ADC, Tiefpassfilter, Fensterfunktion, FFT, und eine Displayansteuerung :)


1639764501862.png
 
Kleiner Tipp bzgl. FFT: normalerweise sind die Bänder bei der FFT alle gleich breit. D.h. wenn du in den tiefen Frequenzen eine Frequenzabstufung von sagen wir 50 Hz haben willst und somit die Breite der Taps auf 50 Hz festlegst, dann brauchst du um bis 18 kHz zu kommen rechnerisch 360 Taps. Bei den hohen Frequenzen brauchst du aber eigentlich gar keine Auflösung von 50 Hz. Wenn du andererseits die Breite der Taps auf 1 kHz festlegst, wird alles von 0 bis 1000 Hz in einen tap zusammengerechnet. Die Tiefen kann man so nicht mehr differenzieren.
Das ist auch der Grund für viele schmale Taps (FFT-Size: 1024) bei meinem Design, von denen je weiter man nach "oben kommt" immer mehr zusammengefasst werden. Die Skalierung der Frequenz-Achse ist leider nicht linear ;-)
 
Naja im MSGEQ7 sieht es sehr viel einfacher aus:

1639778152198.png
Das mit einem Arduino wird mir reichen für den Anfang.

Das Prinzip ist ja im Wesentlichen das selbe
Nur sehr viel komplizierter/aufwendiger zu realisieren, auch wenn es viel genauer ist und spektakulärer ausschaut.
Ich würde gerne erst mal die Möglichkeiten mit 7 Bändern und einem Arduino ausloten.
 
Nunja, ne Filterkaskade ist dann wohl doch nicht das gleiche Prinzip, aber wie sagt man so schön: "es gibt immer mehrere Wege...." oder so ähnlich ;-)

Auf jeden Fall wünsche ich viel Spaß mit solch einem Projekt, denn das Ergebnis wird sich lohnen. Ich könnte dem Ding stundenlang zuschauen :)
 
Oha, eine komplett analoge Lösung, sehr interessant. Da sieht man auch deutlich welchen Aufwand er sich gemacht hat bei der Überlegung wieviele Bänder er benötigt und wie breit diese sein sollen.
 
Wichtig ist mir Übersteuerung / Clipping im jeweiligen Band sichtbar zu machen.

Übersteuerung / Clipping ist nichts, was in einem Band stattfindet, sondern ein breitbandiges Ereignis.
Die Erkennung von Übersteuerung / Clipping müsste parallel zum Spektrum Analyser anhand eines vorher abgezweigten Signals erfolgen.
Wäre also gescheiter: 7 Kanäle Spectrum + 1 Kanal für Summen-Pegel Übersteuerung / Clipping - Schwellen.

Habt ihr so etwas schon realisiert? Für Tipps und Anregungen bin ich offen.

Ich habe schon verschiedene Sachen mit verschiedenen Chips (auch mit Arduino) gebaut.
Im Grunde gibt es zwei Optionen:
1: eine idiotensichere Anleitung 1:1 nachbauen und hoffen dass es funktioniert
2: die Teile immer schön Schritt für Schritt einzeln zusammensetzen und in Betrieb nehmen und sich dabei genau mit der Funktion auseinandersetzen

Variante 2 ist aufwändiger, aber man lernt mehr dabei und hat auch die Chance, das was man baut/programmiert an die eigenen Bedürfnisse anzupassen.

Worauf du auf jeden Fall achten solltest: Die verschiedenen Arduino-Chips haben nicht alle die gleiche Logik-Spannung an den Digital-Pins.
Einige (die alten) arbeiten mit 5V, andere (die meisten neueren) mit 3,3V.
Das WS2812 LED Band braucht meines Wissens 5V, der MSGEQ7 geht mit 3,3V, soll aber mit 5V besser gehen.
Musst du mal in die Specs von deinem Nano-Board rein gucken, ob das mit 5V-Logik arbeitet.
Wenn nicht, dann ist es billiger, das UNO-Board nachzukaufen, was auf GitHub empfohlen wird, als da was zwecks Pegelanpassung zu basteln.

im MSGEQ7 sieht es sehr viel einfacher aus

Wenn du den MSGEQ7 verwendest, dann kannst du dir den ganzen FFT-Kram schenken und brauchst auch kein FPGA.
Das ist alles im MSGEQ7 drin.

An deiner Stelle würde ich erstmal das da nachbauen: https://github.com/GeorgiZhelezov/arduino-msgeq7
Musst ja die LEDs erstmal noch nicht zerschneiden ...
Und dann den zweiten MSGEQ7 anbauen (sind genug Analog-Eingänge frei) und mal in den Code reich schauen... das lässt sich bestimmt umprogrammieren.

Und wenn du gut bist, dann baust du an einen weiteren Analog-Eingang einen weiteren Regler, über den du im Code zwischen verschiedenen Betriebsarten umschalten kannst. :cool:
So werde ich das zumindest machen. Weiß nur noch nicht wann... aktuell muss erstmal meine Moog/Eurorack-Kiste fertig werden.
 
könnte man den zweiseitig bauen? also ne kompression zeigen? oder ne rauschreduzierung? oder man nimmt den raum als kompressionssignal übern mic. sieht nur ganzschön gebastelt aus mit led streifen müsste man giessen das fertige produkt oder einzelne leds benutzen aber das is fummelscheisse bestimmt... bleibt noch drucken , ne maske oder kelche für die leds... oder nur indirekt nutzen als reflektion oder transmission ... geht aber energie verloren .... hmmm
 
Also gut, ich habe die Hardware schon mal fast fertig:

DSC_1989.JPG DSC_1991.JPG

Pinbelegung:

MSGEQ7 Nano
Reset - D9
Strobe - D10
Out L - A0
Out R - A1

DatenLED - D6


Die Neo Pixel Matrix ist in 16 Spalten und 10 Zeilen angeordnet und soll wie folgt aussehen.

1641375595696.png

Bin jetzt dabei alles zu verkabeln , dann erste Tests der Matrix Arduino IDE Sketch.
Völlig unklar ist mir noch die Programierung des Ganzen, das vielversprechendste Projekt aus dem Video ist leider mit .hex Code geteilt.
Also bin ich echt auf Hilfe angewiesen um von Grund auf einen Sketch zu erstellen.
 
Zuletzt bearbeitet:
Ich habe einfach mal begonnen mit dem angehängten Sketch der mithilfe eines Freundes angepasst wurde.
Die beiden MSGEQ7 senden Daten und die Neopixel zeigen 16k in der ersten Spalte korrekt an. Die 2. bis 7. Spalte ist dann verdreht also 2. macht 63Herz und die 7. Spalte dann 6k. Alles ist erstmal in Grün. Spalte 8 bis 16 bleiben dunkel.
Mir selbst ist das alles unklar. Ich schaue mir seit Stunden verschiedene Sketches an um zu verstehen wie das funktioniert und komme nicht wirklich weiter. Es ist wie chinesisch für mich.
 
Ich hab gerade keine Zeit mir das im Detail anzuschauen, kann dir aber nur folgende (und bewährte) Empfehlung geben:
versuche die einzelne Komponenten Schritt für Schritt zum Funktionieren zu bekommen - nur so hast du eine Chance zu Verstehen wie etwas funktioniert und warum etwas nicht funktioniert.
Also zB.:
1. MSEQ7 testen (klappt die Kommunikation zum Arduino, kommt etwas sinnvolles an, wie sehen die Werte aus, liegen sie im erwarteten Bereich : meist gibt es zu solchen Bausteinen Test-Skripte für genau solche Zwecke)
2. Neopixel testen (auch da gibt es in der Regel Demo-Skripte: können alle Pixel angesteuert werden, kannst du die einzelnen Balken ansteuern wie du es gern möchtest)

Danach sollte das Zusammenfügen auch besser klappen.

Viele Grüße, Sascha
 
1. MSEQ7 testen (klappt die Kommunikation zum Arduino, kommt etwas sinnvolles an, wie sehen die Werte aus, liegen sie im erwarteten Bereich : meist gibt es zu solchen Bausteinen Test-Skripte für genau solche Zwecke)
2. Neopixel testen (auch da gibt es in der Regel Demo-Skripte: können alle Pixel angesteuert werden, kannst du die einzelnen Balken ansteuern wie du es gern möchtest)

Danke, so habe ich es gemacht.
Dann aber einen fertigen Sketch auf meine HW angepasst und erweitert.... (mit Hilfe)

DSC_2010.JPGDSC_2014.JPG

Soweit läuft es schon gut, im Moment will ich ein Poti zum Regeln der Helligkeit hinzufügen....
Wie die Werte von den MSGEQ7 interpretiert werden um die LED leuchten zu lassen würde mich als nächstes interessieren.
Die Arduino Funktionen map und constrain sind wohl dafür verantwortlich.
Eine kleine Verzögerung der Spitzenwerte ist sicher praktisch.
Bei halben Level/Pegel wird alles gut dargestellt , bei normalen Pegel werden die Bänder ziemlich breit ohne das sich die Spitzen groß ändern.
Der linke Kanal wird ein wenig leiser dargestellt als der rechte z.B. kann man das im Code anpassen? Wenn ja wo?
Oder muss ich das Audio IN zurecht trimmen?
 
Zuletzt bearbeitet:
Der linke Kanal wird ein wenig leiser dargestellt als der rechte z.B. kann man das im Code anpassen? Wenn ja wo?
Oder muss ich das Audio IN zurecht trimmen?
Ich habe gemerkt das ohne USB Verbindung zum Arduino der Pegel auf beiden Kanälen relativ gleich dargestellt wird.
Da die analogen "Pegel" der Bänder vom MSGEQ7 1:1 auf die zugehörigen 10 LED skaliert werden läßt sich auch nix im Code anpassen.

Soweit so gut, Poti für Helligkeit funktioniert nun auch.

Jetzt noch die 2 LED Strips in der Mitte für den gesamt Pegel L/R zum leuchten bringen.
Die Bänder der MSGEQ7 dafür zu nutzen ist wohl zu ungenau um Übersteuerung anzuzeigen.
Die Audio IN mit Offset direkt an 2 analog Eingänge des Arduino zu leiten ist wohl am besten.
 
Habe es jetzt erstmal ohne Offset gemacht. Stunden der Coderei macht mir das Hirn weich, alleine hätte ich es nie hinbekommen.
Aber es zappelt nun in der Mitte auch, ist noch viel zu schnell das VU Meter muss noch ansehnlicher werden. Das Peaks langsamer fallen Code gesucht....
 

Anhänge

  • dual_msgeq7_VU_code.zip
    2,1 KB · Aufrufe: 4
Hi,
ich habe mal in den Code geschaut, ist für meinen Geschmack ein bisschen umständlich programmiert und das gänge einfacher - aber das sagt sich leicht von"außen".

2 Dinge:
- ich würde nach dem Einlesen aller 7 Frequenzbänder in der Funktion readData() immer wieder einen Reset des MSEQ machen, um sicherzugehen das im nächsten Durchlauf auch wieder von vorn angefangen wird, z.B. in der Funktion loop() nach readData() diese beiden Zeilen einfügen:
digitalWrite(resetPin, HIGH); //reset the MSGEQ7s
delay (100);
- ich verstehe nicht was an den Pins "analogPinsVU" anliegt und wieso dort etwas eingelesen werden muss? Mein Verständnis wäre, das der MSEQ alle Informationen zu den Pegeln der Frequenzbänder liefert und diese dann in den Neopixeln dargestellt werden. Wieso dann noch leftVU und rightVU benötigt werden ist mir rätselhaft, zumal wenn ich es richtig erkenne in dem Bild weiter oben die entsprechenden Pins ( 2 & 3) beim Arduino nicht belegt sind?

Wenn du die Peaks langsamer machen willst kann man einen Tiefpass nehmen (hab ich hier mal im Detail beschrieben Link ), filter_shift ist die "Zeitkonstante" : 1 = 3 samples, 2 = 8 samples, etc

Der Code müsste allerdings auf 2 x 7 Kanäle erweitert werden, sollte aber nicht so schwer sein.. filter_input ist leftMSGEQ[0..6] und rightMSGEQ[0..6]

// filter_shift 1..7 sets frequency int8_t Lowpass(int8_t filter_input, uint8_t filter_shift) { static int16_t filter_reg = 0; // Delay element – 16 bits // Update filter with current sample. filter_reg = filter_reg - (filter_reg >> filter_shift) + filter_input ; // sum = sum - filter_out + filter_in; // Scale output for unity gain. return (int8_t)(filter_reg >> filter_shift); }
 
was an den Pins "analogPinsVU" anliegt und wieso dort etwas eingelesen werden muss?
Da liegt das Audio Signal nochmal ungefiltert an, um VU L/R zu messen.
Funktioniert schon ziemlich gut.....
Die Bänder sind eher ungeeignet für VU Messung weil das Signal je einen Kammfilter durchläuft und Peaks verstärkt oder abgeschwächt je nach Frequenz werden.
Clippinganzeige, also wenn das Peak den kritischen Punkt erreicht bleibt das Pixel länger an, funktioniert nun.
Werde mal ein Video machen demnächst.
Der aktuelle Code im Anhang...
 

Anhänge

  • dual_msgeq7_VU_code.zip
    2,3 KB · Aufrufe: 4
Wenn du die Peaks langsamer machen willst kann man einen Tiefpass nehmen (hab ich hier mal im Detail beschrieben Link )
Würde doch aber die Höhen wegfiltern :denk: , habe mir deine Mathematischen Filter angesehen kann aber damit nicht viel anfangen...

Langsamer könnte es auch mit readDataDelay = 1 werden aber ich will es eigentlich nicht generell langsamer dargestellt bekommen.
Nur die max. Pegel könnten ein wenig länger gehalten werden um es besser zu sehen... also immer die oberste erreichte LED.
Habe aber keinen Plan wie ich das in den Code bekomme.
 
Würde doch aber die Höhen wegfiltern :denk: , habe mir deine Mathematischen Filter angesehen kann aber damit nicht viel anfangen...

Langsamer könnte es auch mit readDataDelay = 1 werden aber ich will es eigentlich nicht generell langsamer dargestellt bekommen.
Nur die max. Pegel könnten ein wenig länger gehalten werden um es besser zu sehen... also immer die oberste erreichte LED.
Habe aber keinen Plan wie ich das in den Code bekomme.

Ein Tiefpass im zeitlichen Bereich ist nichts anderes wie ein Verzögerungsglied, würde also genau das machen was du möchtest (kannst du dir vorstellen wie einen Kondensator der "langsam" aufgeladen oder entladen wird). Wenn du die max-Pegel länger halten möchtest muss geschaut werden ob der aktuelle Pegel < als der vorherige Pegel ist und dann der Tiefpass (Verzögerungs-Glied) angewendet werden.

Ansonsten "zappelt" es ja schon schön im Video!

Viele Grüße, Sascha
 
Ein Tiefpass im zeitlichen Bereich ist nichts anderes wie ein Verzögerungsglied, würde also genau das machen was du möchtest (kannst du dir vorstellen wie einen Kondensator der "langsam" aufgeladen oder entladen wird). Wenn du die max-Pegel länger halten möchtest muss geschaut werden ob der aktuelle Pegel < als der vorherige Pegel ist und dann der Tiefpass (Verzögerungs-Glied) angewendet werden.
Versteh ich noch nicht wirklich, werden denn dann kurze Peaks nicht geschluckt (herausgefiltert).

In der Zeile leftVU = map(leftVU, 0, 500 , 0 , 10); wird der analog IN auf die LEDs skaliert, nun wird aber scheinbar der Wert 500 als Maximum definiert, alles was drüber (lauter) ist wird ignoriert. Wie kann ich auch größere Werte auf LED 10 mappen?
 
Na indem du in den Map Befehl einen andere obere Grenze als 500 reinschreibst, z.B.
leftVU = map(leftVU, 0, 1023 , 0 , 10);
 
Versteh ich noch nicht wirklich, werden denn dann kurze Peaks nicht geschluckt (herausgefiltert).
Nicht wenn der der Tiefpass nur angewendet wird wenn der aktuelle Pegel < als der vorherige Pegel (d.h. der Pegel sinkt)

Sollte dann ungefähr so aussehen im zeitlichen Verlauf.. (blau die Rohdaten, orange mit Verzögerung der fallenden Pegel..)
1641980411792.png
 
Na indem du in den Map Befehl einen andere obere Grenze als 500 reinschreibst, z.B.
leftVU = map(leftVU, 0, 1023 , 0 , 10);
Dann würde mein echtes Clipping am Mischer nicht mehr in den LEDs angezeigt.

Ich habe das jetzt so: if (leftVU > 430) leftVU = 10; else leftVU = map(leftVU, 0, 430 , 0 , 10);
damit werden größere Werte als die Clippingschwelle (bei mir 430) nicht mehr ignoriert....

Nicht wenn der der Tiefpass nur angewendet wird wenn der aktuelle Pegel < als der vorherige Pegel (d.h. der Pegel sinkt)
Ok das leuchtet ein, nur das in den Code zu bringen überfordert mich...
 
Nicht wenn der der Tiefpass nur angewendet wird wenn der aktuelle Pegel < als der vorherige Pegel (d.h. der Pegel sinkt)

Sollte dann ungefähr so aussehen im zeitlichen Verlauf.. (blau die Rohdaten, orange mit Verzögerung der fallenden Pegel..)
Anhang anzeigen 126726
Der "Pegel" also die Amplitude des Stromes an analogPinsVU wechselt eh schnell zwischen + und - , am Eingang des Arduino werden aber nur positive Spannungen abgetastet/gemessen. Ich weiß nicht mit welcher Frequenz "abgetastet" wird aber die Schwingung des Stromes in den negativen Bereich "zieht" den Pegel ja auch immer runter.
Würde mich also sehr interessieren wie man den Code mit deinem Tiefpass versieht. Allerdings nur für VU, die Bänder würde ich so lassen.
 


Neueste Beiträge

News

Zurück
Oben