Multiple changes:

- change arduinoFFT to float (custom)
- update audioreactive to use float
- update effects to use float
- info slider (usermod)
- hide Peek in 2D
- minor bugfixes
This commit is contained in:
Blaz Kristan 2022-07-03 22:55:37 +02:00
parent 569138ac80
commit 0a2e01a616
10 changed files with 1973 additions and 1906 deletions

View File

@ -31,7 +31,7 @@
constexpr i2s_port_t I2S_PORT = I2S_NUM_0; constexpr i2s_port_t I2S_PORT = I2S_NUM_0;
constexpr int BLOCK_SIZE = 128; constexpr int BLOCK_SIZE = 128;
constexpr int SAMPLE_RATE = 10240; // Base sample rate in Hz constexpr int SAMPLE_RATE = 20480; // Base sample rate in Hz
// #define MIC_LOGGER // #define MIC_LOGGER
// #define MIC_SAMPLING_LOG // #define MIC_SAMPLING_LOG
@ -51,17 +51,17 @@ static uint8_t audioSyncEnabled = 0; // bit field: bit 0 - send, bit 1
// Note: in C++, "const" implies "static" - no need to explicitly declare everything as "static const" // Note: in C++, "const" implies "static" - no need to explicitly declare everything as "static const"
// //
#define AGC_NUM_PRESETS 3 // AGC presets: normal, vivid, lazy #define AGC_NUM_PRESETS 3 // AGC presets: normal, vivid, lazy
const double agcSampleDecay[AGC_NUM_PRESETS] = { 0.9994f, 0.9985f, 0.9997f}; // decay factor for sampleMax, in case the current sample is below sampleMax const float agcSampleDecay[AGC_NUM_PRESETS] = { 0.9994f, 0.9985f, 0.9997f}; // decay factor for sampleMax, in case the current sample is below sampleMax
const float agcZoneLow[AGC_NUM_PRESETS] = { 32, 28, 36}; // low volume emergency zone const float agcZoneLow[AGC_NUM_PRESETS] = { 32, 28, 36}; // low volume emergency zone
const float agcZoneHigh[AGC_NUM_PRESETS] = { 240, 240, 248}; // high volume emergency zone const float agcZoneHigh[AGC_NUM_PRESETS] = { 240, 240, 248}; // high volume emergency zone
const float agcZoneStop[AGC_NUM_PRESETS] = { 336, 448, 304}; // disable AGC integrator if we get above this level const float agcZoneStop[AGC_NUM_PRESETS] = { 336, 448, 304}; // disable AGC integrator if we get above this level
const float agcTarget0[AGC_NUM_PRESETS] = { 112, 144, 164}; // first AGC setPoint -> between 40% and 65% const float agcTarget0[AGC_NUM_PRESETS] = { 112, 144, 164}; // first AGC setPoint -> between 40% and 65%
const float agcTarget0Up[AGC_NUM_PRESETS] = { 88, 64, 116}; // setpoint switching value (a poor man's bang-bang) const float agcTarget0Up[AGC_NUM_PRESETS] = { 88, 64, 116}; // setpoint switching value (a poor man's bang-bang)
const float agcTarget1[AGC_NUM_PRESETS] = { 220, 224, 216}; // second AGC setPoint -> around 85% const float agcTarget1[AGC_NUM_PRESETS] = { 220, 224, 216}; // second AGC setPoint -> around 85%
const double agcFollowFast[AGC_NUM_PRESETS] = { 1/192.f, 1/128.f, 1/256.f}; // quickly follow setpoint - ~0.15 sec const float agcFollowFast[AGC_NUM_PRESETS] = { 1/192.f, 1/128.f, 1/256.f}; // quickly follow setpoint - ~0.15 sec
const double agcFollowSlow[AGC_NUM_PRESETS] = {1/6144.f,1/4096.f,1/8192.f}; // slowly follow setpoint - ~2-15 secs const float agcFollowSlow[AGC_NUM_PRESETS] = {1/6144.f,1/4096.f,1/8192.f}; // slowly follow setpoint - ~2-15 secs
const double agcControlKp[AGC_NUM_PRESETS] = { 0.6f, 1.5f, 0.65f}; // AGC - PI control, proportional gain parameter const float agcControlKp[AGC_NUM_PRESETS] = { 0.6f, 1.5f, 0.65f}; // AGC - PI control, proportional gain parameter
const double agcControlKi[AGC_NUM_PRESETS] = { 1.7f, 1.85f, 1.2f}; // AGC - PI control, integral gain parameter const float agcControlKi[AGC_NUM_PRESETS] = { 1.7f, 1.85f, 1.2f}; // AGC - PI control, integral gain parameter
const float agcSampleSmooth[AGC_NUM_PRESETS] = { 1/12.f, 1/6.f, 1/16.f}; // smoothing factor for sampleAgc (use rawSampleAgc if you want the non-smoothed value) const float agcSampleSmooth[AGC_NUM_PRESETS] = { 1/12.f, 1/6.f, 1/16.f}; // smoothing factor for sampleAgc (use rawSampleAgc if you want the non-smoothed value)
// AGC presets end // AGC presets end
@ -80,12 +80,12 @@ static float multAgc = 1.0f; // sample * multAgc = sampleAgc.
// FFT Variables // FFT Variables
constexpr uint16_t samplesFFT = 512; // Samples in an FFT batch - This value MUST ALWAYS be a power of 2 constexpr uint16_t samplesFFT = 512; // Samples in an FFT batch - This value MUST ALWAYS be a power of 2
static double FFT_MajorPeak = 0; static float FFT_MajorPeak = 0.0f;
static double FFT_Magnitude = 0; static float FFT_Magnitude = 0.0f;
// These are the input and output vectors. Input vectors receive computed results from FFT. // These are the input and output vectors. Input vectors receive computed results from FFT.
static double vReal[samplesFFT]; static float vReal[samplesFFT];
static double vImag[samplesFFT]; static float vImag[samplesFFT];
static float fftBin[samplesFFT]; static float fftBin[samplesFFT];
// Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256. // Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256.
@ -97,6 +97,11 @@ static float fftResultMax[16]; // A table used for test
#endif #endif
static float fftAvg[16]; static float fftAvg[16];
#ifdef WLED_DEBUG
static unsigned long fftTime = 0;
static unsigned long sampleTime = 0;
#endif
// Table of linearNoise results to be multiplied by soundSquelch in order to reduce squelch across fftResult bins. // Table of linearNoise results to be multiplied by soundSquelch in order to reduce squelch across fftResult bins.
static uint8_t linearNoise[16] = { 34, 28, 26, 25, 20, 12, 9, 6, 4, 4, 3, 2, 2, 2, 2, 2 }; static uint8_t linearNoise[16] = { 34, 28, 26, 25, 20, 12, 9, 6, 4, 4, 3, 2, 2, 2, 2, 2 };
@ -107,12 +112,12 @@ static float fftResultPink[16] = { 1.70f, 1.71f, 1.73f, 1.78f, 1.68f, 1.56f, 1.5
static arduinoFFT FFT = arduinoFFT(vReal, vImag, samplesFFT, SAMPLE_RATE); static arduinoFFT FFT = arduinoFFT(vReal, vImag, samplesFFT, SAMPLE_RATE);
static TaskHandle_t FFT_Task; static TaskHandle_t FFT_Task;
float fftAdd(int from, int to) { float fftAddAvg(int from, int to) {
float result = 0.0f; float result = 0.0f;
for (int i = from; i <= to; i++) { for (int i = from; i <= to; i++) {
result += fftBin[i]; result += fftBin[i];
} }
return result; return result / float(to - from + 1);
} }
// FFT main code // FFT main code
@ -120,7 +125,7 @@ void FFTcode(void * parameter)
{ {
DEBUGSR_PRINT("FFT running on core: "); DEBUGSR_PRINTLN(xPortGetCoreID()); DEBUGSR_PRINT("FFT running on core: "); DEBUGSR_PRINTLN(xPortGetCoreID());
#ifdef MAJORPEAK_SUPPRESS_NOISE #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}; static float 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};
#endif #endif
for(;;) { for(;;) {
@ -130,8 +135,16 @@ void FFTcode(void * parameter)
// Only run the FFT computing code if we're not in Receive mode // Only run the FFT computing code if we're not in Receive mode
if (audioSyncEnabled & 0x02) continue; if (audioSyncEnabled & 0x02) continue;
#ifdef WLED_DEBUG
unsigned long start = millis();
#endif
if (audioSource) audioSource->getSamples(vReal, samplesFFT); if (audioSource) audioSource->getSamples(vReal, samplesFFT);
#ifdef WLED_DEBUG
sampleTime = ((millis() - start)*3 + sampleTime*7)/10; // smooth
#endif
// old code - Last sample in vReal is our current mic sample // old code - Last sample in vReal is our current mic sample
//micDataSm = (uint16_t)vReal[samplesFFT - 1]; // will do a this a bit later //micDataSm = (uint16_t)vReal[samplesFFT - 1]; // will do a this a bit later
//micDataSm = ((micData * 3) + micData)/4; //micDataSm = ((micData * 3) + micData)/4;
@ -172,31 +185,31 @@ void FFTcode(void * parameter)
// //
#ifdef MAJORPEAK_SUPPRESS_NOISE #ifdef MAJORPEAK_SUPPRESS_NOISE
// teporarily reduce signal strength in the highest + lowest bins // teporarily reduce signal strength in the highest + lowest bins
xtemp[0] = vReal[0]; vReal[0] *= 0.005; xtemp[0] = vReal[0]; vReal[0] *= 0.005f;
xtemp[1] = vReal[1]; vReal[1] *= 0.005; xtemp[1] = vReal[1]; vReal[1] *= 0.005f;
xtemp[2] = vReal[2]; vReal[2] *= 0.005; xtemp[2] = vReal[2]; vReal[2] *= 0.005f;
xtemp[3] = vReal[3]; vReal[3] *= 0.02; xtemp[3] = vReal[3]; vReal[3] *= 0.02f;
xtemp[4] = vReal[4]; vReal[4] *= 0.02; xtemp[4] = vReal[4]; vReal[4] *= 0.02f;
xtemp[5] = vReal[5]; vReal[5] *= 0.02; xtemp[5] = vReal[5]; vReal[5] *= 0.02f;
xtemp[6] = vReal[6]; vReal[6] *= 0.05; xtemp[6] = vReal[6]; vReal[6] *= 0.05f;
xtemp[7] = vReal[7]; vReal[7] *= 0.08; xtemp[7] = vReal[7]; vReal[7] *= 0.08f;
xtemp[8] = vReal[8]; vReal[8] *= 0.1; xtemp[8] = vReal[8]; vReal[8] *= 0.1f;
xtemp[9] = vReal[9]; vReal[9] *= 0.2; xtemp[9] = vReal[9]; vReal[9] *= 0.2f;
xtemp[10] = vReal[10]; vReal[10] *= 0.2; xtemp[10] = vReal[10]; vReal[10] *= 0.2f;
xtemp[11] = vReal[11]; vReal[11] *= 0.25; xtemp[11] = vReal[11]; vReal[11] *= 0.25f;
xtemp[12] = vReal[12]; vReal[12] *= 0.3; xtemp[12] = vReal[12]; vReal[12] *= 0.3f;
xtemp[13] = vReal[13]; vReal[13] *= 0.3; xtemp[13] = vReal[13]; vReal[13] *= 0.3f;
xtemp[14] = vReal[14]; vReal[14] *= 0.4; xtemp[14] = vReal[14]; vReal[14] *= 0.4f;
xtemp[15] = vReal[15]; vReal[15] *= 0.4; xtemp[15] = vReal[15]; vReal[15] *= 0.4f;
xtemp[16] = vReal[16]; vReal[16] *= 0.4; xtemp[16] = vReal[16]; vReal[16] *= 0.4f;
xtemp[17] = vReal[17]; vReal[17] *= 0.5; xtemp[17] = vReal[17]; vReal[17] *= 0.5f;
xtemp[18] = vReal[18]; vReal[18] *= 0.5; xtemp[18] = vReal[18]; vReal[18] *= 0.5f;
xtemp[19] = vReal[19]; vReal[19] *= 0.6; xtemp[19] = vReal[19]; vReal[19] *= 0.6f;
xtemp[20] = vReal[20]; vReal[20] *= 0.7; xtemp[20] = vReal[20]; vReal[20] *= 0.7f;
xtemp[21] = vReal[21]; vReal[21] *= 0.8; xtemp[21] = vReal[21]; vReal[21] *= 0.8f;
xtemp[22] = vReal[samplesFFT-2]; vReal[samplesFFT-2] =0.0; xtemp[22] = vReal[samplesFFT-2]; vReal[samplesFFT-2] = 0.0f;
xtemp[23] = vReal[samplesFFT-1]; vReal[samplesFFT-1] =0.0; xtemp[23] = vReal[samplesFFT-1]; vReal[samplesFFT-1] = 0.0f;
#endif #endif
FFT.MajorPeak(&FFT_MajorPeak, &FFT_Magnitude); // let the effects know which freq was most dominant FFT.MajorPeak(&FFT_MajorPeak, &FFT_Magnitude); // let the effects know which freq was most dominant
@ -233,7 +246,7 @@ void FFTcode(void * parameter)
for (int i = 0; i < samplesFFT; i++) { // Values for bins 0 and 1 are WAY too large. Might as well start at 3. for (int i = 0; i < samplesFFT; i++) { // Values for bins 0 and 1 are WAY too large. Might as well start at 3.
float t = fabs(vReal[i]); // just to be sure - values in fft bins should be positive any way float t = fabs(vReal[i]); // just to be sure - values in fft bins should be positive any way
fftBin[i] = t / 16.0; // Reduce magnitude. Want end result to be linear and ~4096 max. fftBin[i] = t / 16.0f; // Reduce magnitude. Want end result to be linear and ~4096 max.
} // for() } // for()
@ -248,22 +261,22 @@ void FFTcode(void * parameter)
* Multiplier = 1.320367784 * Multiplier = 1.320367784
*/ */
// Range // Range
fftCalc[0] = (fftAdd(3,4)) /2; // 60 - 100 fftCalc[ 0] = fftAddAvg(3,4); // 60 - 100
fftCalc[1] = (fftAdd(4,5)) /2; // 80 - 120 fftCalc[ 1] = fftAddAvg(4,5); // 80 - 120
fftCalc[2] = (fftAdd(5,7)) /3; // 100 - 160 fftCalc[ 2] = fftAddAvg(5,7); // 100 - 160
fftCalc[3] = (fftAdd(7,9)) /3; // 140 - 200 fftCalc[ 3] = fftAddAvg(7,9); // 140 - 200
fftCalc[4] = (fftAdd(9,12)) /4; // 180 - 260 fftCalc[ 4] = fftAddAvg(9,12); // 180 - 260
fftCalc[5] = (fftAdd(12,16)) /5; // 240 - 340 fftCalc[ 5] = fftAddAvg(12,16); // 240 - 340
fftCalc[6] = (fftAdd(16,21)) /6; // 320 - 440 fftCalc[ 6] = fftAddAvg(16,21); // 320 - 440
fftCalc[7] = (fftAdd(21,28)) /8; // 420 - 600 fftCalc[ 7] = fftAddAvg(21,28); // 420 - 600
fftCalc[8] = (fftAdd(29,37)) /10; // 580 - 760 fftCalc[ 8] = fftAddAvg(29,37); // 580 - 760
fftCalc[9] = (fftAdd(37,48)) /12; // 740 - 980 fftCalc[ 9] = fftAddAvg(37,48); // 740 - 980
fftCalc[10] = (fftAdd(48,64)) /17; // 960 - 1300 fftCalc[10] = fftAddAvg(48,64); // 960 - 1300
fftCalc[11] = (fftAdd(64,84)) /21; // 1280 - 1700 fftCalc[11] = fftAddAvg(64,84); // 1280 - 1700
fftCalc[12] = (fftAdd(84,111)) /28; // 1680 - 2240 fftCalc[12] = fftAddAvg(84,111); // 1680 - 2240
fftCalc[13] = (fftAdd(111,147)) /37; // 2220 - 2960 fftCalc[13] = fftAddAvg(111,147); // 2220 - 2960
fftCalc[14] = (fftAdd(147,194)) /48; // 2940 - 3900 fftCalc[14] = fftAddAvg(147,194); // 2940 - 3900
fftCalc[15] = (fftAdd(194, 255)) /62; // 3880 - 5120 fftCalc[15] = fftAddAvg(194,255); // 3880 - 5120
for (int i=0; i < 16; i++) { for (int i=0; i < 16; i++) {
// Noise supression of fftCalc bins using soundSquelch adjustment for different input types. // Noise supression of fftCalc bins using soundSquelch adjustment for different input types.
@ -283,10 +296,14 @@ void FFTcode(void * parameter)
micDataSm = (uint16_t)maxSample2; micDataSm = (uint16_t)maxSample2;
micDataReal = maxSample2; micDataReal = maxSample2;
#ifdef WLED_DEBUG
fftTime = ((millis() - start)*3 + fftTime*7)/10;
#endif
#ifdef SR_DEBUG #ifdef SR_DEBUG
// Looking for fftResultMax for each bin using Pink Noise // Looking for fftResultMax for each bin using Pink Noise
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
fftResultMax[i] = ((fftResultMax[i] * 63.0) + fftResult[i]) / 64.0; fftResultMax[i] = ((fftResultMax[i] * 63.0f) + fftResult[i]) / 64.0f;
DEBUGSR_PRINT(fftResultMax[i]*fftResultPink[i]); DEBUGSR_PRINT("\t"); DEBUGSR_PRINT(fftResultMax[i]*fftResultPink[i]); DEBUGSR_PRINT("\t");
} }
DEBUGSR_PRINTLN(); DEBUGSR_PRINTLN();
@ -397,6 +414,7 @@ class AudioReactive : public Usermod {
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
static const char _name[]; static const char _name[];
static const char _enabled[]; static const char _enabled[];
static const char _inputLvl[];
static const char _analogmic[]; static const char _analogmic[];
static const char _digitalmic[]; static const char _digitalmic[];
static const char UDP_SYNC_HEADER[]; static const char UDP_SYNC_HEADER[];
@ -563,16 +581,16 @@ class AudioReactive : public Usermod {
// NOW finally amplify the signal // NOW finally amplify the signal
tmpAgc = sampleReal * multAgcTemp; // apply gain to signal tmpAgc = sampleReal * multAgcTemp; // apply gain to signal
if (fabs(sampleReal) < 2.0f) tmpAgc = 0; // apply squelch threshold if (fabsf(sampleReal) < 2.0f) tmpAgc = 0.0f; // apply squelch threshold
//tmpAgc = constrain(tmpAgc, 0, 255); //tmpAgc = constrain(tmpAgc, 0, 255);
if (tmpAgc > 255) tmpAgc = 255; // limit to 8bit if (tmpAgc > 255) tmpAgc = 255.0f; // limit to 8bit
if (tmpAgc < 1) tmpAgc = 0; // just to be sure if (tmpAgc < 1) tmpAgc = 0.0f; // just to be sure
// update global vars ONCE - multAgc, sampleAGC, rawSampleAgc // update global vars ONCE - multAgc, sampleAGC, rawSampleAgc
multAgc = multAgcTemp; multAgc = multAgcTemp;
rawSampleAgc = 0.8f * tmpAgc + 0.2f * (float)rawSampleAgc; rawSampleAgc = 0.8f * tmpAgc + 0.2f * (float)rawSampleAgc;
// update smoothed AGC sample // update smoothed AGC sample
if (fabs(tmpAgc) < 1.0f) if (fabsf(tmpAgc) < 1.0f)
sampleAgc = 0.5f * tmpAgc + 0.5f * sampleAgc; // fast path to zero sampleAgc = 0.5f * tmpAgc + 0.5f * sampleAgc; // fast path to zero
else else
sampleAgc += agcSampleSmooth[AGC_preset] * (tmpAgc - sampleAgc); // smooth path sampleAgc += agcSampleSmooth[AGC_preset] * (tmpAgc - sampleAgc); // smooth path
@ -613,14 +631,14 @@ class AudioReactive : public Usermod {
expAdjF = (weighting * micInNoDC + (1.0-weighting) * expAdjF); expAdjF = (weighting * micInNoDC + (1.0-weighting) * expAdjF);
expAdjF = (expAdjF <= soundSquelch) ? 0: expAdjF; // simple noise gate expAdjF = (expAdjF <= soundSquelch) ? 0: expAdjF; // simple noise gate
expAdjF = fabs(expAdjF); // Now (!) take the absolute value expAdjF = fabsf(expAdjF); // Now (!) take the absolute value
tmpSample = expAdjF; tmpSample = expAdjF;
DEBUGSR_PRINT("\t\t"); DEBUGSR_PRINT(tmpSample); DEBUGSR_PRINT("\t\t"); DEBUGSR_PRINT(tmpSample);
micIn = abs(micIn); // And get the absolute value of each sample micIn = abs(micIn); // And get the absolute value of each sample
sampleAdj = tmpSample * sampleGain / 40 * inputLevel/128 + tmpSample / 16; // Adjust the gain. with inputLevel adjustment sampleAdj = tmpSample * sampleGain / 40.0f * inputLevel/128.0f + tmpSample / 16.0f; // Adjust the gain. with inputLevel adjustment
//sampleReal = sampleAdj; //sampleReal = sampleAdj;
sampleReal = tmpSample; sampleReal = tmpSample;
@ -647,8 +665,8 @@ class AudioReactive : public Usermod {
uint16_t MinShowDelay = strip.getMinShowDelay(); uint16_t MinShowDelay = strip.getMinShowDelay();
if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed. if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed.
samplePeak = 0; samplePeak = false;
udpSamplePeak = 0; udpSamplePeak = false;
} }
//if (userVar1 == 0) samplePeak = 0; //if (userVar1 == 0) samplePeak = 0;
@ -664,9 +682,9 @@ class AudioReactive : public Usermod {
if ((fftBin[binNum] > maxVol) && (millis() > (timeOfPeak + 100))) { // This goes through ALL of the 255 bins if ((fftBin[binNum] > maxVol) && (millis() > (timeOfPeak + 100))) { // This goes through ALL of the 255 bins
// if (sample > (sampleAvg + maxVol) && millis() > (timeOfPeak + 200)) { // if (sample > (sampleAvg + maxVol) && millis() > (timeOfPeak + 200)) {
// Then we got a peak, else we don't. The peak has to time out on its own in order to support UDP sound sync. // Then we got a peak, else we don't. The peak has to time out on its own in order to support UDP sound sync.
samplePeak = 1; samplePeak = true;
timeOfPeak = millis(); timeOfPeak = millis();
udpSamplePeak = 1; udpSamplePeak = true;
//userVar1 = samplePeak; //userVar1 = samplePeak;
} }
} // getSample() } // getSample()
@ -776,9 +794,9 @@ class AudioReactive : public Usermod {
um_data->u_data[ 5] = &samplePeak; //*used (Puddlepeak, Ripplepeak, Waterfall) um_data->u_data[ 5] = &samplePeak; //*used (Puddlepeak, Ripplepeak, Waterfall)
um_data->u_type[ 5] = UMT_BYTE; um_data->u_type[ 5] = UMT_BYTE;
um_data->u_data[ 6] = &FFT_MajorPeak; //*used (Ripplepeak, Freqmap, Freqmatrix, Freqpixels, Freqwave, Gravfreq, Rocktaves, Waterfall) um_data->u_data[ 6] = &FFT_MajorPeak; //*used (Ripplepeak, Freqmap, Freqmatrix, Freqpixels, Freqwave, Gravfreq, Rocktaves, Waterfall)
um_data->u_type[ 6] = UMT_DOUBLE; um_data->u_type[ 6] = UMT_FLOAT;
um_data->u_data[ 7] = &FFT_Magnitude; //*used (Binmap, Freqmap, Freqpixels, Rocktaves, Waterfall) um_data->u_data[ 7] = &FFT_Magnitude; //*used (Binmap, Freqmap, Freqpixels, Rocktaves, Waterfall)
um_data->u_type[ 7] = UMT_DOUBLE; um_data->u_type[ 7] = UMT_FLOAT;
um_data->u_data[ 8] = fftResult; //*used (Blurz, DJ Light, Noisemove, GEQ_base, 2D Funky Plank, Akemi) um_data->u_data[ 8] = fftResult; //*used (Blurz, DJ Light, Noisemove, GEQ_base, 2D Funky Plank, Akemi)
um_data->u_type[ 8] = UMT_BYTE_ARR; um_data->u_type[ 8] = UMT_BYTE_ARR;
um_data->u_data[ 9] = &maxVol; // assigned in effect function from UI element!!! (Puddlepeak, Ripplepeak, Waterfall) um_data->u_data[ 9] = &maxVol; // assigned in effect function from UI element!!! (Puddlepeak, Ripplepeak, Waterfall)
@ -966,6 +984,9 @@ class AudioReactive : public Usermod {
void onUpdateBegin(bool init) void onUpdateBegin(bool init)
{ {
#ifdef WLED_DEBUG
fftTime = sampleTime = 0;
#endif
if (init) vTaskDelete(FFT_Task); // update is about to begin, remove task to prevent crash if (init) vTaskDelete(FFT_Task); // update is about to begin, remove task to prevent crash
else { // update has failed or create task requested else { // update has failed or create task requested
// Define the FFT Task and lock it to core 0 // Define the FFT Task and lock it to core 0
@ -1021,6 +1042,25 @@ class AudioReactive : public Usermod {
uiDomString += F("\">&#xe08f;</i>"); uiDomString += F("\">&#xe08f;</i>");
uiDomString += F("</button>"); uiDomString += F("</button>");
infoArr.add(uiDomString); infoArr.add(uiDomString);
infoArr = user.createNestedArray(F("Input level"));
uiDomString = F("<div class=\"slider\"><div class=\"sliderwrap il\"><input class=\"noslide\" onchange=\"requestJson({");
uiDomString += FPSTR(_name);
uiDomString += F(":{");
uiDomString += FPSTR(_inputLvl);
uiDomString += F(":parseInt(this.value)}});\" oninput=\"updateTrail(this);\" max=255 min=0 type=\"range\" value=");
uiDomString += inputLevel;
uiDomString += F(" /><div class=\"sliderdisplay\"></div></div></div>"); //<output class=\"sliderbubble\"></output>
infoArr.add(uiDomString);
#ifdef WLED_DEBUG
infoArr = user.createNestedArray(F("Sampling time"));
infoArr.add(sampleTime);
infoArr.add("ms");
infoArr = user.createNestedArray(F("FFT time"));
infoArr.add(fftTime-sampleTime);
infoArr.add("ms");
#endif
} }
@ -1050,6 +1090,9 @@ class AudioReactive : public Usermod {
enabled = usermod[FPSTR(_enabled)].as<bool>(); enabled = usermod[FPSTR(_enabled)].as<bool>();
if (prevEnabled != enabled) onUpdateBegin(!enabled); if (prevEnabled != enabled) onUpdateBegin(!enabled);
} }
if (usermod[FPSTR(_inputLvl)].is<int>()) {
inputLevel = min(255,max(0,usermod[FPSTR(_inputLvl)].as<int>()));
}
} }
} }
@ -1215,6 +1258,7 @@ class AudioReactive : public Usermod {
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
const char AudioReactive::_name[] PROGMEM = "AudioReactive"; const char AudioReactive::_name[] PROGMEM = "AudioReactive";
const char AudioReactive::_enabled[] PROGMEM = "enabled"; const char AudioReactive::_enabled[] PROGMEM = "enabled";
const char AudioReactive::_inputLvl[] PROGMEM = "inputLevel";
const char AudioReactive::_analogmic[] PROGMEM = "analogmic"; const char AudioReactive::_analogmic[] PROGMEM = "analogmic";
const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic"; const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic";
const char AudioReactive::UDP_SYNC_HEADER[] PROGMEM = "00001"; const char AudioReactive::UDP_SYNC_HEADER[] PROGMEM = "00001";

View File

@ -50,7 +50,7 @@ class AudioSource {
Read num_samples from the microphone, and store them in the provided Read num_samples from the microphone, and store them in the provided
buffer buffer
*/ */
virtual void getSamples(double *buffer, uint16_t num_samples) = 0; virtual void getSamples(float *buffer, uint16_t num_samples) = 0;
/* Get an up-to-date sample without DC offset */ /* Get an up-to-date sample without DC offset */
virtual int getSampleWithoutDCOffset() { return _sampleNoDCOffset; }; virtual int getSampleWithoutDCOffset() { return _sampleNoDCOffset; };
@ -156,7 +156,7 @@ class I2SSource : public AudioSource {
if (_mclkPin != I2S_PIN_NO_CHANGE) pinManager.deallocatePin(_mclkPin, PinOwner::UM_Audioreactive); if (_mclkPin != I2S_PIN_NO_CHANGE) pinManager.deallocatePin(_mclkPin, PinOwner::UM_Audioreactive);
} }
virtual void getSamples(double *buffer, uint16_t num_samples) { virtual void getSamples(float *buffer, uint16_t num_samples) {
if (_initialized) { if (_initialized) {
esp_err_t err; esp_err_t err;
size_t bytes_read = 0; /* Counter variable to check if we actually got enough data */ size_t bytes_read = 0; /* Counter variable to check if we actually got enough data */
@ -184,17 +184,17 @@ class I2SSource : public AudioSource {
if (_shift != 0) if (_shift != 0)
newSamples[i] >>= 16; newSamples[i] >>= 16;
#endif #endif
double currSample = 0.0; float currSample = 0.0f;
if(_shift > 0) if(_shift > 0)
currSample = (double) (newSamples[i] >> _shift); currSample = (float) (newSamples[i] >> _shift);
else { else {
if(_shift < 0) if(_shift < 0)
currSample = (double) (newSamples[i] << (- _shift)); // need to "pump up" 12bit ADC to full 16bit as delivered by other digital mics currSample = (float) (newSamples[i] << (- _shift)); // need to "pump up" 12bit ADC to full 16bit as delivered by other digital mics
else else
#ifdef I2S_SAMPLE_DOWNSCALE_TO_16BIT #ifdef I2S_SAMPLE_DOWNSCALE_TO_16BIT
currSample = (double) newSamples[i] / 65536.0; // _shift == 0 -> use the chance to keep lower 16bits currSample = (float) newSamples[i] / 65536.0f; // _shift == 0 -> use the chance to keep lower 16bits
#else #else
currSample = (double) newSamples[i]; currSample = (float) newSamples[i];
#endif #endif
} }
buffer[i] = currSample; buffer[i] = currSample;
@ -356,7 +356,7 @@ class I2SAdcSource : public I2SSource {
_initialized = true; _initialized = true;
} }
void getSamples(double *buffer, uint16_t num_samples) { void getSamples(float *buffer, uint16_t num_samples) {
/* Enable ADC. This has to be enabled and disabled directly before and /* Enable ADC. This has to be enabled and disabled directly before and
* after sampling, otherwise Wifi dies * after sampling, otherwise Wifi dies
*/ */

View File

@ -9,9 +9,11 @@ The usermod **does not** provide effects or draws anything to LED strip/matrix.
## Installation ## Installation
Add `-D USERMOD_AUDIOREACTIVE` to your PlatformIO environment as well as `arduinoFFT @ 1.5.6` to your `lib_deps`. Add `-D USERMOD_AUDIOREACTIVE` to your PlatformIO environment as well as `arduinoFFT` to your `lib_deps`.
If you are not using PlatformIO (which you should) try adding `#define USERMOD_AUDIOREACTIVE` to *my_config.h* and make sure you have _arduinoFFT_ library downloaded and installed. If you are not using PlatformIO (which you should) try adding `#define USERMOD_AUDIOREACTIVE` to *my_config.h* and make sure you have _arduinoFFT_ library downloaded and installed.
Customised _arduinoFFT_ library for use with this usermod can be found at https://github.com/blazoncek/arduinoFFT.git
## Configuration ## Configuration
All parameters are runtime configurable though some may require hard boot after change (I2S microphone or selected GPIOs). All parameters are runtime configurable though some may require hard boot after change (I2S microphone or selected GPIOs).

View File

@ -5947,7 +5947,7 @@ static const char *_data_FX_MODE_DRIFT_ROSE PROGMEM = "2D Drift Rose@Fade,Blur;;
uint8_t soundAgc = 0, soundSquelch = 10; uint8_t soundAgc = 0, soundSquelch = 10;
bool samplePeak = false; bool samplePeak = false;
float sampleAgc = 0.0f, sampleAgv = 0.0f, multAgc = 0.0f, sampleReal = 0.0f; float sampleAgc = 0.0f, sampleAgv = 0.0f, multAgc = 0.0f, sampleReal = 0.0f;
double FFT_MajorPeak = 0.0, FFT_Magnitude = 0.0; float FFT_MajorPeak = 0.0, FFT_Magnitude = 0.0;
uint8_t *fftResult = nullptr; uint8_t *fftResult = nullptr;
uint16_t *myVals = nullptr; uint16_t *myVals = nullptr;
float *fftBin = nullptr; float *fftBin = nullptr;
@ -5959,8 +5959,8 @@ static const char *_data_FX_MODE_DRIFT_ROSE PROGMEM = "2D Drift Rose@Fade,Blur;;
sample = *(uint16_t*)um_data->u_data[ 3]; sample = *(uint16_t*)um_data->u_data[ 3];
rawSampleAgc = *(uint16_t*)um_data->u_data[ 4]; rawSampleAgc = *(uint16_t*)um_data->u_data[ 4];
samplePeak = *(uint8_t*) um_data->u_data[ 5]; samplePeak = *(uint8_t*) um_data->u_data[ 5];
FFT_MajorPeak = *(double*) um_data->u_data[ 6]; FFT_MajorPeak = *(float*) um_data->u_data[ 6];
FFT_Magnitude = *(double*) um_data->u_data[ 7]; FFT_Magnitude = *(float*) um_data->u_data[ 7];
fftResult = (uint8_t*) um_data->u_data[ 8]; fftResult = (uint8_t*) um_data->u_data[ 8];
maxVol = (uint8_t*) um_data->u_data[ 9]; // requires UI element (SEGMENT.customX?), changes source element maxVol = (uint8_t*) um_data->u_data[ 9]; // requires UI element (SEGMENT.customX?), changes source element
binNum = (uint8_t*) um_data->u_data[10]; // requires UI element (SEGMENT.customX?), changes source element binNum = (uint8_t*) um_data->u_data[10]; // requires UI element (SEGMENT.customX?), changes source element
@ -5998,10 +5998,10 @@ uint16_t WS2812FX::mode_ripplepeak(void) { // * Ripple peak. By A
uint8_t *binNum, *maxVol; // just in case assignment uint8_t *binNum, *maxVol; // just in case assignment
uint8_t samplePeak = 0; // actually a bool uint8_t samplePeak = 0; // actually a bool
double FFT_MajorPeak = 0.0; float FFT_MajorPeak = 0.0;
um_data_t *um_data; um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*) um_data->u_data[6]; FFT_MajorPeak = *(float*) um_data->u_data[6];
binNum = (uint8_t*)um_data->u_data[10]; binNum = (uint8_t*)um_data->u_data[10];
maxVol = (uint8_t*)um_data->u_data[9]; maxVol = (uint8_t*)um_data->u_data[9];
samplePeak = *(uint8_t*)um_data->u_data[5]; samplePeak = *(uint8_t*)um_data->u_data[5];
@ -6885,7 +6885,7 @@ uint16_t WS2812FX::mode_binmap(void) {
uint16_t endBin = FIRSTBIN+(i+1)*(LASTBIN-FIRSTBIN)/SEGLEN; // This is the END bin for this particular pixel. uint16_t endBin = FIRSTBIN+(i+1)*(LASTBIN-FIRSTBIN)/SEGLEN; // This is the END bin for this particular pixel.
if (endBin > startBin) endBin --; // avoid overlapping if (endBin > startBin) endBin --; // avoid overlapping
double sumBin = 0; float sumBin = 0;
for (int j=startBin; j<=endBin; j++) { for (int j=startBin; j<=endBin; j++) {
sumBin += (fftBin[j] < soundSquelch*1.75f) ? 0 : fftBin[j]; // We need some sound temporary squelch for fftBin, because we didn't do it for the raw bins in audio_reactive.h sumBin += (fftBin[j] < soundSquelch*1.75f) ? 0 : fftBin[j]; // We need some sound temporary squelch for fftBin, because we didn't do it for the raw bins in audio_reactive.h
@ -6988,15 +6988,15 @@ uint16_t WS2812FX::mode_freqmap(void) { // Map FFT_MajorPeak t
// Start frequency = 60 Hz and log10(60) = 1.78 // Start frequency = 60 Hz and log10(60) = 1.78
// End frequency = 5120 Hz and lo10(5120) = 3.71 // End frequency = 5120 Hz and lo10(5120) = 3.71
double FFT_MajorPeak = 0.0; float FFT_MajorPeak = 0.0;
double FFT_Magnitude = 0.0; float FFT_Magnitude = 0.0;
uint8_t soundAgc = 0; uint8_t soundAgc = 0;
float sampleAvg = 0.0f; float sampleAvg = 0.0f;
float multAgc = 0.0f; float multAgc = 0.0f;
um_data_t *um_data; um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[6]; FFT_MajorPeak = *(float*)um_data->u_data[6];
FFT_Magnitude = *(double*)um_data->u_data[7]; FFT_Magnitude = *(float*)um_data->u_data[7];
sampleAvg = *(float*)um_data->u_data[0]; sampleAvg = *(float*)um_data->u_data[0];
soundAgc = *(uint8_t*)um_data->u_data[1]; soundAgc = *(uint8_t*)um_data->u_data[1];
multAgc = *(float*)um_data->u_data[11]; multAgc = *(float*)um_data->u_data[11];
@ -7027,11 +7027,11 @@ static const char *_data_FX_MODE_FREQMAP PROGMEM = " ♫ Freqmap@Fade rate,Start
// ** Freqmatrix // // ** Freqmatrix //
/////////////////////// ///////////////////////
uint16_t WS2812FX::mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung. uint16_t WS2812FX::mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung.
double FFT_MajorPeak = 0.0; float FFT_MajorPeak = 0.0;
float sampleAgc = 0.0f; float sampleAgc = 0.0f;
um_data_t *um_data; um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[6]; FFT_MajorPeak = *(float*)um_data->u_data[6];
sampleAgc = *(float*)um_data->u_data[2]; sampleAgc = *(float*)um_data->u_data[2];
} else { } else {
// add support for no audio data // add support for no audio data
@ -7083,15 +7083,15 @@ static const char *_data_FX_MODE_FREQMATRIX PROGMEM = " ♫ Freqmatrix@Time dela
// SEGMENT.speed select faderate // SEGMENT.speed select faderate
// SEGMENT.intensity select colour index // SEGMENT.intensity select colour index
uint16_t WS2812FX::mode_freqpixels(void) { // Freqpixel. By Andrew Tuline. uint16_t WS2812FX::mode_freqpixels(void) { // Freqpixel. By Andrew Tuline.
double FFT_MajorPeak = 0.0; float FFT_MajorPeak = 0.0;
double FFT_Magnitude = 0.0; float FFT_Magnitude = 0.0;
uint8_t soundAgc = 0; uint8_t soundAgc = 0;
float sampleAvg = 0.0f; float sampleAvg = 0.0f;
float multAgc = 0.0f; float multAgc = 0.0f;
um_data_t *um_data; um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[6]; FFT_MajorPeak = *(float*)um_data->u_data[6];
FFT_Magnitude = *(double*)um_data->u_data[7]; FFT_Magnitude = *(float*)um_data->u_data[7];
sampleAvg = *(float*)um_data->u_data[0]; sampleAvg = *(float*)um_data->u_data[0];
soundAgc = *(uint8_t*)um_data->u_data[1]; soundAgc = *(uint8_t*)um_data->u_data[1];
multAgc = *(float*)um_data->u_data[11]; multAgc = *(float*)um_data->u_data[11];
@ -7133,12 +7133,12 @@ static const char *_data_FX_MODE_FREQPIXELS PROGMEM = " ♫ Freqpixels@Fade rate
// As a compromise between speed and accuracy we are currently sampling with 10240Hz, from which we can then determine with a 512bin FFT our max frequency is 5120Hz. // As a compromise between speed and accuracy we are currently sampling with 10240Hz, from which we can then determine with a 512bin FFT our max frequency is 5120Hz.
// Depending on the music stream you have you might find it useful to change the frequency mapping. // Depending on the music stream you have you might find it useful to change the frequency mapping.
uint16_t WS2812FX::mode_freqwave(void) { // Freqwave. By Andreas Pleschung. uint16_t WS2812FX::mode_freqwave(void) { // Freqwave. By Andreas Pleschung.
double FFT_MajorPeak = 0.0; float FFT_MajorPeak = 0.0;
uint8_t soundAgc = 0; uint8_t soundAgc = 0;
float sampleAgc = 0.0f, sampleAvg = 0.0f; float sampleAgc = 0.0f, sampleAvg = 0.0f;
um_data_t *um_data; um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[6]; FFT_MajorPeak = *(float*)um_data->u_data[6];
sampleAvg = *(float*)um_data->u_data[0]; sampleAvg = *(float*)um_data->u_data[0];
soundAgc = *(uint8_t*)um_data->u_data[1]; soundAgc = *(uint8_t*)um_data->u_data[1];
sampleAgc = *(float*)um_data->u_data[2]; sampleAgc = *(float*)um_data->u_data[2];
@ -7203,9 +7203,9 @@ uint16_t WS2812FX::mode_gravfreq(void) { // Gravfreq. By Andrew
um_data_t *um_data; um_data_t *um_data;
uint8_t soundAgc = 0; uint8_t soundAgc = 0;
float sampleAgc = 0.0f, sampleAvg = 0.0f; float sampleAgc = 0.0f, sampleAvg = 0.0f;
double FFT_MajorPeak = 0.0; float FFT_MajorPeak = 0.0;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[6]; FFT_MajorPeak = *(float*)um_data->u_data[6];
soundAgc = *(uint8_t*)um_data->u_data[1]; soundAgc = *(uint8_t*)um_data->u_data[1];
sampleAgc = *(float*)um_data->u_data[2]; sampleAgc = *(float*)um_data->u_data[2];
sampleAvg = *(float*)um_data->u_data[0]; sampleAvg = *(float*)um_data->u_data[0];
@ -7279,15 +7279,15 @@ static const char *_data_FX_MODE_NOISEMOVE PROGMEM = " ♫ Noisemove@Speed of pe
// ** Rocktaves // // ** Rocktaves //
////////////////////// //////////////////////
uint16_t WS2812FX::mode_rocktaves(void) { // Rocktaves. Same note from each octave is same colour. By: Andrew Tuline uint16_t WS2812FX::mode_rocktaves(void) { // Rocktaves. Same note from each octave is same colour. By: Andrew Tuline
double FFT_MajorPeak = 0.0; float FFT_MajorPeak = 0.0;
double FFT_Magnitude = 0.0; float FFT_Magnitude = 0.0;
uint8_t soundAgc = 0; uint8_t soundAgc = 0;
float sampleAvg = 0.0f; float sampleAvg = 0.0f;
float multAgc = 0.0f; float multAgc = 0.0f;
um_data_t *um_data; um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[6]; FFT_MajorPeak = *(float*)um_data->u_data[6];
FFT_Magnitude = *(double*)um_data->u_data[7]; FFT_Magnitude = *(float*)um_data->u_data[7];
sampleAvg = *(float*)um_data->u_data[0]; sampleAvg = *(float*)um_data->u_data[0];
soundAgc = *(uint8_t*)um_data->u_data[1]; soundAgc = *(uint8_t*)um_data->u_data[1];
multAgc = *(float*)um_data->u_data[11]; multAgc = *(float*)um_data->u_data[11];
@ -7333,8 +7333,8 @@ uint16_t WS2812FX::mode_waterfall(void) { // Waterfall. By: An
uint8_t *binNum, *maxVol; uint8_t *binNum, *maxVol;
uint8_t samplePeak = 0; uint8_t samplePeak = 0;
double FFT_MajorPeak = 0.0; float FFT_MajorPeak = 0.0;
double FFT_Magnitude = 0.0; float FFT_Magnitude = 0.0;
uint8_t soundAgc = 0; uint8_t soundAgc = 0;
float sampleAvg = 0.0f; float sampleAvg = 0.0f;
float multAgc = 0.0f; float multAgc = 0.0f;
@ -7343,8 +7343,8 @@ uint16_t WS2812FX::mode_waterfall(void) { // Waterfall. By: An
maxVol = (uint8_t*)um_data->u_data[9]; maxVol = (uint8_t*)um_data->u_data[9];
samplePeak = *(uint8_t*)um_data->u_data[5]; samplePeak = *(uint8_t*)um_data->u_data[5];
binNum = (uint8_t*)um_data->u_data[10]; binNum = (uint8_t*)um_data->u_data[10];
FFT_MajorPeak = *(double*)um_data->u_data[6]; FFT_MajorPeak = *(float*)um_data->u_data[6];
FFT_Magnitude = *(double*)um_data->u_data[7]; FFT_Magnitude = *(float*)um_data->u_data[7];
sampleAvg = *(float*)um_data->u_data[0]; sampleAvg = *(float*)um_data->u_data[0];
soundAgc = *(uint8_t*)um_data->u_data[1]; soundAgc = *(uint8_t*)um_data->u_data[1];
multAgc = *(float*)um_data->u_data[11]; multAgc = *(float*)um_data->u_data[11];
@ -7446,16 +7446,6 @@ uint16_t WS2812FX::mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud
static const char *_data_FX_MODE_2DGEQ PROGMEM = " ♫ 2D GEQ@Fade speed,Ripple decay,# of bands=255,Color bars=64;!,,Peak Color;!=11"; static const char *_data_FX_MODE_2DGEQ PROGMEM = " ♫ 2D GEQ@Fade speed,Ripple decay,# of bands=255,Color bars=64;!,,Peak Color;!=11";
/////////////////////////
// ** 2D CenterBars //
/////////////////////////
// NOTE: obsolete!
uint16_t WS2812FX::mode_2DCenterBars(void) { // Written by Scott Marley Adapted by Spiro-C..
return mode_2DGEQ();
} // mode_2DCenterBars()
static const char *_data_FX_MODE_2DCENTERBARS PROGMEM = " ♫ 2D CenterBars@Bar speed,Ripple decay,# of bands=255,Color bars=64;!,,Peak Color;!=11";
///////////////////////// /////////////////////////
// ** 2D Funky plank // // ** 2D Funky plank //
///////////////////////// /////////////////////////
@ -7834,7 +7824,7 @@ void WS2812FX::setupEffectData() {
addEffect(FX_MODE_GRAVFREQ, &WS2812FX::mode_gravfreq, _data_FX_MODE_GRAVFREQ); addEffect(FX_MODE_GRAVFREQ, &WS2812FX::mode_gravfreq, _data_FX_MODE_GRAVFREQ);
addEffect(FX_MODE_DJLIGHT, &WS2812FX::mode_DJLight, _data_FX_MODE_DJLIGHT); addEffect(FX_MODE_DJLIGHT, &WS2812FX::mode_DJLight, _data_FX_MODE_DJLIGHT);
addEffect(FX_MODE_2DFUNKYPLANK, &WS2812FX::mode_2DFunkyPlank, _data_FX_MODE_2DFUNKYPLANK); addEffect(FX_MODE_2DFUNKYPLANK, &WS2812FX::mode_2DFunkyPlank, _data_FX_MODE_2DFUNKYPLANK);
addEffect(FX_MODE_2DCENTERBARS, &WS2812FX::mode_2DCenterBars, _data_FX_MODE_2DCENTERBARS); //addEffect(FX_MODE_2DCENTERBARS, &WS2812FX::mode_2DCenterBars, _data_FX_MODE_2DCENTERBARS);
addEffect(FX_MODE_2DPULSER, &WS2812FX::mode_2DPulser, _data_FX_MODE_2DPULSER); addEffect(FX_MODE_2DPULSER, &WS2812FX::mode_2DPulser, _data_FX_MODE_2DPULSER);
addEffect(FX_MODE_BLURZ, &WS2812FX::mode_blurz, _data_FX_MODE_BLURZ); addEffect(FX_MODE_BLURZ, &WS2812FX::mode_blurz, _data_FX_MODE_BLURZ);
addEffect(FX_MODE_2DSUNRADIATION, &WS2812FX::mode_2DSunradiation, _data_FX_MODE_2DSUNRADIATION); addEffect(FX_MODE_2DSUNRADIATION, &WS2812FX::mode_2DSunradiation, _data_FX_MODE_2DSUNRADIATION);

View File

@ -327,7 +327,7 @@
#define FX_MODE_GRAVFREQ 158 #define FX_MODE_GRAVFREQ 158
#define FX_MODE_DJLIGHT 159 #define FX_MODE_DJLIGHT 159
#define FX_MODE_2DFUNKYPLANK 160 #define FX_MODE_2DFUNKYPLANK 160
#define FX_MODE_2DCENTERBARS 161 // obsolete by X & Y mirroring //#define FX_MODE_2DCENTERBARS 161 // obsolete by X & Y mirroring
#define FX_MODE_2DPULSER 162 // non audio #define FX_MODE_2DPULSER 162 // non audio
#define FX_MODE_BLURZ 163 #define FX_MODE_BLURZ 163
#define FX_MODE_2DDRIFT 164 // non audio #define FX_MODE_2DDRIFT 164 // non audio
@ -968,7 +968,6 @@ class WS2812FX {
mode_2DAkemi(void); mode_2DAkemi(void);
#else #else
uint16_t uint16_t
GEQ_base(bool centered_horizontal, bool centered_vertical, bool color_vertical),
mode_pixels(void), mode_pixels(void),
mode_pixelwave(void), mode_pixelwave(void),
mode_juggles(void), mode_juggles(void),
@ -991,7 +990,6 @@ class WS2812FX {
mode_ripplepeak(void), mode_ripplepeak(void),
mode_2Dfirenoise(void), mode_2Dfirenoise(void),
mode_2Dsquaredswirl(void), mode_2Dsquaredswirl(void),
//mode_2Dfire2012(void),
mode_2Ddna(void), mode_2Ddna(void),
mode_2Dmatrix(void), mode_2Dmatrix(void),
mode_2Dmetaballs(void), mode_2Dmetaballs(void),
@ -1001,7 +999,6 @@ class WS2812FX {
mode_gravfreq(void), mode_gravfreq(void),
mode_DJLight(void), mode_DJLight(void),
mode_2DFunkyPlank(void), mode_2DFunkyPlank(void),
mode_2DCenterBars(void),
mode_2DPulser(void), mode_2DPulser(void),
mode_blurz(void), mode_blurz(void),
mode_2Dgameoflife(void), mode_2Dgameoflife(void),
@ -1047,6 +1044,7 @@ class WS2812FX {
_triggered; _triggered;
uint8_t _modeCount = MODE_COUNT; uint8_t _modeCount = MODE_COUNT;
// TODO: allocate memory using new or malloc()
mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element
const char *_modeData[MODE_COUNT]; // mode (effect) name and its slider control data array const char *_modeData[MODE_COUNT]; // mode (effect) name and its slider control data array

View File

@ -166,7 +166,7 @@ void WS2812FX::service() {
} }
handle_palette(); handle_palette();
delay = (this->*_mode[SEGMENT.mode])(); //effect function delay = (this->*_mode[SEGMENT.mode])(); // effect function (NOTE: may add SEGMENT and SEGENV to parameters)
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++; if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
} }

View File

@ -531,6 +531,16 @@ button {
z-index: -2; z-index: -2;
} }
#info .slider {
max-width: 200px;
min-width: 145px;
float: right;
margin: 0;
}
#info .sliderwrap {
width: 200px;
}
#info table, #nodes table { #info table, #nodes table {
table-layout: fixed; table-layout: fixed;
width: 100%; width: 100%;
@ -1377,7 +1387,7 @@ TD .checkmark, TD .radiomark {
width: 145px; width: 145px;
} }
#info div, #nodes div { #info div, #nodes div {
width: 320px; max-width: 320px;
} }
} }

View File

@ -605,9 +605,23 @@ function parseInfo(i) {
mh = i.leds.matrix ? i.leds.matrix.h : 0; mh = i.leds.matrix ? i.leds.matrix.h : 0;
isM = mw>0 && mh>0; isM = mw>0 && mh>0;
if (!isM) hideModes("2D "); if (!isM) hideModes("2D ");
else gId('buttonSr').classList.add("hide"); // peek does not work in 2D
if (!i.u || !i.u.AudioReactive) { /*hideModes("♪ ");*/ hideModes("♫ "); } // hide /*audio*/ frequency reactive effects if (!i.u || !i.u.AudioReactive) { /*hideModes("♪ ");*/ hideModes("♫ "); } // hide /*audio*/ frequency reactive effects
} }
//https://stackoverflow.com/questions/2592092/executing-script-elements-inserted-with-innerhtml
//var setInnerHTML = function(elm, html) {
// elm.innerHTML = html;
// Array.from(elm.querySelectorAll("script")).forEach( oldScript => {
// const newScript = document.createElement("script");
// Array.from(oldScript.attributes)
// .forEach( attr => newScript.setAttribute(attr.name, attr.value) );
// newScript.appendChild(document.createTextNode(oldScript.innerHTML));
// oldScript.parentNode.replaceChild(newScript, oldScript);
// });
//}
//setInnerHTML(obj, html);
function populateInfo(i) function populateInfo(i)
{ {
var cn=""; var cn="";
@ -645,6 +659,11 @@ ${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i.
${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")} ${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")}
</table>`; </table>`;
gId('kv').innerHTML = cn; gId('kv').innerHTML = cn;
// update all sliders in Info
for (let sd of (gId('kv').getElementsByClassName('sliderdisplay')||[])) {
let s = sd.previousElementSibling;
if (s) updateTrail(s);
}
} }
function populateSegments(s) function populateSegments(s)
@ -1346,15 +1365,16 @@ function setSliderAndColorControl(idx, applyDef=false)
else if (i==1) btn.innerHTML = "Bg"; else if (i==1) btn.innerHTML = "Bg";
else btn.innerHTML = "Cs"; else btn.innerHTML = "Cs";
hide = false; hide = false;
if (!cslCnt) selectSlot(i); // select 1st displayed slot
cslCnt++; cslCnt++;
} else if (!controlDefined /*|| paOnOff.length>0*/) { // if no controls then all buttons should be shown for color 1..3 } else if (!controlDefined /*|| paOnOff.length>0*/) { // if no controls then all buttons should be shown for color 1..3
btn.style.display = "inline"; btn.style.display = "inline";
btn.innerHTML = `${i+1}`; btn.innerHTML = `${i+1}`;
hide = false; hide = false;
if (!cslCnt) selectSlot(i); // select 1st displayed slot
cslCnt++; cslCnt++;
} else { } else {
btn.style.display = "none"; btn.style.display = "none";
if (i>0 && csel==i) selectSlot(0);
} }
} }
gId("cslLabel").innerHTML = cslLabel; gId("cslLabel").innerHTML = cslLabel;

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2206291 #define VERSION 2207031
//uncomment this if you have a "my_config.h" file you'd like to use //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG