From cdd114186713226d2ffb0533e8ca8ff09591bbc2 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 16 Dec 2025 00:28:10 +0100 Subject: [PATCH] post-merge fixes * fx.cpp: replace FastLED inoise() with optimized perlin() functions * minor updates for util.cpp and fcn_declare.h --- wled00/FX.cpp | 77 ++++++++++++++++++++++---------------------- wled00/fcn_declare.h | 10 ++---- wled00/util.cpp | 16 ++++++++- 3 files changed, 56 insertions(+), 47 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 6b465cbf..5f9c42ff 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2364,7 +2364,7 @@ uint16_t mode_fillnoise8() { if (SEGENV.call == 0) SEGENV.step = random16(12345); //CRGB fastled_col; for (int i = 0; i < SEGLEN; i++) { - uint8_t index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN); + uint8_t index = perlin8(i * SEGLEN, SEGENV.step + i * SEGLEN); //fastled_col = ColorFromPalette(SEGPALETTE, index, 255, LINEARBLEND); //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); @@ -2387,7 +2387,7 @@ uint16_t mode_noise16_1() { uint16_t real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm uint16_t real_y = (i + shift_y) * scale; // the y position becomes slowly incremented uint32_t real_z = SEGENV.step; // the z position becomes quickly incremented - uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down + uint8_t noise = perlin16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down uint8_t index = sin8_t(noise * 3); // map LED color based on noise data //fastled_col = ColorFromPalette(SEGPALETTE, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. @@ -2408,7 +2408,7 @@ uint16_t mode_noise16_2() { for (int i = 0; i < SEGLEN; i++) { uint16_t shift_x = SEGENV.step >> 6; // x as a function of time uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field - uint8_t noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down + uint8_t noise = perlin16(real_x, 0, 4223) >> 8; // get the noise data and scale it down uint8_t index = sin8_t(noise * 3); // map led color based on noise data //fastled_col = ColorFromPalette(SEGPALETTE, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. @@ -2432,7 +2432,7 @@ uint16_t mode_noise16_3() { uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions uint32_t real_z = SEGENV.step*8; - uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down + uint8_t noise = perlin16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down uint8_t index = sin8_t(noise * 3); // map led color based on noise data //fastled_col = ColorFromPalette(SEGPALETTE, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. @@ -2450,7 +2450,7 @@ uint16_t mode_noise16_4() { //CRGB fastled_col; uint32_t stp = (strip.now * SEGMENT.speed) >> 7; for (int i = 0; i < SEGLEN; i++) { - int16_t index = inoise16(uint32_t(i) << 12, stp); + int16_t index = perlin16(uint32_t(i) << 12, stp); //fastled_col = ColorFromPalette(SEGPALETTE, index); //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); @@ -4368,7 +4368,7 @@ uint16_t phased_base(uint8_t moder) { // We're making sine wave *phase += SEGMENT.speed/32.0f; // You can change the speed of the wave. AKA SPEED (was .4) for (int i = 0; i < SEGLEN; i++) { - if (moder == 1) modVal = (inoise8(i*10 + i*10) /16); // Let's randomize our mod length with some Perlin noise. + if (moder == 1) modVal = (perlin8(i*10 + i*10) /16); // Let's randomize our mod length with some Perlin noise. uint16_t val = (i+1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that led 0 is used. if (modVal == 0) modVal = 1; val += *phase * (i % modVal +1) /2; // This sets the varying phase change of the waves. By Andrew Tuline. @@ -4439,7 +4439,7 @@ uint16_t mode_noisepal(void) { // Slow noise if (SEGMENT.palette > 0) palettes[0] = SEGPALETTE; for (int i = 0; i < SEGLEN; i++) { - uint8_t index = inoise8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis. + uint8_t index = perlin8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis. color = ColorFromPalette(palettes[0], index, 255, LINEARBLEND); // Use the my own palette. SEGMENT.setPixelColor(i, color.red, color.green, color.blue); } @@ -5057,7 +5057,7 @@ uint16_t mode_perlinmove(void) { if (SEGENV.call == 0) {SEGENV.setUpLeds(); SEGMENT.fill(BLACK);} // WLEDMM use lossless getPixelColor() SEGMENT.fade_out(255-SEGMENT.custom1); for (int i = 0; i < SEGMENT.intensity/16 + 1; i++) { - uint16_t locn = inoise16(strip.now*128/(260-SEGMENT.speed)+i*15000, strip.now*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise. + uint16_t locn = perlin16(strip.now*128/(260-SEGMENT.speed)+i*15000, strip.now*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise. uint16_t pixloc = map(locn, 50*256, 192*256, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over. SEGMENT.setPixelColor(pixloc, SEGMENT.color_from_palette(pixloc%255, false, PALETTE_SOLID_WRAP, 0)); } @@ -5166,7 +5166,7 @@ uint16_t mode_shimmer() { if (SEGMENT.check1) { modVal = (sin16_t((i * SEGMENT.custom2 << 6) + (strip.now * SEGMENT.custom3 << 5)) >> 8) + 128; // sine modulation: regular "Zebra" stripes } else { - modVal = inoise16((i * SEGMENT.custom2 << 7), strip.now * SEGMENT.custom3 << 5) >> 8; // perlin noise modulation + modVal = perlin16((i * SEGMENT.custom2 << 7), strip.now * SEGMENT.custom3 << 5) >> 8; // perlin noise modulation } color = color_fade(color, modVal, true); // dim by modulator value } @@ -5452,7 +5452,7 @@ uint16_t mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline for (int j=0; j < cols; j++) { for (int i=0; i < rows; i++) { - indexx = inoise8(j*yscale*rows/255, i*xscale+strip.now/4); // We're moving along our Perlin map. + indexx = perlin8(j*yscale*rows/255, i*xscale+strip.now/4); // We're moving along our Perlin map. SEGMENT.setPixelColorXY(j, i, ColorFromPalette(pal, min(i*(indexx)>>4, 255U), i*255/cols, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED. } // for i } // for j @@ -6172,11 +6172,11 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have float speed = 0.25f * (1+(SEGMENT.speed>>6)); // get some 2 random moving points - uint8_t x2 = map(inoise8(strip.now * speed, 25355, 685), 0, 255, 0, cols-1); - uint8_t y2 = map(inoise8(strip.now * speed, 355, 11685), 0, 255, 0, rows-1); + uint8_t x2 = map(perlin8(strip.now * speed, 25355, 685), 0, 255, 0, cols-1); + uint8_t y2 = map(perlin8(strip.now * speed, 355, 11685), 0, 255, 0, rows-1); - uint8_t x3 = map(inoise8(strip.now * speed, 55355, 6685), 0, 255, 0, cols-1); - uint8_t y3 = map(inoise8(strip.now * speed, 25355, 22685), 0, 255, 0, rows-1); + uint8_t x3 = map(perlin8(strip.now * speed, 55355, 6685), 0, 255, 0, cols-1); + uint8_t y3 = map(perlin8(strip.now * speed, 25355, 22685), 0, 255, 0, rows-1); // and one Lissajou function uint8_t x1 = beatsin8_t(23 * speed, 0, cols-1); @@ -6232,7 +6232,7 @@ uint16_t mode_2Dnoise(void) { // By Andrew Tuline for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { - uint8_t pixelHue8 = inoise8(x * scale, y * scale, strip.now / (16 - SEGMENT.speed/16)); + uint8_t pixelHue8 = perlin8(x * scale, y * scale, strip.now / (16 - SEGMENT.speed/16)); SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, pixelHue8)); } } @@ -6260,10 +6260,10 @@ uint16_t mode_2DPlasmaball(void) { // By: Stepko https://edito uint_fast32_t t = (strip.now * 8) / (256 - SEGMENT.speed); // optimized to avoid float for (int i = 0; i < cols; i++) { - uint16_t thisVal = inoise8(i * 30, t, t); + uint16_t thisVal = perlin8(i * 30, t, t); uint16_t thisMax = map(thisVal, 0, 255, 0, cols-1); for (int j = 0; j < rows; j++) { - uint16_t thisVal_ = inoise8(t, j * 30, t); + uint16_t thisVal_ = perlin8(t, j * 30, t); uint16_t thisMax_ = map(thisVal_, 0, 255, 0, rows-1); uint16_t x = (i + thisMax_ - cols / 2); uint16_t y = (j + thisMax - cols / 2); @@ -6353,7 +6353,7 @@ uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https SEGENV.step++; SEGMENT.setPixelColorXY(x, y, ColorFromPalette(effectPalette, qsub8( - inoise8((SEGENV.step%2) + x * _scale, y * 16 + SEGENV.step % 16, SEGENV.step / _speed), + perlin8((SEGENV.step%2) + x * _scale, y * 16 + SEGENV.step % 16, SEGENV.step / _speed), fabsf(rows_2 - (float)y) * adjustHeight))); // WLEDMM } } @@ -6488,7 +6488,8 @@ uint16_t mode_2DSunradiation(void) { // By: ldirko https://edi uint8_t someVal = SEGMENT.speed/4; // Was 25. for (int j = 0; j < (rows + 2); j++) { for (int i = 0; i < (cols + 2); i++) { - byte col = (inoise8_raw(i * someVal, j * someVal, t)) / 2; + //byte col = (inoise8_raw(i * someVal, j * someVal, t)) / 2; + byte col = ((int16_t)perlin8(i * someVal, j * someVal, t) - 0x7F) / 3; bump[index++] = col; } } @@ -7262,8 +7263,8 @@ uint16_t mode_2DWaverly(void) { long t = strip.now / 2; for (int i = 0; i < cols; i++) { - //uint16_t thisVal = volumeSmth*SEGMENT.intensity/64 * inoise8(i * 45 , t , t)/64; // WLEDMM back to SR code - unsigned thisVal = unsigned(volumeSmth*SEGMENT.intensity) * inoise8(i * 45 , t , t) / (64*64); // WLEDMM same result but more accurate + //uint16_t thisVal = volumeSmth*SEGMENT.intensity/64 * perlin8(i * 45 , t , t)/64; // WLEDMM back to SR code + unsigned thisVal = unsigned(volumeSmth*SEGMENT.intensity) * perlin8(i * 45 , t , t) / (64*64); // WLEDMM same result but more accurate //int thisMax = map(thisVal, 0, 512, 0, rows); int thisMax = (thisVal * rows) / 512; // WLEDMM same result, just faster @@ -7318,7 +7319,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. uint8_t gravity = 8 - SEGMENT.speed/32; for (int i=0; i 0.85) // hide main "bar" in silence for (int i=0; iSEGLEN/2) maxLen = SEGLEN/2; for (int i=(SEGLEN/2-maxLen); i<(SEGLEN/2+maxLen); i++) { - uint8_t index = inoise8(i*volumeSmth+SEGENV.aux0, SEGENV.aux1+i*volumeSmth); // Get a value from the noise function. I'm using both x and y axis. + uint8_t index = perlin8(i*volumeSmth+SEGENV.aux0, SEGENV.aux1+i*volumeSmth); // Get a value from the noise function. I'm using both x and y axis. SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } @@ -7592,7 +7593,7 @@ uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline. if (SEGENV.call == 0) SEGMENT.fill(BLACK); for (int i = 0; i < SEGLEN; i++) { - uint16_t index = inoise8(i*SEGMENT.speed/64,strip.now*SEGMENT.speed/64*SEGLEN/255); // X location is constant, but we move along the Y at the rate of strip.now. By Andrew Tuline. + uint16_t index = perlin8(i*SEGMENT.speed/64,strip.now*SEGMENT.speed/64*SEGLEN/255); // X location is constant, but we move along the Y at the rate of strip.now. By Andrew Tuline. index = (255 - i*256/SEGLEN) * index/(256-SEGMENT.intensity); // Now we need to scale index so that it gets blacker as we get close to one of the ends. // This is a simple y=mx+b equation that's been scaled. index/128 is another scaling. @@ -7625,7 +7626,7 @@ uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline. if (maxLen >SEGLEN) maxLen = SEGLEN; for (int i=0; i> 8; //WLEDMM SuperSync + uint8_t data = perlin16(noise32_x_MM + ioffset, noise32_y_MM + joffset, noise32_z_MM) >> 8; //WLEDMM SuperSync noise3d[XY(i,j)] = scale8(noise3d[XY(i,j)], smoothness) + scale8(data, 255 - smoothness); } } @@ -9560,7 +9561,7 @@ uint16_t mode_particlefire(void) { if (SEGMENT.call % 10 == 0) SEGENV.aux1++; // move in noise y direction so noise does not repeat as often // add wind force to all particles - int8_t windspeed = ((int16_t)(inoise8(SEGENV.aux0, SEGENV.aux1) - 127) * SEGMENT.custom2) >> 7; + int8_t windspeed = ((int16_t)(perlin8(SEGENV.aux0, SEGENV.aux1) - 127) * SEGMENT.custom2) >> 7; PartSys->applyForce(windspeed, 0); } SEGENV.step++; @@ -9569,7 +9570,7 @@ uint16_t mode_particlefire(void) { if (SEGMENT.call % map(firespeed, 0, 255, 4, 15) == 0) { for (i = 0; i < PartSys->usedParticles; i++) { if (PartSys->particles[i].y < PartSys->maxY / 4) { // do not apply turbulance everywhere -> bottom quarter seems a good balance - int32_t curl = ((int32_t)inoise8(PartSys->particles[i].x, PartSys->particles[i].y, SEGENV.step << 4) - 127); + int32_t curl = ((int32_t)perlin8(PartSys->particles[i].x, PartSys->particles[i].y, SEGENV.step << 4) - 127); PartSys->particles[i].vx += (curl * (firespeed + 10)) >> 9; } } @@ -9786,8 +9787,8 @@ uint16_t mode_particlebox(void) { SEGENV.aux0 -= increment; if (SEGMENT.check1) { // random, use perlin noise - xgravity = ((int16_t)inoise8(SEGENV.aux0) - 127); - ygravity = ((int16_t)inoise8(SEGENV.aux0 + 10000) - 127); + xgravity = ((int16_t)perlin8(SEGENV.aux0) - 127); + ygravity = ((int16_t)perlin8(SEGENV.aux0 + 10000) - 127); // scale the gravity force xgravity = (xgravity * SEGMENT.custom1) / 128; ygravity = (ygravity * SEGMENT.custom1) / 128; @@ -9858,11 +9859,11 @@ uint16_t mode_particleperlin(void) { uint32_t scale = 16 - ((31 - SEGMENT.custom3) >> 1); uint16_t xnoise = PartSys->particles[i].x / scale; // position in perlin noise, scaled by slider uint16_t ynoise = PartSys->particles[i].y / scale; - int16_t baseheight = inoise8(xnoise, ynoise, SEGENV.aux0); // noise value at particle position + int16_t baseheight = perlin8(xnoise, ynoise, SEGENV.aux0); // noise value at particle position PartSys->particles[i].hue = baseheight; // color particles to perlin noise value if (SEGMENT.call % 8 == 0) { // do not apply the force every frame, is too chaotic - int8_t xslope = (baseheight + (int16_t)inoise8(xnoise - 10, ynoise, SEGENV.aux0)); - int8_t yslope = (baseheight + (int16_t)inoise8(xnoise, ynoise - 10, SEGENV.aux0)); + int8_t xslope = (baseheight + (int16_t)perlin8(xnoise - 10, ynoise, SEGENV.aux0)); + int8_t yslope = (baseheight + (int16_t)perlin8(xnoise, ynoise - 10, SEGENV.aux0)); PartSys->applyForce(i, xslope, yslope); } } @@ -11230,7 +11231,7 @@ uint16_t mode_particleBalance(void) { int32_t increment = (SEGMENT.speed >> 6) + 1; SEGENV.aux0 += increment; if (SEGMENT.check3) // random, use perlin noise - xgravity = ((int16_t)inoise8(SEGENV.aux0) - 128); + xgravity = ((int16_t)perlin8(SEGENV.aux0) - 128); else // sinusoidal xgravity = (int16_t)cos8_t(SEGENV.aux0) - 128;//((int32_t)(SEGMENT.custom3 << 2) * cos8(SEGENV.aux0) // scale the force @@ -11609,7 +11610,7 @@ uint16_t mode_particle1DsonicStream(void) { } if (SEGMENT.check1) { // modulate colors by mid frequencies int mids = sqrt16((int)fftResult[5] + (int)fftResult[6] + (int)fftResult[7] + (int)fftResult[8] + (int)fftResult[9] + (int)fftResult[10]); // average the mids, bin 5 is ~500Hz, bin 10 is ~2kHz (see audio_reactive.h) - PartSys->particles[i].hue += (mids * inoise8(PartSys->particles[i].x << 2, SEGMENT.step << 2)) >> 9; // color by perlin noise from mid frequencies + PartSys->particles[i].hue += (mids * perlin8(PartSys->particles[i].x << 2, SEGMENT.step << 2)) >> 9; // color by perlin noise from mid frequencies } } @@ -11697,7 +11698,7 @@ uint16_t mode_particle1DsonicBoom(void) { for (uint32_t i = 0; i < PartSys->usedParticles; i++) { if (SEGMENT.check1) { // modulate colors by mid frequencies int mids = sqrt16((int)fftResult[5] + (int)fftResult[6] + (int)fftResult[7] + (int)fftResult[8] + (int)fftResult[9] + (int)fftResult[10]); // average the mids, bin 5 is ~500Hz, bin 10 is ~2kHz (see audio_reactive.h) - PartSys->particles[i].hue += (mids * inoise8(PartSys->particles[i].x << 2, SEGMENT.step << 2)) >> 9; // color by perlin noise from mid frequencies + PartSys->particles[i].hue += (mids * perlin8(PartSys->particles[i].x << 2, SEGMENT.step << 2)) >> 9; // color by perlin noise from mid frequencies } if (PartSys->particles[i].ttl > 16) { PartSys->particles[i].ttl -= 16; //ttl is linked to brightness, this allows to use higher brightness but still a (very) short lifespan diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 0dd753ca..ac7a8008 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -395,16 +395,10 @@ void userConnected(); void userLoop(); //util.cpp -#ifdef ESP8266 -#define HW_RND_REGISTER RANDOM_REG32 -#else // ESP32 family -#include "soc/wdev_reg.h" -#define HW_RND_REGISTER REG_READ(WDEV_RND_REG) -#endif #define inoise8 perlin8 // fastled legacy alias #define inoise16 perlin16 // fastled legacy alias #define hex2int(a) (((a)>='0' && (a)<='9') ? (a)-'0' : ((a)>='A' && (a)<='F') ? (a)-'A'+10 : ((a)>='a' && (a)<='f') ? (a)-'a'+10 : 0) -int getNumVal(const String* req, uint16_t pos); +int __attribute__((pure)) getNumVal(const String* req, uint16_t pos); void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); @@ -421,7 +415,7 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr); int16_t extractModeDefaults(uint8_t mode, const char *segVar); void checkSettingsPIN(const char *pin); -uint16_t __attribute__((pure)) crc16(const unsigned char* data_p, size_t length); // WLEDMM: added attribute pure +uint16_t __attribute__((pure)) crc16(const unsigned char* data_p, size_t length); // WLEDMM: added attribute pure String computeSHA1(const String& input); String getDeviceId(); uint16_t beatsin88_t(accum88 beats_per_minute_88, uint16_t lowest = 0, uint16_t highest = 65535, uint32_t timebase = 0, uint16_t phase_offset = 0); diff --git a/wled00/util.cpp b/wled00/util.cpp index 91ddf957..c47a7845 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -625,7 +625,7 @@ CRGB getCRGBForBand(int x, uint8_t *fftResult, int pal) { uint8_t get_random_wheel_index(uint8_t pos) { uint8_t r = 0, x = 0, y = 0, d = 0; while (d < 42) { - r = random8(); + r = hw_random8(); x = abs(pos - r); y = 255 - x; d = MIN(x, y); @@ -633,6 +633,19 @@ uint8_t get_random_wheel_index(uint8_t pos) { return r; } +// float version of map() - WLEDMM not used +//float mapf(float x, float in_min, float in_max, float out_min, float out_max) { +// return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +//} + +//uint32_t hashInt(uint32_t s) { // WLEDMM not used +// // borrowed from https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key +// s = ((s >> 16) ^ s) * 0x45d9f3b; +// s = ((s >> 16) ^ s) * 0x45d9f3b; +// return (s >> 16) ^ s; +//} + + // WLEDMM extended "trim string" function to support enumerateLedmaps // The function takes char* as input, and removes all leading and trailing "decorations" like spaces, tabs, line endings, quotes, colons // The conversion is "in place" (destructive). @@ -662,6 +675,7 @@ char *cleanUpName(char *in) { return(in); } + // 32 bit hardware random number generator, inlining uses more code, use hw_random16() if speed is critical (see fcn_declare.h) uint32_t hw_random(uint32_t upperlimit) { uint32_t rnd = hw_random();