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 (useRandomColors) {
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
SEGENV.aux0 = random8(); SEGENV.aux0 = hw_random8();
SEGENV.step = 3; SEGENV.step = 3;
} }
if (SEGENV.step == 1) { //if flag set, change to new random color 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) { if (SEGENV.call == 0) {
SEGENV.aux0 = random8(); SEGENV.aux0 = hw_random8();
SEGENV.step = 2; SEGENV.step = 2;
} }
if (it != SEGENV.step) //new color if (it != SEGENV.step) //new color
@ -328,7 +328,7 @@ uint16_t mode_dynamic(void) {
if(SEGENV.call == 0) { if(SEGENV.call == 0) {
//SEGMENT.fill(BLACK); //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; 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 if (it != SEGENV.step && SEGMENT.speed != 0) //new color
{ {
for (unsigned i = 0; i < SEGLEN; i++) { 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; SEGENV.step = it;
} }
@ -617,7 +617,7 @@ uint16_t mode_twinkle(void) {
if (SEGENV.aux0 >= maxOn) if (SEGENV.aux0 >= maxOn)
{ {
SEGENV.aux0 = 0; SEGENV.aux0 = 0;
SEGENV.aux1 = random16(); //new seed for our PRNG SEGENV.aux1 = hw_random(); //new seed for our PRNG
} }
SEGENV.aux0++; SEGENV.aux0++;
SEGENV.step = it; SEGENV.step = it;
@ -651,9 +651,9 @@ uint16_t dissolve(uint32_t color) {
} }
for (unsigned j = 0; j <= SEGLEN / 15; j++) { 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 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 index = i >> 3;
unsigned bitNum = i & 0x07; unsigned bitNum = i & 0x07;
bool fadeUp = bitRead(SEGENV.data[index], bitNum); bool fadeUp = bitRead(SEGENV.data[index], bitNum);
@ -693,7 +693,7 @@ uint16_t dissolve(uint32_t color) {
* Blink several LEDs on and then off * Blink several LEDs on and then off
*/ */
uint16_t mode_dissolve(void) { 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;!,!;!"; 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 * Blink several LEDs on and then off in random colors
*/ */
uint16_t mode_dissolve_random(void) { 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;,!;!"; 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; uint32_t it = strip.now / cycleTime;
if (it != SEGENV.step) 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; SEGENV.step = it;
} }
@ -739,8 +739,8 @@ uint16_t mode_flash_sparkle(void) {
} }
if (strip.now - SEGENV.aux0 > SEGENV.step) { if (strip.now - SEGENV.aux0 > SEGENV.step) {
if(random8((255-SEGMENT.intensity) >> 4) == 0) { if(hw_random8((255-SEGMENT.intensity) >> 4) == 0) {
SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1)); //flash SEGMENT.setPixelColor(hw_random16(SEGLEN), SEGCOLOR(1)); //flash
} }
SEGENV.step = strip.now; SEGENV.step = strip.now;
SEGENV.aux0 = 255-SEGMENT.speed; SEGENV.aux0 = 255-SEGMENT.speed;
@ -760,10 +760,10 @@ uint16_t mode_hyper_sparkle(void) {
} }
if (strip.now - SEGENV.aux0 > SEGENV.step) { 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); int len = max(1, (int)SEGLEN/3);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1)); SEGMENT.setPixelColor(hw_random16(SEGLEN), SEGCOLOR(1));
} }
} }
SEGENV.step = strip.now; 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) { uint16_t mode_running_random(void) {
uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed)); uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed));
uint32_t it = strip.now / cycleTime; 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; unsigned zoneSize = ((255-SEGMENT.intensity) >> 4) +1;
uint16_t PRNG16 = SEGENV.aux0; uint16_t PRNG16 = SEGENV.aux0;
@ -1278,11 +1278,11 @@ uint16_t mode_fireworks() {
} }
for (int i=0; i<max(1, width/20); i++) { for (int i=0; i<max(1, width/20); i++) {
if (random8(129 - (SEGMENT.intensity >> 1)) == 0) { if (hw_random8(129 - (SEGMENT.intensity >> 1)) == 0) {
uint16_t index = random16(width*height); uint16_t index = hw_random16(width*height);
x = index % width; x = index % width;
y = 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); if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, col);
else SEGMENT.setPixelColor(index, col); else SEGMENT.setPixelColor(index, col);
SEGENV.aux1 = SEGENV.aux0; // old spark 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; byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255;
lum /= (((256-SEGMENT.intensity)/16)+1); lum /= (((256-SEGMENT.intensity)/16)+1);
for (unsigned i = 0; i < SEGLEN; i++) { for (unsigned i = 0; i < SEGLEN; i++) {
byte flicker = random8(lum); byte flicker = hw_random8(lum);
if (SEGMENT.palette == 0) { if (SEGMENT.palette == 0) {
SEGMENT.setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0)); SEGMENT.setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0));
} else { } else {
@ -1475,11 +1475,11 @@ uint16_t mode_fairy() {
if (stateTime > flashers[f].stateDur * 10) { if (stateTime > flashers[f].stateDur * 10) {
flashers[f].stateOn = !flashers[f].stateOn; flashers[f].stateOn = !flashers[f].stateOn;
if (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 { } 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; flashers[f].stateStart = now16;
if (stateTime < 255) { if (stateTime < 255) {
flashers[f].stateStart -= 255 -stateTime; //start early to get correct bri 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; flashers[f].stateOn = !flashers[f].stateOn;
bool init = !flashers[f].stateDur; bool init = !flashers[f].stateDur;
if (flashers[f].stateOn) { 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 { } 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; flashers[f].stateStart = now16;
stateTime = 0; stateTime = 0;
if (init) { if (init) {
flashers[f].stateStart -= riseFallTime; //start lit 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; stateTime = riseFallTime;
} }
} }
@ -1611,13 +1611,13 @@ uint16_t mode_icu(void) {
SEGMENT.setPixelColor(dest + SEGLEN/space, col); SEGMENT.setPixelColor(dest + SEGLEN/space, col);
if(SEGENV.aux0 == dest) { // pause between eye movements 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, SEGCOLOR(1));
SEGMENT.setPixelColor(dest + SEGLEN/space, SEGCOLOR(1)); SEGMENT.setPixelColor(dest + SEGLEN/space, SEGCOLOR(1));
return 200; return 200;
} }
SEGENV.aux0 = random16(SEGLEN-SEGLEN/space); SEGENV.aux0 = hw_random16(SEGLEN-SEGLEN/space);
return 1000 + random16(2000); return 1000 + hw_random16(2000);
} }
if(SEGENV.aux0 > SEGENV.step) { if(SEGENV.aux0 > SEGENV.step) {
@ -1747,7 +1747,7 @@ uint16_t mode_multi_comet(void) {
} }
comets[i]++; comets[i]++;
} else { } else {
if(!random16(SEGLEN)) { if(!hw_random16(SEGLEN)) {
comets[i] = 0; comets[i] = 0;
} }
} }
@ -1831,12 +1831,12 @@ uint16_t mode_oscillate(void) {
oscillators[i].pos = 0; oscillators[i].pos = 0;
oscillators[i].dir = 1; oscillators[i].dir = 1;
// make bigger steps for faster speeds // 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))) { if((oscillators[i].dir == 1) && (oscillators[i].pos >= (SEGLEN - 1))) {
oscillators[i].pos = SEGLEN - 1; oscillators[i].pos = SEGLEN - 1;
oscillators[i].dir = -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 //TODO
uint16_t mode_lightning(void) { uint16_t mode_lightning(void) {
if (SEGLEN == 1) return mode_static(); if (SEGLEN == 1) return mode_static();
unsigned ledstart = random16(SEGLEN); // Determine starting location of flash unsigned ledstart = hw_random16(SEGLEN); // Determine starting location of flash
unsigned ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) unsigned ledlen = 1 + hw_random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
uint8_t bri = 255/random8(1, 3); uint8_t bri = 255/hw_random8(1, 3);
if (SEGENV.aux1 == 0) //init, leader flash 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; SEGENV.aux1 *= 2;
bri = 52; //leader has lower brightness bri = 52; //leader has lower brightness
@ -1882,15 +1882,15 @@ uint16_t mode_lightning(void) {
SEGENV.aux1--; SEGENV.aux1--;
SEGENV.step = strip.now; 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 { } else {
if (strip.now - SEGENV.step > SEGENV.aux0) { if (strip.now - SEGENV.step > SEGENV.aux0) {
SEGENV.aux1--; SEGENV.aux1--;
if (SEGENV.aux1 < 2) SEGENV.aux1 = 0; 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) { 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; SEGENV.step = strip.now;
} }
@ -2103,7 +2103,7 @@ uint16_t mode_fire_2012() {
// Step 1. Cool down every cell a little // Step 1. Cool down every cell a little
for (unsigned i = 0; i < SEGLEN; i++) { 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 minTemp = (i<ignition) ? (ignition-i)/4 + 16 : 0; // should not become black in ignition area
uint8_t temp = qsub8(heat[i], cool); uint8_t temp = qsub8(heat[i], cool);
heat[i] = temp<minTemp ? minTemp : temp; 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 // Step 3. Randomly ignite new 'sparks' of heat near the bottom
if (random8() <= SEGMENT.intensity) { if (hw_random8() <= SEGMENT.intensity) {
uint8_t y = random8(ignition); uint8_t y = hw_random8(ignition);
uint8_t boost = (17+SEGMENT.custom3) * (ignition - y/2) / ignition; // integer math! 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() { 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++) { for (unsigned i = 0; i < SEGLEN; i++) {
unsigned index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN); unsigned index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN);
SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); 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++) { 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 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) { if (SEGMENT.getPixelColor(i) == 0) {
unsigned index = i >> 3; unsigned index = i >> 3;
unsigned bitNum = i & 0x07; unsigned bitNum = i & 0x07;
bitWrite(SEGENV.data[index], bitNum, true); 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 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 // fade all leds to colors[1] in LEDs one step
for (unsigned i = 0; i < SEGLEN; i++) { for (unsigned i = 0; i < SEGLEN; i++) {
uint32_t col; uint32_t col;
if (random8() <= 255 - SEGMENT.intensity) { if (hw_random8() <= 255 - SEGMENT.intensity) {
if(meteorSmooth) { 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); 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); col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255);
} }
else { else {
trail[i] = scale8(trail[i], 128 + random8(127)); trail[i] = scale8(trail[i], 128 + hw_random8(127));
int index = trail[i]; int index = trail[i];
int idx = 255; int idx = 255;
int bri = SEGMENT.palette==35 || SEGMENT.palette==36 ? 255 : trail[i]; int bri = SEGMENT.palette==35 || SEGMENT.palette==36 ? 255 : trail[i];
@ -2523,10 +2523,10 @@ static uint16_t ripple_base(uint8_t blurAmount = 0) {
ripplestate += rippledecay; ripplestate += rippledecay;
ripples[i].state = (ripplestate > 254) ? 0 : ripplestate; ripples[i].state = (ripplestate > 254) ? 0 : ripplestate;
} else {//randomly create new wave } 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].state = 1;
ripples[i].pos = SEGMENT.is2D() ? ((random8(SEG_W)<<8) | (random8(SEG_H))) : random16(SEGLEN); ripples[i].pos = SEGMENT.is2D() ? ((hw_random8(SEG_W)<<8) | (hw_random8(SEG_H))) : hw_random16(SEGLEN);
ripples[i].color = random8(); //color 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) { uint16_t mode_ripple_rainbow(void) {
if (SEGLEN == 1) return mode_static(); if (SEGLEN == 1) return mode_static();
if (SEGENV.call ==0) { if (SEGENV.call ==0) {
SEGENV.aux0 = random8(); SEGENV.aux0 = hw_random8();
SEGENV.aux1 = random8(); SEGENV.aux1 = hw_random8();
} }
if (SEGENV.aux0 == SEGENV.aux1) { if (SEGENV.aux0 == SEGENV.aux1) {
SEGENV.aux1 = random8(); SEGENV.aux1 = hw_random8();
} else if (SEGENV.aux1 > SEGENV.aux0) { } else if (SEGENV.aux1 > SEGENV.aux0) {
SEGENV.aux0++; SEGENV.aux0++;
} else { } else {
@ -2750,10 +2750,10 @@ uint16_t mode_halloween_eyes()
// - select a duration // - select a duration
// - immediately switch to eyes on state. // - immediately switch to eyes on state.
data.startPos = random16(0, maxWidth - eyeLength - 1); data.startPos = hw_random16(0, maxWidth - eyeLength - 1);
data.color = random8(); data.color = hw_random8();
if (strip.isMatrix) SEGMENT.offset = random16(SEG_H-1); // a hack: reuse offset since it is not used in matrices if (strip.isMatrix) SEGMENT.offset = hw_random16(SEG_H-1); // a hack: reuse offset since it is not used in matrices
duration = 128u + random16(SEGMENT.intensity*64u); duration = 128u + hw_random16(SEGMENT.intensity*64u);
data.duration = duration; data.duration = duration;
data.state = eyeState::on; data.state = eyeState::on;
[[fallthrough]]; [[fallthrough]];
@ -2780,11 +2780,11 @@ uint16_t mode_halloween_eyes()
} else if (elapsedTime > minimumOnTimeBegin) { } else if (elapsedTime > minimumOnTimeBegin) {
const uint32_t remainingTime = (elapsedTime >= duration) ? 0u : (duration - elapsedTime); const uint32_t remainingTime = (elapsedTime >= duration) ? 0u : (duration - elapsedTime);
if (remainingTime > minimumOnTimeEnd) { if (remainingTime > minimumOnTimeEnd) {
if (random8() < 4u) if (hw_random8() < 4u)
{ {
c = backgroundColor; c = backgroundColor;
data.state = eyeState::blink; 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 // - immediately switch to eyes-off state
const unsigned eyeOffTimeBase = SEGMENT.speed*128u; const unsigned eyeOffTimeBase = SEGMENT.speed*128u;
duration = eyeOffTimeBase + random16(eyeOffTimeBase); duration = eyeOffTimeBase + hw_random16(eyeOffTimeBase);
data.duration = duration; data.duration = duration;
data.state = eyeState::off; data.state = eyeState::off;
[[fallthrough]]; [[fallthrough]];
@ -3008,7 +3008,7 @@ uint16_t mode_bouncing_balls(void) {
balls[i].lastBounceTime = time; balls[i].lastBounceTime = time;
if (balls[i].impactVelocity < 0.015f) { 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; balls[i].impactVelocity = impactVelocityStart;
} }
} else if (balls[i].height > 1.0f) { } 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 SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); // start clean
for (unsigned i = 0; i < maxNumBalls; i++) { for (unsigned i = 0; i < maxNumBalls; i++) {
balls[i].lastBounceUpdate = strip.now; balls[i].lastBounceUpdate = strip.now;
balls[i].velocity = 20.0f * float(random16(1000, 10000))/10000.0f; // number from 1 to 10 balls[i].velocity = 20.0f * float(hw_random16(1000, 10000))/10000.0f; // number from 1 to 10
if (random8()<128) balls[i].velocity = -balls[i].velocity; // 50% chance of reverse direction if (hw_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].height = (float(hw_random16(0, 10000)) / 10000.0f); // from 0. to 1.
balls[i].mass = (float(random16(1000, 10000)) / 10000.0f); // from .1 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 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 // 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) { 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; balls[i].lastBounceUpdate = strip.now;
} }
// check if reached ends of the strip // 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 // utility function that will add random glitter to SEGMENT
void glitter_base(uint8_t intensity, uint32_t col = ULTRAWHITE) { 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 //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].pos += popcorn[i].vel;
popcorn[i].vel += gravity; popcorn[i].vel += gravity;
} else { // if kernel is inactive, randomly pop it } else { // if kernel is inactive, randomly pop it
if (random8() < 2) { // POP!!! if (hw_random8() < 2) { // POP!!!
popcorn[i].pos = 0.01f; 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; peakHeight = (peakHeight * (SEGLEN -1)) >> 8;
popcorn[i].vel = sqrtf(-2.0f * gravity * peakHeight); popcorn[i].vel = sqrtf(-2.0f * gravity * peakHeight);
if (SEGMENT.palette) if (SEGMENT.palette)
{ {
popcorn[i].colIndex = random8(); popcorn[i].colIndex = hw_random8();
} else { } else {
byte col = random8(0, NUM_COLORS); byte col = hw_random8(0, NUM_COLORS);
if (!SEGCOLOR(2) || !SEGCOLOR(col)) col = 0; if (!SEGCOLOR(2) || !SEGCOLOR(col)) col = 0;
popcorn[i].colIndex = col; 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]; s = SEGENV.data[d]; s_target = SEGENV.data[d+1]; fadeStep = SEGENV.data[d+2];
} }
if (fadeStep == 0) { //init vals 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; bool newTarget = false;
@ -3363,8 +3363,8 @@ uint16_t candle(bool multi)
} }
if (newTarget) { if (newTarget) {
s_target = random8(rndval) + random8(rndval); //between 0 and rndval*2 -2 = 252 s_target = hw_random8(rndval) + hw_random8(rndval); //between 0 and rndval*2 -2 = 252
if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + random8(rndval); if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + hw_random8(rndval);
unsigned offset = (255 - valrange); unsigned offset = (255 - valrange);
s_target += offset; s_target += offset;
@ -3450,19 +3450,19 @@ uint16_t mode_starburst(void) {
for (unsigned j = 0; j < numStars; j++) for (unsigned j = 0; j < numStars; j++)
{ {
// speed to adjust chance of a burst, max is nearly always. // 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. // Pick a random color and location.
unsigned startPos = random16(SEGLEN-1); unsigned startPos = hw_random16(SEGLEN-1);
float multiplier = (float)(random8())/255.0f * 1.0f; 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].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].birth = it;
stars[j].last = it; stars[j].last = it;
// more fragments means larger burst effect // 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++) { for (int i=0; i < STARBURST_MAX_FRAG; i++) {
if (i < num) stars[j].fragment[i] = startPos; 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 < 2) { //FLARE
if (SEGENV.aux0 == 0) { //init flare if (SEGENV.aux0 == 0) { //init flare
flare->pos = 0; flare->pos = 0;
flare->posX = SEGMENT.is2D() ? random16(2,cols-3) : (SEGMENT.intensity > random8()); // will enable random firing side on 1D flare->posX = SEGMENT.is2D() ? hw_random16(2,cols-3) : (SEGMENT.intensity > hw_random8()); // will enable random firing side on 1D
unsigned peakHeight = 75 + random8(180); //0-255 unsigned peakHeight = 75 + hw_random8(180); //0-255
peakHeight = (peakHeight * (rows -1)) >> 8; peakHeight = (peakHeight * (rows -1)) >> 8;
flare->vel = sqrtf(-2.0f * gravity * peakHeight); 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 flare->col = 255; //brightness
SEGENV.aux0 = 1; SEGENV.aux0 = 1;
} }
@ -3610,7 +3610,7 @@ uint16_t mode_exploding_fireworks(void)
* Explosion happens where the flare ended. * Explosion happens where the flare ended.
* Size is proportional to the height. * 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::max(nSparks, 4U); // This is not a standard constrain; numSparks is not guaranteed to be at least 4
nSparks = std::min(nSparks, numSparks); nSparks = std::min(nSparks, numSparks);
@ -3619,12 +3619,12 @@ uint16_t mode_exploding_fireworks(void)
for (unsigned i = 1; i < nSparks; i++) { for (unsigned i = 1; i < nSparks; i++) {
sparks[i].pos = flare->pos; sparks[i].pos = flare->pos;
sparks[i].posX = flare->posX; 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].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 = 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].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].vel *= flare->pos/rows; // proportional to height
sparks[i].velX *= SEGMENT.is2D() ? flare->posX/cols : 0; // proportional to width sparks[i].velX *= SEGMENT.is2D() ? flare->posX/cols : 0; // proportional to width
sparks[i].vel *= -gravity *50; sparks[i].vel *= -gravity *50;
@ -3662,7 +3662,7 @@ uint16_t mode_exploding_fireworks(void)
if (SEGMENT.check3) SEGMENT.blur(16); if (SEGMENT.check3) SEGMENT.blur(16);
*dying_gravity *= .8f; // as sparks burn out they fall slower *dying_gravity *= .8f; // as sparks burn out they fall slower
} else { } else {
SEGENV.aux0 = 6 + random8(10); //wait for this many frames SEGENV.aux0 = 6 + hw_random8(10); //wait for this many frames
} }
} else { } else {
SEGENV.aux0--; SEGENV.aux0--;
@ -3717,7 +3717,7 @@ uint16_t mode_drip(void)
drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling 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].colIndex=2; //fall
drops[j].col=255; 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 // 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 // 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 // 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 speed = map(speed, 1, 255, 5000, 250); // time taken for full (SEGLEN) drop
drop->speed = float(SEGLEN * FRAMETIME) / float(speed); // set speed drop->speed = float(SEGLEN * FRAMETIME) / float(speed); // set speed
drop->pos = SEGLEN; // start at end of segment (no need to subtract 1) 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->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 (drop->step == 1) { // forming
if (random8()>>6) { // random drop if (hw_random8()>>6) { // random drop
drop->step = 2; // fall 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) { uint16_t mode_plasma(void) {
// initialize phases on start // initialize phases on start
if (SEGENV.call == 0) { 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 thisPhase = beatsin8_t(6+SEGENV.aux0,-64,64);
unsigned thatPhase = beatsin8_t(7+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; SEGENV.step = strip.now;
unsigned baseI = random8(); unsigned baseI = hw_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))); 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) //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) { if (initialize || respawn) {
spotlights[i].colorIdx = random8(); spotlights[i].colorIdx = hw_random8();
spotlights[i].width = random8(1, 10); 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) { if (initialize) {
spotlights[i].position = random16(SEGLEN); spotlights[i].position = hw_random16(SEGLEN);
spotlights[i].speed *= random8(2) ? 1.0 : -1.0; spotlights[i].speed *= hw_random8(2) ? 1.0 : -1.0;
} else { } else {
if (random8(2)) { if (hw_random8(2)) {
spotlights[i].position = SEGLEN + spotlights[i].width; spotlights[i].position = SEGLEN + spotlights[i].width;
spotlights[i].speed *= -1.0; spotlights[i].speed *= -1.0;
}else { }else {
@ -4392,7 +4392,7 @@ uint16_t mode_dancing_shadows(void)
} }
spotlights[i].lastUpdateTime = time; 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); 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 // create a new sceene
if (((strip.now - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) { if (((strip.now - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) {
tvSimulator->sceeneStart = strip.now; // remember the start of the new sceene 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->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 = random16( 0, 768); // random start color-tone for the sceene tvSimulator->sceeneColorHue = hw_random16( 0, 768); // random start color-tone for the sceene
tvSimulator->sceeneColorSat = random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene tvSimulator->sceeneColorSat = hw_random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene
tvSimulator->sceeneColorBri = random8 ( 200, 240); // random start color-brightness for the sceene tvSimulator->sceeneColorBri = hw_random8 ( 200, 240); // random start color-brightness for the sceene
SEGENV.aux1 = 1; SEGENV.aux1 = 1;
SEGENV.aux0 = 0; SEGENV.aux0 = 0;
} }
@ -4562,16 +4562,16 @@ uint16_t mode_tv_simulator(void) {
// slightly change the color-tone in this sceene // slightly change the color-tone in this sceene
if (SEGENV.aux0 == 0) { if (SEGENV.aux0 == 0) {
// hue change in both directions // hue change in both directions
j = random8(4 * colorIntensity); j = hw_random8(4 * colorIntensity);
hue = (random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative 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 ((j + tvSimulator->sceeneColorHue) < 767 ? tvSimulator->sceeneColorHue + j : tvSimulator->sceeneColorHue + j - 767) ; // positive
// saturation // saturation
j = random8(2 * colorIntensity); j = hw_random8(2 * colorIntensity);
sat = (tvSimulator->sceeneColorSat - j) < 0 ? 0 : tvSimulator->sceeneColorSat - j; sat = (tvSimulator->sceeneColorSat - j) < 0 ? 0 : tvSimulator->sceeneColorSat - j;
// brightness // brightness
j = random8(100); j = hw_random8(100);
bri = (tvSimulator->sceeneColorBri - j) < 0 ? 0 : tvSimulator->sceeneColorBri - j; bri = (tvSimulator->sceeneColorBri - j) < 0 ? 0 : tvSimulator->sceeneColorBri - j;
// calculate R,G,B from HSV // calculate R,G,B from HSV
@ -4597,9 +4597,9 @@ uint16_t mode_tv_simulator(void) {
SEGENV.aux0 = 1; SEGENV.aux0 = 1;
// randomize total duration and fade duration for the actual color // randomize total duration and fade duration for the actual color
tvSimulator->totalTime = random16(250, 2500); // Semi-random pixel-to-pixel time tvSimulator->totalTime = hw_random16(250, 2500); // Semi-random pixel-to-pixel time
tvSimulator->fadeTime = random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time tvSimulator->fadeTime = hw_random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time
if (random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time if (hw_random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time
tvSimulator->startTime = strip.now; tvSimulator->startTime = strip.now;
} // end of initialization } // end of initialization
@ -4664,15 +4664,15 @@ class AuroraWave {
public: public:
void init(uint32_t segment_length, CRGB color) { void init(uint32_t segment_length, CRGB color) {
ttl = random16(500, 1501); ttl = hw_random16(500, 1501);
basecolor = color; basecolor = color;
basealpha = random8(60, 101) / (float)100; basealpha = hw_random8(60, 101) / (float)100;
age = 0; 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; if (!width) width = 1;
center = random8(101) / (float)100 * segment_length; center = hw_random8(101) / (float)100 * segment_length;
goingleft = random8(0, 2) == 0; goingleft = hw_random8(0, 2) == 0;
speed_factor = (random8(10, 31) / (float)100 * W_MAX_SPEED / 255); speed_factor = (hw_random8(10, 31) / (float)100 * W_MAX_SPEED / 255);
alive = true; alive = true;
} }
@ -4757,7 +4757,7 @@ uint16_t mode_aurora(void) {
waves = reinterpret_cast<AuroraWave*>(SEGENV.data); waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
for (int i = 0; i < SEGENV.aux1; i++) { 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 { } else {
waves = reinterpret_cast<AuroraWave*>(SEGENV.data); waves = reinterpret_cast<AuroraWave*>(SEGENV.data);
@ -4769,7 +4769,7 @@ uint16_t mode_aurora(void) {
if(!(waves[i].stillAlive())) { if(!(waves[i].stillAlive())) {
//If a wave dies, reinitialize it starts over. //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) { if (SEGENV.call == 0 || strip.now - SEGMENT.step > 3000) {
SEGENV.step = strip.now; SEGENV.step = strip.now;
SEGENV.aux0 = 0; 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) //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++) { 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) if (state == 0)
SEGMENT.setPixelColorXY(x,y, backgroundColor); SEGMENT.setPixelColorXY(x,y, backgroundColor);
else 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; 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++) for (int i=0; i<9 && colorsCount[i].count != 0; i++)
if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i]; if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i];
// assign the dominant color w/ a bit of randomness to avoid "gliders" // assign the dominant color w/ a bit of randomness to avoid "gliders"
if (dominantColorCount.count > 0 && random8(128)) SEGMENT.setPixelColorXY(x,y, dominantColorCount.color); if (dominantColorCount.count > 0 && hw_random8(128)) SEGMENT.setPixelColorXY(x,y, dominantColorCount.color);
} else if ((col == bgc) && (neighbors == 2) && !random8(128)) { // Mutation } else if ((col == bgc) && (neighbors == 2) && !hw_random8(128)) { // Mutation
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));
} }
// else do nothing! // else do nothing!
} //x,y } //x,y
@ -5433,8 +5432,8 @@ uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams.
} }
// spawn new falling code // spawn new falling code
if (random8() <= SEGMENT.intensity || emptyScreen) { if (hw_random8() <= SEGMENT.intensity || emptyScreen) {
uint8_t spawnX = random8(cols); uint8_t spawnX = hw_random8(cols);
SEGMENT.setPixelColorXY(spawnX, 0, spawnColor); SEGMENT.setPixelColorXY(spawnX, 0, spawnColor);
// update hint for next run // update hint for next run
unsigned index = XY(spawnX, 0) >> 3; 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 uint32_t tb = strip.now >> 12; // every ~4s
if (tb > SEGENV.step) { if (tb > SEGENV.step) {
int dir = ++SEGENV.aux0; int dir = ++SEGENV.aux0;
dir += (int)random8(3)-1; dir += (int)hw_random8(3)-1;
if (dir > 7) SEGENV.aux0 = 0; if (dir > 7) SEGENV.aux0 = 0;
else if (dir < 0) SEGENV.aux0 = 7; else if (dir < 0) SEGENV.aux0 = 7;
else SEGENV.aux0 = dir; else SEGENV.aux0 = dir;
SEGENV.step = tb + random8(4); SEGENV.step = tb + hw_random8(4);
} }
SEGMENT.fadeToBlackBy(map(SEGMENT.speed, 0, 255, 248, 16)); 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) { if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) {
SEGENV.aux0 = cols; SEGENV.aux0 = cols;
SEGENV.aux1 = rows; SEGENV.aux1 = rows;
//random16_set_seed(strip.now); lighter->angleSpeed = hw_random8(0,20) - 10;
lighter->angleSpeed = random8(0,20) - 10; lighter->gAngle = hw_random16();
lighter->gAngle = random16();
lighter->Vspeed = 5; lighter->Vspeed = 5;
lighter->gPosX = (cols/2) * 10; lighter->gPosX = (cols/2) * 10;
lighter->gPosY = (rows/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 < 0) lighter->gPosY = (rows - 1) * 10;
if (lighter->gPosY > (rows - 1) * 10) lighter->gPosY = 0; if (lighter->gPosY > (rows - 1) * 10) lighter->gPosY = 0;
for (size_t i = 0; i < maxLighters; i++) { 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 || if (lighter->time[i] >= 255 ||
(lighter->lightersPosX[i] <= 0) || (lighter->lightersPosX[i] <= 0) ||
(lighter->lightersPosX[i] >= (cols - 1) * 10) || (lighter->lightersPosX[i] >= (cols - 1) * 10) ||
@ -5962,7 +5960,7 @@ uint16_t mode_2Dghostrider(void) {
if (lighter->reg[i]) { if (lighter->reg[i]) {
lighter->lightersPosY[i] = lighter->gPosY; lighter->lightersPosY[i] = lighter->gPosY;
lighter->lightersPosX[i] = lighter->gPosX; 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->time[i] = 0;
lighter->reg[i] = false; lighter->reg[i] = false;
} else { } else {
@ -6008,12 +6006,12 @@ uint16_t mode_2Dfloatingblobs(void) {
SEGENV.aux1 = rows; SEGENV.aux1 = rows;
//SEGMENT.fill(BLACK); //SEGMENT.fill(BLACK);
for (size_t i = 0; i < MAX_BLOBS; i++) { for (size_t i = 0; i < MAX_BLOBS; i++) {
blob->r[i] = random8(1, cols>8 ? (cols/4) : 2); blob->r[i] = hw_random8(1, cols>8 ? (cols/4) : 2);
blob->sX[i] = (float) random8(3, cols) / (float)(256 - SEGMENT.speed); // speed x blob->sX[i] = (float) hw_random8(3, cols) / (float)(256 - SEGMENT.speed); // speed x
blob->sY[i] = (float) random8(3, rows) / (float)(256 - SEGMENT.speed); // speed y blob->sY[i] = (float) hw_random8(3, rows) / (float)(256 - SEGMENT.speed); // speed y
blob->x[i] = random8(0, cols-1); blob->x[i] = hw_random8(0, cols-1);
blob->y[i] = random8(0, rows-1); blob->y[i] = hw_random8(0, rows-1);
blob->color[i] = random8(); blob->color[i] = hw_random8();
blob->grow[i] = (blob->r[i] < 1.f); blob->grow[i] = (blob->r[i] < 1.f);
if (blob->sX[i] == 0) blob->sX[i] = 1; if (blob->sX[i] == 0) blob->sX[i] = 1;
if (blob->sY[i] == 0) blob->sY[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]; else blob->y[i] += blob->sY[i];
// bounce x // bounce x
if (blob->x[i] < 0.01f) { 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; blob->x[i] = 0.01f;
} else if (blob->x[i] > (float)cols - 1.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->sX[i] = -blob->sX[i];
blob->x[i] = (float)cols - 1.01f; blob->x[i] = (float)cols - 1.01f;
} }
// bounce y // bounce y
if (blob->y[i] < 0.01f) { 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; blob->y[i] = 0.01f;
} else if (blob->y[i] > (float)rows - 1.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->sY[i] = -blob->sY[i];
blob->y[i] = (float)rows - 1.01f; blob->y[i] = (float)rows - 1.01f;
} }
@ -6306,13 +6304,13 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli
break; break;
case 255: // Initialize ripple variables. case 255: // Initialize ripple variables.
ripples[i].pos = random16(SEGLEN); ripples[i].pos = hw_random16(SEGLEN);
#ifdef ESP32 #ifdef ESP32
if (FFT_MajorPeak > 1) // log10(0) is "forbidden" (throws exception) if (FFT_MajorPeak > 1) // log10(0) is "forbidden" (throws exception)
ripples[i].color = (int)(log10f(FFT_MajorPeak)*128); ripples[i].color = (int)(log10f(FFT_MajorPeak)*128);
else ripples[i].color = 0; else ripples[i].color = 0;
#else #else
ripples[i].color = random8(); ripples[i].color = hw_random8();
#endif #endif
ripples[i].state = 0; ripples[i].state = 0;
break; break;
@ -6760,7 +6758,7 @@ uint16_t mode_puddles_base(bool peakdetect) {
if (SEGLEN == 1) return mode_static(); if (SEGLEN == 1) return mode_static();
unsigned size = 0; unsigned size = 0;
uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254); 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); SEGMENT.fade_out(fadeVal);
um_data_t *um_data = getAudioData(); 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)); SEGMENT.fade_out(64+(SEGMENT.speed>>1));
for (int i=0; i <SEGMENT.intensity/8; i++) { 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))); 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; SEGENV.step += FRAMETIME;
if (SEGENV.step > SPEED_FORMULA_L) { 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]))); 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 ++(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. 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 if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow
for (int i=0; i < SEGMENT.intensity/32+1; i++) { 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)); 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 // init
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
*noise32_x = random16(); *noise32_x = hw_random();
*noise32_y = random16(); *noise32_y = hw_random();
*noise32_z = random16(); *noise32_z = hw_random();
} else { } else {
*noise32_x += mov; *noise32_x += mov;
*noise32_y += mov; *noise32_y += mov;

View File

@ -125,68 +125,68 @@ void setRandomColor(byte* rgb)
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
{ {
CHSV palettecolors[4]; // array of colors for the new palette CHSV palettecolors[4]; // array of colors for the new palette
uint8_t keepcolorposition = random8(4); //color position of current random palette to keep 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] = 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 palettecolors[keepcolorposition].hue += hw_random8(10)-5; // +/- 5 randomness of base color
// generate 4 saturation and brightness value numbers // generate 4 saturation and brightness value numbers
// only one saturation is allowed to be below 200 creating mostly vibrant colors // 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 // only one brightness value number is allowed below 200, creating mostly bright palettes
for (int i = 0; i < 3; i++) { // generate three high values for (int i = 0; i < 3; i++) { // generate three high values
palettecolors[i].saturation = random8(200,255); palettecolors[i].saturation = hw_random8(200,255);
palettecolors[i].value = random8(220,255); palettecolors[i].value = hw_random8(220,255);
} }
// allow one to be lower // allow one to be lower
palettecolors[3].saturation = random8(20,255); palettecolors[3].saturation = hw_random8(20,255);
palettecolors[3].value = random8(80,255); palettecolors[3].value = hw_random8(80,255);
// shuffle the arrays // shuffle the arrays
for (int i = 3; i > 0; i--) { for (int i = 3; i > 0; i--) {
std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation); std::swap(palettecolors[i].saturation, palettecolors[hw_random8(i + 1)].saturation);
std::swap(palettecolors[i].value, palettecolors[random8(i + 1)].value); 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 basehue = palettecolors[keepcolorposition].hue;
uint8_t harmonics[3]; // hues that are harmonic but still a little random uint8_t harmonics[3]; // hues that are harmonic but still a little random
uint8_t type = random8(5); //choose a harmony type uint8_t type = hw_random8(5); // choose a harmony type
switch (type) { switch (type) {
case 0: // analogous case 0: // analogous
harmonics[0] = basehue + random8(30, 50); harmonics[0] = basehue + hw_random8(30, 50);
harmonics[1] = basehue + random8(10, 30); harmonics[1] = basehue + hw_random8(10, 30);
harmonics[2] = basehue - random8(10, 30); harmonics[2] = basehue - hw_random8(10, 30);
break; break;
case 1: // triadic case 1: // triadic
harmonics[0] = basehue + 113 + random8(15); harmonics[0] = basehue + 113 + hw_random8(15);
harmonics[1] = basehue + 233 + random8(15); harmonics[1] = basehue + 233 + hw_random8(15);
harmonics[2] = basehue - 7 + random8(15); harmonics[2] = basehue - 7 + hw_random8(15);
break; break;
case 2: // split-complementary case 2: // split-complementary
harmonics[0] = basehue + 145 + random8(10); harmonics[0] = basehue + 145 + hw_random8(10);
harmonics[1] = basehue + 205 + random8(10); harmonics[1] = basehue + 205 + hw_random8(10);
harmonics[2] = basehue - 5 + random8(10); harmonics[2] = basehue - 5 + hw_random8(10);
break; break;
case 3: // square case 3: // square
harmonics[0] = basehue + 85 + random8(10); harmonics[0] = basehue + 85 + hw_random8(10);
harmonics[1] = basehue + 175 + random8(10); harmonics[1] = basehue + 175 + hw_random8(10);
harmonics[2] = basehue + 265 + random8(10); harmonics[2] = basehue + 265 + hw_random8(10);
break; break;
case 4: // tetradic case 4: // tetradic
harmonics[0] = basehue + 80 + random8(20); harmonics[0] = basehue + 80 + hw_random8(20);
harmonics[1] = basehue + 170 + random8(20); harmonics[1] = basehue + 170 + hw_random8(20);
harmonics[2] = basehue - 15 + random8(30); harmonics[2] = basehue - 15 + hw_random8(30);
break; break;
} }
if (random8() < 128) { if (hw_random8() < 128) {
// 50:50 chance of shuffling hues or keep the color order // 50:50 chance of shuffling hues or keep the color order
for (int i = 2; i > 0; i--) { for (int i = 2; i > 0; i--) {
std::swap(harmonics[i], harmonics[random8(i + 1)]); std::swap(harmonics[i], harmonics[hw_random8(i + 1)]);
} }
} }
@ -199,7 +199,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
} }
bool makepastelpalette = false; bool makepastelpalette = false;
if (random8() < 25) { //~10% chance of desaturated 'pastel' colors if (hw_random8() < 25) { // ~10% chance of desaturated 'pastel' colors
makepastelpalette = true; makepastelpalette = true;
} }
@ -221,10 +221,10 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
CRGBPalette16 generateRandomPalette() // generate fully random palette CRGBPalette16 generateRandomPalette() // generate fully random palette
{ {
return CRGBPalette16(CHSV(random8(), random8(160, 255), random8(128, 255)), return CRGBPalette16(CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
CHSV(random8(), random8(160, 255), 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) 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(); void userLoop();
//util.cpp //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); int getNumVal(const String* req, uint16_t pos);
void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); 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) 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); 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); 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 // RAII guard class for the JSON Buffer lock
// Modeled after std::lock_guard // Modeled after std::lock_guard
class JSONBufferGuard { class JSONBufferGuard {

View File

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

View File

@ -146,7 +146,7 @@ static bool remoteJson(int button)
parsed = true; parsed = true;
} else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback } else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback
uint8_t p1 = fdo["PL"] | 1; 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; uint8_t p3 = fdo["FP"] | 0;
presetWithFallback(p1, p2, p3); presetWithFallback(p1, p2, p3);
parsed = true; 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) void parseNumber(const char* str, byte* val, byte minv, byte maxv)
{ {
if (str == nullptr || str[0] == '\0') return; 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; bool wrap = false;
if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;} if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;}
if (str[0] == '~') { if (str[0] == '~') {
@ -474,9 +474,9 @@ um_data_t* simulateSound(uint8_t simulationId)
break; break;
case UMS_WeWillRockYou: case UMS_WeWillRockYou:
if (ms%2000 < 200) { if (ms%2000 < 200) {
volumeSmth = random8(255); volumeSmth = hw_random8();
for (int i = 0; i<5; i++) for (int i = 0; i<5; i++)
fftResult[i] = random8(255); fftResult[i] = hw_random8();
} }
else if (ms%2000 < 400) { else if (ms%2000 < 400) {
volumeSmth = 0; volumeSmth = 0;
@ -484,9 +484,9 @@ um_data_t* simulateSound(uint8_t simulationId)
fftResult[i] = 0; fftResult[i] = 0;
} }
else if (ms%2000 < 600) { else if (ms%2000 < 600) {
volumeSmth = random8(255); volumeSmth = hw_random8();
for (int i = 5; i<11; i++) for (int i = 5; i<11; i++)
fftResult[i] = random8(255); fftResult[i] = hw_random8();
} }
else if (ms%2000 < 800) { else if (ms%2000 < 800) {
volumeSmth = 0; volumeSmth = 0;
@ -494,9 +494,9 @@ um_data_t* simulateSound(uint8_t simulationId)
fftResult[i] = 0; fftResult[i] = 0;
} }
else if (ms%2000 < 1000) { else if (ms%2000 < 1000) {
volumeSmth = random8(255); volumeSmth = hw_random8();
for (int i = 11; i<16; i++) for (int i = 11; i<16; i++)
fftResult[i] = random8(255); fftResult[i] = hw_random8();
} }
else { else {
volumeSmth = 0; volumeSmth = 0;
@ -516,7 +516,7 @@ um_data_t* simulateSound(uint8_t simulationId)
break; break;
} }
samplePeak = random8() > 250; samplePeak = hw_random8() > 250;
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz
maxVol = 31; // this gets feedback fro UI maxVol = 31; // this gets feedback fro UI
binNum = 8; // 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 get_random_wheel_index(uint8_t pos) {
uint8_t r = 0, x = 0, y = 0, d = 0; uint8_t r = 0, x = 0, y = 0, d = 0;
while (d < 42) { while (d < 42) {
r = random8(); r = hw_random8();
x = abs(pos - r); x = abs(pos - r);
y = 255 - x; y = 255 - x;
d = MIN(x, y); 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) { 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; 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 #endif
// Seed FastLED random functions with an esp random value, which already works properly at this point. // 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 = hw_random();
const uint32_t seed32 = esp_random(); random16_set_seed((uint16_t)seed32);
#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)));
#if WLED_WATCHDOG_TIMEOUT > 0 #if WLED_WATCHDOG_TIMEOUT > 0
enableWatchdog(); enableWatchdog();