Various fixes.

Added support for no audio to some effects.
This commit is contained in:
Blaz Kristan 2022-06-16 16:10:38 +02:00
parent f92c336ae4
commit 12a94c50b8
3 changed files with 426 additions and 355 deletions

View File

@ -149,7 +149,6 @@ float fftAdd(int from, int to) {
// FFT main code
void FFTcode(void * parameter) {
DEBUGSR_PRINT("FFT running on core: "); DEBUGSR_PRINTLN(xPortGetCoreID());
#ifdef MAJORPEAK_SUPPRESS_NOISE
static double xtemp[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@ -169,16 +168,15 @@ void FFTcode(void * parameter) {
//micDataSm = ((micData * 3) + micData)/4;
const int halfSamplesFFT = samplesFFT / 2; // samplesFFT divided by 2
float maxSample1 = 0.0; // max sample from first half of FFT batch
float maxSample2 = 0.0; // max sample from second half of FFT batch
for (int i=0; i < samplesFFT; i++)
{
float maxSample1 = 0.0f; // max sample from first half of FFT batch
float maxSample2 = 0.0f; // max sample from second half of FFT batch
for (int i=0; i < samplesFFT; i++) {
// set imaginary parts to 0
vImag[i] = 0;
// pick our our current mic sample - we take the max value from all samples that go into FFT
if ((vReal[i] <= (INT16_MAX - 1024)) && (vReal[i] >= (INT16_MIN + 1024))) //skip extreme values - normally these are artefacts
{
if (i <= halfSamplesFFT) {
if (i < halfSamplesFFT) {
if (fabsf((float)vReal[i]) > maxSample1) maxSample1 = fabsf((float)vReal[i]);
} else {
if (fabsf((float)vReal[i]) > maxSample2) maxSample2 = fabsf((float)vReal[i]);
@ -299,18 +297,15 @@ void FFTcode(void * parameter) {
for (int i=0; i < 16; i++) {
// Noise supression of fftCalc bins using soundSquelch adjustment for different input types.
fftCalc[i] = (fftCalc[i] - (float)soundSquelch * (float)linearNoise[i] / 4.0f <= 0.0f) ? 0 : fftCalc[i];
fftCalc[i] = (fftCalc[i] < ((float)soundSquelch * (float)linearNoise[i] / 4.0f)) ? 0 : fftCalc[i];
// Adjustment for frequency curves.
fftCalc[i] *= fftResultPink[i];
// Manual linear adjustment of gain using sampleGain adjustment for different input types.
fftCalc[i] *= soundAgc ? multAgc : (float)sampleGain/40.0f * inputLevel/128 + (float)fftCalc[i]/16.0f; //with inputLevel adjustment
fftCalc[i] *= soundAgc ? multAgc : ((float)sampleGain/40.0f * (float)inputLevel/128.0f + 1.0f/16.0f); //with inputLevel adjustment
// Now, let's dump it all into fftResult. Need to do this, otherwise other routines might grab fftResult values prematurely.
// fftResult[i] = (int)fftCalc[i];
fftResult[i] = constrain((int)fftCalc[i], 0, 254); // question: why do we constrain values to 8bit here ???
fftAvg[i] = (float)fftResult[i]*0.05f + (1.0f - 0.05f)*fftAvg[i]; // why no just 0.95f*fftAvg[i]?
fftResult[i] = constrain((int)fftCalc[i], 0, 254);
fftAvg[i] = (float)fftResult[i]*0.05f + 0.95f*fftAvg[i];
}
// release second sample to volume reactive effects.
@ -318,13 +313,14 @@ void FFTcode(void * parameter) {
micDataSm = (uint16_t)maxSample2;
micDataReal = maxSample2;
#ifdef SR_DEBUG
// Looking for fftResultMax for each bin using Pink Noise
// for (int i=0; i<16; i++) {
// fftResultMax[i] = ((fftResultMax[i] * 63.0) + fftResult[i]) / 64.0;
// Serial.print(fftResultMax[i]*fftResultPink[i]); Serial.print("\t");
// }
// Serial.println(" ");
// for (int i=0; i<16; i++) {
// fftResultMax[i] = ((fftResultMax[i] * 63.0) + fftResult[i]) / 64.0;
// Serial.print(fftResultMax[i]*fftResultPink[i]); Serial.print("\t");
// }
// Serial.println();
#endif
} // for(;;)
} // FFTcode()
@ -390,6 +386,8 @@ class AudioReactive : public Usermod {
WiFiUDP fftUdp;
// set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
bool enabled = true;
bool initDone = false;
const uint16_t delayMs = 10; // I don't want to sample too often and overload WLED
uint8_t maxVol = 10; // Reasonable value for constant volume for 'peak detector', as it won't always trigger
@ -739,48 +737,50 @@ class AudioReactive : public Usermod {
*/
void setup() {
// usermod exchangeable data
// we will assign all usermod exportable data here as pointers to original variables or arrays and allocate memory for pointers
um_data = new um_data_t;
um_data->u_size = 18;
um_data->u_type = new um_types_t[um_data->u_size];
um_data->u_data = new void*[um_data->u_size];
um_data->u_data[0] = &maxVol; // assigned in effect function!!!
um_data->u_type[0] = UMT_BYTE;
um_data->u_data[1] = fftResult; //*used
um_data->u_type[1] = UMT_BYTE_ARR;
um_data->u_data[2] = &sample; //*used (for debugging)
um_data->u_type[2] = UMT_INT16;
um_data->u_data[3] = &rawSampleAgc; //*used
um_data->u_type[3] = UMT_INT16;
um_data->u_data[4] = &samplePeak; //*used
um_data->u_type[4] = UMT_BYTE;
um_data->u_data[5] = &binNum; // assigned in effect function!!!
um_data->u_type[5] = UMT_BYTE;
um_data->u_data[6] = &FFT_MajorPeak; //*used
um_data->u_type[6] = UMT_DOUBLE;
um_data->u_data[7] = &FFT_Magnitude; //*used
um_data->u_type[7] = UMT_DOUBLE;
um_data->u_data[8] = &sampleAvg; //*used
um_data->u_type[8] = UMT_FLOAT;
um_data->u_data[9] = &soundAgc; //*used
um_data->u_type[9] = UMT_BYTE;
um_data->u_data[10] = &sampleAgc; //*used (can be calculated as: sampleReal * multAgc)
um_data->u_type[10] = UMT_FLOAT;
um_data->u_data[11] = &multAgc; //*used (for debugging)
um_data->u_type[11] = UMT_FLOAT;
um_data->u_data[12] = &sampleReal; //*used (for debugging)
um_data->u_type[12] = UMT_FLOAT;
um_data->u_data[13] = &sampleGain; //*used (for debugging & Binmap)
um_data->u_type[13] = UMT_FLOAT;
um_data->u_data[14] = myVals; //*used (only once, Pixels)
um_data->u_type[14] = UMT_UINT16_ARR;
um_data->u_data[15] = &soundSquelch; //*used (only once, Binmap)
um_data->u_type[15] = UMT_BYTE;
um_data->u_data[16] = fftBin; //*used (only once, Binmap)
um_data->u_type[16] = UMT_FLOAT_ARR;
um_data->u_data[17] = &inputLevel; // assigned in effect function!!!
um_data->u_type[17] = UMT_BYTE;
if (!initDone) {
// usermod exchangeable data
// we will assign all usermod exportable data here as pointers to original variables or arrays and allocate memory for pointers
um_data = new um_data_t;
um_data->u_size = 18;
um_data->u_type = new um_types_t[um_data->u_size];
um_data->u_data = new void*[um_data->u_size];
um_data->u_data[0] = &maxVol; // assigned in effect function!!!
um_data->u_type[0] = UMT_BYTE;
um_data->u_data[1] = fftResult; //*used
um_data->u_type[1] = UMT_BYTE_ARR;
um_data->u_data[2] = &sample; //*used (for debugging)
um_data->u_type[2] = UMT_INT16;
um_data->u_data[3] = &rawSampleAgc; //*used
um_data->u_type[3] = UMT_INT16;
um_data->u_data[4] = &samplePeak; //*used
um_data->u_type[4] = UMT_BYTE;
um_data->u_data[5] = &binNum; // assigned in effect function!!!
um_data->u_type[5] = UMT_BYTE;
um_data->u_data[6] = &FFT_MajorPeak; //*used
um_data->u_type[6] = UMT_DOUBLE;
um_data->u_data[7] = &FFT_Magnitude; //*used
um_data->u_type[7] = UMT_DOUBLE;
um_data->u_data[8] = &sampleAvg; //*used
um_data->u_type[8] = UMT_FLOAT;
um_data->u_data[9] = &soundAgc; //*used
um_data->u_type[9] = UMT_BYTE;
um_data->u_data[10] = &sampleAgc; //*used (can be calculated as: sampleReal * multAgc)
um_data->u_type[10] = UMT_FLOAT;
um_data->u_data[11] = &multAgc; //*used (for debugging)
um_data->u_type[11] = UMT_FLOAT;
um_data->u_data[12] = &sampleReal; //*used (for debugging)
um_data->u_type[12] = UMT_FLOAT;
um_data->u_data[13] = &sampleGain; //*used (for debugging & Binmap)
um_data->u_type[13] = UMT_FLOAT;
um_data->u_data[14] = myVals; //*used (only once, Pixels)
um_data->u_type[14] = UMT_UINT16_ARR;
um_data->u_data[15] = &soundSquelch; //*used (only once, Binmap)
um_data->u_type[15] = UMT_BYTE;
um_data->u_data[16] = fftBin; //*used (only once, Binmap)
um_data->u_type[16] = UMT_FLOAT_ARR;
um_data->u_data[17] = &inputLevel; // assigned in effect function!!!
um_data->u_type[17] = UMT_BYTE;
}
// Reset I2S peripheral for good measure
i2s_driver_uninstall(I2S_NUM_0);
@ -833,7 +833,7 @@ class AudioReactive : public Usermod {
//sampling_period_us = round(1000000*(1.0/SAMPLE_RATE));
onUpdateBegin(false); // create FFT task
if (enabled) onUpdateBegin(false); // create FFT task
/*
// Define the FFT Task and lock it to core 0
xTaskCreatePinnedToCore(
@ -845,6 +845,7 @@ class AudioReactive : public Usermod {
&FFT_Task, // Task handle
0); // Core where the task should run
*/
initDone = true;
}
@ -1002,7 +1003,7 @@ class AudioReactive : public Usermod {
bool getUMData(um_data_t **data) {
if (!data) return false; // no pointer provided by caller -> exit
if (!data || !enabled) return false; // no pointer provided by caller or not enabled -> exit
*data = um_data;
return true;
}
@ -1107,6 +1108,7 @@ class AudioReactive : public Usermod {
void addToConfig(JsonObject& root)
{
JsonObject top = root.createNestedObject(FPSTR(_name));
top[F("enabled")] = enabled;
JsonObject amic = top.createNestedObject(FPSTR(_analogmic));
amic["pin"] = audioPin;
@ -1154,6 +1156,12 @@ class AudioReactive : public Usermod {
bool configComplete = !top.isNull();
bool prevEnabled = enabled;
configComplete &= getJsonValue(top[F("enabled")], enabled);
if (initDone && prevEnabled != enabled) {
onUpdateBegin(!enabled); // create or remove FFT task
}
configComplete &= getJsonValue(top[FPSTR(_analogmic)]["pin"], audioPin);
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["type"], dmType);

View File

@ -5537,110 +5537,6 @@ uint16_t WS2812FX::mode_2Dtartan(void) { // By: Elliott Kember https:/
static const char *_data_FX_MODE_2DTARTAN PROGMEM = "2D Tartan@X scale,Y scale;;!";
/////////////////////////
// 2D Akemi //
/////////////////////////
static uint8_t akemi[] PROGMEM = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,2,2,3,3,3,3,3,3,2,2,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,2,3,3,0,0,0,0,0,0,3,3,2,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,2,3,0,0,0,6,5,5,4,0,0,0,3,2,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,2,3,0,0,6,6,5,5,5,5,4,4,0,0,3,2,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,2,3,0,6,5,5,5,5,5,5,5,5,4,0,3,2,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,2,3,0,6,5,5,5,5,5,5,5,5,5,5,4,0,3,2,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,3,2,0,6,5,5,5,5,5,5,5,5,5,5,4,0,2,3,0,0,0,0,0,0,0,
0,0,0,0,0,0,3,2,3,6,5,5,7,7,5,5,5,5,7,7,5,5,4,3,2,3,0,0,0,0,0,0,
0,0,0,0,0,2,3,1,3,6,5,1,7,7,7,5,5,1,7,7,7,5,4,3,1,3,2,0,0,0,0,0,
0,0,0,0,0,8,3,1,3,6,5,1,7,7,7,5,5,1,7,7,7,5,4,3,1,3,8,9,0,0,0,0,
0,0,0,0,0,8,3,1,3,6,5,5,1,1,5,5,5,5,1,1,5,5,4,3,1,3,8,0,0,0,0,0,
0,0,0,0,0,2,3,1,3,6,5,5,5,5,5,5,5,5,5,5,5,5,4,3,1,3,2,0,0,0,0,0,
0,0,0,0,0,0,3,2,3,6,5,5,5,5,5,5,5,5,5,5,5,5,4,3,2,3,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,6,5,5,5,5,5,7,7,5,5,5,5,5,4,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,0,0,0,0,
1,0,0,0,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,0,0,0,2,
0,2,2,2,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,2,2,2,0,
0,0,0,3,2,0,0,0,6,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,2,2,0,0,0,
0,0,0,3,2,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,2,3,0,0,0,
0,0,0,0,3,2,0,0,0,0,3,3,0,3,3,0,0,3,3,0,3,3,0,0,0,0,2,2,0,0,0,0,
0,0,0,0,3,2,0,0,0,0,3,2,0,3,2,0,0,3,2,0,3,2,0,0,0,0,2,3,0,0,0,0,
0,0,0,0,0,3,2,0,0,3,2,0,0,3,2,0,0,3,2,0,0,3,2,0,0,2,3,0,0,0,0,0,
0,0,0,0,0,3,2,2,2,2,0,0,0,3,2,0,0,3,2,0,0,0,3,2,2,2,3,0,0,0,0,0,
0,0,0,0,0,0,3,3,3,0,0,0,0,3,2,0,0,3,2,0,0,0,0,3,3,3,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
uint16_t WS2812FX::mode_2DAkemi(void) {
if (!isMatrix) return mode_static(); // not a 2D set-up
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
uint16_t counter = (now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF;
counter = counter >> 8;
const float lightFactor = 0.15f;
const float normalFactor = 0.4f;
float base = 0.0f;
uint8_t *fftResult = nullptr;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
fftResult = (uint8_t*)um_data->u_data[1];
base = fftResult[0]/255.0f;
}
//draw and color Akemi
for (uint16_t y=0; y < rows; y++) for (uint16_t x=0; x < cols; x++) {
CRGB color;
CRGB soundColor = ORANGE;
CRGB faceColor = color_wheel(counter);
CRGB armsAndLegsColor = SEGCOLOR(1) > 0 ? SEGCOLOR(1) : 0xFFE0A0; //default warmish white 0xABA8FF; //0xFF52e5;//
uint8_t ak = pgm_read_byte_near(akemi + ((y * 32)/rows) * 32 + (x * 32)/cols); // akemi[(y * 32)/rows][(x * 32)/cols]
switch (ak) {
case 0: color = BLACK; break;
case 3: armsAndLegsColor.r *= lightFactor; armsAndLegsColor.g *= lightFactor; armsAndLegsColor.b *= lightFactor; color = armsAndLegsColor; break; //light arms and legs 0x9B9B9B
case 2: armsAndLegsColor.r *= normalFactor; armsAndLegsColor.g *= normalFactor; armsAndLegsColor.b *= normalFactor; color = armsAndLegsColor; break; //normal arms and legs 0x888888
case 1: color = armsAndLegsColor; break; //dark arms and legs 0x686868
case 6: faceColor.r *= lightFactor; faceColor.g *= lightFactor; faceColor.b *= lightFactor; color=faceColor; break; //light face 0x31AAFF
case 5: faceColor.r *= normalFactor; faceColor.g *= normalFactor; faceColor.b *= normalFactor; color=faceColor; break; //normal face 0x0094FF
case 4: color = faceColor; break; //dark face 0x007DC6
case 7: color = SEGCOLOR(2) > 0 ? SEGCOLOR(2) : 0xFFFFFF; break; //eyes and mouth default white
case 8: if (base > 0.4) {soundColor.r *= base; soundColor.g *= base; soundColor.b *= base; color=soundColor;} else color = armsAndLegsColor; break;
default: color = BLACK;
}
if (SEGMENT.intensity > 128 && fftResult && fftResult[0] > 128) { //dance if base is high
setPixelColorXY(x, 0, BLACK);
setPixelColorXY(x, y+1, color);
} else
setPixelColorXY(x, y, color);
}
//add geq left and right
if (um_data && fftResult) {
for (uint16_t x=0; x < cols/8; x++) {
uint16_t band = x * cols/8;
uint16_t barHeight = map(fftResult[band], 0, 255, 0, 17*rows/32);
CRGB color = color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0);
for (uint16_t y=0; y < barHeight; y++) {
setPixelColorXY(x, rows/2-y, color);
setPixelColorXY(cols-1-x, rows/2-y, color);
}
}
}
return FRAMETIME;
} // mode_2DAkemi
static const char *_data_FX_MODE_2DAKEMI PROGMEM = "2D Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette";
/////////////////////////
// 2D spaceships //
/////////////////////////
@ -6048,7 +5944,193 @@ static const char *_data_FX_MODE_DRIFT_ROSE PROGMEM = "2D Drift Rose@Fade,Blur;;
///////////////////////////////////////////////////////////////////////////////
//************************* audio routines **********************************
/******************** audio enhanced routines ************************/
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////
// * Ripple Peak //
/////////////////////////////////
uint16_t WS2812FX::mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuline.
// This currently has no controls.
#define maxsteps 16 // Case statement wouldn't allow a variable.
uint16_t maxRipples = 16;
uint16_t dataSize = sizeof(Ripple) * maxRipples;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
Ripple* ripples = reinterpret_cast<Ripple*>(SEGENV.data);
uint8_t *binNum = (uint8_t*)&SEGENV.aux1, *maxVol = (uint8_t*)(&SEGENV.aux1+1); // just in case assignment
uint8_t samplePeak = 0; // actually a bool
double FFT_MajorPeak = 0.0;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[8];
binNum = (uint8_t*)um_data->u_data[5];
maxVol = (uint8_t*)um_data->u_data[0];
samplePeak = *(uint8_t*)um_data->u_data[4];
} else {
// add support for no audio data
uint32_t ms = millis();
samplePeak = random8() > 250;
FFT_MajorPeak = inoise8(beatsin8(90, 0, 200)*15 + (ms>>10), ms>>3);
}
if (SEGENV.call == 0) SEGENV.aux0 = 255;
*binNum = SEGMENT.custom2; // Select a bin.
*maxVol = SEGMENT.custom3/2; // Our volume comparator.
fade_out(240); // Lower frame rate means less effective fading than FastLED
fade_out(240);
for (uint16_t i = 0; i < SEGMENT.intensity/16; i++) { // Limit the number of ripples.
if (samplePeak) ripples[i].state = 255;
switch (ripples[i].state) {
case 254: // Inactive mode
break;
case 255: // Initialize ripple variables.
ripples[i].pos = random16(SEGLEN);
#ifdef ESP32
ripples[i].color = (int)(log10f(FFT_MajorPeak)*128);
#else
ripples[i].color = random8();
#endif
ripples[i].state = 0;
break;
case 0:
setPixelColor(ripples[i].pos, color_blend(SEGCOLOR(1), color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0));
ripples[i].state++;
break;
case maxsteps: // At the end of the ripples. 254 is an inactive mode.
ripples[i].state = 254;
break;
default: // Middle of the ripples.
setPixelColor((ripples[i].pos + ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0/ripples[i].state*2));
setPixelColor((ripples[i].pos - ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0/ripples[i].state*2));
ripples[i].state++; // Next step.
break;
} // switch step
} // for i
return FRAMETIME;
} // mode_ripplepeak()
static const char *_data_FX_MODE_RIPPLEPEAK PROGMEM = " ♪ Ripple Peak@Fade rate,Max # of ripples,,Select bin,Volume (minimum);!,!;!";
/////////////////////////
// * 2D Swirl //
/////////////////////////
// By: Mark Kriegsman https://gist.github.com/kriegsman/5adca44e14ad025e6d3b , modified by Andrew Tuline
uint16_t WS2812FX::mode_2DSwirl(void) {
if (!isMatrix) return mode_static(); // not a 2D set-up
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
const uint16_t dataSize = sizeof(CRGB) * SEGMENT.width() * SEGMENT.height(); // using width*height prevents reallocation if mirroring is enabled
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
if (SEGENV.call == 0) fill_solid(leds, CRGB::Black);
const uint8_t borderWidth = 2;
blur2d(leds, SEGMENT.custom1);
uint8_t i = beatsin8( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth);
uint8_t j = beatsin8( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth);
uint8_t ni = (cols - 1) - i;
uint8_t nj = (cols - 1) - j;
uint16_t ms = millis();
uint8_t soundAgc = 0;
int16_t rawSampleAgc = 0, sample;
float sampleAvg = 0.0f;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
soundAgc = *(uint8_t*)um_data->u_data[9];
rawSampleAgc = *(int16_t*)um_data->u_data[3];
sample = *(int16_t*)um_data->u_data[2];
sampleAvg = *(float*)um_data->u_data[8];
} else {
// add support for no audio data
sample = inoise8(beatsin8(120, 10, 30)*10 + (ms>>14), ms>>3);
sample = map(sample, 50, 190, 0, 224);
sampleAvg = inoise8(beatsin8(90, 0, 200)*15 + (ms>>10), ms>>3);
//sampleAvg = mapf(sampleAvg, 0, 255, 0, 255); // help me out here
}
int tmpSound = (soundAgc) ? rawSampleAgc : sample;
leds[XY( i, j)] += ColorFromPalette(currentPalette, (ms / 11 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 11, 200, 255);
leds[XY( j, i)] += ColorFromPalette(currentPalette, (ms / 13 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 13, 200, 255);
leds[XY(ni, nj)] += ColorFromPalette(currentPalette, (ms / 17 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 17, 200, 255);
leds[XY(nj, ni)] += ColorFromPalette(currentPalette, (ms / 29 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 29, 200, 255);
leds[XY( i, nj)] += ColorFromPalette(currentPalette, (ms / 37 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 37, 200, 255);
leds[XY(ni, j)] += ColorFromPalette(currentPalette, (ms / 41 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 41, 200, 255);
setPixels(leds);
return FRAMETIME;
} // mode_2DSwirl()
static const char *_data_FX_MODE_2DSWIRL PROGMEM = " ♪ 2D Swirl@!,Sensitivity=64,Blur;,Bg Swirl;!";
/////////////////////////
// * 2D Waverly //
/////////////////////////
// By: Stepko, https://editor.soulmatelights.com/gallery/652-wave , modified by Andrew Tuline
uint16_t WS2812FX::mode_2DWaverly(void) {
if (!isMatrix) return mode_static(); // not a 2D set-up
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
const uint16_t dataSize = sizeof(CRGB) * SEGMENT.width() * SEGMENT.height(); // using width*height prevents reallocation if mirroring is enabled
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
if (SEGENV.call == 0) {
fill_solid(leds, CRGB::Black);
}
um_data_t *um_data;
uint8_t soundAgc = 0;
float sampleAgc = 0.0f, sampleAvg = 0.0f;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
soundAgc = *(uint8_t*)um_data->u_data[9];
sampleAgc = *(float*)um_data->u_data[10];
sampleAvg = *(float*)um_data->u_data[8];
}
fadeToBlackBy(leds, SEGMENT.speed);
long t = millis() / 2;
for (uint16_t i = 0; i < cols; i++) {
uint16_t thisVal = (1 + SEGMENT.intensity/64) * inoise8(i * 45 , t , t)/2;
// use audio if available
if (um_data) {
thisVal /= 32; // reduce intensity of inoise8()
thisVal *= (soundAgc) ? sampleAgc : sampleAvg;
}
uint16_t thisMax = map(thisVal, 0, 512, 0, rows);
for (uint16_t j = 0; j < thisMax; j++) {
leds[XY(i, j)] += ColorFromPalette(currentPalette, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND);
leds[XY((cols - 1) - i, (rows - 1) - j)] += ColorFromPalette(currentPalette, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND);
}
}
blur2d(leds, 16);
setPixels(leds);
return FRAMETIME;
} // mode_2DWaverly()
static const char *_data_FX_MODE_2DWAVERLY PROGMEM = " ♪ 2D Waverly@Amplification,Sensitivity=64;;!";
// float version of map()
@ -6062,7 +6144,6 @@ typedef struct Gravity {
int gravityCounter;
} gravity;
///////////////////////
// * GRAVCENTER //
///////////////////////
@ -6079,6 +6160,11 @@ uint16_t WS2812FX::mode_gravcenter(void) { // Gravcenter. By Andr
//sampleAgc = *(float*)um_data->u_data[10];
//sampleAvg = *(float*)um_data->u_data[8];
tmpSound = *(uint8_t*)um_data->u_data[9] ? *(float*)um_data->u_data[10] : *(float*)um_data->u_data[8];
} else {
// add support for no audio data
uint32_t ms = millis();
tmpSound = inoise8(beatsin8(120, 10, 30)*10 + (ms>>14), ms>>3);
//tmpSound = map(sample, 50, 190, 0, 255);
}
fade_out(240);
@ -6128,6 +6214,11 @@ uint16_t WS2812FX::mode_gravcentric(void) { // Gravcentric.
//sampleAgc = *(float*)um_data->u_data[10];
//sampleAvg = *(float*)um_data->u_data[8];
tmpSound = *(uint8_t*)um_data->u_data[9] ? *(float*)um_data->u_data[10] : *(float*)um_data->u_data[8];
} else {
// add support for no audio data
uint32_t ms = millis();
tmpSound = inoise8(beatsin8(120, 10, 30)*10 + (ms>>14), ms>>3);
//tmpSound = map(sample, 50, 190, 0, 255);
}
fade_out(240);
@ -6179,6 +6270,11 @@ uint16_t WS2812FX::mode_gravimeter(void) { // Gravmeter. By Andre
//sampleAgc = *(float*)um_data->u_data[10];
//sampleAvg = *(float*)um_data->u_data[8];
tmpSound = *(uint8_t*)um_data->u_data[9] ? *(float*)um_data->u_data[10] : *(float*)um_data->u_data[8];
} else {
// add support for no audio data
uint32_t ms = millis();
tmpSound = inoise8(beatsin8(120, 10, 30)*10 + (ms>>14), ms>>3);
//tmpSound = map(sample, 50, 190, 0, 255);
}
fade_out(240);
@ -6289,6 +6385,11 @@ uint16_t WS2812FX::mode_juggles(void) { // Juggles. By Andrew
float sampleAgc = 0.0f;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
sampleAgc = *(float*)um_data->u_data[10];
} else {
// add support for no audio data
uint32_t ms = millis();
sampleAgc = inoise8(beatsin8(120, 10, 30)*10 + (ms>>14), ms>>3);
//sampleAgc = map(sample, 50, 190, 0, 255);
}
fade_out(224);
@ -6309,11 +6410,16 @@ static const char *_data_FX_MODE_JUGGLES PROGMEM = " ♪ Juggles@!,# of balls;,!
uint16_t WS2812FX::mode_matripix(void) { // Matripix. By Andrew Tuline.
um_data_t *um_data;
uint8_t soundAgc = 0;
int16_t rawSampleAgc = 0, sample = inoise8(23455,4234); // I have no idea what that does
int16_t rawSampleAgc = 0, sample;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
soundAgc = *(uint8_t*)um_data->u_data[9];
rawSampleAgc = *(int16_t*)um_data->u_data[3];
sample = *(int16_t*)um_data->u_data[2];
} else {
// add support for no audio data
uint32_t ms = millis();
sample = inoise8(beatsin8(120, 10, 30)*10 + (ms>>14), ms>>3);
sample = map(sample, 50, 190, 0, 255);
}
if (SEGENV.call == 0) fill(BLACK);
@ -6346,6 +6452,11 @@ uint16_t WS2812FX::mode_midnoise(void) { // Midnoise. By Andrew
soundAgc = *(uint8_t*)um_data->u_data[9];
sampleAgc = *(float*)um_data->u_data[10];
sampleAvg = *(float*)um_data->u_data[8];
} else {
// add support for no audio data
uint32_t ms = millis();
sampleAvg = inoise8(beatsin8(90, 0, 200)*15 + (ms>>10), ms>>3);
//sampleAvg = mapf(sampleAvg, 0, 255, 0, 255); // help me out here
}
fade_out(SEGMENT.speed);
@ -6390,6 +6501,9 @@ uint16_t WS2812FX::mode_noisefire(void) { // Noisefire. By Andre
sampleAvg = *(float*)um_data->u_data[8];
} else {
// add support for no audio data
uint32_t ms = millis();
sampleAvg = inoise8(beatsin8(90, 0, 200)*15 + (ms>>10), ms>>3);
//sampleAvg = mapf(sampleAvg, 0, 255, 0, 255); // help me out here
}
for (uint16_t i = 0; i < SEGLEN; i++) {
@ -6414,8 +6528,8 @@ uint16_t WS2812FX::mode_noisemeter(void) { // Noisemeter. By Andr
um_data_t *um_data;
uint8_t soundAgc = 0;
int16_t rawSampleAgc = 0, sample = inoise8(23455,4234); // I have no idea what that does
float sampleAgc = 0.0f, sampleAvg = 0.0f;
int16_t rawSampleAgc = 0, sample;
float sampleAgc = 0.0f, sampleAvg;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
soundAgc = *(uint8_t*)um_data->u_data[9];
sampleAgc = *(float*)um_data->u_data[10];
@ -6424,6 +6538,11 @@ uint16_t WS2812FX::mode_noisemeter(void) { // Noisemeter. By Andr
sample = *(int16_t*)um_data->u_data[2];
} else {
// add support for no audio data
uint32_t ms = millis();
sample = inoise8(beatsin8(120, 10, 30)*10 + (ms>>14), ms>>3);
sample = map(sample, 50, 190, 0, 255);
sampleAvg = inoise8(beatsin8(90, 0, 200)*15 + (ms>>10), ms>>3);
//sampleAvg = mapf(sampleAvg, 0, 255, 0, 255); // help me out here
}
uint8_t fadeRate = map(SEGMENT.speed,0,255,224,255);
@ -6482,13 +6601,16 @@ uint16_t WS2812FX::mode_pixelwave(void) { // Pixelwave. By Andre
um_data_t *um_data;
uint8_t soundAgc = 0;
int16_t rawSampleAgc = 0, sample = inoise8(23455,4234); // I have no idea what that does
int16_t rawSampleAgc = 0, sample;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
soundAgc = *(uint8_t*)um_data->u_data[9];
rawSampleAgc = *(int16_t*)um_data->u_data[3];
sample = *(int16_t*)um_data->u_data[2];
} else {
// add support for no audio data
uint32_t ms = millis();
sample = inoise8(beatsin8(120, 10, 30)*10 + (ms>>14), ms>>3);
sample = map(sample, 50, 190, 0, 255);
}
uint8_t secondHand = micros()/(256-SEGMENT.speed)/500+1 % 16;
@ -6524,13 +6646,16 @@ uint16_t WS2812FX::mode_plasmoid(void) { // Plasmoid. By Andrew
um_data_t *um_data;
uint8_t soundAgc = 0;
float sampleAgc = 0.0f, sampleAvg = 0.0f;
float sampleAgc = 0.0f, sampleAvg;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
soundAgc = *(uint8_t*)um_data->u_data[9];
sampleAgc = *(float*)um_data->u_data[10];
sampleAvg = *(float*)um_data->u_data[8];
} else {
// add support for no audio data
uint32_t ms = millis();
sampleAvg = inoise8(beatsin8(90, 0, 200)*15 + (ms>>10), ms>>3);
//sampleAvg = mapf(sampleAvg, 0, 255, 0, 255); // help me out here
}
fade_out(64);
@ -6565,7 +6690,7 @@ uint16_t WS2812FX::mode_puddlepeak(void) { // Puddlepeak. By Andr
uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 255);
uint16_t pos = random(SEGLEN); // Set a random starting position.
uint8_t *binNum = (uint8_t*)&SEGENV.aux1, *maxVol = (uint8_t*)(&SEGENV.aux1+1); // just in case assignment
uint8_t *binNum = (uint8_t*)&SEGENV.aux1, *maxVol = (uint8_t*)(&SEGENV.aux0); // just in case assignment
uint8_t samplePeak = 0;
float sampleAgc = 0.0f;
um_data_t *um_data;
@ -6576,6 +6701,10 @@ uint16_t WS2812FX::mode_puddlepeak(void) { // Puddlepeak. By Andr
samplePeak = *(uint8_t*)um_data->u_data[4];
} else {
// add support for no audio data
uint32_t ms = millis();
samplePeak = random8() > 250;
sampleAgc = inoise8(beatsin8(90, 0, 200)*15 + (ms>>10), ms>>3);
//sampleAgc = mapf(sampleAvg, 0, 255, 0, 255); // help me out here
}
*binNum = SEGMENT.custom2; // Select a bin.
@ -6608,7 +6737,7 @@ uint16_t WS2812FX::mode_puddles(void) { // Puddles. By Andrew
fade_out(fadeVal);
uint8_t soundAgc = 0;
int16_t rawSampleAgc = 0, sample = inoise8(23455,4234); // I have no idea what that does
int16_t rawSampleAgc = 0, sample;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
soundAgc = *(uint8_t*)um_data->u_data[9];
@ -6616,6 +6745,9 @@ uint16_t WS2812FX::mode_puddles(void) { // Puddles. By Andrew
sample = *(int16_t*)um_data->u_data[2];
} else {
// add support for no audio data
uint32_t ms = millis();
sample = inoise8(beatsin8(120, 10, 30)*10 + (ms>>14), ms>>3);
sample = map(sample, 50, 190, 0, 255);
}
uint16_t tmpSound = (soundAgc) ? rawSampleAgc : sample;
@ -6634,182 +6766,9 @@ uint16_t WS2812FX::mode_puddles(void) { // Puddles. By Andrew
static const char *_data_FX_MODE_PUDDLES PROGMEM = " ♪ Puddles@Fade rate,Puddle size;!,!;!";
/////////////////////////////////
// * Ripple Peak //
/////////////////////////////////
uint16_t WS2812FX::mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuline.
// This currently has no controls.
#define maxsteps 16 // Case statement wouldn't allow a variable.
uint16_t maxRipples = 16;
uint16_t dataSize = sizeof(Ripple) * maxRipples;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
Ripple* ripples = reinterpret_cast<Ripple*>(SEGENV.data);
uint8_t *binNum = (uint8_t*)&SEGENV.aux1, *maxVol = (uint8_t*)(&SEGENV.aux1+1); // just in case assignment
uint8_t samplePeak = 0;
double FFT_MajorPeak = 0.0;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[8];
binNum = (uint8_t*)um_data->u_data[5];
maxVol = (uint8_t*)um_data->u_data[0];
samplePeak = *(uint8_t*)um_data->u_data[4];
} else {
// add support for no audio data
}
if (SEGENV.call == 0) SEGENV.aux0 = 255;
*binNum = SEGMENT.custom2; // Select a bin.
*maxVol = SEGMENT.custom3/2; // Our volume comparator.
fade_out(240); // Lower frame rate means less effective fading than FastLED
fade_out(240);
for (uint16_t i = 0; i < SEGMENT.intensity/16; i++) { // Limit the number of ripples.
if (samplePeak) ripples[i].state = 255;
switch (ripples[i].state) {
case 254: // Inactive mode
break;
case 255: // Initialize ripple variables.
ripples[i].pos = random16(SEGLEN);
#ifdef ESP32
ripples[i].color = (int)(log10f(FFT_MajorPeak)*128);
#else
ripples[i].color = random8();
#endif
ripples[i].state = 0;
break;
case 0:
setPixelColor(ripples[i].pos, color_blend(SEGCOLOR(1), color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0));
ripples[i].state++;
break;
case maxsteps: // At the end of the ripples. 254 is an inactive mode.
ripples[i].state = 254;
break;
default: // Middle of the ripples.
setPixelColor((ripples[i].pos + ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0/ripples[i].state*2));
setPixelColor((ripples[i].pos - ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0/ripples[i].state*2));
ripples[i].state++; // Next step.
break;
} // switch step
} // for i
return FRAMETIME;
} // mode_ripplepeak()
static const char *_data_FX_MODE_RIPPLEPEAK PROGMEM = " ♪ Ripple Peak@Fade rate,Max # of ripples,,Select bin,Volume (minimum);!,!;!";
/////////////////////////
// * 2D Swirl //
/////////////////////////
// By: Mark Kriegsman https://gist.github.com/kriegsman/5adca44e14ad025e6d3b , modified by Andrew Tuline
uint16_t WS2812FX::mode_2DSwirl(void) {
if (!isMatrix) return mode_static(); // not a 2D set-up
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
const uint16_t dataSize = sizeof(CRGB) * SEGMENT.width() * SEGMENT.height(); // using width*height prevents reallocation if mirroring is enabled
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
if (SEGENV.call == 0) fill_solid(leds, CRGB::Black);
const uint8_t borderWidth = 2;
blur2d( leds, SEGMENT.custom1);
uint8_t i = beatsin8( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth);
uint8_t j = beatsin8( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth);
uint8_t ni = (cols - 1) - i;
uint8_t nj = (cols - 1) - j;
uint16_t ms = millis();
uint8_t soundAgc = 0;
int16_t rawSampleAgc = 0, sample = inoise8(23455,4234); // I have no idea what that does
float sampleAvg = 0.0f;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
soundAgc = *(uint8_t*)um_data->u_data[9];
rawSampleAgc = *(int16_t*)um_data->u_data[3];
sample = *(int16_t*)um_data->u_data[2];
sampleAvg = *(float*)um_data->u_data[8];
} else {
// add support for no audio data
}
int tmpSound = (soundAgc) ? rawSampleAgc : sample;
leds[XY( i, j)] += ColorFromPalette(currentPalette, (ms / 11 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 11, 200, 255);
leds[XY( j, i)] += ColorFromPalette(currentPalette, (ms / 13 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 13, 200, 255);
leds[XY(ni, nj)] += ColorFromPalette(currentPalette, (ms / 17 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 17, 200, 255);
leds[XY(nj, ni)] += ColorFromPalette(currentPalette, (ms / 29 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 29, 200, 255);
leds[XY( i, nj)] += ColorFromPalette(currentPalette, (ms / 37 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 37, 200, 255);
leds[XY(ni, j)] += ColorFromPalette(currentPalette, (ms / 41 + sampleAvg*4), tmpSound * SEGMENT.intensity / 64, LINEARBLEND); //CHSV( ms / 41, 200, 255);
setPixels(leds);
return FRAMETIME;
} // mode_2DSwirl()
static const char *_data_FX_MODE_2DSWIRL PROGMEM = " ♪ 2D Swirl@!,Sensitivity=64,Blur;,Bg Swirl;!";
/////////////////////////
// * 2D Waverly //
/////////////////////////
// By: Stepko, https://editor.soulmatelights.com/gallery/652-wave , modified by Andrew Tuline
uint16_t WS2812FX::mode_2DWaverly(void) {
if (!isMatrix) return mode_static(); // not a 2D set-up
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
const uint16_t dataSize = sizeof(CRGB) * SEGMENT.width() * SEGMENT.height(); // using width*height prevents reallocation if mirroring is enabled
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGB *leds = reinterpret_cast<CRGB*>(SEGENV.data);
if (SEGENV.call == 0) {
fill_solid(leds, CRGB::Black);
}
um_data_t *um_data;
uint8_t soundAgc = 0;
float sampleAgc = 0.0f, sampleAvg = 0.0f;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
soundAgc = *(uint8_t*)um_data->u_data[9];
sampleAgc = *(float*)um_data->u_data[10];
sampleAvg = *(float*)um_data->u_data[8];
}
fadeToBlackBy(leds, SEGMENT.speed);
long t = millis() / 2;
for (uint16_t i = 0; i < cols; i++) {
uint16_t thisVal = (1 + SEGMENT.intensity/64) * inoise8(i * 45 , t , t)/2;
// use audio if available
if (um_data) {
thisVal /= 32; // reduce intensity of inoise8()
thisVal *= (soundAgc) ? sampleAgc : sampleAvg;
}
uint16_t thisMax = map(thisVal, 0, 512, 0, rows);
for (uint16_t j = 0; j < thisMax; j++) {
leds[XY(i, j)] += ColorFromPalette(currentPalette, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND);
leds[XY((cols - 1) - i, (rows - 1) - j)] += ColorFromPalette(currentPalette, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND);
}
}
blur2d(leds, 16);
setPixels(leds);
return FRAMETIME;
} // mode_2DWaverly()
static const char *_data_FX_MODE_2DWAVERLY PROGMEM = " ♪ 2D Waverly@Amplification,Sensitivity=64;;!";
///////////////////////////////////////////////////////////////////////////////
/******************** audio only routines ************************/
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////
@ -7517,6 +7476,110 @@ uint16_t WS2812FX::mode_2DFunkyPlank(void) { // Written by ??? Adap
static const char *_data_FX_MODE_2DFUNKYPLANK PROGMEM = " ♫ 2D Funky Plank@Scroll speed,,# of bands;;";
/////////////////////////
// 2D Akemi //
/////////////////////////
static uint8_t akemi[] PROGMEM = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,2,2,3,3,3,3,3,3,2,2,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,2,3,3,0,0,0,0,0,0,3,3,2,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,2,3,0,0,0,6,5,5,4,0,0,0,3,2,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,2,3,0,0,6,6,5,5,5,5,4,4,0,0,3,2,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,2,3,0,6,5,5,5,5,5,5,5,5,4,0,3,2,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,2,3,0,6,5,5,5,5,5,5,5,5,5,5,4,0,3,2,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,3,2,0,6,5,5,5,5,5,5,5,5,5,5,4,0,2,3,0,0,0,0,0,0,0,
0,0,0,0,0,0,3,2,3,6,5,5,7,7,5,5,5,5,7,7,5,5,4,3,2,3,0,0,0,0,0,0,
0,0,0,0,0,2,3,1,3,6,5,1,7,7,7,5,5,1,7,7,7,5,4,3,1,3,2,0,0,0,0,0,
0,0,0,0,0,8,3,1,3,6,5,1,7,7,7,5,5,1,7,7,7,5,4,3,1,3,8,9,0,0,0,0,
0,0,0,0,0,8,3,1,3,6,5,5,1,1,5,5,5,5,1,1,5,5,4,3,1,3,8,0,0,0,0,0,
0,0,0,0,0,2,3,1,3,6,5,5,5,5,5,5,5,5,5,5,5,5,4,3,1,3,2,0,0,0,0,0,
0,0,0,0,0,0,3,2,3,6,5,5,5,5,5,5,5,5,5,5,5,5,4,3,2,3,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,6,5,5,5,5,5,7,7,5,5,5,5,5,4,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,0,0,0,0,
1,0,0,0,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,0,0,0,2,
0,2,2,2,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,0,0,2,2,2,0,
0,0,0,3,2,0,0,0,6,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,2,2,0,0,0,
0,0,0,3,2,0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,0,0,0,2,3,0,0,0,
0,0,0,0,3,2,0,0,0,0,3,3,0,3,3,0,0,3,3,0,3,3,0,0,0,0,2,2,0,0,0,0,
0,0,0,0,3,2,0,0,0,0,3,2,0,3,2,0,0,3,2,0,3,2,0,0,0,0,2,3,0,0,0,0,
0,0,0,0,0,3,2,0,0,3,2,0,0,3,2,0,0,3,2,0,0,3,2,0,0,2,3,0,0,0,0,0,
0,0,0,0,0,3,2,2,2,2,0,0,0,3,2,0,0,3,2,0,0,0,3,2,2,2,3,0,0,0,0,0,
0,0,0,0,0,0,3,3,3,0,0,0,0,3,2,0,0,3,2,0,0,0,0,3,3,3,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
uint16_t WS2812FX::mode_2DAkemi(void) {
if (!isMatrix) return mode_static(); // not a 2D set-up
const uint16_t cols = SEGMENT.virtualWidth();
const uint16_t rows = SEGMENT.virtualHeight();
uint16_t counter = (now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF;
counter = counter >> 8;
const float lightFactor = 0.15f;
const float normalFactor = 0.4f;
float base = 0.0f;
uint8_t *fftResult = nullptr;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
fftResult = (uint8_t*)um_data->u_data[1];
base = fftResult[0]/255.0f;
}
//draw and color Akemi
for (uint16_t y=0; y < rows; y++) for (uint16_t x=0; x < cols; x++) {
CRGB color;
CRGB soundColor = ORANGE;
CRGB faceColor = color_wheel(counter);
CRGB armsAndLegsColor = SEGCOLOR(1) > 0 ? SEGCOLOR(1) : 0xFFE0A0; //default warmish white 0xABA8FF; //0xFF52e5;//
uint8_t ak = pgm_read_byte_near(akemi + ((y * 32)/rows) * 32 + (x * 32)/cols); // akemi[(y * 32)/rows][(x * 32)/cols]
switch (ak) {
case 0: color = BLACK; break;
case 3: armsAndLegsColor.r *= lightFactor; armsAndLegsColor.g *= lightFactor; armsAndLegsColor.b *= lightFactor; color = armsAndLegsColor; break; //light arms and legs 0x9B9B9B
case 2: armsAndLegsColor.r *= normalFactor; armsAndLegsColor.g *= normalFactor; armsAndLegsColor.b *= normalFactor; color = armsAndLegsColor; break; //normal arms and legs 0x888888
case 1: color = armsAndLegsColor; break; //dark arms and legs 0x686868
case 6: faceColor.r *= lightFactor; faceColor.g *= lightFactor; faceColor.b *= lightFactor; color=faceColor; break; //light face 0x31AAFF
case 5: faceColor.r *= normalFactor; faceColor.g *= normalFactor; faceColor.b *= normalFactor; color=faceColor; break; //normal face 0x0094FF
case 4: color = faceColor; break; //dark face 0x007DC6
case 7: color = SEGCOLOR(2) > 0 ? SEGCOLOR(2) : 0xFFFFFF; break; //eyes and mouth default white
case 8: if (base > 0.4) {soundColor.r *= base; soundColor.g *= base; soundColor.b *= base; color=soundColor;} else color = armsAndLegsColor; break;
default: color = BLACK;
}
if (SEGMENT.intensity > 128 && fftResult && fftResult[0] > 128) { //dance if base is high
setPixelColorXY(x, 0, BLACK);
setPixelColorXY(x, y+1, color);
} else
setPixelColorXY(x, y, color);
}
//add geq left and right
if (um_data && fftResult) {
for (uint16_t x=0; x < cols/8; x++) {
uint16_t band = x * cols/8;
uint16_t barHeight = map(fftResult[band], 0, 255, 0, 17*rows/32);
CRGB color = color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0);
for (uint16_t y=0; y < barHeight; y++) {
setPixelColorXY(x, rows/2-y, color);
setPixelColorXY(cols-1-x, rows/2-y, color);
}
}
}
return FRAMETIME;
} // mode_2DAkemi
static const char *_data_FX_MODE_2DAKEMI PROGMEM = "2D Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette";
//////////////////////////////////////////////////////////////////////////////////////////
// mode data
static const char *_data_RESERVED PROGMEM = "Reserved";

View File

@ -265,7 +265,7 @@
#define FX_MODE_PUDDLEPEAK 144
#define FX_MODE_NOISEMOVE 145
#define FX_MODE_2DNOISE 146 // non audio
#define FX_MODE_PERLINMOVE 147 // should be moved to 124
#define FX_MODE_PERLINMOVE 147 // should be moved to 53
#define FX_MODE_RIPPLEPEAK 148
#define FX_MODE_2DFIRENOISE 149 // non audio
#define FX_MODE_2DSQUAREDSWIRL 150 // non audio
@ -297,12 +297,12 @@
#define FX_MODE_2DLISSAJOUS 176 // non audio
#define FX_MODE_2DFRIZZLES 177 // non audio
#define FX_MODE_2DPLASMABALL 178 // non audio
#define FX_MODE_FLOWSTRIPE 179 // should be moved to 125
#define FX_MODE_FLOWSTRIPE 179 // should be moved to 114
#define FX_MODE_2DHIPHOTIC 180 // non audio
#define FX_MODE_2DSINDOTS 181 // non audio
#define FX_MODE_2DDNASPIRAL 182 // non audio
#define FX_MODE_2DBLACKHOLE 183 // non audio
#define FX_MODE_WAVESINS 184 // should be moved to 126
#define FX_MODE_WAVESINS 184 // should be moved to 48
#define FX_MODE_ROCKTAVES 185
#define FX_MODE_2DAKEMI 186
//#define FX_MODE_CUSTOMEFFECT 187 //WLEDSR Custom Effects