Replace PRNG with hardware RNG (#4225)

Both ESP8266 and ESP32 have a hardware random register. This update makes use of that. It is slightly faster than the fastled variants but mostly it is truly random, even when the timing limitations stated in the datasheet are disregarded. Also saves a bit on code size.

- Replaced all random8() and random16() calls with new hw_random() versions
- Not replaced in FX where PRNG is required
This commit is contained in:
Damian Schneider 2024-12-20 19:12:29 +01:00 committed by GitHub
parent 07cc3aa5c0
commit 5f77478841
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 256 additions and 226 deletions

View File

@ -211,7 +211,7 @@ uint16_t color_wipe(bool rev, bool useRandomColors) {
if (useRandomColors) {
if (SEGENV.call == 0) {
SEGENV.aux0 = random8();
SEGENV.aux0 = hw_random8();
SEGENV.step = 3;
}
if (SEGENV.step == 1) { //if flag set, change to new random color
@ -303,7 +303,7 @@ uint16_t mode_random_color(void) {
}
if (SEGENV.call == 0) {
SEGENV.aux0 = random8();
SEGENV.aux0 = hw_random8();
SEGENV.step = 2;
}
if (it != SEGENV.step) //new color
@ -328,7 +328,7 @@ uint16_t mode_dynamic(void) {
if(SEGENV.call == 0) {
//SEGMENT.fill(BLACK);
for (unsigned i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8();
for (unsigned i = 0; i < SEGLEN; i++) SEGENV.data[i] = hw_random8();
}
uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*15;
@ -336,7 +336,7 @@ uint16_t mode_dynamic(void) {
if (it != SEGENV.step && SEGMENT.speed != 0) //new color
{
for (unsigned i = 0; i < SEGLEN; i++) {
if (random8() <= SEGMENT.intensity) SEGENV.data[i] = random8(); // random color index
if (hw_random8() <= SEGMENT.intensity) SEGENV.data[i] = hw_random8(); // random color index
}
SEGENV.step = it;
}
@ -617,7 +617,7 @@ uint16_t mode_twinkle(void) {
if (SEGENV.aux0 >= maxOn)
{
SEGENV.aux0 = 0;
SEGENV.aux1 = random16(); //new seed for our PRNG
SEGENV.aux1 = hw_random(); //new seed for our PRNG
}
SEGENV.aux0++;
SEGENV.step = it;
@ -651,9 +651,9 @@ uint16_t dissolve(uint32_t color) {
}
for (unsigned j = 0; j <= SEGLEN / 15; j++) {
if (random8() <= SEGMENT.intensity) {
if (hw_random8() <= SEGMENT.intensity) {
for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times
unsigned i = random16(SEGLEN);
unsigned i = hw_random16(SEGLEN);
unsigned index = i >> 3;
unsigned bitNum = i & 0x07;
bool fadeUp = bitRead(SEGENV.data[index], bitNum);
@ -693,7 +693,7 @@ uint16_t dissolve(uint32_t color) {
* Blink several LEDs on and then off
*/
uint16_t mode_dissolve(void) {
return dissolve(SEGMENT.check1 ? SEGMENT.color_wheel(random8()) : SEGCOLOR(0));
return dissolve(SEGMENT.check1 ? SEGMENT.color_wheel(hw_random8()) : SEGCOLOR(0));
}
static const char _data_FX_MODE_DISSOLVE[] PROGMEM = "Dissolve@Repeat speed,Dissolve speed,,,,Random;!,!;!";
@ -702,7 +702,7 @@ static const char _data_FX_MODE_DISSOLVE[] PROGMEM = "Dissolve@Repeat speed,Diss
* Blink several LEDs on and then off in random colors
*/
uint16_t mode_dissolve_random(void) {
return dissolve(SEGMENT.color_wheel(random8()));
return dissolve(SEGMENT.color_wheel(hw_random8()));
}
static const char _data_FX_MODE_DISSOLVE_RANDOM[] PROGMEM = "Dissolve Rnd@Repeat speed,Dissolve speed;,!;!";
@ -719,7 +719,7 @@ uint16_t mode_sparkle(void) {
uint32_t it = strip.now / cycleTime;
if (it != SEGENV.step)
{
SEGENV.aux0 = random16(SEGLEN); // aux0 stores the random led index
SEGENV.aux0 = hw_random16(SEGLEN); // aux0 stores the random led index
SEGENV.step = it;
}
@ -739,8 +739,8 @@ uint16_t mode_flash_sparkle(void) {
}
if (strip.now - SEGENV.aux0 > SEGENV.step) {
if(random8((255-SEGMENT.intensity) >> 4) == 0) {
SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1)); //flash
if(hw_random8((255-SEGMENT.intensity) >> 4) == 0) {
SEGMENT.setPixelColor(hw_random16(SEGLEN), SEGCOLOR(1)); //flash
}
SEGENV.step = strip.now;
SEGENV.aux0 = 255-SEGMENT.speed;
@ -760,10 +760,10 @@ uint16_t mode_hyper_sparkle(void) {
}
if (strip.now - SEGENV.aux0 > SEGENV.step) {
if (random8((255-SEGMENT.intensity) >> 4) == 0) {
if (hw_random8((255-SEGMENT.intensity) >> 4) == 0) {
int len = max(1, (int)SEGLEN/3);
for (int i = 0; i < len; i++) {
SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1));
SEGMENT.setPixelColor(hw_random16(SEGLEN), SEGCOLOR(1));
}
}
SEGENV.step = strip.now;
@ -1133,7 +1133,7 @@ static const char _data_FX_MODE_RUNNING_COLOR[] PROGMEM = "Chase 2@!,Width;!,!;!
uint16_t mode_running_random(void) {
uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed));
uint32_t it = strip.now / cycleTime;
if (SEGENV.call == 0) SEGENV.aux0 = random16(); // random seed for PRNG on start
if (SEGENV.call == 0) SEGENV.aux0 = hw_random(); // random seed for PRNG on start
unsigned zoneSize = ((255-SEGMENT.intensity) >> 4) +1;
uint16_t PRNG16 = SEGENV.aux0;
@ -1278,11 +1278,11 @@ uint16_t mode_fireworks() {
}
for (int i=0; i<max(1, width/20); i++) {
if (random8(129 - (SEGMENT.intensity >> 1)) == 0) {
uint16_t index = random16(width*height);
if (hw_random8(129 - (SEGMENT.intensity >> 1)) == 0) {
uint16_t index = hw_random16(width*height);
x = index % width;
y = index / width;
uint32_t col = SEGMENT.color_from_palette(random8(), false, false, 0);
uint32_t col = SEGMENT.color_from_palette(hw_random8(), false, false, 0);
if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, col);
else SEGMENT.setPixelColor(index, col);
SEGENV.aux1 = SEGENV.aux0; // old spark
@ -1344,7 +1344,7 @@ uint16_t mode_fire_flicker(void) {
byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255;
lum /= (((256-SEGMENT.intensity)/16)+1);
for (unsigned i = 0; i < SEGLEN; i++) {
byte flicker = random8(lum);
byte flicker = hw_random8(lum);
if (SEGMENT.palette == 0) {
SEGMENT.setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0));
} else {
@ -1475,11 +1475,11 @@ uint16_t mode_fairy() {
if (stateTime > flashers[f].stateDur * 10) {
flashers[f].stateOn = !flashers[f].stateOn;
if (flashers[f].stateOn) {
flashers[f].stateDur = 12 + random8(12 + ((255 - SEGMENT.speed) >> 2)); //*10, 250ms to 1250ms
flashers[f].stateDur = 12 + hw_random8(12 + ((255 - SEGMENT.speed) >> 2)); //*10, 250ms to 1250ms
} else {
flashers[f].stateDur = 20 + random8(6 + ((255 - SEGMENT.speed) >> 2)); //*10, 250ms to 1250ms
flashers[f].stateDur = 20 + hw_random8(6 + ((255 - SEGMENT.speed) >> 2)); //*10, 250ms to 1250ms
}
//flashers[f].stateDur = 51 + random8(2 + ((255 - SEGMENT.speed) >> 1));
//flashers[f].stateDur = 51 + hw_random8(2 + ((255 - SEGMENT.speed) >> 1));
flashers[f].stateStart = now16;
if (stateTime < 255) {
flashers[f].stateStart -= 255 -stateTime; //start early to get correct bri
@ -1535,15 +1535,15 @@ uint16_t mode_fairytwinkle() {
flashers[f].stateOn = !flashers[f].stateOn;
bool init = !flashers[f].stateDur;
if (flashers[f].stateOn) {
flashers[f].stateDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + random8(12 + ((255 - SEGMENT.intensity) >> 1)) +1;
flashers[f].stateDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + hw_random8(12 + ((255 - SEGMENT.intensity) >> 1)) +1;
} else {
flashers[f].stateDur = riseFallTime/100 + random8(3 + ((255 - SEGMENT.speed) >> 6)) +1;
flashers[f].stateDur = riseFallTime/100 + hw_random8(3 + ((255 - SEGMENT.speed) >> 6)) +1;
}
flashers[f].stateStart = now16;
stateTime = 0;
if (init) {
flashers[f].stateStart -= riseFallTime; //start lit
flashers[f].stateDur = riseFallTime/100 + random8(12 + ((255 - SEGMENT.intensity) >> 1)) +5; //fire up a little quicker
flashers[f].stateDur = riseFallTime/100 + hw_random8(12 + ((255 - SEGMENT.intensity) >> 1)) +5; //fire up a little quicker
stateTime = riseFallTime;
}
}
@ -1611,13 +1611,13 @@ uint16_t mode_icu(void) {
SEGMENT.setPixelColor(dest + SEGLEN/space, col);
if(SEGENV.aux0 == dest) { // pause between eye movements
if(random8(6) == 0) { // blink once in a while
if(hw_random8(6) == 0) { // blink once in a while
SEGMENT.setPixelColor(dest, SEGCOLOR(1));
SEGMENT.setPixelColor(dest + SEGLEN/space, SEGCOLOR(1));
return 200;
}
SEGENV.aux0 = random16(SEGLEN-SEGLEN/space);
return 1000 + random16(2000);
SEGENV.aux0 = hw_random16(SEGLEN-SEGLEN/space);
return 1000 + hw_random16(2000);
}
if(SEGENV.aux0 > SEGENV.step) {
@ -1747,7 +1747,7 @@ uint16_t mode_multi_comet(void) {
}
comets[i]++;
} else {
if(!random16(SEGLEN)) {
if(!hw_random16(SEGLEN)) {
comets[i] = 0;
}
}
@ -1831,12 +1831,12 @@ uint16_t mode_oscillate(void) {
oscillators[i].pos = 0;
oscillators[i].dir = 1;
// make bigger steps for faster speeds
oscillators[i].speed = SEGMENT.speed > 100 ? random8(2, 4):random8(1, 3);
oscillators[i].speed = SEGMENT.speed > 100 ? hw_random8(2, 4):hw_random8(1, 3);
}
if((oscillators[i].dir == 1) && (oscillators[i].pos >= (SEGLEN - 1))) {
oscillators[i].pos = SEGLEN - 1;
oscillators[i].dir = -1;
oscillators[i].speed = SEGMENT.speed > 100 ? random8(2, 4):random8(1, 3);
oscillators[i].speed = SEGMENT.speed > 100 ? hw_random8(2, 4):hw_random8(1, 3);
}
}
@ -1859,13 +1859,13 @@ static const char _data_FX_MODE_OSCILLATE[] PROGMEM = "Oscillate";
//TODO
uint16_t mode_lightning(void) {
if (SEGLEN == 1) return mode_static();
unsigned ledstart = random16(SEGLEN); // Determine starting location of flash
unsigned ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
uint8_t bri = 255/random8(1, 3);
unsigned ledstart = hw_random16(SEGLEN); // Determine starting location of flash
unsigned ledlen = 1 + hw_random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
uint8_t bri = 255/hw_random8(1, 3);
if (SEGENV.aux1 == 0) //init, leader flash
{
SEGENV.aux1 = random8(4, 4 + SEGMENT.intensity/20); //number of flashes
SEGENV.aux1 = hw_random8(4, 4 + SEGMENT.intensity/20); //number of flashes
SEGENV.aux1 *= 2;
bri = 52; //leader has lower brightness
@ -1882,15 +1882,15 @@ uint16_t mode_lightning(void) {
SEGENV.aux1--;
SEGENV.step = strip.now;
//return random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds
//return hw_random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds
} else {
if (strip.now - SEGENV.step > SEGENV.aux0) {
SEGENV.aux1--;
if (SEGENV.aux1 < 2) SEGENV.aux1 = 0;
SEGENV.aux0 = (50 + random8(100)); //delay between flashes
SEGENV.aux0 = (50 + hw_random8(100)); //delay between flashes
if (SEGENV.aux1 == 2) {
SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes
SEGENV.aux0 = (hw_random8(255 - SEGMENT.speed) * 100); // delay between strikes
}
SEGENV.step = strip.now;
}
@ -2103,7 +2103,7 @@ uint16_t mode_fire_2012() {
// Step 1. Cool down every cell a little
for (unsigned i = 0; i < SEGLEN; i++) {
uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random8(4);
uint8_t cool = (it != SEGENV.step) ? hw_random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : hw_random8(4);
uint8_t minTemp = (i<ignition) ? (ignition-i)/4 + 16 : 0; // should not become black in ignition area
uint8_t temp = qsub8(heat[i], cool);
heat[i] = temp<minTemp ? minTemp : temp;
@ -2116,10 +2116,10 @@ uint16_t mode_fire_2012() {
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
if (random8() <= SEGMENT.intensity) {
uint8_t y = random8(ignition);
if (hw_random8() <= SEGMENT.intensity) {
uint8_t y = hw_random8(ignition);
uint8_t boost = (17+SEGMENT.custom3) * (ignition - y/2) / ignition; // integer math!
heat[y] = qadd8(heat[y], random8(96+2*boost,207+boost));
heat[y] = qadd8(heat[y], hw_random8(96+2*boost,207+boost));
}
}
@ -2208,7 +2208,7 @@ static const char _data_FX_MODE_BPM[] PROGMEM = "Bpm@!;!;!;;sx=64";
uint16_t mode_fillnoise8() {
if (SEGENV.call == 0) SEGENV.step = random16(12345);
if (SEGENV.call == 0) SEGENV.step = hw_random();
for (unsigned i = 0; i < SEGLEN; i++) {
unsigned index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN);
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0));
@ -2328,14 +2328,14 @@ uint16_t mode_colortwinkle() {
}
for (unsigned j = 0; j <= SEGLEN / 50; j++) {
if (random8() <= SEGMENT.intensity) {
if (hw_random8() <= SEGMENT.intensity) {
for (unsigned times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times
int i = random16(SEGLEN);
int i = hw_random16(SEGLEN);
if (SEGMENT.getPixelColor(i) == 0) {
unsigned index = i >> 3;
unsigned bitNum = i & 0x07;
bitWrite(SEGENV.data[index], bitNum, true);
SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, random8(), 64, NOBLEND));
SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, hw_random8(), 64, NOBLEND));
break; //only spawn 1 new pixel per frame per 50 LEDs
}
}
@ -2386,14 +2386,14 @@ uint16_t mode_meteor() {
// fade all leds to colors[1] in LEDs one step
for (unsigned i = 0; i < SEGLEN; i++) {
uint32_t col;
if (random8() <= 255 - SEGMENT.intensity) {
if (hw_random8() <= 255 - SEGMENT.intensity) {
if(meteorSmooth) {
int change = trail[i] + 4 - random8(24); //change each time between -20 and +4
int change = trail[i] + 4 - hw_random8(24); //change each time between -20 and +4
trail[i] = constrain(change, 0, max);
col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255);
}
else {
trail[i] = scale8(trail[i], 128 + random8(127));
trail[i] = scale8(trail[i], 128 + hw_random8(127));
int index = trail[i];
int idx = 255;
int bri = SEGMENT.palette==35 || SEGMENT.palette==36 ? 255 : trail[i];
@ -2410,8 +2410,8 @@ uint16_t mode_meteor() {
// draw meteor
for (unsigned j = 0; j < meteorSize; j++) {
unsigned index = (meteorstart + j) % SEGLEN;
if(meteorSmooth) {
unsigned index = (meteorstart + j) % SEGLEN;
if(meteorSmooth) {
trail[index] = max;
uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255);
SEGMENT.setPixelColor(index, col);
@ -2422,7 +2422,7 @@ uint16_t mode_meteor() {
if (!SEGMENT.check1) {
i = map(index,0,SEGLEN,0,max);
idx = 0;
}
}
uint32_t col = SEGMENT.color_from_palette(i, false, false, idx, 255); // full brightness
SEGMENT.setPixelColor(index, col);
}
@ -2523,10 +2523,10 @@ static uint16_t ripple_base(uint8_t blurAmount = 0) {
ripplestate += rippledecay;
ripples[i].state = (ripplestate > 254) ? 0 : ripplestate;
} else {//randomly create new wave
if (random16(IBN + 10000) <= (SEGMENT.intensity >> (SEGMENT.is2D()*3))) {
if (hw_random16(IBN + 10000) <= (SEGMENT.intensity >> (SEGMENT.is2D()*3))) {
ripples[i].state = 1;
ripples[i].pos = SEGMENT.is2D() ? ((random8(SEG_W)<<8) | (random8(SEG_H))) : random16(SEGLEN);
ripples[i].color = random8(); //color
ripples[i].pos = SEGMENT.is2D() ? ((hw_random8(SEG_W)<<8) | (hw_random8(SEG_H))) : hw_random16(SEGLEN);
ripples[i].color = hw_random8(); //color
}
}
}
@ -2551,11 +2551,11 @@ static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,Blur,,,,Over
uint16_t mode_ripple_rainbow(void) {
if (SEGLEN == 1) return mode_static();
if (SEGENV.call ==0) {
SEGENV.aux0 = random8();
SEGENV.aux1 = random8();
SEGENV.aux0 = hw_random8();
SEGENV.aux1 = hw_random8();
}
if (SEGENV.aux0 == SEGENV.aux1) {
SEGENV.aux1 = random8();
SEGENV.aux1 = hw_random8();
} else if (SEGENV.aux1 > SEGENV.aux0) {
SEGENV.aux0++;
} else {
@ -2750,10 +2750,10 @@ uint16_t mode_halloween_eyes()
// - select a duration
// - immediately switch to eyes on state.
data.startPos = random16(0, maxWidth - eyeLength - 1);
data.color = random8();
if (strip.isMatrix) SEGMENT.offset = random16(SEG_H-1); // a hack: reuse offset since it is not used in matrices
duration = 128u + random16(SEGMENT.intensity*64u);
data.startPos = hw_random16(0, maxWidth - eyeLength - 1);
data.color = hw_random8();
if (strip.isMatrix) SEGMENT.offset = hw_random16(SEG_H-1); // a hack: reuse offset since it is not used in matrices
duration = 128u + hw_random16(SEGMENT.intensity*64u);
data.duration = duration;
data.state = eyeState::on;
[[fallthrough]];
@ -2780,11 +2780,11 @@ uint16_t mode_halloween_eyes()
} else if (elapsedTime > minimumOnTimeBegin) {
const uint32_t remainingTime = (elapsedTime >= duration) ? 0u : (duration - elapsedTime);
if (remainingTime > minimumOnTimeEnd) {
if (random8() < 4u)
if (hw_random8() < 4u)
{
c = backgroundColor;
data.state = eyeState::blink;
data.blinkEndTime = strip.now + random8(8, 128);
data.blinkEndTime = strip.now + hw_random8(8, 128);
}
}
}
@ -2818,7 +2818,7 @@ uint16_t mode_halloween_eyes()
// - immediately switch to eyes-off state
const unsigned eyeOffTimeBase = SEGMENT.speed*128u;
duration = eyeOffTimeBase + random16(eyeOffTimeBase);
duration = eyeOffTimeBase + hw_random16(eyeOffTimeBase);
data.duration = duration;
data.state = eyeState::off;
[[fallthrough]];
@ -3008,7 +3008,7 @@ uint16_t mode_bouncing_balls(void) {
balls[i].lastBounceTime = time;
if (balls[i].impactVelocity < 0.015f) {
float impactVelocityStart = sqrtf(-2.0f * gravity) * random8(5,11)/10.0f; // randomize impact velocity
float impactVelocityStart = sqrtf(-2.0f * gravity) * hw_random8(5,11)/10.0f; // randomize impact velocity
balls[i].impactVelocity = impactVelocityStart;
}
} else if (balls[i].height > 1.0f) {
@ -3071,10 +3071,10 @@ static uint16_t rolling_balls(void) {
SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); // start clean
for (unsigned i = 0; i < maxNumBalls; i++) {
balls[i].lastBounceUpdate = strip.now;
balls[i].velocity = 20.0f * float(random16(1000, 10000))/10000.0f; // number from 1 to 10
if (random8()<128) balls[i].velocity = -balls[i].velocity; // 50% chance of reverse direction
balls[i].height = (float(random16(0, 10000)) / 10000.0f); // from 0. to 1.
balls[i].mass = (float(random16(1000, 10000)) / 10000.0f); // from .1 to 1.
balls[i].velocity = 20.0f * float(hw_random16(1000, 10000))/10000.0f; // number from 1 to 10
if (hw_random8()<128) balls[i].velocity = -balls[i].velocity; // 50% chance of reverse direction
balls[i].height = (float(hw_random16(0, 10000)) / 10000.0f); // from 0. to 1.
balls[i].mass = (float(hw_random16(1000, 10000)) / 10000.0f); // from .1 to 1.
}
}
@ -3090,7 +3090,7 @@ static uint16_t rolling_balls(void) {
float thisHeight = balls[i].height + balls[i].velocity * timeSinceLastUpdate; // this method keeps higher resolution
// test if intensity level was increased and some balls are way off the track then put them back
if (thisHeight < -0.5f || thisHeight > 1.5f) {
thisHeight = balls[i].height = (float(random16(0, 10000)) / 10000.0f); // from 0. to 1.
thisHeight = balls[i].height = (float(hw_random16(0, 10000)) / 10000.0f); // from 0. to 1.
balls[i].lastBounceUpdate = strip.now;
}
// check if reached ends of the strip
@ -3200,7 +3200,7 @@ static const char _data_FX_MODE_SINELON_RAINBOW[] PROGMEM = "Sinelon Rainbow@!,T
// utility function that will add random glitter to SEGMENT
void glitter_base(uint8_t intensity, uint32_t col = ULTRAWHITE) {
if (intensity > random8()) SEGMENT.setPixelColor(random16(SEGLEN), col);
if (intensity > hw_random8()) SEGMENT.setPixelColor(hw_random16(SEGLEN), col);
}
//Glitter with palette background, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6
@ -3277,18 +3277,18 @@ uint16_t mode_popcorn(void) {
popcorn[i].pos += popcorn[i].vel;
popcorn[i].vel += gravity;
} else { // if kernel is inactive, randomly pop it
if (random8() < 2) { // POP!!!
if (hw_random8() < 2) { // POP!!!
popcorn[i].pos = 0.01f;
unsigned peakHeight = 128 + random8(128); //0-255
unsigned peakHeight = 128 + hw_random8(128); //0-255
peakHeight = (peakHeight * (SEGLEN -1)) >> 8;
popcorn[i].vel = sqrtf(-2.0f * gravity * peakHeight);
if (SEGMENT.palette)
{
popcorn[i].colIndex = random8();
popcorn[i].colIndex = hw_random8();
} else {
byte col = random8(0, NUM_COLORS);
byte col = hw_random8(0, NUM_COLORS);
if (!SEGCOLOR(2) || !SEGCOLOR(col)) col = 0;
popcorn[i].colIndex = col;
}
@ -3350,7 +3350,7 @@ uint16_t candle(bool multi)
s = SEGENV.data[d]; s_target = SEGENV.data[d+1]; fadeStep = SEGENV.data[d+2];
}
if (fadeStep == 0) { //init vals
s = 128; s_target = 130 + random8(4); fadeStep = 1;
s = 128; s_target = 130 + hw_random8(4); fadeStep = 1;
}
bool newTarget = false;
@ -3363,8 +3363,8 @@ uint16_t candle(bool multi)
}
if (newTarget) {
s_target = random8(rndval) + random8(rndval); //between 0 and rndval*2 -2 = 252
if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + random8(rndval);
s_target = hw_random8(rndval) + hw_random8(rndval); //between 0 and rndval*2 -2 = 252
if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + hw_random8(rndval);
unsigned offset = (255 - valrange);
s_target += offset;
@ -3450,19 +3450,19 @@ uint16_t mode_starburst(void) {
for (unsigned j = 0; j < numStars; j++)
{
// speed to adjust chance of a burst, max is nearly always.
if (random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0)
if (hw_random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0)
{
// Pick a random color and location.
unsigned startPos = random16(SEGLEN-1);
float multiplier = (float)(random8())/255.0f * 1.0f;
unsigned startPos = hw_random16(SEGLEN-1);
float multiplier = (float)(hw_random8())/255.0f * 1.0f;
stars[j].color = CRGB(SEGMENT.color_wheel(random8()));
stars[j].color = CRGB(SEGMENT.color_wheel(hw_random8()));
stars[j].pos = startPos;
stars[j].vel = maxSpeed * (float)(random8())/255.0f * multiplier;
stars[j].vel = maxSpeed * (float)(hw_random8())/255.0f * multiplier;
stars[j].birth = it;
stars[j].last = it;
// more fragments means larger burst effect
int num = random8(3,6 + (SEGMENT.intensity >> 5));
int num = hw_random8(3,6 + (SEGMENT.intensity >> 5));
for (int i=0; i < STARBURST_MAX_FRAG; i++) {
if (i < num) stars[j].fragment[i] = startPos;
@ -3578,11 +3578,11 @@ uint16_t mode_exploding_fireworks(void)
if (SEGENV.aux0 < 2) { //FLARE
if (SEGENV.aux0 == 0) { //init flare
flare->pos = 0;
flare->posX = SEGMENT.is2D() ? random16(2,cols-3) : (SEGMENT.intensity > random8()); // will enable random firing side on 1D
unsigned peakHeight = 75 + random8(180); //0-255
flare->posX = SEGMENT.is2D() ? hw_random16(2,cols-3) : (SEGMENT.intensity > hw_random8()); // will enable random firing side on 1D
unsigned peakHeight = 75 + hw_random8(180); //0-255
peakHeight = (peakHeight * (rows -1)) >> 8;
flare->vel = sqrtf(-2.0f * gravity * peakHeight);
flare->velX = SEGMENT.is2D() ? (random8(9)-4)/64.0f : 0; // no X velocity on 1D
flare->velX = SEGMENT.is2D() ? (hw_random8(9)-4)/64.0f : 0; // no X velocity on 1D
flare->col = 255; //brightness
SEGENV.aux0 = 1;
}
@ -3610,7 +3610,7 @@ uint16_t mode_exploding_fireworks(void)
* Explosion happens where the flare ended.
* Size is proportional to the height.
*/
unsigned nSparks = flare->pos + random8(4);
unsigned nSparks = flare->pos + hw_random8(4);
nSparks = std::max(nSparks, 4U); // This is not a standard constrain; numSparks is not guaranteed to be at least 4
nSparks = std::min(nSparks, numSparks);
@ -3619,12 +3619,12 @@ uint16_t mode_exploding_fireworks(void)
for (unsigned i = 1; i < nSparks; i++) {
sparks[i].pos = flare->pos;
sparks[i].posX = flare->posX;
sparks[i].vel = (float(random16(20001)) / 10000.0f) - 0.9f; // from -0.9 to 1.1
sparks[i].vel = (float(hw_random16(20001)) / 10000.0f) - 0.9f; // from -0.9 to 1.1
sparks[i].vel *= rows<32 ? 0.5f : 1; // reduce velocity for smaller strips
sparks[i].velX = SEGMENT.is2D() ? (float(random16(20001)) / 10000.0f) - 1.0f : 0; // from -1 to 1
sparks[i].velX = SEGMENT.is2D() ? (float(hw_random16(20001)) / 10000.0f) - 1.0f : 0; // from -1 to 1
sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright
//sparks[i].col = constrain(sparks[i].col, 0, 345);
sparks[i].colIndex = random8();
sparks[i].colIndex = hw_random8();
sparks[i].vel *= flare->pos/rows; // proportional to height
sparks[i].velX *= SEGMENT.is2D() ? flare->posX/cols : 0; // proportional to width
sparks[i].vel *= -gravity *50;
@ -3662,7 +3662,7 @@ uint16_t mode_exploding_fireworks(void)
if (SEGMENT.check3) SEGMENT.blur(16);
*dying_gravity *= .8f; // as sparks burn out they fall slower
} else {
SEGENV.aux0 = 6 + random8(10); //wait for this many frames
SEGENV.aux0 = 6 + hw_random8(10); //wait for this many frames
}
} else {
SEGENV.aux0--;
@ -3717,7 +3717,7 @@ uint16_t mode_drip(void)
drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling
if (random8() < drops[j].col/10) { // random drop
if (hw_random8() < drops[j].col/10) { // random drop
drops[j].colIndex=2; //fall
drops[j].col=255;
}
@ -3803,17 +3803,17 @@ uint16_t mode_tetrix(void) {
// speed calculation: a single brick should reach bottom of strip in X seconds
// if the speed is set to 1 this should take 5s and at 255 it should take 0.25s
// as this is dependant on SEGLEN it should be taken into account and the fact that effect runs every FRAMETIME s
int speed = SEGMENT.speed ? SEGMENT.speed : random8(1,255);
int speed = SEGMENT.speed ? SEGMENT.speed : hw_random8(1,255);
speed = map(speed, 1, 255, 5000, 250); // time taken for full (SEGLEN) drop
drop->speed = float(SEGLEN * FRAMETIME) / float(speed); // set speed
drop->pos = SEGLEN; // start at end of segment (no need to subtract 1)
if (!SEGMENT.check1) drop->col = random8(0,15)<<4; // limit color choices so there is enough HUE gap
if (!SEGMENT.check1) drop->col = hw_random8(0,15)<<4; // limit color choices so there is enough HUE gap
drop->step = 1; // drop state (0 init, 1 forming, 2 falling)
drop->brick = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : random8(1,5)) * (1+(SEGLEN>>6)); // size of brick
drop->brick = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : hw_random8(1,5)) * (1+(SEGLEN>>6)); // size of brick
}
if (drop->step == 1) { // forming
if (random8()>>6) { // random drop
if (hw_random8()>>6) { // random drop
drop->step = 2; // fall
}
}
@ -3862,7 +3862,7 @@ static const char _data_FX_MODE_TETRIX[] PROGMEM = "Tetrix@!,Width,,,,One color;
uint16_t mode_plasma(void) {
// initialize phases on start
if (SEGENV.call == 0) {
SEGENV.aux0 = random8(0,2); // add a bit of randomness
SEGENV.aux0 = hw_random8(0,2); // add a bit of randomness
}
unsigned thisPhase = beatsin8_t(6+SEGENV.aux0,-64,64);
unsigned thatPhase = beatsin8_t(7+SEGENV.aux0,-64,64);
@ -4206,8 +4206,8 @@ uint16_t mode_noisepal(void) { // Slow noise
{
SEGENV.step = strip.now;
unsigned baseI = random8();
palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255)));
unsigned baseI = hw_random8();
palettes[1] = CRGBPalette16(CHSV(baseI+hw_random8(64), 255, hw_random8(128,255)), CHSV(baseI+128, 255, hw_random8(128,255)), CHSV(baseI+hw_random8(92), 192, hw_random8(128,255)), CHSV(baseI+hw_random8(92), 255, hw_random8(128,255)));
}
//EVERY_N_MILLIS(10) { //(don't have to time this, effect function is only called every 24ms)
@ -4374,16 +4374,16 @@ uint16_t mode_dancing_shadows(void)
}
if (initialize || respawn) {
spotlights[i].colorIdx = random8();
spotlights[i].width = random8(1, 10);
spotlights[i].colorIdx = hw_random8();
spotlights[i].width = hw_random8(1, 10);
spotlights[i].speed = 1.0/random8(4, 50);
spotlights[i].speed = 1.0/hw_random8(4, 50);
if (initialize) {
spotlights[i].position = random16(SEGLEN);
spotlights[i].speed *= random8(2) ? 1.0 : -1.0;
spotlights[i].position = hw_random16(SEGLEN);
spotlights[i].speed *= hw_random8(2) ? 1.0 : -1.0;
} else {
if (random8(2)) {
if (hw_random8(2)) {
spotlights[i].position = SEGLEN + spotlights[i].width;
spotlights[i].speed *= -1.0;
}else {
@ -4392,7 +4392,7 @@ uint16_t mode_dancing_shadows(void)
}
spotlights[i].lastUpdateTime = time;
spotlights[i].type = random8(SPOT_TYPES_COUNT);
spotlights[i].type = hw_random8(SPOT_TYPES_COUNT);
}
uint32_t color = SEGMENT.color_from_palette(spotlights[i].colorIdx, false, false, 255);
@ -4551,10 +4551,10 @@ uint16_t mode_tv_simulator(void) {
// create a new sceene
if (((strip.now - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) {
tvSimulator->sceeneStart = strip.now; // remember the start of the new sceene
tvSimulator->sceeneDuration = random16(60* 250* colorSpeed, 60* 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider)
tvSimulator->sceeneColorHue = random16( 0, 768); // random start color-tone for the sceene
tvSimulator->sceeneColorSat = random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene
tvSimulator->sceeneColorBri = random8 ( 200, 240); // random start color-brightness for the sceene
tvSimulator->sceeneDuration = hw_random16(60* 250* colorSpeed, 60* 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider)
tvSimulator->sceeneColorHue = hw_random16( 0, 768); // random start color-tone for the sceene
tvSimulator->sceeneColorSat = hw_random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene
tvSimulator->sceeneColorBri = hw_random8 ( 200, 240); // random start color-brightness for the sceene
SEGENV.aux1 = 1;
SEGENV.aux0 = 0;
}
@ -4562,16 +4562,16 @@ uint16_t mode_tv_simulator(void) {
// slightly change the color-tone in this sceene
if (SEGENV.aux0 == 0) {
// hue change in both directions
j = random8(4 * colorIntensity);
hue = (random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative
j = hw_random8(4 * colorIntensity);
hue = (hw_random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative
((j + tvSimulator->sceeneColorHue) < 767 ? tvSimulator->sceeneColorHue + j : tvSimulator->sceeneColorHue + j - 767) ; // positive
// saturation
j = random8(2 * colorIntensity);
j = hw_random8(2 * colorIntensity);
sat = (tvSimulator->sceeneColorSat - j) < 0 ? 0 : tvSimulator->sceeneColorSat - j;
// brightness
j = random8(100);
j = hw_random8(100);
bri = (tvSimulator->sceeneColorBri - j) < 0 ? 0 : tvSimulator->sceeneColorBri - j;
// calculate R,G,B from HSV
@ -4597,9 +4597,9 @@ uint16_t mode_tv_simulator(void) {
SEGENV.aux0 = 1;
// randomize total duration and fade duration for the actual color
tvSimulator->totalTime = random16(250, 2500); // Semi-random pixel-to-pixel time
tvSimulator->fadeTime = random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time
if (random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time
tvSimulator->totalTime = hw_random16(250, 2500); // Semi-random pixel-to-pixel time
tvSimulator->fadeTime = hw_random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time
if (hw_random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time
tvSimulator->startTime = strip.now;
} // end of initialization
@ -4664,15 +4664,15 @@ class AuroraWave {
public:
void init(uint32_t segment_length, CRGB color) {
ttl = random16(500, 1501);
ttl = hw_random16(500, 1501);
basecolor = color;
basealpha = random8(60, 101) / (float)100;
basealpha = hw_random8(60, 101) / (float)100;
age = 0;
width = random16(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
width = hw_random16(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier
if (!width) width = 1;
center = random8(101) / (float)100 * segment_length;
goingleft = random8(0, 2) == 0;
speed_factor = (random8(10, 31) / (float)100 * W_MAX_SPEED / 255);
center = hw_random8(101) / (float)100 * segment_length;
goingleft = hw_random8(0, 2) == 0;
speed_factor = (hw_random8(10, 31) / (float)100 * W_MAX_SPEED / 255);
alive = true;
}
@ -4757,7 +4757,7 @@ uint16_t mode_aurora(void) {
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
for (int i = 0; i < SEGENV.aux1; i++) {
waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random8(0, 3))));
waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(hw_random8(), false, false, hw_random8(0, 3))));
}
} else {
waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
@ -4769,7 +4769,7 @@ uint16_t mode_aurora(void) {
if(!(waves[i].stillAlive())) {
//If a wave dies, reinitialize it starts over.
waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random8(0, 3))));
waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(hw_random8(), false, false, hw_random8(0, 3))));
}
}
@ -5124,15 +5124,14 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
if (SEGENV.call == 0 || strip.now - SEGMENT.step > 3000) {
SEGENV.step = strip.now;
SEGENV.aux0 = 0;
//random16_set_seed(millis()>>2); //seed the random generator
//give the leds random state and colors (based on intensity, colors from palette or all posible colors are chosen)
for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) {
unsigned state = random8()%2;
unsigned state = hw_random8()%2;
if (state == 0)
SEGMENT.setPixelColorXY(x,y, backgroundColor);
else
SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 255));
SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(hw_random8(), false, PALETTE_SOLID_WRAP, 255));
}
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) prevLeds[XY(x,y)] = CRGB::Black;
@ -5187,9 +5186,9 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
for (int i=0; i<9 && colorsCount[i].count != 0; i++)
if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i];
// assign the dominant color w/ a bit of randomness to avoid "gliders"
if (dominantColorCount.count > 0 && random8(128)) SEGMENT.setPixelColorXY(x,y, dominantColorCount.color);
} else if ((col == bgc) && (neighbors == 2) && !random8(128)) { // Mutation
SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 255));
if (dominantColorCount.count > 0 && hw_random8(128)) SEGMENT.setPixelColorXY(x,y, dominantColorCount.color);
} else if ((col == bgc) && (neighbors == 2) && !hw_random8(128)) { // Mutation
SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(hw_random8(), false, PALETTE_SOLID_WRAP, 255));
}
// else do nothing!
} //x,y
@ -5433,8 +5432,8 @@ uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams.
}
// spawn new falling code
if (random8() <= SEGMENT.intensity || emptyScreen) {
uint8_t spawnX = random8(cols);
if (hw_random8() <= SEGMENT.intensity || emptyScreen) {
uint8_t spawnX = hw_random8(cols);
SEGMENT.setPixelColorXY(spawnX, 0, spawnColor);
// update hint for next run
unsigned index = XY(spawnX, 0) >> 3;
@ -5787,11 +5786,11 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht
uint32_t tb = strip.now >> 12; // every ~4s
if (tb > SEGENV.step) {
int dir = ++SEGENV.aux0;
dir += (int)random8(3)-1;
dir += (int)hw_random8(3)-1;
if (dir > 7) SEGENV.aux0 = 0;
else if (dir < 0) SEGENV.aux0 = 7;
else SEGENV.aux0 = dir;
SEGENV.step = tb + random8(4);
SEGENV.step = tb + hw_random8(4);
}
SEGMENT.fadeToBlackBy(map(SEGMENT.speed, 0, 255, 248, 16));
@ -5921,9 +5920,8 @@ uint16_t mode_2Dghostrider(void) {
if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) {
SEGENV.aux0 = cols;
SEGENV.aux1 = rows;
//random16_set_seed(strip.now);
lighter->angleSpeed = random8(0,20) - 10;
lighter->gAngle = random16();
lighter->angleSpeed = hw_random8(0,20) - 10;
lighter->gAngle = hw_random16();
lighter->Vspeed = 5;
lighter->gPosX = (cols/2) * 10;
lighter->gPosY = (rows/2) * 10;
@ -5951,7 +5949,7 @@ uint16_t mode_2Dghostrider(void) {
if (lighter->gPosY < 0) lighter->gPosY = (rows - 1) * 10;
if (lighter->gPosY > (rows - 1) * 10) lighter->gPosY = 0;
for (size_t i = 0; i < maxLighters; i++) {
lighter->time[i] += random8(5, 20);
lighter->time[i] += hw_random8(5, 20);
if (lighter->time[i] >= 255 ||
(lighter->lightersPosX[i] <= 0) ||
(lighter->lightersPosX[i] >= (cols - 1) * 10) ||
@ -5962,7 +5960,7 @@ uint16_t mode_2Dghostrider(void) {
if (lighter->reg[i]) {
lighter->lightersPosY[i] = lighter->gPosY;
lighter->lightersPosX[i] = lighter->gPosX;
lighter->Angle[i] = lighter->gAngle + ((int)random8(20) - 10);
lighter->Angle[i] = lighter->gAngle + ((int)hw_random8(20) - 10);
lighter->time[i] = 0;
lighter->reg[i] = false;
} else {
@ -6008,12 +6006,12 @@ uint16_t mode_2Dfloatingblobs(void) {
SEGENV.aux1 = rows;
//SEGMENT.fill(BLACK);
for (size_t i = 0; i < MAX_BLOBS; i++) {
blob->r[i] = random8(1, cols>8 ? (cols/4) : 2);
blob->sX[i] = (float) random8(3, cols) / (float)(256 - SEGMENT.speed); // speed x
blob->sY[i] = (float) random8(3, rows) / (float)(256 - SEGMENT.speed); // speed y
blob->x[i] = random8(0, cols-1);
blob->y[i] = random8(0, rows-1);
blob->color[i] = random8();
blob->r[i] = hw_random8(1, cols>8 ? (cols/4) : 2);
blob->sX[i] = (float) hw_random8(3, cols) / (float)(256 - SEGMENT.speed); // speed x
blob->sY[i] = (float) hw_random8(3, rows) / (float)(256 - SEGMENT.speed); // speed y
blob->x[i] = hw_random8(0, cols-1);
blob->y[i] = hw_random8(0, rows-1);
blob->color[i] = hw_random8();
blob->grow[i] = (blob->r[i] < 1.f);
if (blob->sX[i] == 0) blob->sX[i] = 1;
if (blob->sY[i] == 0) blob->sY[i] = 1;
@ -6052,19 +6050,19 @@ uint16_t mode_2Dfloatingblobs(void) {
else blob->y[i] += blob->sY[i];
// bounce x
if (blob->x[i] < 0.01f) {
blob->sX[i] = (float)random8(3, cols) / (256 - SEGMENT.speed);
blob->sX[i] = (float)hw_random8(3, cols) / (256 - SEGMENT.speed);
blob->x[i] = 0.01f;
} else if (blob->x[i] > (float)cols - 1.01f) {
blob->sX[i] = (float)random8(3, cols) / (256 - SEGMENT.speed);
blob->sX[i] = (float)hw_random8(3, cols) / (256 - SEGMENT.speed);
blob->sX[i] = -blob->sX[i];
blob->x[i] = (float)cols - 1.01f;
}
// bounce y
if (blob->y[i] < 0.01f) {
blob->sY[i] = (float)random8(3, rows) / (256 - SEGMENT.speed);
blob->sY[i] = (float)hw_random8(3, rows) / (256 - SEGMENT.speed);
blob->y[i] = 0.01f;
} else if (blob->y[i] > (float)rows - 1.01f) {
blob->sY[i] = (float)random8(3, rows) / (256 - SEGMENT.speed);
blob->sY[i] = (float)hw_random8(3, rows) / (256 - SEGMENT.speed);
blob->sY[i] = -blob->sY[i];
blob->y[i] = (float)rows - 1.01f;
}
@ -6306,13 +6304,13 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli
break;
case 255: // Initialize ripple variables.
ripples[i].pos = random16(SEGLEN);
ripples[i].pos = hw_random16(SEGLEN);
#ifdef ESP32
if (FFT_MajorPeak > 1) // log10(0) is "forbidden" (throws exception)
ripples[i].color = (int)(log10f(FFT_MajorPeak)*128);
else ripples[i].color = 0;
#else
ripples[i].color = random8();
ripples[i].color = hw_random8();
#endif
ripples[i].state = 0;
break;
@ -6760,7 +6758,7 @@ uint16_t mode_puddles_base(bool peakdetect) {
if (SEGLEN == 1) return mode_static();
unsigned size = 0;
uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254);
unsigned pos = random16(SEGLEN); // Set a random starting position.
unsigned pos = hw_random16(SEGLEN); // Set a random starting position.
SEGMENT.fade_out(fadeVal);
um_data_t *um_data = getAudioData();
@ -6823,7 +6821,7 @@ uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline.
SEGMENT.fade_out(64+(SEGMENT.speed>>1));
for (int i=0; i <SEGMENT.intensity/8; i++) {
unsigned segLoc = random16(SEGLEN); // 16 bit for larger strands of LED's.
unsigned segLoc = hw_random16(SEGLEN); // 16 bit for larger strands of LED's.
SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(myVals[i%32]+i*4, false, PALETTE_SOLID_WRAP, 0), uint8_t(volumeSmth)));
}
@ -6851,7 +6849,7 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline.
SEGENV.step += FRAMETIME;
if (SEGENV.step > SPEED_FORMULA_L) {
unsigned segLoc = random16(SEGLEN);
unsigned segLoc = hw_random16(SEGLEN);
SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, (int)SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), uint8_t(2*fftResult[SEGENV.aux0%16])));
++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16
@ -7005,7 +7003,7 @@ uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline.
uint8_t pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index.
if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow
for (int i=0; i < SEGMENT.intensity/32+1; i++) {
unsigned locn = random16(0,SEGLEN);
unsigned locn = hw_random16(0,SEGLEN);
SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (uint8_t)my_magnitude));
}
@ -7473,9 +7471,9 @@ uint16_t mode_2Dsoap() {
// init
if (SEGENV.call == 0) {
*noise32_x = random16();
*noise32_y = random16();
*noise32_z = random16();
*noise32_x = hw_random();
*noise32_y = hw_random();
*noise32_z = hw_random();
} else {
*noise32_x += mov;
*noise32_y += mov;

View File

@ -124,86 +124,86 @@ void setRandomColor(byte* rgb)
*/
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
{
CHSV palettecolors[4]; //array of colors for the new palette
uint8_t keepcolorposition = random8(4); //color position of current random palette to keep
palettecolors[keepcolorposition] = rgb2hsv(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette
palettecolors[keepcolorposition].hue += random8(10)-5; // +/- 5 randomness of base color
//generate 4 saturation and brightness value numbers
//only one saturation is allowed to be below 200 creating mostly vibrant colors
//only one brightness value number is allowed below 200, creating mostly bright palettes
CHSV palettecolors[4]; // array of colors for the new palette
uint8_t keepcolorposition = hw_random8(4); // color position of current random palette to keep
palettecolors[keepcolorposition] = rgb2hsv(basepalette.entries[keepcolorposition*5]); // read one of the base colors of the current palette
palettecolors[keepcolorposition].hue += hw_random8(10)-5; // +/- 5 randomness of base color
// generate 4 saturation and brightness value numbers
// only one saturation is allowed to be below 200 creating mostly vibrant colors
// only one brightness value number is allowed below 200, creating mostly bright palettes
for (int i = 0; i < 3; i++) { //generate three high values
palettecolors[i].saturation = random8(200,255);
palettecolors[i].value = random8(220,255);
for (int i = 0; i < 3; i++) { // generate three high values
palettecolors[i].saturation = hw_random8(200,255);
palettecolors[i].value = hw_random8(220,255);
}
//allow one to be lower
palettecolors[3].saturation = random8(20,255);
palettecolors[3].value = random8(80,255);
// allow one to be lower
palettecolors[3].saturation = hw_random8(20,255);
palettecolors[3].value = hw_random8(80,255);
//shuffle the arrays
// shuffle the arrays
for (int i = 3; i > 0; i--) {
std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation);
std::swap(palettecolors[i].value, palettecolors[random8(i + 1)].value);
std::swap(palettecolors[i].saturation, palettecolors[hw_random8(i + 1)].saturation);
std::swap(palettecolors[i].value, palettecolors[hw_random8(i + 1)].value);
}
//now generate three new hues based off of the hue of the chosen current color
// now generate three new hues based off of the hue of the chosen current color
uint8_t basehue = palettecolors[keepcolorposition].hue;
uint8_t harmonics[3]; //hues that are harmonic but still a little random
uint8_t type = random8(5); //choose a harmony type
uint8_t harmonics[3]; // hues that are harmonic but still a little random
uint8_t type = hw_random8(5); // choose a harmony type
switch (type) {
case 0: // analogous
harmonics[0] = basehue + random8(30, 50);
harmonics[1] = basehue + random8(10, 30);
harmonics[2] = basehue - random8(10, 30);
harmonics[0] = basehue + hw_random8(30, 50);
harmonics[1] = basehue + hw_random8(10, 30);
harmonics[2] = basehue - hw_random8(10, 30);
break;
case 1: // triadic
harmonics[0] = basehue + 113 + random8(15);
harmonics[1] = basehue + 233 + random8(15);
harmonics[2] = basehue - 7 + random8(15);
harmonics[0] = basehue + 113 + hw_random8(15);
harmonics[1] = basehue + 233 + hw_random8(15);
harmonics[2] = basehue - 7 + hw_random8(15);
break;
case 2: // split-complementary
harmonics[0] = basehue + 145 + random8(10);
harmonics[1] = basehue + 205 + random8(10);
harmonics[2] = basehue - 5 + random8(10);
harmonics[0] = basehue + 145 + hw_random8(10);
harmonics[1] = basehue + 205 + hw_random8(10);
harmonics[2] = basehue - 5 + hw_random8(10);
break;
case 3: // square
harmonics[0] = basehue + 85 + random8(10);
harmonics[1] = basehue + 175 + random8(10);
harmonics[2] = basehue + 265 + random8(10);
harmonics[0] = basehue + 85 + hw_random8(10);
harmonics[1] = basehue + 175 + hw_random8(10);
harmonics[2] = basehue + 265 + hw_random8(10);
break;
case 4: // tetradic
harmonics[0] = basehue + 80 + random8(20);
harmonics[1] = basehue + 170 + random8(20);
harmonics[2] = basehue - 15 + random8(30);
harmonics[0] = basehue + 80 + hw_random8(20);
harmonics[1] = basehue + 170 + hw_random8(20);
harmonics[2] = basehue - 15 + hw_random8(30);
break;
}
if (random8() < 128) {
//50:50 chance of shuffling hues or keep the color order
if (hw_random8() < 128) {
// 50:50 chance of shuffling hues or keep the color order
for (int i = 2; i > 0; i--) {
std::swap(harmonics[i], harmonics[random8(i + 1)]);
std::swap(harmonics[i], harmonics[hw_random8(i + 1)]);
}
}
//now set the hues
// now set the hues
int j = 0;
for (int i = 0; i < 4; i++) {
if (i==keepcolorposition) continue; //skip the base color
if (i==keepcolorposition) continue; // skip the base color
palettecolors[i].hue = harmonics[j];
j++;
}
bool makepastelpalette = false;
if (random8() < 25) { //~10% chance of desaturated 'pastel' colors
if (hw_random8() < 25) { // ~10% chance of desaturated 'pastel' colors
makepastelpalette = true;
}
//apply saturation & gamma correction
// apply saturation & gamma correction
CRGB RGBpalettecolors[4];
for (int i = 0; i < 4; i++) {
if (makepastelpalette && palettecolors[i].saturation > 180) {
@ -219,12 +219,12 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
RGBpalettecolors[3]);
}
CRGBPalette16 generateRandomPalette() //generate fully random palette
CRGBPalette16 generateRandomPalette() // generate fully random palette
{
return CRGBPalette16(CHSV(random8(), random8(160, 255), random8(128, 255)),
CHSV(random8(), random8(160, 255), random8(128, 255)),
CHSV(random8(), random8(160, 255), random8(128, 255)),
CHSV(random8(), random8(160, 255), random8(128, 255)));
return CRGBPalette16(CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)));
}
void hsv2rgb(const CHSV32& hsv, uint32_t& rgb) // convert HSV (16bit hue) to RGB (32bit with white = 0)

View File

@ -458,6 +458,12 @@ 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
int 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); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form)
@ -485,6 +491,23 @@ void enumerateLedmaps();
uint8_t get_random_wheel_index(uint8_t pos);
float mapf(float x, float in_min, float in_max, float out_min, float out_max);
// fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1
// note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz)
// tests show it is still highly random reading it quickly in a loop (better than fastled PRNG)
// for 8bit and 16bit random functions: no limit check is done for best speed
// 32bit inputs are used for speed and code size, limits don't work if inverted or out of range
// inlining does save code size except for random(a,b) and 32bit random with limits
#define random hw_random // replace arduino random()
inline uint32_t hw_random() { return HW_RND_REGISTER; };
uint32_t hw_random(uint32_t upperlimit); // not inlined for code size
int32_t hw_random(int32_t lowerlimit, int32_t upperlimit);
inline uint16_t hw_random16() { return HW_RND_REGISTER; };
inline uint16_t hw_random16(uint32_t upperlimit) { return (hw_random16() * upperlimit) >> 16; }; // input range 0-65535 (uint16_t)
inline int16_t hw_random16(int32_t lowerlimit, int32_t upperlimit) { int32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random16(range); }; // signed limits, use int16_t ranges
inline uint8_t hw_random8() { return HW_RND_REGISTER; };
inline uint8_t hw_random8(uint32_t upperlimit) { return (hw_random8() * upperlimit) >> 8; }; // input range 0-255
inline uint8_t hw_random8(uint32_t lowerlimit, uint32_t upperlimit) { uint32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random8(range); }; // input range 0-255
// RAII guard class for the JSON Buffer lock
// Modeled after std::lock_guard
class JSONBufferGuard {

View File

@ -593,7 +593,7 @@ static void decodeIRJson(uint32_t code)
decBrightness();
} else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback
uint8_t p1 = fdo["PL"] | 1;
uint8_t p2 = fdo["FX"] | random8(strip.getModeCount() -1);
uint8_t p2 = fdo["FX"] | hw_random8(strip.getModeCount() -1);
uint8_t p3 = fdo["FP"] | 0;
presetFallback(p1, p2, p3);
}

View File

@ -146,7 +146,7 @@ static bool remoteJson(int button)
parsed = true;
} else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback
uint8_t p1 = fdo["PL"] | 1;
uint8_t p2 = fdo["FX"] | random8(strip.getModeCount() -1);
uint8_t p2 = fdo["FX"] | hw_random8(strip.getModeCount() -1);
uint8_t p3 = fdo["FP"] | 0;
presetWithFallback(p1, p2, p3);
parsed = true;

View File

@ -14,7 +14,7 @@ int getNumVal(const String* req, uint16_t pos)
void parseNumber(const char* str, byte* val, byte minv, byte maxv)
{
if (str == nullptr || str[0] == '\0') return;
if (str[0] == 'r') {*val = random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0
if (str[0] == 'r') {*val = hw_random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0
bool wrap = false;
if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;}
if (str[0] == '~') {
@ -474,9 +474,9 @@ um_data_t* simulateSound(uint8_t simulationId)
break;
case UMS_WeWillRockYou:
if (ms%2000 < 200) {
volumeSmth = random8(255);
volumeSmth = hw_random8();
for (int i = 0; i<5; i++)
fftResult[i] = random8(255);
fftResult[i] = hw_random8();
}
else if (ms%2000 < 400) {
volumeSmth = 0;
@ -484,9 +484,9 @@ um_data_t* simulateSound(uint8_t simulationId)
fftResult[i] = 0;
}
else if (ms%2000 < 600) {
volumeSmth = random8(255);
volumeSmth = hw_random8();
for (int i = 5; i<11; i++)
fftResult[i] = random8(255);
fftResult[i] = hw_random8();
}
else if (ms%2000 < 800) {
volumeSmth = 0;
@ -494,9 +494,9 @@ um_data_t* simulateSound(uint8_t simulationId)
fftResult[i] = 0;
}
else if (ms%2000 < 1000) {
volumeSmth = random8(255);
volumeSmth = hw_random8();
for (int i = 11; i<16; i++)
fftResult[i] = random8(255);
fftResult[i] = hw_random8();
}
else {
volumeSmth = 0;
@ -516,7 +516,7 @@ um_data_t* simulateSound(uint8_t simulationId)
break;
}
samplePeak = random8() > 250;
samplePeak = hw_random8() > 250;
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz
maxVol = 31; // this gets feedback fro UI
binNum = 8; // this gets feedback fro UI
@ -582,7 +582,7 @@ void enumerateLedmaps() {
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);
@ -594,3 +594,18 @@ uint8_t get_random_wheel_index(uint8_t pos) {
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;
}
// 32 bit 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();
uint64_t scaled = uint64_t(rnd) * uint64_t(upperlimit);
return scaled >> 32;
}
int32_t hw_random(int32_t lowerlimit, int32_t upperlimit) {
if(lowerlimit >= upperlimit) {
return lowerlimit;
}
uint32_t diff = upperlimit - lowerlimit;
return hw_random(diff) + lowerlimit;
}

View File

@ -544,14 +544,8 @@ void WLED::setup()
#endif
// Seed FastLED random functions with an esp random value, which already works properly at this point.
#if defined(ARDUINO_ARCH_ESP32)
const uint32_t seed32 = esp_random();
#elif defined(ARDUINO_ARCH_ESP8266)
const uint32_t seed32 = RANDOM_REG32;
#else
const uint32_t seed32 = random(std::numeric_limits<long>::max());
#endif
random16_set_seed((uint16_t)((seed32 & 0xFFFF) ^ (seed32 >> 16)));
const uint32_t seed32 = hw_random();
random16_set_seed((uint16_t)seed32);
#if WLED_WATCHDOG_TIMEOUT > 0
enableWatchdog();