Update FX.cpp
* add more accurate version of map() - reduces slight flickering in some 2D effects * cache fftResult[] in effects (um_data->fftresult might get updated while the effect still calculates)
This commit is contained in:
@@ -79,6 +79,24 @@ static float mapf(float x, float in_min, float in_max, float out_min, float out_
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
// more accurate integer version of map() - based on map3() proposed in https://forum.arduino.cc/t/how-map-loses-precision-and-how-to-fix-it/371026/3
|
||||
// rounding instead of truncation, better handling of inverted ranges
|
||||
static long map2(long x, long in_min, long in_max, long out_min, long out_max)
|
||||
{
|
||||
long out_range = out_max - out_min;
|
||||
if (out_range > 0) out_range ++;
|
||||
else if (out_range < 0) out_range --;
|
||||
else return out_min; // output range is 0
|
||||
|
||||
long in_range = in_max - in_min;
|
||||
if (in_range > 0) in_range++;
|
||||
else if (in_range < 0) in_range --;
|
||||
else return out_min; // input range is 0 - Result is actually infinity but long has no such thing. The least negative long is another choice.
|
||||
|
||||
return ((x - in_min) * out_range) / in_range + out_min;
|
||||
}
|
||||
|
||||
|
||||
// effect functions
|
||||
|
||||
/*
|
||||
@@ -1986,7 +2004,7 @@ uint16_t mode_partyjerk() {
|
||||
if (SEGENV.aux1 > 254) {
|
||||
SEGENV.aux1 = 0;
|
||||
}
|
||||
if (SEGENV.aux0 > map(SEGMENT.custom1, 0, 255, 0, 14)) {
|
||||
if (SEGENV.aux0 > map2(SEGMENT.custom1, 0, 255, 0, 14)) {
|
||||
SEGENV.aux0 = 0;
|
||||
SEGENV.aux1++;
|
||||
}
|
||||
@@ -1995,7 +2013,7 @@ uint16_t mode_partyjerk() {
|
||||
uint16_t counter = 0;
|
||||
|
||||
if (volumeSmth * 2 > (255 - SEGMENT.intensity)) {
|
||||
speed = SEGMENT.speed * map(SEGMENT.custom2, 0, 255, 0, 100);
|
||||
speed = SEGMENT.speed * map2(SEGMENT.custom2, 0, 255, 0, 100);
|
||||
} else {
|
||||
speed = SEGMENT.speed;
|
||||
};
|
||||
@@ -4768,7 +4786,7 @@ uint16_t mode_aurora(void) {
|
||||
|
||||
if(SEGENV.aux0 != SEGMENT.intensity || SEGENV.call == 0) {
|
||||
//Intensity slider changed or first call
|
||||
SEGENV.aux1 = map(SEGMENT.intensity, 0, 255, 2, W_MAX_COUNT);
|
||||
SEGENV.aux1 = map2(SEGMENT.intensity, 0, 255, 2, W_MAX_COUNT);
|
||||
SEGENV.aux0 = SEGMENT.intensity;
|
||||
|
||||
if(!SEGENV.allocateData(sizeof(AuroraWave) * SEGENV.aux1)) { // 26 on 32 segment ESP32, 9 on 16 segment ESP8266
|
||||
@@ -5187,9 +5205,9 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
|
||||
bool allColors = SEGMENT.check1;
|
||||
bool overlayBG = SEGMENT.check2;
|
||||
bool wrap = SEGMENT.check3;
|
||||
byte blur = map(SEGMENT.custom1, 0, 255, 255, 0);
|
||||
byte blur = map2(SEGMENT.custom1, 0, 255, 255, 0);
|
||||
bool bgBlendMode = SEGMENT.custom1 > 220 && !overlayBG; // if blur is high and not overlaying, use bg blend mode
|
||||
byte bgBlur = map(SEGMENT.custom1 - 220, 0, 35, 255, 128);
|
||||
byte bgBlur = map2(SEGMENT.custom1 - 220, 0, 35, 255, 128);
|
||||
uint32_t bgColor = SEGCOLOR(1);
|
||||
uint32_t color = allColors ? random16() * random16() : SEGMENT.color_from_palette(0, false, PALETTE_SOLID_WRAP, 0);
|
||||
uint16_t cIndex;
|
||||
@@ -5748,7 +5766,7 @@ uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https
|
||||
}
|
||||
|
||||
float adjustHeight = mapf(rows, 8, maxRows, 28, minScale); // maybe use mapf() ??? // WLEDMM yes!
|
||||
uint16_t adjScale = map(cols, 8, 64, 310, 63);
|
||||
uint16_t adjScale = map2(cols, 8, 64, 310, 63);
|
||||
|
||||
adjustHeight = max(min(adjustHeight, 28.0f), minScale); // WLEDMM bugfix for larger fixtures
|
||||
adjScale = max(min(adjScale, uint16_t(310)), uint16_t(63)); // WLEDMM
|
||||
@@ -5767,8 +5785,8 @@ uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https
|
||||
}
|
||||
}
|
||||
*/
|
||||
uint16_t _scale = map(SEGMENT.intensity, 0, 255, 30, adjScale);
|
||||
byte _speed = map(SEGMENT.speed, 0, 255, 128, 16);
|
||||
uint16_t _scale = map2(SEGMENT.intensity, 0, 255, 30, adjScale);
|
||||
byte _speed = map2(SEGMENT.speed, 0, 255, 128, 16);
|
||||
|
||||
//WLEDMM add SuperSync control
|
||||
uint16_t xStart, xEnd, yStart, yEnd;
|
||||
@@ -6439,6 +6457,10 @@ static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur;;;
|
||||
volumeSmth = *(float*) um_data->u_data[0];
|
||||
volumeRaw = *(int16_t*) um_data->u_data[1];
|
||||
fftResult = (uint8_t*) um_data->u_data[2];
|
||||
or
|
||||
uint8_t fftResult[NUM_GEQ_CHANNELS] = {0};
|
||||
if (um_data->u_data != nullptr) memcpy(fftResult, um_data->u_data[2], sizeof(fftResult)); // WLEDMM to buffer curent values
|
||||
|
||||
samplePeak = *(uint8_t*) um_data->u_data[3];
|
||||
FFT_MajorPeak = *(float*) um_data->u_data[4];
|
||||
my_magnitude = *(float*) um_data->u_data[5];
|
||||
@@ -6456,6 +6478,8 @@ static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur;;;
|
||||
|
||||
// a few constants needed for AudioReactive effects
|
||||
|
||||
#define NUM_GEQ_CHANNELS 16 // number of audioreactive frequency channels.
|
||||
|
||||
// for 22Khz sampling
|
||||
#define MIN_FREQUENCY 80 // 80 HZ - due to lower resolution
|
||||
#define MIN_FREQ_LOG10 1.90309f // log10(MIN_FREQUENCY)
|
||||
@@ -7018,7 +7042,7 @@ uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline.
|
||||
if (SEGENV.call == 0) {SEGENV.setUpLeds(); SEGMENT.fill(BLACK);} // WLEDMM use lossless getPixelColor()
|
||||
|
||||
//uint8_t fadeRate = map(SEGMENT.speed,0,255,224,255);
|
||||
uint8_t fadeRate = map(SEGMENT.speed,0,255,200,254);
|
||||
uint8_t fadeRate = map2(SEGMENT.speed,0,255,200,254);
|
||||
SEGMENT.fade_out(fadeRate);
|
||||
|
||||
float tmpSound2 = volumeRaw * 2.0 * (float)SEGMENT.intensity / 255.0;
|
||||
@@ -7128,7 +7152,7 @@ static const char _data_FX_MODE_PLASMOID[] PROGMEM = "Plasmoid@Phase,# of pixels
|
||||
uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline.
|
||||
|
||||
uint16_t size = 0;
|
||||
uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 254);
|
||||
uint8_t fadeVal = map2(SEGMENT.speed,0,255, 224, 254);
|
||||
uint16_t pos = random16(SEGLEN); // Set a random starting position.
|
||||
|
||||
um_data_t *um_data;
|
||||
@@ -7174,7 +7198,7 @@ static const char _data_FX_MODE_PUDDLEPEAK[] PROGMEM = "Puddlepeak@Fade rate,Pud
|
||||
//////////////////////
|
||||
uint16_t mode_puddles(void) { // Puddles. By Andrew Tuline.
|
||||
uint16_t size = 0;
|
||||
uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254);
|
||||
uint8_t fadeVal = map2(SEGMENT.speed, 0, 255, 224, 254);
|
||||
uint16_t pos = random16(SEGLEN); // Set a random starting position.
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
@@ -7380,7 +7404,7 @@ uint16_t mode_DJLight(void) { // Written by Stefan Petrick, Ad
|
||||
//if (color.getLuma() > 12) color.maximizeBrightness(); // for testing
|
||||
|
||||
//SEGMENT.setPixelColor(mid, color.fadeToBlackBy(map(fftResult[4], 0, 255, 255, 4))); // 0.13.x fade -> 180hz-260hz
|
||||
uint8_t fadeVal = map(fftResult[3], 0, 255, 255, 4); // 0.14.x fade -> 216hz-301hz
|
||||
uint8_t fadeVal = map2(fftResult[3], 0, 255, 255, 4); // 0.14.x fade -> 216hz-301hz
|
||||
if (SEGENV.check1) fadeVal = constrain(fadeVal, 0, 176); // "candy factory" mode - avoid complete fade-out
|
||||
SEGMENT.setPixelColor(mid, color.fadeToBlackBy(fadeVal));
|
||||
|
||||
@@ -7684,7 +7708,8 @@ uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuli
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
uint8_t fftResult[NUM_GEQ_CHANNELS] = {0};
|
||||
if (um_data->u_data != nullptr) memcpy(fftResult, um_data->u_data[2], sizeof(fftResult)); // WLEDMM buffer curent values
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGENV.setUpLeds(); // WLEDMM use lossless getPixelColor()
|
||||
@@ -7694,11 +7719,11 @@ uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuli
|
||||
int fadeoutDelay = (256 - SEGMENT.speed) / 96;
|
||||
if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(4+ SEGMENT.speed/4);
|
||||
|
||||
uint8_t numBins = map(SEGMENT.intensity,0,255,0,16); // Map slider to fftResult bins.
|
||||
uint8_t numBins = map2(SEGMENT.intensity,0,255,0,16); // Map slider to fftResult bins.
|
||||
for (int i=0; i<numBins; i++) { // How many active bins are we using.
|
||||
uint16_t locn = inoise16(strip.now*SEGMENT.speed+i*50000, strip.now*SEGMENT.speed); // Get a new pixel location from moving noise.
|
||||
// if SEGLEN equals 1 locn will be always 0, hence we set the first pixel only
|
||||
locn = map(locn, 7500, 58000, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over.
|
||||
locn = map2(locn, 7500, 58000, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over.
|
||||
SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*64, false, PALETTE_SOLID_WRAP, 0), fftResult[i % 16]*4));
|
||||
}
|
||||
|
||||
@@ -7816,7 +7841,7 @@ static const char _data_FX_MODE_WATERFALL[] PROGMEM = "Waterfall@!,Adjust color,
|
||||
uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma.
|
||||
if (!strip.isMatrix) return mode_static(); // not a 2D set-up
|
||||
|
||||
const int NUM_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16);
|
||||
const int NUM_BANDS = map2(SEGMENT.custom1, 0, 255, 1, 16);
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
if ((cols <=1) || (rows <=1)) return mode_static(); // not really a 2D set-up
|
||||
@@ -7829,7 +7854,9 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma.
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
uint8_t fftResult[NUM_GEQ_CHANNELS] = {0};
|
||||
if (um_data->u_data != nullptr) memcpy(fftResult, um_data->u_data[2], sizeof(fftResult)); // WLEDMM buffer curent values
|
||||
|
||||
#ifdef SR_DEBUG
|
||||
uint8_t samplePeak = *(uint8_t*)um_data->u_data[3];
|
||||
#endif
|
||||
@@ -7862,7 +7889,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma.
|
||||
remaining--; //consume remaining
|
||||
|
||||
// Serial.printf("x %d b %d n %d w %f %f\n", x, band, NUM_BANDS, bandwidth, remaining);
|
||||
uint8_t frBand = ((NUM_BANDS < 16) && (NUM_BANDS > 1)) ? map(band, 0, NUM_BANDS - 1, 0, 15):band; // always use full range. comment out this line to get the previous behaviour.
|
||||
uint8_t frBand = ((NUM_BANDS < 16) && (NUM_BANDS > 1)) ? map2(band, 0, NUM_BANDS - 1, 0, 15):band; // always use full range. comment out this line to get the previous behaviour.
|
||||
// frBand = constrain(frBand, 0, 15); //WLEDMM can never be out of bounds (I think...)
|
||||
uint16_t colorIndex = frBand * 17; //WLEDMM 0.255
|
||||
uint16_t bandHeight = fftResult[frBand]; // WLEDMM we use the original ffResult, to preserve accuracy
|
||||
@@ -7872,7 +7899,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma.
|
||||
// get height of next (right side) bar
|
||||
uint8_t nextband = (remaining < 1)? band +1: band;
|
||||
nextband = constrain(nextband, 0, 15); // just to be sure
|
||||
frBand = ((NUM_BANDS < 16) && (NUM_BANDS > 1)) ? map(nextband, 0, NUM_BANDS - 1, 0, 15):nextband; // always use full range. comment out this line to get the previous behaviour.
|
||||
frBand = ((NUM_BANDS < 16) && (NUM_BANDS > 1)) ? map2(nextband, 0, NUM_BANDS - 1, 0, 15):nextband; // always use full range. comment out this line to get the previous behaviour.
|
||||
uint16_t nextBandHeight = fftResult[frBand];
|
||||
// smooth Band height
|
||||
bandHeight = (7*bandHeight + 3*lastBandHeight + 3*nextBandHeight) / 12; // yeees, its 12 not 13 (10% amplification)
|
||||
@@ -7920,7 +7947,7 @@ uint16_t mode_2DFunkyPlank(void) { // Written by ??? Adapted by Wil
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
int NUMB_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16);
|
||||
int NUMB_BANDS = map2(SEGMENT.custom1, 0, 255, 1, 16);
|
||||
int barWidth = (cols / NUMB_BANDS);
|
||||
int bandInc = 1;
|
||||
if (barWidth == 0) {
|
||||
@@ -7934,7 +7961,8 @@ uint16_t mode_2DFunkyPlank(void) { // Written by ??? Adapted by Wil
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
uint8_t fftResult[NUM_GEQ_CHANNELS] = {0};
|
||||
if (um_data->u_data != nullptr) memcpy(fftResult, um_data->u_data[2], sizeof(fftResult)); // WLEDMM buffer curent values
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
@@ -7949,7 +7977,7 @@ uint16_t mode_2DFunkyPlank(void) { // Written by ??? Adapted by Wil
|
||||
int b = 0;
|
||||
for (int band = 0; band < NUMB_BANDS; band += bandInc, b++) {
|
||||
int hue = fftResult[band % 16];
|
||||
int v = map(fftResult[band % 16], 0, 255, 10, 255);
|
||||
int v = map2(fftResult[band % 16], 0, 255, 10, 255);
|
||||
for (int w = 0; w < barWidth; w++) {
|
||||
int xpos = (barWidth * b) + w;
|
||||
SEGMENT.setPixelColorXY(xpos, 0, CHSV(hue, 255, v));
|
||||
@@ -8021,11 +8049,12 @@ uint16_t mode_2DAkemi(void) {
|
||||
const float lightFactor = 0.15f;
|
||||
const float normalFactor = 0.4f;
|
||||
|
||||
um_data_t *um_data;
|
||||
um_data_t *um_data = nullptr;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
uint8_t fftResult[NUM_GEQ_CHANNELS] = {0};
|
||||
if (um_data->u_data != nullptr) memcpy(fftResult, um_data->u_data[2], sizeof(fftResult)); // WLEDMM buffer curent values
|
||||
float base = fftResult[0]/255.0f;
|
||||
|
||||
//draw and color Akemi
|
||||
@@ -8047,7 +8076,7 @@ uint16_t mode_2DAkemi(void) {
|
||||
default: color = BLACK; break;
|
||||
}
|
||||
|
||||
if (SEGMENT.intensity > 128 && fftResult && fftResult[0] > 128) { //dance if base is high
|
||||
if (SEGMENT.intensity > 128 && um_data && fftResult[0] > 128) { //dance if base is high
|
||||
SEGMENT.setPixelColorXY(x, 0, BLACK);
|
||||
SEGMENT.setPixelColorXY(x, y+1, color);
|
||||
} else
|
||||
@@ -8055,11 +8084,11 @@ uint16_t mode_2DAkemi(void) {
|
||||
}
|
||||
|
||||
//add geq left and right
|
||||
if (um_data && fftResult) {
|
||||
if (um_data) {
|
||||
for (int x=0; x < cols/8; x++) {
|
||||
uint16_t band = x * cols/8;
|
||||
band = constrain(band, 0, 15);
|
||||
uint16_t barHeight = map(fftResult[band], 0, 255, 0, 17*rows/32);
|
||||
uint16_t barHeight = map2(fftResult[band], 0, 255, 0, 17*rows/32);
|
||||
CRGB color = SEGMENT.color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0);
|
||||
|
||||
for (int y=0; y < barHeight; y++) {
|
||||
|
||||
Reference in New Issue
Block a user