From 7b855c851d7824596557d4444796c2c3aec6356c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 5 Oct 2024 12:29:31 +0200 Subject: [PATCH 1/7] Added integer based `sin()/cos()` functions, changed all trig functions to wled_math - `sin16_t() / cos16_t()` are faster and more accurate than fastled versions - `sin_approx() / cos_approx()` are float wrappers for `sin16_t() / cos16_t()` and are accurate enough to replace `sinf()/cosf()` - `atan2()` is used only in octopus to calculate center offset, new approximated version saves flash - `tan(), atan(), asin(), acos(), floor(), fmod()` are used only for sunrise/sunset calculation, using wled_math version saves flash - `beatsinx()` replacements are to make use of new `sin16_t()/sin8_t()` functions to reduce flash size - Extensively tested surnise/sunset calculation: deviation is 1min. max - Tested some of the relevant FX and found no visual difference: Julia, 2D Drift, Drift Rose, Ghost rider, Rotozoomer, Palette, Arc 1D expansion - total flash savings: 7.4k --- usermods/Analog_Clock/Analog_Clock.h | 4 +- wled00/FX.cpp | 258 +++++++++++++-------------- wled00/fcn_declare.h | 53 +++--- wled00/util.cpp | 41 ++++- wled00/wled_math.cpp | 89 ++++++++- 5 files changed, 288 insertions(+), 157 deletions(-) diff --git a/usermods/Analog_Clock/Analog_Clock.h b/usermods/Analog_Clock/Analog_Clock.h index 596f0acb3b..9d82f7670c 100644 --- a/usermods/Analog_Clock/Analog_Clock.h +++ b/usermods/Analog_Clock/Analog_Clock.h @@ -102,9 +102,9 @@ class AnalogClockUsermod : public Usermod { void secondsEffectSineFade(int16_t secondLed, Toki::Time const& time) { uint32_t ms = time.ms % 1000; - uint8_t b0 = (cos8(ms * 64 / 1000) - 128) * 2; + uint8_t b0 = (cos8_t(ms * 64 / 1000) - 128) * 2; setPixelColor(secondLed, gamma32(scale32(secondColor, b0))); - uint8_t b1 = (sin8(ms * 64 / 1000) - 128) * 2; + uint8_t b1 = (sin8_t(ms * 64 / 1000) - 128) * 2; setPixelColor(inc(secondLed, 1, secondsSegment), gamma32(scale32(secondColor, b1))); } diff --git a/wled00/FX.cpp b/wled00/FX.cpp index f3e82275c6..338dd2df90 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -39,7 +39,7 @@ // effect utility functions uint8_t sin_gap(uint16_t in) { if (in & 0x100) return 0; - return sin8(in + 192); // correct phase shift of sine so that it starts and stops at 0 + return sin8_t(in + 192); // correct phase shift of sine so that it starts and stops at 0 } uint16_t triwave16(uint16_t in) { @@ -349,7 +349,7 @@ uint16_t mode_breath(void) { counter = (counter >> 2) + (counter >> 4); //0-16384 + 0-2048 if (counter < 16384) { if (counter > 8192) counter = 8192 - (counter - 8192); - var = sin16(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 + var = sin16_t(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 } unsigned lum = 30 + var; @@ -531,7 +531,7 @@ static uint16_t running_base(bool saw, bool dual=false) { } a = 255 - a; } - uint8_t s = dual ? sin_gap(a) : sin8(a); + uint8_t s = dual ? sin_gap(a) : sin8_t(a); uint32_t ca = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s); if (dual) { unsigned b = (SEGLEN-1-i)*x_scale - counter; @@ -1893,16 +1893,16 @@ uint16_t mode_pride_2015(void) { unsigned sPseudotime = SEGENV.step; unsigned sHue16 = SEGENV.aux0; - uint8_t sat8 = beatsin88( 87, 220, 250); - uint8_t brightdepth = beatsin88( 341, 96, 224); - unsigned brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); - unsigned msmultiplier = beatsin88(147, 23, 60); + uint8_t sat8 = beatsin88_t( 87, 220, 250); + uint8_t brightdepth = beatsin88_t( 341, 96, 224); + unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256)); + unsigned msmultiplier = beatsin88_t(147, 23, 60); unsigned hue16 = sHue16;//gHue * 256; - unsigned hueinc16 = beatsin88(113, 1, 3000); + unsigned hueinc16 = beatsin88_t(113, 1, 3000); sPseudotime += duration * msmultiplier; - sHue16 += duration * beatsin88( 400, 5,9); + sHue16 += duration * beatsin88_t( 400, 5,9); unsigned brightnesstheta16 = sPseudotime; for (unsigned i = 0 ; i < SEGLEN; i++) { @@ -1910,7 +1910,7 @@ uint16_t mode_pride_2015(void) { uint8_t hue8 = hue16 >> 8; brightnesstheta16 += brightnessthetainc16; - unsigned b16 = sin16( brightnesstheta16 ) + 32768; + unsigned b16 = sin16_t( brightnesstheta16 ) + 32768; unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; @@ -1935,7 +1935,7 @@ uint16_t mode_juggle(void) { CRGB fastled_col; byte dothue = 0; for (int i = 0; i < 8; i++) { - int index = 0 + beatsin88((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); + int index = 0 + beatsin88_t((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); fastled_col = CRGB(SEGMENT.getPixelColor(index)); fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):ColorFromPalette(SEGPALETTE, dothue, 255); SEGMENT.setPixelColor(index, fastled_col); @@ -1956,8 +1956,8 @@ uint16_t mode_palette() { constexpr mathType maxAngle = 0x8000; constexpr mathType staticRotationScale = 256; constexpr mathType animatedRotationScale = 1; - constexpr int16_t (*sinFunction)(uint16_t) = &sin16; - constexpr int16_t (*cosFunction)(uint16_t) = &cos16; + constexpr int16_t (*sinFunction)(uint16_t) = &sin16_t; + constexpr int16_t (*cosFunction)(uint16_t) = &cos16_t; #else using mathType = float; using wideMathType = float; @@ -2141,15 +2141,15 @@ uint16_t mode_colorwaves() { unsigned sPseudotime = SEGENV.step; unsigned sHue16 = SEGENV.aux0; - unsigned brightdepth = beatsin88(341, 96, 224); - unsigned brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); - unsigned msmultiplier = beatsin88(147, 23, 60); + unsigned brightdepth = beatsin88_t(341, 96, 224); + unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256)); + unsigned msmultiplier = beatsin88_t(147, 23, 60); unsigned hue16 = sHue16;//gHue * 256; - unsigned hueinc16 = beatsin88(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues + unsigned hueinc16 = beatsin88_t(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues sPseudotime += duration * msmultiplier; - sHue16 += duration * beatsin88(400, 5, 9); + sHue16 += duration * beatsin88_t(400, 5, 9); unsigned brightnesstheta16 = sPseudotime; for (int i = 0 ; i < SEGLEN; i++) { @@ -2163,7 +2163,7 @@ uint16_t mode_colorwaves() { } brightnesstheta16 += brightnessthetainc16; - unsigned b16 = sin16(brightnesstheta16) + 32768; + unsigned b16 = sin16_t(brightnesstheta16) + 32768; unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; @@ -2182,7 +2182,7 @@ static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!"; // colored stripes pulsing at a defined Beats-Per-Minute (BPM) uint16_t mode_bpm() { uint32_t stp = (strip.now / 20) & 0xFF; - uint8_t beat = beatsin8(SEGMENT.speed, 64, 255); + uint8_t beat = beatsin8_t(SEGMENT.speed, 64, 255); for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10))); } @@ -2198,7 +2198,7 @@ uint16_t mode_fillnoise8() { unsigned index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } - SEGENV.step += beatsin8(SEGMENT.speed, 1, 6); //10,1,4 + SEGENV.step += beatsin8_t(SEGMENT.speed, 1, 6); //10,1,4 return FRAMETIME; } @@ -2210,13 +2210,13 @@ uint16_t mode_noise16_1() { SEGENV.step += (1 + SEGMENT.speed/16); for (int i = 0; i < SEGLEN; i++) { - unsigned shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm + unsigned shift_x = beatsin8_t(11); // the x position of the noise field swings @ 17 bpm unsigned shift_y = SEGENV.step/42; // the y position becomes slowly incremented unsigned real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm unsigned real_y = (i + shift_y) * scale; // the y position becomes slowly incremented uint32_t real_z = SEGENV.step; // the z position becomes quickly incremented unsigned noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down - unsigned index = sin8(noise * 3); // map LED color based on noise data + unsigned index = sin8_t(noise * 3); // map LED color based on noise data SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } @@ -2234,7 +2234,7 @@ uint16_t mode_noise16_2() { unsigned 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 unsigned noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down - unsigned index = sin8(noise * 3); // map led color based on noise data + unsigned index = sin8_t(noise * 3); // map led color based on noise data SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, noise)); } @@ -2255,7 +2255,7 @@ uint16_t mode_noise16_3() { uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions uint32_t real_z = SEGENV.step*8; unsigned noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down - unsigned index = sin8(noise * 3); // map led color based on noise data + unsigned index = sin8_t(noise * 3); // map led color based on noise data SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, noise)); } @@ -2335,13 +2335,13 @@ static const char _data_FX_MODE_COLORTWINKLE[] PROGMEM = "Colortwinkles@Fade spe //Calm effect, like a lake at night uint16_t mode_lake() { unsigned sp = SEGMENT.speed/10; - int wave1 = beatsin8(sp +2, -64,64); - int wave2 = beatsin8(sp +1, -64,64); - int wave3 = beatsin8(sp +2, 0,80); + int wave1 = beatsin8_t(sp +2, -64,64); + int wave2 = beatsin8_t(sp +1, -64,64); + int wave3 = beatsin8_t(sp +2, 0,80); for (int i = 0; i < SEGLEN; i++) { - int index = cos8((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; + int index = cos8_t((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; uint8_t lum = (index > wave3) ? index - wave3 : 0; SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, 0, lum)); } @@ -2514,7 +2514,7 @@ static uint16_t ripple_base() { propI /= 2; unsigned cx = rippleorigin >> 8; unsigned cy = rippleorigin & 0xFF; - unsigned mag = scale8(sin8((propF>>2)), amp); + unsigned mag = scale8(sin8_t((propF>>2)), amp); if (propI > 0) SEGMENT.drawCircle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag), true); } else #endif @@ -2581,7 +2581,7 @@ static CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) unsigned ticks = ms / SEGENV.aux0; unsigned fastcycle8 = ticks; unsigned slowcycle16 = (ticks >> 8) + salt; - slowcycle16 += sin8(slowcycle16); + slowcycle16 += sin8_t(slowcycle16); slowcycle16 = (slowcycle16 * 2053) + 1384; unsigned slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8); @@ -3152,7 +3152,7 @@ static const char _data_FX_MODE_ROLLINGBALLS[] PROGMEM = "Rolling Balls@!,# of b static uint16_t sinelon_base(bool dual, bool rainbow=false) { if (SEGLEN == 1) return mode_static(); SEGMENT.fade_out(SEGMENT.intensity); - unsigned pos = beatsin16(SEGMENT.speed/10,0,SEGLEN-1); + unsigned pos = beatsin16_t(SEGMENT.speed/10,0,SEGLEN-1); if (SEGENV.call == 0) SEGENV.aux0 = pos; uint32_t color1 = SEGMENT.color_from_palette(pos, true, false, 0); uint32_t color2 = SEGCOLOR(2); @@ -3868,13 +3868,13 @@ uint16_t mode_plasma(void) { if (SEGENV.call == 0) { SEGENV.aux0 = random8(0,2); // add a bit of randomness } - unsigned thisPhase = beatsin8(6+SEGENV.aux0,-64,64); - unsigned thatPhase = beatsin8(7+SEGENV.aux0,-64,64); + unsigned thisPhase = beatsin8_t(6+SEGENV.aux0,-64,64); + unsigned thatPhase = beatsin8_t(7+SEGENV.aux0,-64,64); for (unsigned i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows: unsigned colorIndex = cubicwave8((i*(2+ 3*(SEGMENT.speed >> 5))+thisPhase) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change. - + cos8((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. - unsigned thisBright = qsub8(colorIndex, beatsin8(7,0, (128 - (SEGMENT.intensity>>1)))); + + cos8_t((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. + unsigned thisBright = qsub8(colorIndex, beatsin8_t(7,0, (128 - (SEGMENT.intensity>>1)))); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0, thisBright)); } @@ -4001,10 +4001,10 @@ static CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, u unsigned wavescale_half = (wavescale >> 1) + 20; waveangle += ((120 + SEGMENT.intensity) * i); //original 250 * i - unsigned s16 = sin16(waveangle) + 32768; + unsigned s16 = sin16_t(waveangle) + 32768; unsigned cs = scale16(s16, wavescale_half) + wavescale_half; ci += (cs * i); - unsigned sindex16 = sin16(ci) + 32768; + unsigned sindex16 = sin16_t(ci) + 32768; unsigned sindex8 = scale16(sindex16, 240); return ColorFromPalette(p, sindex8, bri, LINEARBLEND); } @@ -4036,34 +4036,34 @@ uint16_t mode_pacifica() uint64_t deltat = (strip.now >> 2) + ((strip.now * SEGMENT.speed) >> 7); strip.now = deltat; - unsigned speedfactor1 = beatsin16(3, 179, 269); - unsigned speedfactor2 = beatsin16(4, 179, 269); + unsigned speedfactor1 = beatsin16_t(3, 179, 269); + unsigned speedfactor2 = beatsin16_t(4, 179, 269); uint32_t deltams1 = (deltams * speedfactor1) / 256; uint32_t deltams2 = (deltams * speedfactor2) / 256; uint32_t deltams21 = (deltams1 + deltams2) / 2; - sCIStart1 += (deltams1 * beatsin88(1011,10,13)); - sCIStart2 -= (deltams21 * beatsin88(777,8,11)); - sCIStart3 -= (deltams1 * beatsin88(501,5,7)); - sCIStart4 -= (deltams2 * beatsin88(257,4,6)); + sCIStart1 += (deltams1 * beatsin88_t(1011,10,13)); + sCIStart2 -= (deltams21 * beatsin88_t(777,8,11)); + sCIStart3 -= (deltams1 * beatsin88_t(501,5,7)); + sCIStart4 -= (deltams2 * beatsin88_t(257,4,6)); SEGENV.aux0 = sCIStart1; SEGENV.aux1 = sCIStart2; SEGENV.step = sCIStart4; SEGENV.step = (SEGENV.step << 16) + sCIStart3; // Clear out the LED array to a dim background blue-green //SEGMENT.fill(132618); - unsigned basethreshold = beatsin8( 9, 55, 65); + unsigned basethreshold = beatsin8_t( 9, 55, 65); unsigned wave = beat8( 7 ); for (int i = 0; i < SEGLEN; i++) { CRGB c = CRGB(2, 6, 10); // Render each of four layers, with different scales and speeds, that vary over time - c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0-beat16(301)); - c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16(4, 6 * 256, 9 * 256), beatsin8(17, 40, 80), beat16(401)); - c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8(9, 10,38) , 0-beat16(503)); - c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8(8, 10,28) , beat16(601)); + c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16_t(3, 11 * 256, 14 * 256), beatsin8_t(10, 70, 130), 0-beat16(301)); + c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16_t(4, 6 * 256, 9 * 256), beatsin8_t(17, 40, 80), beat16(401)); + c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8_t(9, 10,38) , 0-beat16(503)); + c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8_t(8, 10,28) , beat16(601)); // Add extra 'white' to areas where the four layers of light have lined up brightly - unsigned threshold = scale8( sin8( wave), 20) + basethreshold; + unsigned threshold = scale8( sin8_t( wave), 20) + basethreshold; wave += 7; unsigned l = c.getAverageLight(); if (l > threshold) { @@ -4187,7 +4187,7 @@ uint16_t mode_twinkleup(void) { // A very short twinkle routine for (int i = 0; i < SEGLEN; i++) { unsigned ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work. - unsigned pixBri = sin8(ranstart + 16 * strip.now/(256-SEGMENT.speed)); + unsigned pixBri = sin8_t(ranstart + 16 * strip.now/(256-SEGMENT.speed)); if (random8() > SEGMENT.intensity) pixBri = 0; SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(random8()+strip.now/100, false, PALETTE_SOLID_WRAP, 0), pixBri)); } @@ -4230,7 +4230,7 @@ uint16_t mode_noisepal(void) { // Slow noise SEGMENT.setPixelColor(i, color.red, color.green, color.blue); } - SEGENV.aux0 += beatsin8(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. + SEGENV.aux0 += beatsin8_t(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. return FRAMETIME; } @@ -4312,7 +4312,7 @@ uint16_t mode_chunchun(void) for (unsigned i = 0; i < numBirds; i++) { counter -= span; - unsigned megumin = sin16(counter) + 0x8000; + unsigned megumin = sin16_t(counter) + 0x8000; unsigned bird = uint32_t(megumin * SEGLEN) >> 16; uint32_t c = SEGMENT.color_from_palette((i * 255)/ numBirds, false, false, 0); // no palette wrapping bird = constrain(bird, 0U, SEGLEN-1U); @@ -4481,7 +4481,7 @@ uint16_t mode_washing_machine(void) { SEGENV.step += (speed * 2048) / (512 - SEGMENT.speed); for (int i = 0; i < SEGLEN; i++) { - uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); + uint8_t col = sin8_t(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(col, false, PALETTE_SOLID_WRAP, 3)); } @@ -4837,8 +4837,8 @@ static const char _data_FX_MODE_PERLINMOVE[] PROGMEM = "Perlin Move@!,# of pixel uint16_t mode_wavesins(void) { for (int i = 0; i < SEGLEN; i++) { - uint8_t bri = sin8(strip.now/4 + i * SEGMENT.intensity); - uint8_t index = beatsin8(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider + uint8_t bri = sin8_t(strip.now/4 + i * SEGMENT.intensity); + uint8_t index = beatsin8_t(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider //SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, index, bri, LINEARBLEND)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, bri)); } @@ -4860,9 +4860,9 @@ uint16_t mode_FlowStripe(void) { for (int i = 0; i < SEGLEN; i++) { int c = (abs(i - hl) / hl) * 127; - c = sin8(c); - c = sin8(c / 2 + t); - byte b = sin8(c + t/8); + c = sin8_t(c); + c = sin8_t(c / 2 + t); + byte b = sin8_t(c + t/8); SEGMENT.setPixelColor(i, CHSV(b + hue, 255, 255)); } @@ -4889,14 +4889,14 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma unsigned long t = strip.now/128; // timebase // outer stars for (size_t i = 0; i < 8; i++) { - x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); - y = beatsin8(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i); + x = beatsin8_t(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); + y = beatsin8_t(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i); SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(i*32, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255)); } // inner stars for (size_t i = 0; i < 4; i++) { - x = beatsin8(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i); - y = beatsin8(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i); + x = beatsin8_t(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i); + y = beatsin8_t(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i); SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(255-i*64, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255)); } // central white dot @@ -4930,10 +4930,10 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so SEGENV.aux0++; // hue SEGMENT.fadeToBlackBy(40); for (size_t i = 0; i < numLines; i++) { - byte x1 = beatsin8(2 + SEGMENT.speed/16, 0, (cols - 1)); - byte x2 = beatsin8(1 + SEGMENT.speed/16, 0, (rows - 1)); - byte y1 = beatsin8(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24); - byte y2 = beatsin8(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); + byte x1 = beatsin8_t(2 + SEGMENT.speed/16, 0, (cols - 1)); + byte x2 = beatsin8_t(1 + SEGMENT.speed/16, 0, (rows - 1)); + byte y1 = beatsin8_t(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24); + byte y2 = beatsin8_t(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); CRGB color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND); byte xsteps = abs8(x1 - y1) + 1; @@ -4972,8 +4972,8 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa SEGMENT.fadeToBlackBy(64); for (int i = 0; i < cols; i++) { - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10+128), LINEARBLEND)); } SEGMENT.blur(SEGMENT.intensity>>3); @@ -5002,8 +5002,8 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma SEGMENT.fadeToBlackBy(135); for (int i = 0; i < rows; i++) { - int x = beatsin8(speeds, 0, cols - 1, 0, i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, i * freq + 128); - int x1 = beatsin8(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); + int x = beatsin8_t(speeds, 0, cols - 1, 0, i * freq) + beatsin8_t(speeds - 7, 0, cols - 1, 0, i * freq + 128); + int x1 = beatsin8_t(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8_t(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); unsigned hue = (i * 128 / rows) + ms; // skip every 4th row every now and then (fade it more) if ((i + ms / 8) & 3) { @@ -5104,9 +5104,9 @@ uint16_t mode_2DFrizzles(void) { // By: Stepko https://editor.so SEGMENT.fadeToBlackBy(16); for (size_t i = 8; i > 0; i--) { - SEGMENT.addPixelColorXY(beatsin8(SEGMENT.speed/8 + i, 0, cols - 1), - beatsin8(SEGMENT.intensity/8 - i, 0, rows - 1), - ColorFromPalette(SEGPALETTE, beatsin8(12, 0, 255), 255, LINEARBLEND)); + SEGMENT.addPixelColorXY(beatsin8_t(SEGMENT.speed/8 + i, 0, cols - 1), + beatsin8_t(SEGMENT.intensity/8 - i, 0, rows - 1), + ColorFromPalette(SEGPALETTE, beatsin8_t(12, 0, 255), 255, LINEARBLEND)); } SEGMENT.blur(SEGMENT.custom1>>3); @@ -5238,7 +5238,7 @@ uint16_t mode_2DHiphotic() { // By: ldirko https://edit for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(sin8(cos8(x * SEGMENT.speed/16 + a / 3) + sin8(y * SEGMENT.intensity/16 + a / 4) + a), false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(sin8_t(cos8_t(x * SEGMENT.speed/16 + a / 3) + sin8_t(y * SEGMENT.intensity/16 + a / 4) + a), false, PALETTE_SOLID_WRAP, 0)); } } @@ -5378,10 +5378,10 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline //for (int i=0; i < 4*(cols+rows); i ++) { for (int i=0; i < 256; i ++) { - //float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f; - //float ylocn = float(cos8(now/4+i*2)) / 255.0f; - uint_fast8_t xlocn = sin8(phase/2 + (i*SEGMENT.speed)/32); - uint_fast8_t ylocn = cos8(phase/2 + i*2); + //float xlocn = float(sin8_t(now/4+i*(SEGMENT.speed>>5))) / 255.0f; + //float ylocn = float(cos8_t(now/4+i*2)) / 255.0f; + uint_fast8_t xlocn = sin8_t(phase/2 + (i*SEGMENT.speed)/32); + uint_fast8_t ylocn = cos8_t(phase/2 + i*2); xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "(2* ..... +1) /2" for proper rounding ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 1" is needed to avoid div/0 in map() SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); @@ -5481,8 +5481,8 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have int y3 = map(inoise8(strip.now * speed, 25355, 22685), 0, 255, 0, rows-1); // and one Lissajou function - int x1 = beatsin8(23 * speed, 0, cols-1); - int y1 = beatsin8(28 * speed, 0, rows-1); + int x1 = beatsin8_t(23 * speed, 0, cols-1); + int y1 = beatsin8_t(28 * speed, 0, rows-1); for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { @@ -5647,7 +5647,7 @@ uint16_t mode_2DPulser(void) { // By: ldirko https://edi SEGMENT.fadeToBlackBy(8 - (SEGMENT.intensity>>5)); uint32_t a = strip.now / (18 - SEGMENT.speed / 16); int x = (a / 14) % cols; - int y = map((sin8(a * 5) + sin8(a * 4) + sin8(a * 2)), 0, 765, rows-1, 0); + int y = map((sin8_t(a * 5) + sin8_t(a * 4) + sin8_t(a * 2)), 0, 765, rows-1, 0); SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, map(y, 0, rows-1, 0, 255), 255, LINEARBLEND)); SEGMENT.blur(SEGMENT.intensity>>4); @@ -5673,10 +5673,10 @@ uint16_t mode_2DSindots(void) { // By: ldirko http SEGMENT.fadeToBlackBy(SEGMENT.custom1>>3); byte t1 = strip.now / (257 - SEGMENT.speed); // 20; - byte t2 = sin8(t1) / 4 * 2; + byte t2 = sin8_t(t1) / 4 * 2; for (int i = 0; i < 13; i++) { - int x = sin8(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! - int y = sin8(t2 + i * SEGMENT.intensity/8)*(rows-1)/255; // max index now 255x15/255=15! + int x = sin8_t(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! + int y = sin8_t(t2 + i * SEGMENT.intensity/8)*(rows-1)/255; // max index now 255x15/255=15! SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, i * 255 / 13, 255, LINEARBLEND)); } SEGMENT.blur(SEGMENT.custom2>>3); @@ -5703,12 +5703,12 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g SEGMENT.blur(SEGMENT.custom3>>1); // Use two out-of-sync sine waves - int i = beatsin8(19, kBorderWidth, cols-kBorderWidth); - int j = beatsin8(22, kBorderWidth, cols-kBorderWidth); - int k = beatsin8(17, kBorderWidth, cols-kBorderWidth); - int m = beatsin8(18, kBorderWidth, rows-kBorderWidth); - int n = beatsin8(15, kBorderWidth, rows-kBorderWidth); - int p = beatsin8(20, kBorderWidth, rows-kBorderWidth); + int i = beatsin8_t(19, kBorderWidth, cols-kBorderWidth); + int j = beatsin8_t(22, kBorderWidth, cols-kBorderWidth); + int k = beatsin8_t(17, kBorderWidth, cols-kBorderWidth); + int m = beatsin8_t(18, kBorderWidth, rows-kBorderWidth); + int n = beatsin8_t(15, kBorderWidth, rows-kBorderWidth); + int p = beatsin8_t(20, kBorderWidth, rows-kBorderWidth); SEGMENT.addPixelColorXY(i, m, ColorFromPalette(SEGPALETTE, strip.now/29, 255, LINEARBLEND)); SEGMENT.addPixelColorXY(j, n, ColorFromPalette(SEGPALETTE, strip.now/41, 255, LINEARBLEND)); @@ -5784,19 +5784,19 @@ uint16_t mode_2Dtartan(void) { // By: Elliott Kember https://editor.so uint8_t hue, bri; size_t intensity; - int offsetX = beatsin16(3, -360, 360); - int offsetY = beatsin16(2, -360, 360); + int offsetX = beatsin16_t(3, -360, 360); + int offsetY = beatsin16_t(2, -360, 360); int sharpness = SEGMENT.custom3 / 8; // 0-3 for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - hue = x * beatsin16(10, 1, 10) + offsetY; - intensity = bri = sin8(x * SEGMENT.speed/2 + offsetX); + hue = x * beatsin16_t(10, 1, 10) + offsetY; + intensity = bri = sin8_t(x * SEGMENT.speed/2 + offsetX); for (int i=0; i>= 8*sharpness; SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND)); hue = y * 3 + offsetX; - intensity = bri = sin8(y * SEGMENT.intensity/2 + offsetY); + intensity = bri = sin8_t(y * SEGMENT.intensity/2 + offsetY); for (int i=0; i>= 8*sharpness; SEGMENT.addPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND)); @@ -5831,9 +5831,9 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht SEGMENT.move(SEGENV.aux0, 1); for (size_t i = 0; i < 8; i++) { - int x = beatsin8(12 + i, 2, cols - 3); - int y = beatsin8(15 + i, 2, rows - 3); - CRGB color = ColorFromPalette(SEGPALETTE, beatsin8(12 + i, 0, 255), 255); + int x = beatsin8_t(12 + i, 2, cols - 3); + int y = beatsin8_t(15 + i, 2, rows - 3); + CRGB color = ColorFromPalette(SEGPALETTE, beatsin8_t(12 + i, 0, 255), 255); SEGMENT.addPixelColorXY(x, y, color); if (cols > 24 || rows > 24) { SEGMENT.addPixelColorXY(x+1, y, color); @@ -6229,8 +6229,8 @@ uint16_t mode_2Ddriftrose(void) { SEGMENT.fadeToBlackBy(32+(SEGMENT.speed>>3)); for (size_t i = 1; i < 37; i++) { float angle = radians(i * 10); - uint32_t x = (CX + (sin_t(angle) * (beatsin8(i, 0, L*2)-L))) * 255.f; - uint32_t y = (CY + (cos_t(angle) * (beatsin8(i, 0, L*2)-L))) * 255.f; + uint32_t x = (CX + (sin_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f; + uint32_t y = (CY + (cos_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f; SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255)); } SEGMENT.blur(SEGMENT.intensity>>4); @@ -6426,8 +6426,8 @@ uint16_t mode_2DSwirl(void) { SEGMENT.blur(SEGMENT.custom1); - int i = beatsin8( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); - int j = beatsin8( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); + int i = beatsin8_t( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); + int j = beatsin8_t( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); int ni = (cols - 1) - i; int nj = (cols - 1) - j; @@ -6639,7 +6639,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. for (size_t i=0; ithisphase += beatsin8(6,-4,4); // You can change direction and speed individually. - plasmoip->thatphase += beatsin8(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. + plasmoip->thisphase += beatsin8_t(6,-4,4); // You can change direction and speed individually. + plasmoip->thatphase += beatsin8_t(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows. // updated, similar to "plasma" effect - softhack007 uint8_t thisbright = cubicwave8(((i*(1 + (3*SEGMENT.speed/32)))+plasmoip->thisphase) & 0xFF)/2; - thisbright += cos8(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. + thisbright += cos8_t(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. uint8_t colorIndex=thisbright; if (volumeSmth * SEGMENT.intensity / 64 < thisbright) {thisbright = 0;} @@ -7280,7 +7280,7 @@ uint16_t mode_rocktaves(void) { // Rocktaves. Same note from eac frTemp -= 132.0f; // This should give us a base musical note of C3 frTemp = fabsf(frTemp * 2.1f); // Fudge factors to compress octave range starting at 0 and going to 255; - unsigned i = map(beatsin8(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1); + unsigned i = map(beatsin8_t(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1); i = constrain(i, 0U, SEGLEN-1U); SEGMENT.addPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette((uint8_t)frTemp, false, PALETTE_SOLID_WRAP, 0), volTemp)); @@ -7567,12 +7567,12 @@ uint16_t mode_2Ddistortionwaves() { unsigned a2 = a/2; unsigned a3 = a/3; - unsigned cx = beatsin8(10-speed,0,cols-1)*scale; - unsigned cy = beatsin8(12-speed,0,rows-1)*scale; - unsigned cx1 = beatsin8(13-speed,0,cols-1)*scale; - unsigned cy1 = beatsin8(15-speed,0,rows-1)*scale; - unsigned cx2 = beatsin8(17-speed,0,cols-1)*scale; - unsigned cy2 = beatsin8(14-speed,0,rows-1)*scale; + unsigned cx = beatsin8_t(10-speed,0,cols-1)*scale; + unsigned cy = beatsin8_t(12-speed,0,rows-1)*scale; + unsigned cx1 = beatsin8_t(13-speed,0,cols-1)*scale; + unsigned cy1 = beatsin8_t(15-speed,0,rows-1)*scale; + unsigned cx2 = beatsin8_t(17-speed,0,cols-1)*scale; + unsigned cy2 = beatsin8_t(14-speed,0,rows-1)*scale; unsigned xoffs = 0; for (int x = 0; x < cols; x++) { @@ -7582,17 +7582,17 @@ uint16_t mode_2Ddistortionwaves() { for (int y = 0; y < rows; y++) { yoffs += scale; - byte rdistort = cos8((cos8(((x<<3)+a )&255)+cos8(((y<<3)-a2)&255)+a3 )&255)>>1; - byte gdistort = cos8((cos8(((x<<3)-a2)&255)+cos8(((y<<3)+a3)&255)+a+32 )&255)>>1; - byte bdistort = cos8((cos8(((x<<3)+a3)&255)+cos8(((y<<3)-a) &255)+a2+64)&255)>>1; + byte rdistort = cos8_t((cos8_t(((x<<3)+a )&255)+cos8_t(((y<<3)-a2)&255)+a3 )&255)>>1; + byte gdistort = cos8_t((cos8_t(((x<<3)-a2)&255)+cos8_t(((y<<3)+a3)&255)+a+32 )&255)>>1; + byte bdistort = cos8_t((cos8_t(((x<<3)+a3)&255)+cos8_t(((y<<3)-a) &255)+a2+64)&255)>>1; byte valueR = rdistort+ w* (a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 )); byte valueG = gdistort+ w* (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 )); byte valueB = bdistort+ w* (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 )); - valueR = gamma8(cos8(valueR)); - valueG = gamma8(cos8(valueG)); - valueB = gamma8(cos8(valueB)); + valueR = gamma8(cos8_t(valueR)); + valueG = gamma8(cos8_t(valueG)); + valueB = gamma8(cos8_t(valueB)); SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0)); } @@ -7749,7 +7749,7 @@ uint16_t mode_2Doctopus() { const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - rMap[XY(x, y)].angle = 40.7436f * atan2f((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI + rMap[XY(x, y)].angle = 40.7436f * atan2_t((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI rMap[XY(x, y)].radius = hypotf((x - C_X), (y - C_Y)) * mapp; //thanks Sutaburosu } } @@ -7760,8 +7760,8 @@ uint16_t mode_2Doctopus() { for (int y = 0; y < rows; y++) { byte angle = rMap[XY(x,y)].angle; byte radius = rMap[XY(x,y)].radius; - //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); - unsigned intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); + //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8_t(sin8_t((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); + unsigned intensity = sin8_t(sin8_t((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); intensity = map((intensity*intensity) & 0xFFFF, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); SEGMENT.setPixelColorXY(x, y, c); @@ -7769,7 +7769,7 @@ uint16_t mode_2Doctopus() { } return FRAMETIME; } -static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs;;!;2;"; +static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs,fasttan;;!;2;"; //Waving Cell @@ -7786,7 +7786,7 @@ uint16_t mode_2Dwavingcell() { uint8_t aY = SEGMENT.custom2/16 + 1; uint8_t aZ = SEGMENT.custom3 + 1; for (int x = 0; x < cols; x++) for (int y = 0; y T atan_t(T x); - float cos_t(float phi); - float sin_t(float x); - float tan_t(float x); - float acos_t(float x); - float asin_t(float x); - float floor_t(float x); - float fmod_t(float num, float denom); -#else - #include - #define sin_t sinf - #define cos_t cosf - #define tan_t tanf - #define asin_t asinf - #define acos_t acosf - #define atan_t atanf - #define fmod_t fmodf - #define floor_t floorf -#endif +//float cos_t(float phi); // use float math +//float sin_t(float phi); +//float tan_t(float x); +int16_t sin16_t(uint16_t theta); +int16_t cos16_t(uint16_t theta); +uint8_t sin8_t(uint8_t theta); +uint8_t cos8_t(uint8_t theta); +float sin_approx(float theta); // uses integer math (converted to float), accuracy +/-0.0015 (compared to sinf()) +float cos_approx(float theta); +float tan_approx(float x); +float atan2_t(float y, float x); +float acos_t(float x); +float asin_t(float x); +template T atan_t(T x); +float floor_t(float x); +float fmod_t(float num, float denom); +#define sin_t sin_approx +#define cos_t cos_approx +#define tan_t tan_approx +/* +#include // standard math functions. use a lot of flash +#define sin_t sinf +#define cos_t cosf +#define tan_t tanf +#define asin_t asinf +#define acos_t acosf +#define atan_t atanf +#define fmod_t fmodf +#define floor_t floorf +*/ //wled_serial.cpp void handleSerial(); void updateBaudRate(uint32_t rate); diff --git a/wled00/util.cpp b/wled00/util.cpp index 0b78a46469..c43fdeabf0 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -372,6 +372,39 @@ uint16_t crc16(const unsigned char* data_p, size_t length) { return crc; } +// fastled beatsin: 1:1 replacements to remove the use of fastled sin16() +// Generates a 16-bit sine wave at a given BPM that oscillates within a given range. see fastled for details. +uint16_t beatsin88_t(accum88 beats_per_minute_88, uint16_t lowest, uint16_t highest, uint32_t timebase, uint16_t phase_offset) +{ + uint16_t beat = beat88( beats_per_minute_88, timebase); + uint16_t beatsin (sin16_t( beat + phase_offset) + 32768); + uint16_t rangewidth = highest - lowest; + uint16_t scaledbeat = scale16( beatsin, rangewidth); + uint16_t result = lowest + scaledbeat; + return result; +} + +// Generates a 16-bit sine wave at a given BPM that oscillates within a given range. see fastled for details. +uint16_t beatsin16_t(accum88 beats_per_minute, uint16_t lowest, uint16_t highest, uint32_t timebase, uint16_t phase_offset) +{ + uint16_t beat = beat16( beats_per_minute, timebase); + uint16_t beatsin = (sin16_t( beat + phase_offset) + 32768); + uint16_t rangewidth = highest - lowest; + uint16_t scaledbeat = scale16( beatsin, rangewidth); + uint16_t result = lowest + scaledbeat; + return result; +} + +// Generates an 8-bit sine wave at a given BPM that oscillates within a given range. see fastled for details. +uint8_t beatsin8_t(accum88 beats_per_minute, uint8_t lowest, uint8_t highest, uint32_t timebase, uint8_t phase_offset) +{ + uint8_t beat = beat8( beats_per_minute, timebase); + uint8_t beatsin = sin8_t( beat + phase_offset); + uint8_t rangewidth = highest - lowest; + uint8_t scaledbeat = scale8( beatsin, rangewidth); + uint8_t result = lowest + scaledbeat; + return result; +} /////////////////////////////////////////////////////////////////////////////// // Begin simulateSound (to enable audio enhanced effects to display something) @@ -431,8 +464,8 @@ um_data_t* simulateSound(uint8_t simulationId) default: case UMS_BeatSin: for (int i = 0; i<16; i++) - fftResult[i] = beatsin8(120 / (i+1), 0, 255); - // fftResult[i] = (beatsin8(120, 0, 255) + (256/16 * i)) % 256; + fftResult[i] = beatsin8_t(120 / (i+1), 0, 255); + // fftResult[i] = (beatsin8_t(120, 0, 255) + (256/16 * i)) % 256; volumeSmth = fftResult[8]; break; case UMS_WeWillRockYou: @@ -469,12 +502,12 @@ um_data_t* simulateSound(uint8_t simulationId) break; case UMS_10_13: for (int i = 0; i<16; i++) - fftResult[i] = inoise8(beatsin8(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3); + fftResult[i] = inoise8(beatsin8_t(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3); volumeSmth = fftResult[8]; break; case UMS_14_3: for (int i = 0; i<16; i++) - fftResult[i] = inoise8(beatsin8(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3); + fftResult[i] = inoise8(beatsin8_t(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3); volumeSmth = fftResult[8]; break; } diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index a4c9fc123c..401446a238 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -12,6 +12,12 @@ #define modd(x, y) ((x) - (int)((x) / (y)) * (y)) +// Note: cos_t, sin_t and tan_t are very accurate but may be slow +// the math.h functions use several kB of flash and are to be avoided if possible +// sin16_t / cos16_t are faster and much more accurate than the fastled variants +// sin_approx and cos_approx are float wrappers for sin16_t/cos16_t and have an accuracy of +/-0.0015 compared to sinf() +// sin8_t / cos8_t are fastled replacements and use sin16_t / cos16_t. Slightly slower than fastled version but very accurate + float cos_t(float phi) { float x = modd(phi, TWO_PI); @@ -31,8 +37,8 @@ float cos_t(float phi) return res; } -float sin_t(float x) { - float res = cos_t(HALF_PI - x); +float sin_t(float phi) { + float res = cos_t(HALF_PI - phi); #ifdef WLED_DEBUG_MATH Serial.printf("sin: %f,%f,%f,(%f)\n",x,res,sin(x),res-sin(x)); #endif @@ -49,6 +55,85 @@ float tan_t(float x) { return res; } +// 16-bit, integer based Bhaskara I's sine approximation: 16*x*(pi - x) / (5*pi^2 - 4*x*(pi - x)) +// input is 16bit unsigned (0-65535), output is 16bit signed (-32767 to +32767) +// optimized integer implementation by @dedehai +int16_t sin16_t(uint16_t theta) { + int scale = 1; + if (theta > 0x7FFF) { + theta = 0xFFFF - theta; + scale = -1; // second half of the sine function is negative (pi - 2*pi) + } + uint32_t precal = theta * (0x7FFF - theta); + uint64_t numerator = (uint64_t)precal * (4 * 0x7FFF); // 64bit required + int32_t denominator = 1342095361 - precal; // 1342095361 is 5 * 0x7FFF^2 / 4 + int16_t result = numerator / denominator; + return result * scale; +} + +int16_t cos16_t(uint16_t theta) { + return sin16_t(theta + 16384); //cos(x) = sin(x+pi/2) +} + +uint8_t sin8_t(uint8_t theta) { + int32_t sin16 = sin16_t((uint16_t)theta * 257); // 255 * 257 = 0xFFFF + sin16 += 0x7FFF; //shift result to range 0-0xFFFF + return sin16 >> 8; +} + +uint8_t cos8_t(uint8_t theta) { + return sin8_t(theta + 64); //cos(x) = sin(x+pi/2) +} + +float sin_approx(float theta) +{ + theta = modd(theta, TWO_PI); // modulo: bring to -2pi to 2pi range + if(theta < 0) theta += M_TWOPI; // 0-2pi range + uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / M_TWOPI)); + int32_t result = sin16_t(scaled_theta); + float sin = float(result) / 0x7FFF; + return sin; +} + +float cos_approx(float theta) +{ + return sin_approx(theta + M_PI_2); +} + +float tan_approx(float x) { + float c = cos_approx(x); + if (c==0.0f) return 0; + float res = sin_approx(x) / c; + return res; +} + +#define ATAN2_CONST_A 0.1963f +#define ATAN2_CONST_B 0.9817f + +// fast atan2() approximation source: public domain +float atan2_t(float y, float x) { + if (x == 0.0f) return (y > 0.0f) ? M_PI_2 : (y < 0.0f) ? -M_PI_2 : 0.0f; + + float abs_y = (y < 0.0f) ? -y : y + 1e-10f; // make sure y is not zero to prevent division by 0 + float z = abs_y / x; + float atan_approx; + + if (z < 1.0f) { + atan_approx = z / (1.0f + ATAN2_CONST_A * z * z); + if (x < 0.0f) { + return (y >= 0.0f) ? atan_approx + PI : atan_approx - PI; + } + } + else { + z = x / abs_y; + atan_approx = M_PI_2 - z / (1.0f + ATAN2_CONST_A * z * z); + if (y < 0.0f) { + return -atan_approx; + } + } + return atan_approx; +} + //https://stackoverflow.com/questions/3380628 // Absolute error <= 6.7e-5 float acos_t(float x) { From f301296f1e1c9ba9ceeb49aead1f89fc3cd94ba6 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 6 Oct 2024 21:27:58 +0200 Subject: [PATCH 2/7] added rounding to sin8_t thx to @softhack007 --- wled00/wled_math.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index 401446a238..080cc9425a 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -77,8 +77,8 @@ int16_t cos16_t(uint16_t theta) { uint8_t sin8_t(uint8_t theta) { int32_t sin16 = sin16_t((uint16_t)theta * 257); // 255 * 257 = 0xFFFF - sin16 += 0x7FFF; //shift result to range 0-0xFFFF - return sin16 >> 8; + sin16 += 0x7FFF + 128; //shift result to range 0-0xFFFF, +128 for rounding + return min(sin16, int32_t(0xFFFF)) >> 8; // min performs saturation, and prevents overflow } uint8_t cos8_t(uint8_t theta) { From 5e29f2c1b7844492c5ccaf194f524fe810947c3f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 15 Oct 2024 20:11:33 +0200 Subject: [PATCH 3/7] fixed atan2_t approximation was incorrect, now doing it right. also removed hypotf() from octopus, saving a little flash. --- wled00/FX.cpp | 6 ++++-- wled00/wled_math.cpp | 39 +++++++++++++++++---------------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 338dd2df90..5b4513dc78 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7749,8 +7749,10 @@ uint16_t mode_2Doctopus() { const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - rMap[XY(x, y)].angle = 40.7436f * atan2_t((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI - rMap[XY(x, y)].radius = hypotf((x - C_X), (y - C_Y)) * mapp; //thanks Sutaburosu + rMap[XY(x, y)].angle = int(40.7436f * atan2_t((y - C_Y), (x - C_X))); // avoid 128*atan2()/PI + int dx = (x - C_X); + int dy = (y - C_Y); + rMap[XY(x, y)].radius = sqrtf(dx * dx + dy * dy) * mapp; //thanks Sutaburosu } } } diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index 080cc9425a..1825ab1986 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -88,8 +88,8 @@ uint8_t cos8_t(uint8_t theta) { float sin_approx(float theta) { theta = modd(theta, TWO_PI); // modulo: bring to -2pi to 2pi range - if(theta < 0) theta += M_TWOPI; // 0-2pi range - uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / M_TWOPI)); + if(theta < 0) theta += TWO_PI; // 0-2pi range + uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / TWO_PI)); int32_t result = sin16_t(scaled_theta); float sin = float(result) / 0x7FFF; return sin; @@ -110,28 +110,23 @@ float tan_approx(float x) { #define ATAN2_CONST_A 0.1963f #define ATAN2_CONST_B 0.9817f -// fast atan2() approximation source: public domain +// atan2_t approximation, with the idea from https://gist.github.com/volkansalma/2972237?permalink_comment_id=3872525#gistcomment-3872525 float atan2_t(float y, float x) { - if (x == 0.0f) return (y > 0.0f) ? M_PI_2 : (y < 0.0f) ? -M_PI_2 : 0.0f; - - float abs_y = (y < 0.0f) ? -y : y + 1e-10f; // make sure y is not zero to prevent division by 0 - float z = abs_y / x; - float atan_approx; - - if (z < 1.0f) { - atan_approx = z / (1.0f + ATAN2_CONST_A * z * z); - if (x < 0.0f) { - return (y >= 0.0f) ? atan_approx + PI : atan_approx - PI; - } + float abs_y = fabs(y); + float abs_x = fabs(x); + float r = (abs_x - abs_y) / (abs_y + abs_x + 1e-10f); // avoid division by zero by adding a small nubmer + float angle; + if(x < 0) { + r = -r; + angle = M_PI/2.0f + M_PI/4.f; } - else { - z = x / abs_y; - atan_approx = M_PI_2 - z / (1.0f + ATAN2_CONST_A * z * z); - if (y < 0.0f) { - return -atan_approx; - } - } - return atan_approx; + else + angle = M_PI/2.0f - M_PI/4.f; + + float add = (ATAN2_CONST_A * (r * r) - ATAN2_CONST_B) * r; + angle += add; + angle = y < 0 ? -angle : angle; + return angle; } //https://stackoverflow.com/questions/3380628 From 98a6907976bfa3142545467359e876bd6d0ddc22 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 16 Oct 2024 19:53:58 +0200 Subject: [PATCH 4/7] cleanup and improvement to sin_appros() -replaced all PI references with M_PI version -there is no need to do the angle-modulo in float, casting it to an integer does the same BUT it has to be cast to an `int` first, see comment. --- wled00/wled_math.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index 1825ab1986..a191968e1d 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -15,17 +15,17 @@ // Note: cos_t, sin_t and tan_t are very accurate but may be slow // the math.h functions use several kB of flash and are to be avoided if possible // sin16_t / cos16_t are faster and much more accurate than the fastled variants -// sin_approx and cos_approx are float wrappers for sin16_t/cos16_t and have an accuracy of +/-0.0015 compared to sinf() +// sin_approx and cos_approx are float wrappers for sin16_t/cos16_t and have an accuracy better than +/-0.0015 compared to sinf() // sin8_t / cos8_t are fastled replacements and use sin16_t / cos16_t. Slightly slower than fastled version but very accurate float cos_t(float phi) { - float x = modd(phi, TWO_PI); + float x = modd(phi, M_TWOPI); if (x < 0) x = -1 * x; int8_t sign = 1; - if (x > PI) + if (x > M_PI) { - x -= PI; + x -= M_PI; sign = -1; } float xx = x * x; @@ -38,7 +38,7 @@ float cos_t(float phi) } float sin_t(float phi) { - float res = cos_t(HALF_PI - phi); + float res = cos_t(M_PI_2 - phi); #ifdef WLED_DEBUG_MATH Serial.printf("sin: %f,%f,%f,(%f)\n",x,res,sin(x),res-sin(x)); #endif @@ -87,9 +87,7 @@ uint8_t cos8_t(uint8_t theta) { float sin_approx(float theta) { - theta = modd(theta, TWO_PI); // modulo: bring to -2pi to 2pi range - if(theta < 0) theta += TWO_PI; // 0-2pi range - uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / TWO_PI)); + uint16_t scaled_theta = (int)(theta * (0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) int32_t result = sin16_t(scaled_theta); float sin = float(result) / 0x7FFF; return sin; @@ -118,10 +116,10 @@ float atan2_t(float y, float x) { float angle; if(x < 0) { r = -r; - angle = M_PI/2.0f + M_PI/4.f; + angle = M_PI_2 + M_PI_4; } else - angle = M_PI/2.0f - M_PI/4.f; + angle = M_PI_2 - M_PI_4; float add = (ATAN2_CONST_A * (r * r) - ATAN2_CONST_B) * r; angle += add; @@ -140,10 +138,10 @@ float acos_t(float x) { ret = ret * xabs; ret = ret - 0.2121144f; ret = ret * xabs; - ret = ret + HALF_PI; + ret = ret + M_PI_2; ret = ret * sqrt(1.0f-xabs); ret = ret - 2 * negate * ret; - float res = negate * PI + ret; + float res = negate * M_PI + ret; #ifdef WLED_DEBUG_MATH Serial.printf("acos: %f,%f,%f,(%f)\n",x,res,acos(x),res-acos(x)); #endif @@ -151,7 +149,7 @@ float acos_t(float x) { } float asin_t(float x) { - float res = HALF_PI - acos_t(x); + float res = M_PI_2 - acos_t(x); #ifdef WLED_DEBUG_MATH Serial.printf("asin: %f,%f,%f,(%f)\n",x,res,asin(x),res-asin(x)); #endif @@ -167,7 +165,7 @@ float atan_t(float x) { //For A/B/C, see https://stackoverflow.com/a/42542593 static const double A { 0.0776509570923569 }; static const double B { -0.287434475393028 }; - static const double C { ((HALF_PI/2) - A - B) }; + static const double C { ((M_PI_4) - A - B) }; // polynominal factors for approximation between 1 and 5 static const float C0 { 0.089494f }; static const float C1 { 0.974207f }; @@ -182,7 +180,7 @@ float atan_t(float x) { x = std::abs(x); float res; if (x > 5.0f) { // atan(x) converges to pi/2 - (1/x) for large values - res = HALF_PI - (1.0f/x); + res = M_PI_2 - (1.0f/x); } else if (x > 1.0f) { //1 < x < 5 float xx = x * x; res = (C4*xx*xx)+(C3*xx*x)+(C2*xx)+(C1*x)+C0; From 1a8aaa3b26feba106259b6842ad9f8998fb3233d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 26 Nov 2024 20:32:39 +0100 Subject: [PATCH 5/7] Speed improvements, commented legacy _t trig functions - speed improvement: by default M_TWOPI is treated as a double float - directly calling sin16_t in cos_approx() saves a lot of overhead --- wled00/wled_math.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index a191968e1d..583381d66b 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -10,14 +10,17 @@ //#define WLED_DEBUG_MATH -#define modd(x, y) ((x) - (int)((x) / (y)) * (y)) - -// Note: cos_t, sin_t and tan_t are very accurate but may be slow +// Note: cos_t, sin_t and tan_t are very accurate but slow // the math.h functions use several kB of flash and are to be avoided if possible // sin16_t / cos16_t are faster and much more accurate than the fastled variants // sin_approx and cos_approx are float wrappers for sin16_t/cos16_t and have an accuracy better than +/-0.0015 compared to sinf() // sin8_t / cos8_t are fastled replacements and use sin16_t / cos16_t. Slightly slower than fastled version but very accurate + +// Taylor series approximations, replaced with Bhaskara I's approximation +/* +#define modd(x, y) ((x) - (int)((x) / (y)) * (y)) + float cos_t(float phi) { float x = modd(phi, M_TWOPI); @@ -54,6 +57,7 @@ float tan_t(float x) { #endif return res; } +*/ // 16-bit, integer based Bhaskara I's sine approximation: 16*x*(pi - x) / (5*pi^2 - 4*x*(pi - x)) // input is 16bit unsigned (0-65535), output is 16bit signed (-32767 to +32767) @@ -85,17 +89,18 @@ uint8_t cos8_t(uint8_t theta) { return sin8_t(theta + 64); //cos(x) = sin(x+pi/2) } -float sin_approx(float theta) -{ - uint16_t scaled_theta = (int)(theta * (0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) +float sin_approx(float theta) { + uint16_t scaled_theta = (int)(theta * (float)(0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) int32_t result = sin16_t(scaled_theta); float sin = float(result) / 0x7FFF; return sin; } -float cos_approx(float theta) -{ - return sin_approx(theta + M_PI_2); +float cos_approx(float theta) { + uint16_t scaled_theta = (int)(theta * (float)(0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) + int32_t result = sin16_t(scaled_theta + 16384); + float cos = float(result) / 0x7FFF; + return cos; } float tan_approx(float x) { From 4cd0563a9398812f65f8dbbe22d0ab48799f4de8 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 27 Nov 2024 21:53:32 +0100 Subject: [PATCH 6/7] =?UTF-8?q?changed=2090=C2=B0=20offset=20to=20hex,=20f?= =?UTF-8?q?ixed=20potential=20bug=20in=20FX=20using=20sin/cos=20with=20inc?= =?UTF-8?q?rementing=20number?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sin/cos calls with incrementing numbers can lead to bad outcomes, the functions (_approx or original sinf/cosf) return bad values for very large float inputs --- wled00/FX.cpp | 5 +++-- wled00/wled_math.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 5b4513dc78..da2967a3c2 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -5314,8 +5314,8 @@ uint16_t mode_2DJulia(void) { // An animated Julia set reAl = -0.94299f; // PixelBlaze example imAg = 0.3162f; - reAl += sin_t((float)strip.now/305.f)/20.f; - imAg += sin_t((float)strip.now/405.f)/20.f; + reAl += (float)sin16_t(strip.now * 34) / 655340.f; + imAg += (float)sin16_t(strip.now * 26) / 655340.f; dx = (xmax - xmin) / (cols); // Scale the delta x and y values to our matrix size. dy = (ymax - ymin) / (rows); @@ -6279,6 +6279,7 @@ uint16_t mode_2Dplasmarotozoom() { } } *a -= 0.03f + float(SEGENV.speed-128)*0.0002f; // rotation speed + if(*a < -6283.18530718f) *a += 6283.18530718f; // 1000*2*PI, protect sin/cos from very large input float values (will give wrong results) return FRAMETIME; } diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index 583381d66b..a8ec55400f 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -76,7 +76,7 @@ int16_t sin16_t(uint16_t theta) { } int16_t cos16_t(uint16_t theta) { - return sin16_t(theta + 16384); //cos(x) = sin(x+pi/2) + return sin16_t(theta + 0x4000); //cos(x) = sin(x+pi/2) } uint8_t sin8_t(uint8_t theta) { @@ -98,7 +98,7 @@ float sin_approx(float theta) { float cos_approx(float theta) { uint16_t scaled_theta = (int)(theta * (float)(0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) - int32_t result = sin16_t(scaled_theta + 16384); + int32_t result = sin16_t(scaled_theta + 0x4000); float cos = float(result) / 0x7FFF; return cos; } From fa4c23b76ec7843aff6a8f3e5b9bc7a46a41858e Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 27 Nov 2024 22:23:48 +0100 Subject: [PATCH 7/7] minor improvement --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a2ceb591a3..a0d0808183 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7737,9 +7737,9 @@ uint16_t mode_2Doctopus() { const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - rMap[XY(x, y)].angle = int(40.7436f * atan2_t((y - C_Y), (x - C_X))); // avoid 128*atan2()/PI int dx = (x - C_X); int dy = (y - C_Y); + rMap[XY(x, y)].angle = int(40.7436f * atan2_t(dy, dx)); // avoid 128*atan2()/PI rMap[XY(x, y)].radius = sqrtf(dx * dx + dy * dy) * mapp; //thanks Sutaburosu } }