arduino:spektrumanalysator:programmversion_0.4
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
arduino:spektrumanalysator:programmversion_0.4 [03.09.2017 16:54] – Frickelpiet | arduino:spektrumanalysator:programmversion_0.4 [18.05.2023 12:34] (aktuell) – Externe Bearbeitung 127.0.0.1 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
====== Spektrumanalysator - Programmversion 0.4 ====== | ====== Spektrumanalysator - Programmversion 0.4 ====== | ||
- | Diese Programmversion steuert einen NeoPixel-Streifen mit 72 NeoPixeln an. Die 512 " | + | Diese Programmversion |
+ | [[https:// | ||
+ | Das Ergebnis ist durchaus zufriedenstellend, | ||
+ | * Dabei soll die Regelung einerseits so träge sein, dass Pegelschwankungen in einem Song auch durch die Ausschlage des Spektrumanalysators abgebildet werden. | ||
+ | * Außerdem soll durchaus weiterhin der Pegel der Lautsprecher durch den Spektrumanalysator abgebildet werden. | ||
+ | Die automatische Eingangspegelregelung soll also nur innerhalb eines gewissen Bereichs greifen. Optimale Werte bzw. ein praxisnaher Einstellbereich der im Menü veränderbaren Grenzwerte muss experimentell bestimmt werden. | ||
- | |||
- | ToDos: | ||
- | * Ich habe immer noch ein sehr lautes Rauschen in den oberen Frequenzbändern. Um dieses abzustellen will ich das Audio Adaptor Board verwenden. | ||
Interessante Links: | Interessante Links: | ||
* https:// | * https:// | ||
+ | * https:// | ||
+ | * Hexadezimale in dezimale Werte umrechnen: http:// | ||
+ | |||
+ | < | ||
+ | // Spektrumanalysator | ||
+ | // Für einen NeoPixel-Streifen mit 72 NeoPixeln | ||
+ | |||
+ | // | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // Pins | ||
+ | #define encoderChannelA | ||
+ | #define encoderChannelB | ||
+ | #define NEOPIXELPIN | ||
+ | |||
+ | // Dreh-Encoder | ||
+ | Encoder myEnc(encoderChannelA, | ||
+ | |||
+ | long newPosition = 0; | ||
+ | long oldPosition; | ||
+ | |||
+ | // Menü Spektrumanalysator | ||
+ | byte displayMode = 0; // Verschiedene Anzeigemodi | ||
+ | |||
+ | // Automatische Eingangspegelregelung | ||
+ | boolean autoInputLevelControl = true; // Aktiviert und deaktiviert die automatische Eingangspegelregelung | ||
+ | float peakMaxDecrease = 0.001; | ||
+ | |||
+ | float level_L[36]; | ||
+ | float level_R[36]; | ||
+ | float leftPeak; | ||
+ | float rightPeak; | ||
+ | float masterPeak; | ||
+ | float masterPeakMax; | ||
+ | float peakDecrease = 0.001; | ||
+ | float autoGain; | ||
+ | |||
+ | // Konfiguriert den NeoPixel-Ring | ||
+ | int numPixels = 72; // Anzahl der NeoPixel | ||
+ | Adafruit_NeoPixel strip = Adafruit_NeoPixel(numPixels, | ||
+ | |||
+ | // Anzeige Spektrumanalysator | ||
+ | float n; | ||
+ | int i; // Variable zum zählen | ||
+ | byte r = 0; | ||
+ | byte g = 0; | ||
+ | byte b = 0; | ||
+ | byte w = 0; | ||
+ | |||
+ | // GUItool: begin automatically generated code | ||
+ | AudioInputI2S | ||
+ | AudioMixer4 | ||
+ | AudioMixer4 | ||
+ | AudioAnalyzePeak | ||
+ | AudioAnalyzeFFT1024 | ||
+ | AudioAnalyzePeak | ||
+ | AudioAnalyzeFFT1024 | ||
+ | AudioConnection | ||
+ | AudioConnection | ||
+ | AudioConnection | ||
+ | AudioConnection | ||
+ | AudioConnection | ||
+ | AudioConnection | ||
+ | AudioControlSGTL5000 | ||
+ | // GUItool: end automatically generated code | ||
+ | |||
+ | // Definiert die Tracking-Variablen für die IF-Abfragen | ||
+ | unsigned long previousMillisAutoInputLevelControl = 0; // Berechnung des maximalen Peaks für die automatische Inputlevel-Regelung | ||
+ | |||
+ | // Definiert die Intervalle für die IF-Abfragen in Millisekunden | ||
+ | unsigned long intervalAutoInputLevelControl = 100; // Berechnung des maximalen Peaks für die automatische Inputlevel-Regelung | ||
+ | |||
+ | // Taktung Schleifen | ||
+ | unsigned long lastMillis = 0; | ||
+ | unsigned long duration = 0; | ||
+ | |||
+ | |||
+ | void setup() { | ||
+ | Serial.begin(115200); | ||
+ | | ||
+ | AudioMemory(22); | ||
+ | |||
+ | // enable the audio shield | ||
+ | sgtl5000_1.enable(); | ||
+ | sgtl5000_1.muteHeadphone(); | ||
+ | sgtl5000_1.muteLineout(); | ||
+ | sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN); | ||
+ | sgtl5000_1.lineInLevel(5); | ||
+ | // | ||
+ | // | ||
+ | | ||
+ | // Configure the window algorithm to use | ||
+ | fft1024_L.windowFunction(AudioWindowHanning1024); | ||
+ | // | ||
+ | |||
+ | // Initialisiert den NeoPixel-Teststrip | ||
+ | strip.begin(); | ||
+ | strip.show(); | ||
+ | strip.setBrightness(64); | ||
+ | | ||
+ | // Legt den Anzeigemodus fest (provisorisch) | ||
+ | displayMode = 0; | ||
+ | |||
+ | // Schaltet die automatische Inputlevelregelung ein bzw. aus. (Kann später im Menü aktiviert und deaktiviert werden.) | ||
+ | autoInputLevelControl = true; | ||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | // Aktuelle Zeit abfragen | ||
+ | unsigned long currentMillis = millis(); | ||
+ | | ||
+ | // Encoder | ||
+ | newPosition = myEnc.read(); | ||
+ | if (newPosition != oldPosition) { | ||
+ | oldPosition = newPosition; | ||
+ | } | ||
+ | if (newPosition < 0) { | ||
+ | newPosition = 0; | ||
+ | } | ||
+ | if (newPosition >= 120) { | ||
+ | newPosition = 120; | ||
+ | } | ||
+ | |||
+ | // Gain Control | ||
+ | if (autoInputLevelControl == false) { // Die manuelle Inputlevel-Kontrolle ist nur aktiv, wenn die automatische Inputlevel-Regelung deaktiviert ist | ||
+ | mixer_L.gain(0, | ||
+ | mixer_R.gain(0, | ||
+ | } | ||
+ | |||
+ | // Fast Fourier Transformation (FFT) | ||
+ | if (fft1024_L.available() && fft1024_R.available()) { // Wenn die FFT neue Daten berechnet hat, werden für beide Kanäle je 512 FFT Frequenzen ausgelesen und in je 36 Bändern zusammengefasst. | ||
+ | // Zuerst ist der linke Kanal an der Reihe | ||
+ | level_L[35] = fft1024_L.read(0); | ||
+ | level_L[34] = fft1024_L.read(1); | ||
+ | level_L[33] = fft1024_L.read(2); | ||
+ | level_L[32] = fft1024_L.read(3); | ||
+ | level_L[31] = fft1024_L.read(4, | ||
+ | level_L[30] = fft1024_L.read(6, | ||
+ | level_L[29] = fft1024_L.read(8, | ||
+ | level_L[28] = fft1024_L.read(10, | ||
+ | level_L[27] = fft1024_L.read(12, | ||
+ | level_L[26] = fft1024_L.read(15, | ||
+ | level_L[25] = fft1024_L.read(18, | ||
+ | level_L[24] = fft1024_L.read(21, | ||
+ | level_L[23] = fft1024_L.read(25, | ||
+ | level_L[22] = fft1024_L.read(29, | ||
+ | level_L[21] = fft1024_L.read(33, | ||
+ | level_L[20] = fft1024_L.read(38, | ||
+ | level_L[19] = fft1024_L.read(44, | ||
+ | level_L[18] = fft1024_L.read(50, | ||
+ | level_L[17] = fft1024_L.read(57, | ||
+ | level_L[16] = fft1024_L.read(65, | ||
+ | level_L[15] = fft1024_L.read(74, | ||
+ | level_L[14] = fft1024_L.read(84, | ||
+ | level_L[13] = fft1024_L.read(95, | ||
+ | level_L[12] = fft1024_L.read(108, | ||
+ | level_L[11] = fft1024_L.read(122, | ||
+ | level_L[10] = fft1024_L.read(138, | ||
+ | level_L[9] = fft1024_L.read(156, | ||
+ | level_L[8] = fft1024_L.read(176, | ||
+ | level_L[7] = fft1024_L.read(199, | ||
+ | level_L[6] = fft1024_L.read(224, | ||
+ | level_L[5] = fft1024_L.read(252, | ||
+ | level_L[4] = fft1024_L.read(284, | ||
+ | level_L[3] = fft1024_L.read(320, | ||
+ | level_L[2] = fft1024_L.read(360, | ||
+ | level_L[1] = fft1024_L.read(405, | ||
+ | level_L[0] = fft1024_L.read(455, | ||
+ | | ||
+ | // Und dann der rechte Kanal | ||
+ | level_R[0] = fft1024_R.read(0); | ||
+ | level_R[1] = fft1024_R.read(1); | ||
+ | level_R[2] = fft1024_R.read(2); | ||
+ | level_R[3] = fft1024_R.read(3); | ||
+ | level_R[4] = fft1024_R.read(4, | ||
+ | level_R[5] = fft1024_R.read(6, | ||
+ | level_R[6] = fft1024_R.read(8, | ||
+ | level_R[7] = fft1024_R.read(10, | ||
+ | level_R[8] = fft1024_R.read(12, | ||
+ | level_R[9] = fft1024_R.read(15, | ||
+ | level_R[10] = fft1024_R.read(18, | ||
+ | level_R[11] = fft1024_R.read(21, | ||
+ | level_R[12] = fft1024_R.read(25, | ||
+ | level_R[13] = fft1024_R.read(29, | ||
+ | level_R[14] = fft1024_R.read(33, | ||
+ | level_R[15] = fft1024_R.read(38, | ||
+ | level_R[16] = fft1024_R.read(44, | ||
+ | level_R[17] = fft1024_R.read(50, | ||
+ | level_R[18] = fft1024_R.read(57, | ||
+ | level_R[19] = fft1024_R.read(65, | ||
+ | level_R[20] = fft1024_R.read(74, | ||
+ | level_R[21] = fft1024_R.read(84, | ||
+ | level_R[22] = fft1024_R.read(95, | ||
+ | level_R[23] = fft1024_R.read(108, | ||
+ | level_R[24] = fft1024_R.read(122, | ||
+ | level_R[25] = fft1024_R.read(138, | ||
+ | level_R[26] = fft1024_R.read(156, | ||
+ | level_R[27] = fft1024_R.read(176, | ||
+ | level_R[28] = fft1024_R.read(199, | ||
+ | level_R[29] = fft1024_R.read(224, | ||
+ | level_R[30] = fft1024_R.read(252, | ||
+ | level_R[31] = fft1024_R.read(284, | ||
+ | level_R[32] = fft1024_R.read(320, | ||
+ | level_R[33] = fft1024_R.read(360, | ||
+ | level_R[34] = fft1024_R.read(405, | ||
+ | level_R[35] = fft1024_R.read(455, | ||
+ | |||
+ | // Anzeigemodi | ||
+ | //Effekt " | ||
+ | if (displayMode == 0) { | ||
+ | |||
+ | // Anschließend werden Farbwerte für die linke Seite des NeoPixel-Streifens berechnet | ||
+ | for (i=0; i< | ||
+ | n = level_L[i]; | ||
+ | if (n >= 0.01) { | ||
+ | // Scale ' | ||
+ | byte t192 = round((n * 2000 /255.0) * 191); | ||
+ | | ||
+ | byte heatramp = t192 & 0x3F; // 0..63 | ||
+ | heatramp <<= 2; // scale up to 0..252 | ||
+ | |||
+ | if(t192 > 0x80) { // hottest | ||
+ | strip.setPixelColor(i, | ||
+ | } | ||
+ | else if(t192 > 0x40) { // middle | ||
+ | strip.setPixelColor(i, | ||
+ | } | ||
+ | else { // coolest | ||
+ | strip.setPixelColor(i, | ||
+ | } | ||
+ | } | ||
+ | else { | ||
+ | strip.setPixelColor(i, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Dann werden die Farbwerte für die rechte Seite des NeoPixel-Streifens berechnet | ||
+ | for (i=0; i< | ||
+ | n = level_R[i]; | ||
+ | if (n >= 0.01) { | ||
+ | // Scale ' | ||
+ | byte t192 = round((n * 2000 /255.0) * 191); | ||
+ | | ||
+ | byte heatramp = t192 & 0x3F; // 0..63 | ||
+ | heatramp <<= 2; // scale up to 0..252 | ||
+ | | ||
+ | if(t192 > 0x80) { // hottest | ||
+ | strip.setPixelColor(i+36, | ||
+ | } | ||
+ | else if(t192 > 0x40) { // middle | ||
+ | strip.setPixelColor(i+36, | ||
+ | } | ||
+ | else { // coolest | ||
+ | strip.setPixelColor(i+36, | ||
+ | } | ||
+ | } | ||
+ | else { | ||
+ | strip.setPixelColor(i+36, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Die Daten werden an den NeoPixel-Streifen geschickt | ||
+ | strip.show(); | ||
+ | } | ||
+ | |||
+ | |||
+ | // Automatische Eingangspegelregelung | ||
+ | if (autoInputLevelControl == true) { | ||
+ | // Es werden die Pegel des linken und rechten Audiokanals ausgelesen. | ||
+ | if (peak_L.available() && peak_R.available()) { | ||
+ | leftPeak = peak_L.read(); | ||
+ | rightPeak = peak_R.read(); | ||
+ | } | ||
+ | // Für die automatische Eingangspegelregelung wird der lautere der beiden Audiokanäle verwendet. | ||
+ | masterPeak = max(leftPeak, | ||
+ | |||
+ | // Der Maximalpegel wird gespeichert | ||
+ | if (masterPeak > masterPeakMax) { | ||
+ | masterPeakMax = masterPeak; | ||
+ | } | ||
+ | // Alle 100 Millikekunden wird die Eingangspegelanpassung berechnet | ||
+ | if ((unsigned long)(currentMillis - previousMillisAutoInputLevelControl) >= intervalAutoInputLevelControl) { | ||
+ | // Die automatische Eingangspegelanpassung hebt leise Eingangspegel an, aber ohne den Pegel vollständig zu kompensieren. | ||
+ | // Auf diese Weise haben leise Eingangssignale einen geringeren Pegelausschalg als laute, es wird aber dennoch " | ||
+ | masterPeakMax = masterPeakMax - peakDecrease; | ||
+ | |||
+ | autoGain = (1.00 - masterPeakMax) * 4; // autoGain wird berechnet | ||
+ | if (autoGain > 4.00) { // Die Maximale Pegelanhebung soll den Faktor 4 nicht überschreiten | ||
+ | autoGain = 4.00; | ||
+ | } | ||
+ | if (autoGain < 1.00) { // Die Maximale Pegelanhebung soll den Faktor 1 nicht unterschreiten | ||
+ | autoGain = 1.00; | ||
+ | } | ||
+ | mixer_L.gain(0, | ||
+ | mixer_R.gain(0, | ||
+ | | ||
+ | previousMillisAutoInputLevelControl = currentMillis; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | // Es wird die Zeit in Millisekunden berechnet, die für einen Durchgang benötigt wurde | ||
+ | duration = millis()- lastMillis; | ||
+ | | ||
+ | // Serieller Output | ||
+ | Serial.print(" | ||
+ | Serial.print(AudioProcessorUsageMax()); | ||
+ | Serial.print(" | ||
+ | Serial.print(AudioMemoryUsageMax()); | ||
+ | Serial.print(" | ||
+ | Serial.print(duration); | ||
+ | Serial.print(" | ||
+ | Serial.print(float(newPosition) / 40); | ||
+ | Serial.print(" | ||
+ | Serial.print(leftPeak); | ||
+ | Serial.print(" | ||
+ | Serial.print(rightPeak); | ||
+ | Serial.print(" | ||
+ | Serial.print(masterPeak); | ||
+ | Serial.print(" | ||
+ | Serial.print(masterPeakMax); | ||
+ | if (autoInputLevelControl == true) { | ||
+ | Serial.print(" | ||
+ | Serial.print(autoGain); | ||
+ | } | ||
+ | Serial.println(); | ||
+ | |||
+ | lastMillis = millis(); | ||
+ | } | ||
+ | } // Void Loop Ende | ||
+ | </ | ||
+ | {{tag> |
arduino/spektrumanalysator/programmversion_0.4.1504450446.txt.gz · Zuletzt geändert: 18.05.2023 12:16 (Externe Bearbeitung)