From dc8c3cc0024f24da9315f0557baa9224e0a81e3b Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 2 Aug 2023 13:55:02 +0100 Subject: [PATCH 01/24] Add usermod to receive WLED Audio sync data --- platformio.ini | 8 ++++++ src/User/UserModWLEDAudio.h | 52 +++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/User/UserModWLEDAudio.h diff --git a/platformio.ini b/platformio.ini index d5ff26d5..b9333616 100644 --- a/platformio.ini +++ b/platformio.ini @@ -52,6 +52,12 @@ lib_deps = https://github.com/dawidchyrzynski/arduino-home-assistant.git#2.0.0 https://github.com/knolleary/pubsubclient.git#v2.8 +[usermod_wledaudio] +build_flags = + -D USERMOD_WLEDAUDIO +lib_deps = + https://github.com/netmindz/WLED-sync#v0.14.0.b16 + [env:esp32dev] platform = espressif32 board = esp32dev @@ -63,10 +69,12 @@ build_flags = ${appmod_leds.build_flags} ${usermod_e131.build_flags} ${usermod_ha.build_flags} + ${usermod_wledaudio.build_flags} lib_deps = ${starmod.lib_deps} ${appmod_leds.lib_deps} ${usermod_e131.lib_deps} ${usermod_ha.lib_deps} + ${usermod_wledaudio.lib_deps} ; RAM: [== ] 15.6% (used 51124 bytes from 327680 bytes) ; Flash: [======= ] 68.1% (used 892033 bytes from 1310720 bytes) \ No newline at end of file diff --git a/src/User/UserModWLEDAudio.h b/src/User/UserModWLEDAudio.h new file mode 100644 index 00000000..6f72c458 --- /dev/null +++ b/src/User/UserModWLEDAudio.h @@ -0,0 +1,52 @@ +/* + @title StarMod + @file UserModExample.h + @date 20230730 + @repo https://github.com/ewoudwijma/StarMod + @Authors https://github.com/ewoudwijma/StarMod/commits/main + @Copyright (c) 2023 Github StarMod Commit Authors + @license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 +*/ + +#include // https://github.com/netmindz/WLED-sync + +class UserModWLEDAudio:public Module { + +public: + + UserModWLEDAudio() :Module("WLED Audio Sync Receiver") { + print->print("%s %s\n", __PRETTY_FUNCTION__, name); + + print->print("%s %s %s\n", __PRETTY_FUNCTION__, name, success?"success":"failed"); + }; + + //setup filesystem + void setup() { + Module::setup(); + print->print("%s %s\n", __PRETTY_FUNCTION__, name); + + print->print("%s %s %s\n", __PRETTY_FUNCTION__, name, success?"success":"failed"); + } + + void connected() { + sync.begin(); + } + + void loop(){ + // Module::loop(); + if (sync.read()) { + print->print("WLED-Sync: "); + for (int b = 0; b < NUM_GEQ_CHANNELS; b++) { + uint8_t val = sync.fftResult[b]; + print->print("%u ", val); + } + print->print("\n"); + } + } + + private: + WLEDSync sync; + +}; + +static UserModWLEDAudio *wledAudioMod; \ No newline at end of file From 1eaae8c1d17c4941d93759d59e27418d1a38fef7 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 2 Aug 2023 14:02:05 +0100 Subject: [PATCH 02/24] Add usermod to receive WLED Audio sync data --- src/User/UserModWLEDAudio.h | 3 +++ src/main.cpp | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/User/UserModWLEDAudio.h b/src/User/UserModWLEDAudio.h index 6f72c458..eff5bf05 100644 --- a/src/User/UserModWLEDAudio.h +++ b/src/User/UserModWLEDAudio.h @@ -14,6 +14,8 @@ class UserModWLEDAudio:public Module { public: + uint8_t fftResults[NUM_GEQ_CHANNELS]= {0}; + UserModWLEDAudio() :Module("WLED Audio Sync Receiver") { print->print("%s %s\n", __PRETTY_FUNCTION__, name); @@ -38,6 +40,7 @@ class UserModWLEDAudio:public Module { print->print("WLED-Sync: "); for (int b = 0; b < NUM_GEQ_CHANNELS; b++) { uint8_t val = sync.fftResult[b]; + fftResults[b] = val; print->print("%u ", val); } print->print("\n"); diff --git a/src/main.cpp b/src/main.cpp index b62aee61..2a0bd9b1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,6 +30,9 @@ #ifdef USERMOD_HA #include "User/UserModHA.h" #endif +#ifdef USERMOD_WLEDAUDIO + #include "User/UserModWLEDAudio.h" +#endif //setup all modules void setup() { @@ -51,6 +54,9 @@ void setup() { #ifdef USERMOD_HA hamod = new UserModHA(); #endif + #ifdef USERMOD_WLEDAUDIO + wledAudioMod = new UserModWLEDAudio(); + #endif //prefered default order in the UI mdls->add(lds); @@ -69,6 +75,9 @@ void setup() { #ifdef USERMOD_HA mdls->add(hamod); #endif + #ifdef USERMOD_WLEDAUDIO + mdls->add(wledAudioMod); + #endif //do not add mdls itself as it does setup and loop for itself!!! (it is the orchestrator) mdls->setup(); From d97f2fc6fbb7b72974ce5cf814212535c0b2281c Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 2 Aug 2023 14:13:26 +0100 Subject: [PATCH 03/24] Copy paste of WLEDs GEQ --- src/App/AppEffects.h | 87 ++++++++++++++++++++++++++++++++++++++++++++ src/App/AppModLeds.h | 1 + 2 files changed, 88 insertions(+) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index 1f706d48..f28d33a4 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -223,4 +223,91 @@ class Frizzles2D:public Effect { } }; // Frizzles2D +class GEQEffect:public Effect { +public: + const char * name() { + return "GEQ"; + } + void setup() {} //not implemented yet + void loop() { + if (!strip.isMatrix) return mode_static(); // not a 2D set-up + + const int NUM_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16); + const uint16_t cols = SEGMENT.virtualWidth(); + const uint16_t rows = SEGMENT.virtualHeight(); + if ((cols <=1) || (rows <=1)) return mode_static(); // not really a 2D set-up + + if (!SEGENV.allocateData(cols*sizeof(uint16_t))) return mode_static(); //allocation failed + uint16_t *previousBarHeight = reinterpret_cast(SEGENV.data); //array of previous bar heights per frequency band + + uint8_t *fftResult = wledAudioMod->fftResults; + #ifdef SR_DEBUG + uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; + #endif + + if (SEGENV.call == 0) for (int i=0; i= (256U - SEGMENT.intensity)) { + SEGENV.step = millis(); + rippleTime = true; + } + + if (SEGENV.call == 0) SEGMENT.fill(BLACK); + int fadeoutDelay = (256 - SEGMENT.speed) / 64; + if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(SEGMENT.speed); + + uint16_t lastBandHeight = 0; // WLEDMM: for smoothing out bars + + //WLEDMM: evenly ditribut bands + float bandwidth = (float)cols / NUM_BANDS; + float remaining = bandwidth; + uint8_t band = 0; + for (int x=0; x < cols; x++) { + //WLEDMM if not enough remaining + if (remaining < 1) {band++; remaining+= bandwidth;} //increase remaining but keep the current remaining + remaining--; //consume remaining + + // Serial.printf("x %d b %d n %d w %f %f\n", x, band, NUM_BANDS, bandwidth, remaining); + uint8_t frBand = ((NUM_BANDS < 16) && (NUM_BANDS > 1)) ? map(band, 0, NUM_BANDS - 1, 0, 15):band; // always use full range. comment out this line to get the previous behaviour. + // frBand = constrain(frBand, 0, 15); //WLEDMM can never be out of bounds (I think...) + uint16_t colorIndex = frBand * 17; //WLEDMM 0.255 + uint16_t bandHeight = fftResult[frBand]; // WLEDMM we use the original ffResult, to preserve accuracy + + // WLEDMM begin - smooth out bars + if ((x > 0) && (x < (cols-1)) && (SEGMENT.check2)) { + // get height of next (right side) bar + uint8_t nextband = (remaining < 1)? band +1: band; + nextband = constrain(nextband, 0, 15); // just to be sure + frBand = ((NUM_BANDS < 16) && (NUM_BANDS > 1)) ? map(nextband, 0, NUM_BANDS - 1, 0, 15):nextband; // always use full range. comment out this line to get the previous behaviour. + uint16_t nextBandHeight = fftResult[frBand]; + // smooth Band height + bandHeight = (7*bandHeight + 3*lastBandHeight + 3*nextBandHeight) / 12; // yeees, its 12 not 13 (10% amplification) + bandHeight = constrain(bandHeight, 0, 255); // remove potential over/underflows + colorIndex = map(x, 0, cols-1, 0, 255); //WLEDMM + } + lastBandHeight = bandHeight; // remember BandHeight (left side) for next iteration + uint16_t barHeight = map(bandHeight, 0, 255, 0, rows); // Now we map bandHeight to barHeight. do not subtract -1 from rows here + // WLEDMM end + + if (barHeight > rows) barHeight = rows; // WLEDMM map() can "overshoot" due to rounding errors + if (barHeight > previousBarHeight[x]) previousBarHeight[x] = barHeight; //drive the peak up + + uint32_t ledColor = BLACK; + for (int y=0; y < barHeight; y++) { + if (SEGMENT.check1) //color_vertical / color bars toggle + colorIndex = map(y, 0, rows-1, 0, 255); + + ledColor = SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0); + SEGMENT.setPixelColorXY(x, rows-1 - y, ledColor); + } + if ((SEGMENT.intensity < 255) && (previousBarHeight[x] > 0) && (previousBarHeight[x] < rows)) // WLEDMM avoid "overshooting" into other segments + SEGMENT.setPixelColorXY(x, rows - previousBarHeight[x], (SEGCOLOR(2) != BLACK) ? SEGCOLOR(2) : ledColor); + + if (rippleTime && previousBarHeight[x]>0) previousBarHeight[x]--; //delay/ripple effect + + } +}; + + static std::vector effects; \ No newline at end of file diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index e8292d04..a112ffd9 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -225,6 +225,7 @@ class AppModLeds:public Module { effects.push_back(new Ripples3DEffect); effects.push_back(new SphereMove3DEffect); effects.push_back(new Frizzles2D); + effects.push_back(new GEQEffect); // FastLED.addLeds(leds, 1); FastLED.addLeds(ledsP, NUM_LEDS_FastLed); From 92af38f96a3fa3666a1c5d72725b97725017baf3 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 2 Aug 2023 14:17:41 +0100 Subject: [PATCH 04/24] Start updating GEQ effect for StarMod --- src/App/AppEffects.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index f28d33a4..ab7419ed 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -232,9 +232,9 @@ class GEQEffect:public Effect { void loop() { if (!strip.isMatrix) return mode_static(); // not a 2D set-up - const int NUM_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16); - const uint16_t cols = SEGMENT.virtualWidth(); - const uint16_t rows = SEGMENT.virtualHeight(); + const int NUM_BANDS = NUM_GEQ_CHANNELS ; // map(SEGMENT.custom1, 0, 255, 1, 16); + const uint16_t cols = LedsV::widthV + const uint16_t rows = LedsV::heightV if ((cols <=1) || (rows <=1)) return mode_static(); // not really a 2D set-up if (!SEGENV.allocateData(cols*sizeof(uint16_t))) return mode_static(); //allocation failed From fca4b2d0f09c1de905f02ea9c041d813186d634e Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 2 Aug 2023 14:35:18 +0100 Subject: [PATCH 05/24] Disable debug print statements --- src/User/UserModWLEDAudio.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/User/UserModWLEDAudio.h b/src/User/UserModWLEDAudio.h index eff5bf05..92e0c492 100644 --- a/src/User/UserModWLEDAudio.h +++ b/src/User/UserModWLEDAudio.h @@ -37,18 +37,19 @@ class UserModWLEDAudio:public Module { void loop(){ // Module::loop(); if (sync.read()) { - print->print("WLED-Sync: "); + if(debug) print->print("WLED-Sync: "); for (int b = 0; b < NUM_GEQ_CHANNELS; b++) { uint8_t val = sync.fftResult[b]; fftResults[b] = val; - print->print("%u ", val); + if(debug) print->print("%u ", val); } - print->print("\n"); + if(debug) print->print("\n"); } } private: - WLEDSync sync; + WLEDSync sync; + boolean debug; }; From 4656f74b0b9e9dbff5d846f40a8a9df845316438 Mon Sep 17 00:00:00 2001 From: Ewoud Date: Fri, 4 Aug 2023 09:17:33 +0200 Subject: [PATCH 06/24] Change GEQEffect to make it compile (WIP) --- src/App/AppEffects.h | 52 ++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index ab7419ed..382cd8b9 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -10,6 +10,7 @@ static uint8_t gHue = 0; // rotating "base color" used by many of the patterns static unsigned long call = 0; +static unsigned long step = 0; //should not contain variables/bytes to keep mem as small as possible!! class Effect { @@ -223,39 +224,45 @@ class Frizzles2D:public Effect { } }; // Frizzles2D +#define NUM_GEQ_CHANNELS 16 // number of frequency channels. Don't change !! + class GEQEffect:public Effect { public: + byte previousBarHeight[1024]; + uint8_t intensity; + uint8_t speed; + bool check1; + bool check2; + const char * name() { return "GEQ"; } - void setup() {} //not implemented yet + + void setup() { + fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 16); + for (int i=0; i(SEGENV.data); //array of previous bar heights per frequency band uint8_t *fftResult = wledAudioMod->fftResults; #ifdef SR_DEBUG uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; #endif - if (SEGENV.call == 0) for (int i=0; i= (256U - SEGMENT.intensity)) { - SEGENV.step = millis(); + if (millis() - step >= (256U - intensity)) { + step = millis(); rippleTime = true; } - if (SEGENV.call == 0) SEGMENT.fill(BLACK); - int fadeoutDelay = (256 - SEGMENT.speed) / 64; - if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(SEGMENT.speed); + int fadeoutDelay = (256 - speed) / 64; + if ((fadeoutDelay <= 1 ) || ((call % fadeoutDelay) == 0)) fadeToBlackBy( ledsP, LedsV::nrOfLedsP, speed); uint16_t lastBandHeight = 0; // WLEDMM: for smoothing out bars @@ -275,7 +282,7 @@ class GEQEffect:public Effect { uint16_t bandHeight = fftResult[frBand]; // WLEDMM we use the original ffResult, to preserve accuracy // WLEDMM begin - smooth out bars - if ((x > 0) && (x < (cols-1)) && (SEGMENT.check2)) { + if ((x > 0) && (x < (cols-1)) && (check2)) { // get height of next (right side) bar uint8_t nextband = (remaining < 1)? band +1: band; nextband = constrain(nextband, 0, 15); // just to be sure @@ -293,16 +300,19 @@ class GEQEffect:public Effect { if (barHeight > rows) barHeight = rows; // WLEDMM map() can "overshoot" due to rounding errors if (barHeight > previousBarHeight[x]) previousBarHeight[x] = barHeight; //drive the peak up - uint32_t ledColor = BLACK; + CRGB ledColor = CRGB::Black; for (int y=0; y < barHeight; y++) { - if (SEGMENT.check1) //color_vertical / color bars toggle + if (check1) //color_vertical / color bars toggle colorIndex = map(y, 0, rows-1, 0, 255); - ledColor = SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0); - SEGMENT.setPixelColorXY(x, rows-1 - y, ledColor); + CRGBPalette16 palette = PartyColors_p; + ledColor = ColorFromPalette(palette, (uint8_t)colorIndex); + + ledsV.setPixelColor(x + LedsV::widthV * (rows-1 - y), ledColor); } - if ((SEGMENT.intensity < 255) && (previousBarHeight[x] > 0) && (previousBarHeight[x] < rows)) // WLEDMM avoid "overshooting" into other segments - SEGMENT.setPixelColorXY(x, rows - previousBarHeight[x], (SEGCOLOR(2) != BLACK) ? SEGCOLOR(2) : ledColor); + + if ((intensity < 255) && (previousBarHeight[x] > 0) && (previousBarHeight[x] < rows)) // WLEDMM avoid "overshooting" into other segments + ledsV.setPixelColor(x + LedsV::widthV * (rows - previousBarHeight[x]), ledColor); if (rippleTime && previousBarHeight[x]>0) previousBarHeight[x]--; //delay/ripple effect From 862e1e5f2f29b86e0a6ab0e272974aed2796b9c3 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 12:10:05 +0100 Subject: [PATCH 07/24] Fix compile errors --- src/App/AppEffects.h | 12 ++++++++++-- src/App/AppModLeds.h | 3 +++ src/User/UserModWLEDAudio.h | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index 382cd8b9..aec39d48 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -8,6 +8,11 @@ @license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 */ +#ifdef USERMOD_WLEDAUDIO + #include "User/UserModWLEDAudio.h" +#endif + + static uint8_t gHue = 0; // rotating "base color" used by many of the patterns static unsigned long call = 0; static unsigned long step = 0; @@ -224,7 +229,8 @@ class Frizzles2D:public Effect { } }; // Frizzles2D -#define NUM_GEQ_CHANNELS 16 // number of frequency channels. Don't change !! + +#ifdef USERMOD_WLEDAUDIO class GEQEffect:public Effect { public: @@ -241,7 +247,7 @@ class GEQEffect:public Effect { void setup() { fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 16); for (int i=0; i0) previousBarHeight[x]--; //delay/ripple effect + } } }; +#endif // End Audio Effects static std::vector effects; \ No newline at end of file diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index 1988e5a9..532f1431 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -229,7 +229,10 @@ class AppModLeds:public Module { effects.push_back(new Ripples3DEffect); effects.push_back(new SphereMove3DEffect); effects.push_back(new Frizzles2D); +#ifdef USERMOD_WLEDAUDIO effects.push_back(new GEQEffect); +#endif + // FastLED.addLeds(leds, 1); FastLED.addLeds(ledsP, NUM_LEDS_FastLed); diff --git a/src/User/UserModWLEDAudio.h b/src/User/UserModWLEDAudio.h index 92e0c492..b4fc25f0 100644 --- a/src/User/UserModWLEDAudio.h +++ b/src/User/UserModWLEDAudio.h @@ -8,6 +8,8 @@ @license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 */ +#pragma once + #include // https://github.com/netmindz/WLED-sync class UserModWLEDAudio:public Module { From 4a03700d5744dd8444bd68abe69e5a1a2f05757d Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 12:14:41 +0100 Subject: [PATCH 08/24] Disable WLEDAudio debug --- src/User/UserModWLEDAudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/User/UserModWLEDAudio.h b/src/User/UserModWLEDAudio.h index b4fc25f0..5ae4bc42 100644 --- a/src/User/UserModWLEDAudio.h +++ b/src/User/UserModWLEDAudio.h @@ -51,7 +51,7 @@ class UserModWLEDAudio:public Module { private: WLEDSync sync; - boolean debug; + boolean debug = false; }; From 77ff7f7f5205fb1ded603079154673ff2dc134b0 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 12:47:59 +0100 Subject: [PATCH 09/24] Setting speed and intensity from e131 --- src/App/AppEffects.h | 7 ++++++- src/App/AppModLeds.h | 4 +++- src/User/UserModE131.h | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index aec39d48..7209671d 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -7,7 +7,9 @@ @Copyright (c) 2023 Github StarMod Commit Authors @license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 */ - +#ifdef USERMOD_E131 + #include "User/UserModE131.h" +#endif #ifdef USERMOD_WLEDAUDIO #include "User/UserModWLEDAudio.h" #endif @@ -261,6 +263,9 @@ class GEQEffect:public Effect { uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; #endif + speed = e131mod->getValue("speed"); + intensity = e131mod->getValue("intensity"); + bool rippleTime = false; if (millis() - step >= (256U - intensity)) { step = millis(); diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index 532f1431..23981028 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -238,8 +238,10 @@ class AppModLeds:public Module { FastLED.addLeds(ledsP, NUM_LEDS_FastLed); #ifdef USERMOD_E131 - e131mod->addWatch(1, "bri", 256); + e131mod->addWatch(1, "bri"); e131mod->addWatch(2, "fx", effects.size()); + e131mod->addWatch(3, "speed"); // TODO: add constant for name + e131mod->addWatch(4, "intensity"); #endif print->print("%s %s %s\n", __PRETTY_FUNCTION__, name, success?"success":"failed"); diff --git a/src/User/UserModE131.h b/src/User/UserModE131.h index 95158c85..f7af6087 100644 --- a/src/User/UserModE131.h +++ b/src/User/UserModE131.h @@ -84,7 +84,7 @@ class UserModE131:public Module { if (varsToWatch[i].id != nullptr) { print->print(" var: %s\n", varsToWatch[i].id); - mdl->setValueI(varsToWatch[i].id, varsToWatch[i].savedValue%varsToWatch[i].max); // TODO: ugly to have magic string + mdl->setValueI(varsToWatch[i].id, varsToWatch[i].savedValue%varsToWatch[i].max); } else print->print("\n"); @@ -93,11 +93,21 @@ class UserModE131:public Module { } } - void addWatch(uint8_t channel, const char * id, uint16_t max) { + void addWatch(uint8_t channel, const char * id, uint8_t max = 255) { varsToWatch[channel].id = id; varsToWatch[channel].max = max; } + uint8_t getValue(const char * id) { + for (int i=0; i < maxChannels; i++) { + if(varsToWatch[i].id == id) { + return varsToWatch[i].savedValue; + } + } + print->print("ERROR: failed to find param %s\n", id); + return 0; + } + private: ESPAsyncE131 e131; boolean e131Created = false; From 1e323ade93236ae6ea954615827aca1c47da958a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 12:56:08 +0100 Subject: [PATCH 10/24] Setting speed and intensity from model rather than direct from e131 --- src/App/AppEffects.h | 7 ++----- src/User/UserModE131.h | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index 7209671d..472d6cc6 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -7,9 +7,6 @@ @Copyright (c) 2023 Github StarMod Commit Authors @license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 */ -#ifdef USERMOD_E131 - #include "User/UserModE131.h" -#endif #ifdef USERMOD_WLEDAUDIO #include "User/UserModWLEDAudio.h" #endif @@ -263,8 +260,8 @@ class GEQEffect:public Effect { uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; #endif - speed = e131mod->getValue("speed"); - intensity = e131mod->getValue("intensity"); + speed = mdl->getValue("speed"); + intensity = mdl->getValue("intensity"); bool rippleTime = false; if (millis() - step >= (256U - intensity)) { diff --git a/src/User/UserModE131.h b/src/User/UserModE131.h index f7af6087..353d7a21 100644 --- a/src/User/UserModE131.h +++ b/src/User/UserModE131.h @@ -71,7 +71,7 @@ class UserModE131:public Module { for (int i=0; i < maxChannels; i++) { if (packet.property_values[i] != varsToWatch[i].savedValue) { - print->print("Universe %u / %u Channels | Packet#: %u / Errors: %u / CH%d: %u -> %u", + print->print("Universe %u / %u Channels | Packet#: %u / Errors: %u / CH%d: %u -> %u\n", htons(packet.universe), // The Universe for this packet htons(packet.property_value_count) - 1, // Start code is ignored, we're interested in dimmer data e131.stats.num_packets, // Packet counter From 4497d59d1558c9374ca54085c27bd14aca7a6c52 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 13:24:20 +0100 Subject: [PATCH 11/24] Comment now probably redudant getValue from e131 mod --- src/User/UserModE131.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/User/UserModE131.h b/src/User/UserModE131.h index 353d7a21..bac1e4c9 100644 --- a/src/User/UserModE131.h +++ b/src/User/UserModE131.h @@ -71,14 +71,14 @@ class UserModE131:public Module { for (int i=0; i < maxChannels; i++) { if (packet.property_values[i] != varsToWatch[i].savedValue) { - print->print("Universe %u / %u Channels | Packet#: %u / Errors: %u / CH%d: %u -> %u\n", + print->print("Universe %u / %u Channels | Packet#: %u / Errors: %u / CH%d: %u -> %u ", htons(packet.universe), // The Universe for this packet htons(packet.property_value_count) - 1, // Start code is ignored, we're interested in dimmer data e131.stats.num_packets, // Packet counter e131.stats.packet_errors, // Packet error counter i, varsToWatch[i].savedValue, - packet.property_values[i]); // Dimmer data for Channel i + packet.property_values[i]); // value for channel i varsToWatch[i].savedValue = packet.property_values[i]; @@ -98,15 +98,15 @@ class UserModE131:public Module { varsToWatch[channel].max = max; } - uint8_t getValue(const char * id) { - for (int i=0; i < maxChannels; i++) { - if(varsToWatch[i].id == id) { - return varsToWatch[i].savedValue; - } - } - print->print("ERROR: failed to find param %s\n", id); - return 0; - } + // uint8_t getValue(const char * id) { + // for (int i=0; i < maxChannels; i++) { + // if(varsToWatch[i].id == id) { + // return varsToWatch[i].savedValue; + // } + // } + // print->print("ERROR: failed to find param %s\n", id); + // return 0; + // } private: ESPAsyncE131 e131; From ec4c049cc270652c8a3270f8accc9b13e0342ba8 Mon Sep 17 00:00:00 2001 From: Ewoud Date: Fri, 4 Aug 2023 14:31:48 +0200 Subject: [PATCH 12/24] Implement Effect controls AppEffects: - refactor parameters function - use parameters in GEQ AppModLeds - fx.chFun: check if no bogus fx, get the right effect and perform setup() NEW and parameters, if no effect found then still show the random controls --- src/App/AppEffects.h | 46 ++++++++++-------- src/App/AppModLeds.h | 110 +++++++++++++++++++++++-------------------- 2 files changed, 85 insertions(+), 71 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index 472d6cc6..94075c27 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -20,9 +20,9 @@ static unsigned long step = 0; class Effect { public: virtual const char * name() { return nullptr;} - virtual void setup() {} //not implemented yet + virtual void setup() {} virtual void loop() {} - virtual const char * parameters() {return nullptr;} + virtual bool parameters(JsonObject parentVar) {return false;} }; class RainbowEffect:public Effect { @@ -30,7 +30,7 @@ class RainbowEffect:public Effect { const char * name() { return "Rainbow"; } - void setup() {} //not implemented yet + void setup() {} void loop() { // FastLED's built-in rainbow generator fill_rainbow( ledsP, LedsV::nrOfLedsP, gHue, 7); @@ -42,7 +42,7 @@ class RainbowWithGlitterEffect:public RainbowEffect { const char * name() { return "Rainbow with glitter"; } - void setup() {} //not implemented yet + void setup() {} void loop() { // built-in FastLED rainbow, plus some random sparkly glitter RainbowEffect::loop(); @@ -61,7 +61,7 @@ class SinelonEffect:public Effect { const char * name() { return "Sinelon"; } - void setup() {} //not implemented yet + void setup() {} void loop() { // a colored dot sweeping back and forth, with fading trails fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 20); @@ -77,7 +77,7 @@ class RunningEffect:public Effect { const char * name() { return "Running"; } - void setup() {} //not implemented yet + void setup() {} void loop() { // a colored dot sweeping back and forth, with fading trails fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 70); //physical leds @@ -93,7 +93,7 @@ class ConfettiEffect:public Effect { const char * name() { return "Confetti"; } - void setup() {} //not implemented yet + void setup() {} void loop() { // random colored speckles that blink in and fade smoothly fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 10); @@ -107,7 +107,7 @@ class BPMEffect:public Effect { const char * name() { return "Beats per minute"; } - void setup() {} //not implemented yet + void setup() {} void loop() { // colored stripes pulsing at a defined Beats-Per-Minute (BPM) uint8_t BeatsPerMinute = 62; @@ -117,8 +117,8 @@ class BPMEffect:public Effect { ledsV[i] = ColorFromPalette(palette, gHue+(i*2), beat-gHue+(i*10)); } } - const char * parameters() { - return "BeatsPerMinute"; + bool parameters(JsonObject parentVar) { + return false; } }; @@ -127,7 +127,7 @@ class JuggleEffect:public Effect { const char * name() { return "Juggle"; } - void setup() {} //not implemented yet + void setup() {} void loop() { // eight colored dots, weaving in and out of sync with each other fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 20); @@ -144,7 +144,7 @@ class Ripples3DEffect:public Effect { const char * name() { return "Ripples 3D"; } - void setup() {} //not implemented yet + void setup() {} void loop() { float ripple_interval = 1.3;// * (SEGMENT.intensity/128.0); @@ -171,7 +171,7 @@ class SphereMove3DEffect:public Effect { const char * name() { return "SphereMove 3D"; } - void setup() {} //not implemented yet + void setup() {} void loop() { uint16_t origin_x, origin_y, origin_z, d; float diameter; @@ -211,7 +211,7 @@ class Frizzles2D:public Effect { const char * name() { return "Frizzles2D"; } - void setup() {} //not implemented yet + void setup() {} void loop() { fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 16); CRGBPalette16 palette = PartyColors_p; @@ -234,10 +234,6 @@ class Frizzles2D:public Effect { class GEQEffect:public Effect { public: byte previousBarHeight[1024]; - uint8_t intensity; - uint8_t speed; - bool check1; - bool check2; const char * name() { return "GEQ"; @@ -260,8 +256,10 @@ class GEQEffect:public Effect { uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; #endif - speed = mdl->getValue("speed"); - intensity = mdl->getValue("intensity"); + uint8_t speed = mdl->getValue("speed"); + uint8_t intensity = mdl->getValue("intensity"); + bool check1 = mdl->getValue("check1"); + bool check2 = mdl->getValue("check2"); bool rippleTime = false; if (millis() - step >= (256U - intensity)) { @@ -326,6 +324,14 @@ class GEQEffect:public Effect { } } + + bool parameters(JsonObject parentVar) { + ui->initNumber(parentVar, "speed", 128, false); + ui->initNumber(parentVar, "intensity", 128, false); + ui->initCheckBox(parentVar, "check1", false, false); + ui->initCheckBox(parentVar, "check2", false, false); + return true; + } }; #endif // End Audio Effects diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index 23981028..0607ea08 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -69,57 +69,65 @@ class AppModLeds:public Module { ledsV.ledFixProjectAndMap(); //luckily not called during reboot as ledFixNr not defined yet then } - // if (false) { - JsonObject parentVar = mdl->findVar(var["id"]); - parentVar.remove("n"); //tbd: we should also remove the uiFun and chFun !! - - for (int i=0; i<5; i++) { - uint8_t nameNr = random8(6); - uint8_t typeNr = random8(5); - char name[12]; - switch (nameNr) { - case 0: - strcpy(name, "lorum"); - break; - case 1: - strcpy(name, "ipsum"); - break; - case 2: - strcpy(name, "dolor"); - break; - case 3: - strcpy(name, "sit"); - break; - case 4: - strcpy(name, "amet"); - break; - case 5: - strcpy(name, "consectetur"); - break; - } - - switch (typeNr) { - case 0: - ui->initText(parentVar, name, name, false); - break; - case 1: - ui->initNumber(parentVar, name, random8(255), false); - break; - case 2: - ui->initSlider(parentVar, name, random8(255), false); - break; - case 3: - ui->initCheckBox(parentVar, name, random8(2), false); - break; - case 4: - ui->initSelect(parentVar, name, random8(2), false, [](JsonObject var) { //uiFun - JsonArray select = web->addResponseA(var["id"], "select"); - select.add("Oui"); //0 - select.add("Non"); //1 - }); - break; - } - } + if (fx < effects.size()) { + + // if (false) { + JsonObject parentVar = mdl->findVar(var["id"]); + parentVar.remove("n"); //tbd: we should also remove the uiFun and chFun !! + + Effect* effect = effects[fx]; + effect->setup(); //if changed then run setup once (like call==0 in WLED) + if (!effect->parameters(parentVar)) { + for (int i=0; i<5; i++) { + uint8_t nameNr = random8(6); + uint8_t typeNr = random8(5); + char name[12]; + switch (nameNr) { + case 0: + strcpy(name, "lorum"); + break; + case 1: + strcpy(name, "ipsum"); + break; + case 2: + strcpy(name, "dolor"); + break; + case 3: + strcpy(name, "sit"); + break; + case 4: + strcpy(name, "amet"); + break; + case 5: + strcpy(name, "consectetur"); + break; + } + + switch (typeNr) { + case 0: + ui->initText(parentVar, name, name, false); + break; + case 1: + ui->initNumber(parentVar, name, random8(255), false); + break; + case 2: + ui->initSlider(parentVar, name, random8(255), false); + break; + case 3: + ui->initCheckBox(parentVar, name, random8(2), false); + break; + case 4: + ui->initSelect(parentVar, name, random8(2), false, [](JsonObject var) { //uiFun + JsonArray select = web->addResponseA(var["id"], "select"); + select.add("Oui"); //0 + select.add("Non"); //1 + }); + break; + } + } //for loop + } //! parameters + } //fx < size + print->printJson("parentVar", parentVar); web->sendDataWs(parentVar); //always send, also when no children, to remove them from ui }); From b770727173de45ef7e32e6e6519bb7deace0542e Mon Sep 17 00:00:00 2001 From: Ewoud Date: Fri, 4 Aug 2023 14:43:08 +0200 Subject: [PATCH 13/24] Fix --- src/App/AppModLeds.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index 0607ea08..26dbfabf 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -126,10 +126,10 @@ class AppModLeds:public Module { } } //for loop } //! parameters + print->printJson("parentVar", parentVar); + web->sendDataWs(parentVar); //always send, also when no children, to remove them from ui } //fx < size - print->printJson("parentVar", parentVar); - web->sendDataWs(parentVar); //always send, also when no children, to remove them from ui }); ui->initSelect(parentVar, "projection", -1, false, [](JsonObject var) { //uiFun. 1: is default From 50a212f749ec417e83fe8da21080f75aa895765b Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 14:04:39 +0100 Subject: [PATCH 14/24] Map DMX values to the range of the variable, rather than using mod --- src/App/AppModLeds.h | 2 +- src/User/UserModE131.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index 26dbfabf..ba524644 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -247,7 +247,7 @@ class AppModLeds:public Module { #ifdef USERMOD_E131 e131mod->addWatch(1, "bri"); - e131mod->addWatch(2, "fx", effects.size()); + e131mod->addWatch(2, "fx", (effects.size() - 1)); e131mod->addWatch(3, "speed"); // TODO: add constant for name e131mod->addWatch(4, "intensity"); #endif diff --git a/src/User/UserModE131.h b/src/User/UserModE131.h index bac1e4c9..f79af4cc 100644 --- a/src/User/UserModE131.h +++ b/src/User/UserModE131.h @@ -84,7 +84,7 @@ class UserModE131:public Module { if (varsToWatch[i].id != nullptr) { print->print(" var: %s\n", varsToWatch[i].id); - mdl->setValueI(varsToWatch[i].id, varsToWatch[i].savedValue%varsToWatch[i].max); + mdl->setValueI(varsToWatch[i].id, map(varsToWatch[i].savedValue, 0, 255, 0, varsToWatch[i].max)); } else print->print("\n"); From 30f8b7920bc262be49e3ca3991dceab831d11d7b Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 14:17:03 +0100 Subject: [PATCH 15/24] Move e131 channel assigment to effect --- src/App/AppEffects.h | 13 +++++++++++-- src/App/AppModLeds.h | 2 -- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index 94075c27..12f254f0 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -10,6 +10,9 @@ #ifdef USERMOD_WLEDAUDIO #include "User/UserModWLEDAudio.h" #endif +#ifdef USERMOD_E131 + #include "../User/UserModE131.h" +#endif static uint8_t gHue = 0; // rotating "base color" used by many of the patterns @@ -326,10 +329,16 @@ class GEQEffect:public Effect { } bool parameters(JsonObject parentVar) { - ui->initNumber(parentVar, "speed", 128, false); - ui->initNumber(parentVar, "intensity", 128, false); + ui->initNumber(parentVar, "speed", 255, false); + ui->initNumber(parentVar, "intensity", 255, false); ui->initCheckBox(parentVar, "check1", false, false); ui->initCheckBox(parentVar, "check2", false, false); + + // Nice an effect can register it's own DMX channel, but not a fan of repeating the range and type of the param + + e131mod->addWatch(3, "speed", 255); // TODO: add constant for name + e131mod->addWatch(4, "intensity", 255); + return true; } }; diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index ba524644..82548492 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -248,8 +248,6 @@ class AppModLeds:public Module { #ifdef USERMOD_E131 e131mod->addWatch(1, "bri"); e131mod->addWatch(2, "fx", (effects.size() - 1)); - e131mod->addWatch(3, "speed"); // TODO: add constant for name - e131mod->addWatch(4, "intensity"); #endif print->print("%s %s %s\n", __PRETTY_FUNCTION__, name, success?"success":"failed"); From 5d5c423b5b4760c56a7abd4b57091bfe942852c3 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 14:22:17 +0100 Subject: [PATCH 16/24] Rename addWatch to patchChannel to better match its actual function of mapping dmx channel to a variable --- src/App/AppEffects.h | 4 ++-- src/App/AppModLeds.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index 12f254f0..61cf4515 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -336,8 +336,8 @@ class GEQEffect:public Effect { // Nice an effect can register it's own DMX channel, but not a fan of repeating the range and type of the param - e131mod->addWatch(3, "speed", 255); // TODO: add constant for name - e131mod->addWatch(4, "intensity", 255); + e131mod->patchChannel(3, "speed", 255); // TODO: add constant for name + e131mod->patchChannel(4, "intensity", 255); return true; } diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index 82548492..1e70b256 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -246,8 +246,8 @@ class AppModLeds:public Module { FastLED.addLeds(ledsP, NUM_LEDS_FastLed); #ifdef USERMOD_E131 - e131mod->addWatch(1, "bri"); - e131mod->addWatch(2, "fx", (effects.size() - 1)); + e131mod->patchChannel(1, "bri"); + e131mod->patchChannel(2, "fx", (effects.size() - 1)); #endif print->print("%s %s %s\n", __PRETTY_FUNCTION__, name, success?"success":"failed"); From 042176df8af762927eb316b59145c111aaf59cf3 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 15:00:00 +0100 Subject: [PATCH 17/24] Rename addWatch to patchChannel to better match its actual function of mapping dmx channel to a variable --- src/User/UserModE131.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/User/UserModE131.h b/src/User/UserModE131.h index f79af4cc..d6ec4da8 100644 --- a/src/User/UserModE131.h +++ b/src/User/UserModE131.h @@ -93,7 +93,7 @@ class UserModE131:public Module { } } - void addWatch(uint8_t channel, const char * id, uint8_t max = 255) { + void patchChannel(uint8_t channel, const char * id, uint8_t max = 255) { varsToWatch[channel].id = id; varsToWatch[channel].max = max; } From fac5b5653e2f735293067b148cb348ee58575c5a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 15:26:31 +0100 Subject: [PATCH 18/24] Add AudioRings effect --- src/App/AppEffects.h | 64 ++++++++++++++++++++++++++++++++++++++++++++ src/App/AppModLeds.h | 1 + 2 files changed, 65 insertions(+) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index 61cf4515..aa6f2a43 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -343,6 +343,70 @@ class GEQEffect:public Effect { } }; +class AudioRings:public Effect { + private: + uint8_t ringMap[9][2] = { + {0, 0}, //0 Center Point + {1, 8}, //1 + {9, 20}, //2 + {21, 36}, //3 + {37, 60}, //4 + {61, 92}, //5 + {93, 132}, //6 + {133, 180}, //7 + {181, 240}, //8 Outer Ring + }; + uint8_t *fftResult = wledAudioMod->fftResults; + CRGBPalette16 palette = PartyColors_p; + bool INWARD; // TODO: param + + public: + const char * name() { + return "AudioRings"; + } + void setup() {} + void setRing(int ring, CRGB colour) { + for (int i = ringMap[ring][0]; i <= ringMap[ring][1]; i++) { + ledsV[i] = colour; + } + } + + void setRingFromFtt(int index, int ring) { + uint8_t val = fftResult[index]; + // Visualize leds to the beat + CRGB color = ColorFromPalette(palette, val, 255); + color.nscale8_video(val); + setRing(ring, color); + } + + + void loop() { + for (int i = 0; i < 7; i++) { + + uint8_t val; + if(INWARD) { + val = fftResult[(i*2)]; + } + else { + int b = 14 -(i*2); + val = fftResult[b]; + } + + // Visualize leds to the beat + CRGB color = ColorFromPalette(palette, val, val); + // CRGB color = ColorFromPalette(currentPalette, val, 255, currentBlending); + // color.nscale8_video(val); + setRing(i, color); + // setRingFromFtt((i * 2), i); + } + + setRingFromFtt(2, 7); // set outer ring to base + setRingFromFtt(0, 8); // set outer ring to base + + } +}; + + #endif // End Audio Effects static std::vector effects; \ No newline at end of file diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index 1e70b256..74b98bb0 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -239,6 +239,7 @@ class AppModLeds:public Module { effects.push_back(new Frizzles2D); #ifdef USERMOD_WLEDAUDIO effects.push_back(new GEQEffect); + effects.push_back(new AudioRings); #endif From 003fc04ef8e03c618881d90ee2b9f3861db6e340 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 15:29:04 +0100 Subject: [PATCH 19/24] Add comment about ring ordering --- src/App/AppEffects.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index aa6f2a43..e8524134 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -345,7 +345,7 @@ class GEQEffect:public Effect { class AudioRings:public Effect { private: - uint8_t ringMap[9][2] = { + uint8_t ringMap[9][2] = { // If you ring goes from ouside in, then reverse the order of this array {0, 0}, //0 Center Point {1, 8}, //1 {9, 20}, //2 From 1de7a045843a50d04c629c6ed79a65fd4a717396 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 15:41:47 +0100 Subject: [PATCH 20/24] Add base class for 241Ring effects and add RandomFlow as example of non-audio --- src/App/AppEffects.h | 68 ++++++++++++++++++++++++++++++-------------- src/App/AppModLeds.h | 1 + 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index e8524134..f562e444 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -231,6 +231,50 @@ class Frizzles2D:public Effect { } }; // Frizzles2D +class RingEffect:public Effect { + protected: + uint8_t ringMap[9][2] = { // If you ring goes from ouside in, then reverse the order of this array + {0, 0}, //0 Center Point + {1, 8}, //1 + {9, 20}, //2 + {21, 36}, //3 + {37, 60}, //4 + {61, 92}, //5 + {93, 132}, //6 + {133, 180}, //7 + {181, 240}, //8 Outer Ring + }; + CRGBPalette16 palette = PartyColors_p; + bool INWARD; // TODO: param + const static int RINGS = 9; + uint8_t hue[RINGS]; + + void setRing(int ring, CRGB colour) { + for (int i = ringMap[ring][0]; i <= ringMap[ring][1]; i++) { + ledsV[i] = colour; + } + } + +}; + +class RingRandomFlow:public RingEffect { +public: + const char * name() { + return "RingRandomFlow"; + } + void setup() {} + void loop() { + hue[0] = random(0, 255); + for (int r = 0; r < RINGS; r++) { + setRing(r, CHSV(hue[r], 255, 255)); + } + for (int r = (RINGS - 1); r >= 1; r--) { + hue[r] = hue[(r - 1)]; // set this ruing based on the inner + } + // FastLED.delay(SPEED); + } +}; + #ifdef USERMOD_WLEDAUDIO @@ -343,33 +387,15 @@ class GEQEffect:public Effect { } }; -class AudioRings:public Effect { +class AudioRings:public RingEffect { private: - uint8_t ringMap[9][2] = { // If you ring goes from ouside in, then reverse the order of this array - {0, 0}, //0 Center Point - {1, 8}, //1 - {9, 20}, //2 - {21, 36}, //3 - {37, 60}, //4 - {61, 92}, //5 - {93, 132}, //6 - {133, 180}, //7 - {181, 240}, //8 Outer Ring - }; uint8_t *fftResult = wledAudioMod->fftResults; - CRGBPalette16 palette = PartyColors_p; - bool INWARD; // TODO: param public: const char * name() { return "AudioRings"; } void setup() {} - void setRing(int ring, CRGB colour) { - for (int i = ringMap[ring][0]; i <= ringMap[ring][1]; i++) { - ledsV[i] = colour; - } - } void setRingFromFtt(int index, int ring) { uint8_t val = fftResult[index]; @@ -400,8 +426,8 @@ class AudioRings:public Effect { // setRingFromFtt((i * 2), i); } - setRingFromFtt(2, 7); // set outer ring to base - setRingFromFtt(0, 8); // set outer ring to base + setRingFromFtt(2, 7); // set outer ring to bass + setRingFromFtt(0, 8); // set outer ring to bass } }; diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index 74b98bb0..c12670c7 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -237,6 +237,7 @@ class AppModLeds:public Module { effects.push_back(new Ripples3DEffect); effects.push_back(new SphereMove3DEffect); effects.push_back(new Frizzles2D); + effects.push_back(new RingRandomFlow); #ifdef USERMOD_WLEDAUDIO effects.push_back(new GEQEffect); effects.push_back(new AudioRings); From d2a5ab3edfb82c1a3ab36a59ac023dda3ab492cb Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 16:01:03 +0100 Subject: [PATCH 21/24] Reset "old" value when patching --- src/App/AppEffects.h | 4 ++-- src/User/UserModE131.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index f562e444..f9b711a4 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -380,8 +380,8 @@ class GEQEffect:public Effect { // Nice an effect can register it's own DMX channel, but not a fan of repeating the range and type of the param - e131mod->patchChannel(3, "speed", 255); // TODO: add constant for name - e131mod->patchChannel(4, "intensity", 255); + e131mod->patchChannel(3, "speed", 125, 255); // TODO: add constant for name + e131mod->patchChannel(4, "intensity", 125, 255); return true; } diff --git a/src/User/UserModE131.h b/src/User/UserModE131.h index d6ec4da8..c9a921e9 100644 --- a/src/User/UserModE131.h +++ b/src/User/UserModE131.h @@ -95,6 +95,7 @@ class UserModE131:public Module { void patchChannel(uint8_t channel, const char * id, uint8_t max = 255) { varsToWatch[channel].id = id; + varsToWatch[channel].savedValue = 0; // Always reset when (re)patching so variable gets set to DMX value even if unchanged varsToWatch[channel].max = max; } From 3a5454b4ed86b27599dc5a3eb671eb51f8eee371 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 4 Aug 2023 16:02:27 +0100 Subject: [PATCH 22/24] Reset "old" value when patching --- src/App/AppEffects.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index f9b711a4..f562e444 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -380,8 +380,8 @@ class GEQEffect:public Effect { // Nice an effect can register it's own DMX channel, but not a fan of repeating the range and type of the param - e131mod->patchChannel(3, "speed", 125, 255); // TODO: add constant for name - e131mod->patchChannel(4, "intensity", 125, 255); + e131mod->patchChannel(3, "speed", 255); // TODO: add constant for name + e131mod->patchChannel(4, "intensity", 255); return true; } From 68ce304bf92b91de377410bc9c52c0651f363d4e Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 5 Aug 2023 14:54:52 +0100 Subject: [PATCH 23/24] Swap to expecting mapping to be in LEDFixture --- src/App/AppEffects.h | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index f562e444..2285f994 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -233,26 +233,12 @@ class Frizzles2D:public Effect { class RingEffect:public Effect { protected: - uint8_t ringMap[9][2] = { // If you ring goes from ouside in, then reverse the order of this array - {0, 0}, //0 Center Point - {1, 8}, //1 - {9, 20}, //2 - {21, 36}, //3 - {37, 60}, //4 - {61, 92}, //5 - {93, 132}, //6 - {133, 180}, //7 - {181, 240}, //8 Outer Ring - }; CRGBPalette16 palette = PartyColors_p; bool INWARD; // TODO: param - const static int RINGS = 9; - uint8_t hue[RINGS]; + uint8_t hue[9]; // TODO: needs to match LedsV::nrOfLedsV void setRing(int ring, CRGB colour) { - for (int i = ringMap[ring][0]; i <= ringMap[ring][1]; i++) { - ledsV[i] = colour; - } + ledsV[ring] = colour; } }; @@ -265,10 +251,10 @@ class RingRandomFlow:public RingEffect { void setup() {} void loop() { hue[0] = random(0, 255); - for (int r = 0; r < RINGS; r++) { + for (int r = 0; r < LedsV::nrOfLedsV; r++) { setRing(r, CHSV(hue[r], 255, 255)); } - for (int r = (RINGS - 1); r >= 1; r--) { + for (int r = (LedsV::nrOfLedsV - 1); r >= 1; r--) { hue[r] = hue[(r - 1)]; // set this ruing based on the inner } // FastLED.delay(SPEED); From 511cb2362a43f81b3ce135f11159e2ccab265381 Mon Sep 17 00:00:00 2001 From: Ewoud Date: Tue, 15 Aug 2023 16:02:14 +0200 Subject: [PATCH 24/24] Post merge AppEffects: - add 1D/2D to name (temporary) - GEQ 2D rename check1/check2 - rename parameters to controls UserModWLEDAudio - default not ebabled - use onOffChanged --- src/App/AppEffects.h | 22 +++++++++++----------- src/App/AppModLeds.h | 8 ++++---- src/User/UserModWLEDAudio.h | 19 +++++++++++++------ 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/App/AppEffects.h b/src/App/AppEffects.h index 323c53db..d11eadbc 100644 --- a/src/App/AppEffects.h +++ b/src/App/AppEffects.h @@ -467,7 +467,7 @@ class RingEffect:public Effect { class RingRandomFlow:public RingEffect { public: const char * name() { - return "RingRandomFlow"; + return "RingRandomFlow 1D"; } void setup() {} void loop() { @@ -490,7 +490,7 @@ class GEQEffect:public Effect { byte previousBarHeight[1024]; const char * name() { - return "GEQ"; + return "GEQ 2D"; } void setup() { @@ -512,8 +512,8 @@ class GEQEffect:public Effect { uint8_t speed = mdl->getValue("speed"); uint8_t intensity = mdl->getValue("intensity"); - bool check1 = mdl->getValue("check1"); - bool check2 = mdl->getValue("check2"); + bool colorBars = mdl->getValue("colorBars"); + bool smoothBars = mdl->getValue("smoothBars"); bool rippleTime = false; if (millis() - step >= (256U - intensity)) { @@ -542,7 +542,7 @@ class GEQEffect:public Effect { uint16_t bandHeight = fftResult[frBand]; // WLEDMM we use the original ffResult, to preserve accuracy // WLEDMM begin - smooth out bars - if ((x > 0) && (x < (cols-1)) && (check2)) { + if ((x > 0) && (x < (cols-1)) && (smoothBars)) { // get height of next (right side) bar uint8_t nextband = (remaining < 1)? band +1: band; nextband = constrain(nextband, 0, 15); // just to be sure @@ -562,7 +562,7 @@ class GEQEffect:public Effect { CRGB ledColor = CRGB::Black; for (int y=0; y < barHeight; y++) { - if (check1) //color_vertical / color bars toggle + if (colorBars) //color_vertical / color bars toggle colorIndex = map(y, 0, rows-1, 0, 255); CRGBPalette16 palette = PartyColors_p; @@ -579,11 +579,11 @@ class GEQEffect:public Effect { } } - bool parameters(JsonObject parentVar) { + bool controls(JsonObject parentVar) { ui->initNumber(parentVar, "speed", 255, false); ui->initNumber(parentVar, "intensity", 255, false); - ui->initCheckBox(parentVar, "check1", false, false); - ui->initCheckBox(parentVar, "check2", false, false); + ui->initCheckBox(parentVar, "colorBars", false, false); // + ui->initCheckBox(parentVar, "smoothBars", false, false); // Nice an effect can register it's own DMX channel, but not a fan of repeating the range and type of the param @@ -600,7 +600,7 @@ class AudioRings:public RingEffect { public: const char * name() { - return "AudioRings"; + return "AudioRings 1D"; } void setup() {} @@ -614,7 +614,7 @@ class AudioRings:public RingEffect { void loop() { - for (int i = 0; i < 7; i++) { + for (int i = 0; i < 7; i++) { // 7 rings uint8_t val; if(INWARD) { diff --git a/src/App/AppModLeds.h b/src/App/AppModLeds.h index ddbeaadc..02199424 100644 --- a/src/App/AppModLeds.h +++ b/src/App/AppModLeds.h @@ -202,11 +202,11 @@ class AppModLeds:public Module { #endif #ifdef USERMOD_E131 - e131mod->addWatch(1, "bri", 256); - e131mod->addWatch(2, "fx", effects.size()); + e131mod->patchChannel(1, "bri", 255); //should be 256?? + e131mod->patchChannel(2, "fx", effects.size()); // //add these temporary to test remote changing of this values do not crash the system - // e131mod->addWatch(3, "projection", Projections::count); - // e131mod->addWatch(4, "ledFix", 5); //assuming 5!!! + // e131mod->patchChannel(3, "projection", Projections::count); + // e131mod->patchChannel(4, "ledFix", 5); //assuming 5!!! #endif print->print("%s %s %s\n", __PRETTY_FUNCTION__, name, success?"success":"failed"); diff --git a/src/User/UserModWLEDAudio.h b/src/User/UserModWLEDAudio.h index 5ae4bc42..df428976 100644 --- a/src/User/UserModWLEDAudio.h +++ b/src/User/UserModWLEDAudio.h @@ -1,9 +1,9 @@ /* @title StarMod - @file UserModExample.h - @date 20230730 - @repo https://github.com/ewoudwijma/StarMod - @Authors https://github.com/ewoudwijma/StarMod/commits/main + @file UserModWLEDAudio.h + @date 20230810 + @repo https://github.com/ewowi/StarMod + @Authors https://github.com/ewowi/StarMod/commits/main @Copyright (c) 2023 Github StarMod Commit Authors @license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 */ @@ -21,6 +21,8 @@ class UserModWLEDAudio:public Module { UserModWLEDAudio() :Module("WLED Audio Sync Receiver") { print->print("%s %s\n", __PRETTY_FUNCTION__, name); + isEnabled = false; //default off + print->print("%s %s %s\n", __PRETTY_FUNCTION__, name, success?"success":"failed"); }; @@ -32,8 +34,13 @@ class UserModWLEDAudio:public Module { print->print("%s %s %s\n", __PRETTY_FUNCTION__, name, success?"success":"failed"); } - void connected() { - sync.begin(); + void onOffChanged() { + if (SysModModules::isConnected && isEnabled) { + print->print("%s %s\n", __PRETTY_FUNCTION__, name); + sync.begin(); + } else { + // sync.end();??? + } } void loop(){