Skip to content

Commit 8e0d1cf

Browse files
authored
Merge pull request #103 from MoonModules/audio_enhanced_effects
audio-enhanced standard effects: "audio Fireworks", "audio Fw Starburst", "audio Popcorn" (back-ported from WLED-SR)
2 parents faa62a9 + 8e996b0 commit 8e0d1cf

File tree

3 files changed

+116
-12
lines changed

3 files changed

+116
-12
lines changed

wled00/FX.cpp

Lines changed: 106 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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); }
12491280
static 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
12531286
uint16_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); }
32173276
static 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); }
34453534
static 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);

wled00/FX.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,15 @@ void strip_wait_until_idle(String whoCalledMe); // WLEDMM implemented in FX_fcn.
336336
#define FX_MODE_ARTIFX 187 //WLEDMM ARTIFX
337337
#define FX_MODE_PARTYJERK 188
338338

339-
#define MODE_COUNT 189
339+
// Experimental Audioresponsive modes from WLED-SR
340+
// #define FX_MODE_3DSphereMove 189 // experimental WLED-SR "cube" mode
341+
#define FX_MODE_POPCORN_AR 190 // WLED-SR audioreactive popcorn
342+
// #define FX_MODE_MULTI_COMET_AR 191 // WLED-SR audioreactive multi-comet
343+
#define FX_MODE_STARBURST_AR 192 // WLED-SR audioreactive fireworks starburst
344+
// #define FX_MODE_PALETTE_AR 193 // WLED-SR audioreactive palette
345+
#define FX_MODE_FIREWORKS_AR 194 // WLED-SR audioreactive fireworks 1D
346+
347+
#define MODE_COUNT 195
340348

341349
typedef enum mapping1D2D {
342350
M12_Pixels = 0,

wled00/wled.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99

1010
// version code in format yymmddb (b = daily build)
11-
#define VERSION 2312290
11+
#define VERSION 2312310
1212

1313
// WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED.
1414
#define _MoonModules_WLED_

0 commit comments

Comments
 (0)