@@ -1211,7 +1211,7 @@ static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!"
12111211/*
12121212 * Fireworks function.
12131213 */
1214- uint16_t mode_fireworks ( ) {
1214+ static uint16_t mode_fireworks_core ( bool useaudio ) {
12151215 if (SEGLEN == 1 ) return mode_static ();
12161216 const uint16_t width = SEGMENT.is2D () ? SEGMENT.virtualWidth () : SEGMENT.virtualLength ();
12171217 const uint16_t height = SEGMENT.virtualHeight ();
@@ -1227,17 +1227,46 @@ uint16_t mode_fireworks() {
12271227 bool valid1 = (SEGENV.aux0 < width*height);
12281228 bool valid2 = (SEGENV.aux1 < width*height);
12291229 uint32_t sv1 = 0 , sv2 = 0 ;
1230+
1231+ // WLEDMM begin
1232+ um_data_t *um_data;
1233+ if (!usermods.getUMData (&um_data, USERMOD_ID_AUDIOREACTIVE)) {
1234+ useaudio = false ; // no audio - fallback to standard behaviour (don't use soundSim)
1235+ }
1236+ bool addPixels = true ; // false -> inhibit new pixels in silence
1237+ unsigned myIntensity = 129 - (SEGMENT.intensity >> 1 ); // make parameter explicit, so we can work with it
1238+ int soundColor = -1 ; // -1 = random color; 0..255 = use as palette index
1239+
1240+ if (useaudio) {
1241+ float volumeSmth = *(float *) um_data->u_data [0 ];
1242+ float FFT_MajorPeak = *(float *) um_data->u_data [4 ];
1243+ uint8_t samplePeak = *(uint8_t *)um_data->u_data [3 ];
1244+ if ((volumeSmth > 1 .0f ) && (FFT_MajorPeak > 60 .0f )) { // we have sound - select color based on major frequency
1245+ float musicIndex = logf (FFT_MajorPeak); // log scaling of peak freq
1246+ soundColor = mapf (musicIndex, 4 .6f , 9 .06f , 0 , 255 ); // pick color from frequency (4.6 = ln(100), 9.06 = ln(8600))
1247+ soundColor = constrain (soundColor, 0 , 255 ); // remove over-shoot
1248+ if (samplePeak > 0 ) myIntensity -= myIntensity / 2 ; // increase effect intensity at peaks
1249+ else if (volumeSmth > 96 .0f ) myIntensity -= myIntensity / 4 ; // increase effect intensity slightly when music plays
1250+ myIntensity = constrain (myIntensity, 0 , 129 );
1251+ } else { // silence -> fade away
1252+ valid1 = valid2 = false ; // do not copy last pixels
1253+ addPixels = false ; // don't add new pixels
1254+ }
1255+ }
1256+ // WLEDMM end
1257+
12301258 if (valid1) sv1 = SEGMENT.is2D () ? SEGMENT.getPixelColorXY (SEGENV.aux0 %width, SEGENV.aux0 /width) : SEGMENT.getPixelColor (SEGENV.aux0 ); // get spark color
12311259 if (valid2) sv2 = SEGMENT.is2D () ? SEGMENT.getPixelColorXY (SEGENV.aux1 %width, SEGENV.aux1 /width) : SEGMENT.getPixelColor (SEGENV.aux1 );
12321260 if (!SEGENV.step ) SEGMENT.blur (16 );
12331261 if (valid1) { if (SEGMENT.is2D ()) SEGMENT.setPixelColorXY (SEGENV.aux0 %width, SEGENV.aux0 /width, sv1); else SEGMENT.setPixelColor (SEGENV.aux0 , sv1); } // restore spark color after blur
12341262 if (valid2) { if (SEGMENT.is2D ()) SEGMENT.setPixelColorXY (SEGENV.aux1 %width, SEGENV.aux1 /width, sv2); else SEGMENT.setPixelColor (SEGENV.aux1 , sv2); } // restore old spark color after blur
12351263
1264+ if (addPixels) // WLEDMM
12361265 for (int i=0 ; i<max (1 , width/20 ); i++) {
1237- if (random8 (129 - (SEGMENT. intensity >> 1 )) == 0 ) {
1266+ if (random8 (myIntensity) == 0 ) { // WLEDMM
12381267 uint16_t index = random16 (width*height);
12391268 uint16_t j = index % width, k = index / width;
1240- uint32_t col = SEGMENT.color_from_palette (random8 () , false , false , 0 );
1269+ uint32_t col = SEGMENT.color_from_palette ((soundColor > 0 ) ? soundColor + random8 (24 ) : random8 () , false , false , 0 ); // WLEDMM
12411270 if (SEGMENT.is2D ()) SEGMENT.setPixelColorXY (j, k, col);
12421271 else SEGMENT.setPixelColor (index, col);
12431272 SEGENV.aux1 = SEGENV.aux0 ; // old spark
@@ -1246,8 +1275,12 @@ uint16_t mode_fireworks() {
12461275 }
12471276 return FRAMETIME;
12481277}
1278+
1279+ uint16_t mode_fireworks (void ) { return mode_fireworks_core (false ); }
12491280static const char _data_FX_MODE_FIREWORKS[] PROGMEM = " Fireworks@,Frequency;!,!;!;12;ix=192,pal=11" ;
12501281
1282+ uint16_t mode_fireworks_audio (void ) { return mode_fireworks_core (true ); }
1283+ static const char _data_FX_MODE_FIREWORKS_AR[] PROGMEM = " 🎉 audio Fireworks@,Frequency;!,!;!;12;ix=192,pal=11" ;
12511284
12521285// Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h
12531286uint16_t mode_rain () {
@@ -3157,7 +3190,7 @@ typedef struct Spark {
31573190* POPCORN
31583191* modified from https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Popcorn.h
31593192*/
3160- uint16_t mode_popcorn ( void ) {
3193+ static uint16_t mode_popcorn_core ( bool useaudio ) {
31613194 if (SEGLEN == 1 ) return mode_static ();
31623195 // allocate segment data
31633196 uint16_t strips = SEGMENT.nrOfVStrips ();
@@ -3169,20 +3202,44 @@ uint16_t mode_popcorn(void) {
31693202 bool hasCol2 = SEGCOLOR (2 );
31703203 if (!SEGMENT.check2 ) SEGMENT.fill (hasCol2 ? BLACK : SEGCOLOR (1 ));
31713204
3205+ // WLEDMM init um_data
3206+ um_data_t *um_data;
3207+ if (!usermods.getUMData (&um_data, USERMOD_ID_AUDIOREACTIVE)) {
3208+ // no audio - fallback to standard behaviour
3209+ useaudio = false ;
3210+ um_data = simulateSound (SEGMENT.soundSim ); // dummy
3211+ }
3212+
31723213 struct virtualStrip {
3173- static void runStrip (uint16_t stripNr, Spark* popcorn) {
3214+ static void runStrip (uint16_t stripNr, Spark* popcorn, bool useaudio, um_data_t *um_data ) { // WLEDMM added useaudio and um_data
31743215 float gravity = -0.0001 - (SEGMENT.speed /200000.0 ); // m/s/s
31753216 gravity *= SEGLEN;
31763217
31773218 uint8_t numPopcorn = SEGMENT.intensity *maxNumPopcorn/255 ;
31783219 if (numPopcorn == 0 ) numPopcorn = 1 ;
3220+ // WLEDMM audioreactive vars
3221+ float volumeSmth = *(float *) um_data->u_data [0 ];
3222+ int16_t volumeRaw = *(int16_t *) um_data->u_data [1 ];
3223+ uint8_t samplePeak = *(uint8_t *) um_data->u_data [3 ];
31793224
31803225 for (int i = 0 ; i < numPopcorn; i++) {
31813226 if (popcorn[i].pos >= 0 .0f ) { // if kernel is active, update its position
31823227 popcorn[i].pos += popcorn[i].vel ;
31833228 popcorn[i].vel += gravity;
31843229 } else { // if kernel is inactive, randomly pop it
3185- if (random8 () < 2 ) { // POP!!!
3230+ bool doPopCorn = false ; // WLEDMM allows to inhibit new pops
3231+ // WLEDMM begin
3232+ if (useaudio) {
3233+ if ( (volumeSmth > 1 .0f ) // no pops in silence
3234+ &&((samplePeak > 0 ) || (volumeRaw > 128 )) // try to pop at onsets (our peek detector still sucks)
3235+ &&(random8 () < 4 ) ) // stay somewhat random
3236+ doPopCorn = true ;
3237+ } else {
3238+ if (random8 () < 2 ) doPopCorn = true ; // default POP!!!
3239+ }
3240+ // WLEDMM end
3241+
3242+ if (doPopCorn) { // POP!!!
31863243 popcorn[i].pos = 0 .01f ;
31873244
31883245 uint16_t peakHeight = 128 + random8 (128 ); // 0-255
@@ -3210,12 +3267,16 @@ uint16_t mode_popcorn(void) {
32103267 };
32113268
32123269 for (int stripNr=0 ; stripNr<strips; stripNr++)
3213- virtualStrip::runStrip (stripNr, &popcorn[stripNr * maxNumPopcorn]);
3270+ virtualStrip::runStrip (stripNr, &popcorn[stripNr * maxNumPopcorn], useaudio, um_data); // WLEDMM added useaudio and um_data
32143271
32153272 return FRAMETIME;
32163273}
3274+
3275+ uint16_t mode_popcorn (void ) { return mode_popcorn_core (false ); }
32173276static const char _data_FX_MODE_POPCORN[] PROGMEM = " Popcorn@!,!,,,,,Overlay;!,!,!;!;1.5d;m12=1" ; // bar WLEDMM 1.5d
32183277
3278+ uint16_t mode_popcorn_audio (void ) { return mode_popcorn_core (true ); }
3279+ static const char _data_FX_MODE_POPCORN_AR[] PROGMEM = " 🎉 audio Popcorn@!,!,,,,,Overlay;!,!,!;!;1.5d;m12=1" ; // bar WLEDMM 1.5d
32193280
32203281// values close to 100 produce 5Hz flicker, which looks very candle-y
32213282// Inspired by https://github.com/avanhanegem/ArduinoCandleEffectNeoPixel
@@ -3331,7 +3392,7 @@ typedef struct particle {
33313392 float fragment[STARBURST_MAX_FRAG];
33323393} star;
33333394
3334- uint16_t mode_starburst ( void ) {
3395+ static uint16_t mode_starburst_core ( bool useaudio ) {
33353396 if (SEGLEN == 1 ) return mode_static ();
33363397 uint16_t maxData = FAIR_DATA_PER_SEG; // ESP8266: 256 ESP32: 640
33373398 uint8_t segs = strip.getActiveSegmentsNum ();
@@ -3353,18 +3414,44 @@ uint16_t mode_starburst(void) {
33533414 float particleIgnition = 250 .0f ; // How long to "flash"
33543415 float particleFadeTime = 1500 .0f ; // Fade out time
33553416
3417+ // WLEDMM init um_data
3418+ um_data_t *um_data;
3419+ if (!usermods.getUMData (&um_data, USERMOD_ID_AUDIOREACTIVE)) {
3420+ // no audio - fallback to standard behaviour
3421+ useaudio = false ;
3422+ um_data = simulateSound (SEGMENT.soundSim ); // dummy
3423+ }
3424+ float volumeSmth = *(float *) um_data->u_data [0 ];
3425+ int16_t volumeRaw = *(int16_t *) um_data->u_data [1 ];
3426+ uint8_t samplePeak = *(uint8_t *) um_data->u_data [3 ];
3427+
33563428 for (int j = 0 ; j < numStars; j++)
33573429 {
33583430 // speed to adjust chance of a burst, max is nearly always.
3359- if (random8 ((144 -(SEGMENT.speed >> 1 ))) == 0 && stars[j].birth == 0 )
3431+ bool doNewStar = random8 ((144 -(SEGMENT.speed >> 1 ))) == 0 ; // WLEDMM original spawning trigger
3432+ // WLEDMM begin
3433+ if (useaudio) {
3434+ doNewStar = false ;
3435+ int burstplus = (volumeSmth > 159 )? 96 :0 ; // high volume -> more stars
3436+ if (volumeRaw <= 56 ) burstplus = -64 ; // low volume -> fewer stars
3437+ int birthrate = (144 -(SEGMENT.speed >> 1 )) - burstplus;
3438+ birthrate = constrain (birthrate, 4 , 144 );
3439+ if ( (volumeSmth > 1 .0f ) // no bursts in silence
3440+ && ((samplePeak > 0 ) || (volumeRaw > 48 )) // try to burst with sound
3441+ && (random8 (birthrate) == 0 ) ) // original random rate
3442+ doNewStar = true ;
3443+ }
3444+ // WLEDMM end
3445+
3446+ if (doNewStar && stars[j].birth == 0 ) // WLEDMM
33603447 {
33613448 // Pick a random color and location.
33623449 uint16_t startPos = (SEGLEN > 1 ) ? random16 (SEGLEN-1 ) : 0 ;
33633450 float multiplier = (float )(random8 ())/255.0 * 1.0 ;
33643451
33653452 stars[j].color = CRGB (SEGMENT.color_wheel (random8 ()));
33663453 stars[j].pos = startPos;
3367- stars[j].vel = maxSpeed * (float )(random8 ())/255.0 * multiplier;
3454+ stars[j].vel = maxSpeed * (float )(random8 ())/255 .0f * multiplier;
33683455 stars[j].birth = it;
33693456 stars[j].last = it;
33703457 // more fragments means larger burst effect
@@ -3442,8 +3529,12 @@ uint16_t mode_starburst(void) {
34423529 return FRAMETIME;
34433530}
34443531#undef STARBURST_MAX_FRAG
3532+
3533+ uint16_t mode_starburst (void ) { return mode_starburst_core (false ); }
34453534static const char _data_FX_MODE_STARBURST[] PROGMEM = " Fireworks Starburst@Chance,Fragments,,,,,Overlay;,!;!;;pal=11,m12=0" ;
34463535
3536+ uint16_t mode_starburst_audio (void ) { return mode_starburst_core (true ); }
3537+ static const char _data_FX_MODE_STARBURST_AR[] PROGMEM = " 🔨 audio Fw Starburst@Chance,Fragments,,,,,Overlay;,!;!;;pal=11,m12=0" ;
34473538
34483539/*
34493540 * Exploding fireworks effect
@@ -8336,6 +8427,11 @@ void WS2812FX::setupEffectData() {
83368427 addEffect (FX_MODE_WAVESINS, &mode_wavesins, _data_FX_MODE_WAVESINS);
83378428 addEffect (FX_MODE_ROCKTAVES, &mode_rocktaves, _data_FX_MODE_ROCKTAVES);
83388429
8430+ // --- WLEDSR experimental 1D audio enhanced
8431+ addEffect (FX_MODE_POPCORN_AR, &mode_popcorn_audio, _data_FX_MODE_POPCORN_AR);
8432+ addEffect (FX_MODE_STARBURST_AR, &mode_starburst_audio, _data_FX_MODE_STARBURST_AR);
8433+ addEffect (FX_MODE_FIREWORKS_AR, &mode_fireworks_audio, _data_FX_MODE_FIREWORKS_AR);
8434+
83398435 // --- 2D effects ---
83408436#ifndef WLED_DISABLE_2D
83418437 addEffect (FX_MODE_2DSPACESHIPS, &mode_2Dspaceships, _data_FX_MODE_2DSPACESHIPS);
0 commit comments