Float variables instead of double.

This commit is contained in:
Blaz Kristan 2022-07-03 23:00:32 +02:00
parent ae50374d55
commit 8b58d96aea
9 changed files with 2014 additions and 2138 deletions

View File

@ -31,7 +31,7 @@
constexpr i2s_port_t I2S_PORT = I2S_NUM_0;
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_SAMPLING_LOG
@ -51,18 +51,18 @@ 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"
//
#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 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 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 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 double 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 double 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 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 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 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 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 agcTarget1[AGC_NUM_PRESETS] = { 220, 224, 216}; // second AGC setPoint -> around 85%
const float agcFollowFast[AGC_NUM_PRESETS] = { 1/192.f, 1/128.f, 1/256.f}; // quickly follow setpoint - ~0.15 sec
const float agcFollowSlow[AGC_NUM_PRESETS] = {1/6144.f,1/4096.f,1/8192.f}; // slowly follow setpoint - ~2-15 secs
const float agcControlKp[AGC_NUM_PRESETS] = { 0.6f, 1.5f, 0.65f}; // AGC - PI control, proportional 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)
// AGC presets end
static AudioSource *audioSource = nullptr;
@ -80,13 +80,13 @@ static float multAgc = 1.0f; // sample * multAgc = sampleAgc.
// FFT Variables
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 double FFT_Magnitude = 0;
static float FFT_MajorPeak = 0.0f;
static float FFT_Magnitude = 0.0f;
// These are the input and output vectors. Input vectors receive computed results from FFT.
static double vReal[samplesFFT];
static double vImag[samplesFFT];
static float fftBin[samplesFFT];
static float vReal[samplesFFT];
static float vImag[samplesFFT];
static float fftBin[samplesFFT];
// Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256.
// Oh, and bins 0,1,2 are no good, so we'll zero them out.
@ -97,6 +97,11 @@ static float fftResultMax[16]; // A table used for test
#endif
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.
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 TaskHandle_t FFT_Task;
float fftAdd(int from, int to) {
float fftAddAvg(int from, int to) {
float result = 0.0f;
for (int i = from; i <= to; i++) {
result += fftBin[i];
}
return result;
return result / float(to - from + 1);
}
// FFT main code
@ -120,7 +125,7 @@ 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};
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
for(;;) {
@ -130,8 +135,16 @@ void FFTcode(void * parameter)
// Only run the FFT computing code if we're not in Receive mode
if (audioSyncEnabled & 0x02) continue;
#ifdef WLED_DEBUG
unsigned long start = millis();
#endif
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
//micDataSm = (uint16_t)vReal[samplesFFT - 1]; // will do a this a bit later
//micDataSm = ((micData * 3) + micData)/4;
@ -172,31 +185,31 @@ void FFTcode(void * parameter)
//
#ifdef MAJORPEAK_SUPPRESS_NOISE
// teporarily reduce signal strength in the highest + lowest bins
xtemp[0] = vReal[0]; vReal[0] *= 0.005;
xtemp[1] = vReal[1]; vReal[1] *= 0.005;
xtemp[2] = vReal[2]; vReal[2] *= 0.005;
xtemp[3] = vReal[3]; vReal[3] *= 0.02;
xtemp[4] = vReal[4]; vReal[4] *= 0.02;
xtemp[5] = vReal[5]; vReal[5] *= 0.02;
xtemp[6] = vReal[6]; vReal[6] *= 0.05;
xtemp[7] = vReal[7]; vReal[7] *= 0.08;
xtemp[8] = vReal[8]; vReal[8] *= 0.1;
xtemp[9] = vReal[9]; vReal[9] *= 0.2;
xtemp[10] = vReal[10]; vReal[10] *= 0.2;
xtemp[11] = vReal[11]; vReal[11] *= 0.25;
xtemp[12] = vReal[12]; vReal[12] *= 0.3;
xtemp[13] = vReal[13]; vReal[13] *= 0.3;
xtemp[14] = vReal[14]; vReal[14] *= 0.4;
xtemp[15] = vReal[15]; vReal[15] *= 0.4;
xtemp[16] = vReal[16]; vReal[16] *= 0.4;
xtemp[17] = vReal[17]; vReal[17] *= 0.5;
xtemp[18] = vReal[18]; vReal[18] *= 0.5;
xtemp[19] = vReal[19]; vReal[19] *= 0.6;
xtemp[20] = vReal[20]; vReal[20] *= 0.7;
xtemp[21] = vReal[21]; vReal[21] *= 0.8;
xtemp[0] = vReal[0]; vReal[0] *= 0.005f;
xtemp[1] = vReal[1]; vReal[1] *= 0.005f;
xtemp[2] = vReal[2]; vReal[2] *= 0.005f;
xtemp[3] = vReal[3]; vReal[3] *= 0.02f;
xtemp[4] = vReal[4]; vReal[4] *= 0.02f;
xtemp[5] = vReal[5]; vReal[5] *= 0.02f;
xtemp[6] = vReal[6]; vReal[6] *= 0.05f;
xtemp[7] = vReal[7]; vReal[7] *= 0.08f;
xtemp[8] = vReal[8]; vReal[8] *= 0.1f;
xtemp[9] = vReal[9]; vReal[9] *= 0.2f;
xtemp[10] = vReal[10]; vReal[10] *= 0.2f;
xtemp[11] = vReal[11]; vReal[11] *= 0.25f;
xtemp[12] = vReal[12]; vReal[12] *= 0.3f;
xtemp[13] = vReal[13]; vReal[13] *= 0.3f;
xtemp[14] = vReal[14]; vReal[14] *= 0.4f;
xtemp[15] = vReal[15]; vReal[15] *= 0.4f;
xtemp[16] = vReal[16]; vReal[16] *= 0.4f;
xtemp[17] = vReal[17]; vReal[17] *= 0.5f;
xtemp[18] = vReal[18]; vReal[18] *= 0.5f;
xtemp[19] = vReal[19]; vReal[19] *= 0.6f;
xtemp[20] = vReal[20]; vReal[20] *= 0.7f;
xtemp[21] = vReal[21]; vReal[21] *= 0.8f;
xtemp[22] = vReal[samplesFFT-2]; vReal[samplesFFT-2] =0.0;
xtemp[23] = vReal[samplesFFT-1]; vReal[samplesFFT-1] =0.0;
xtemp[22] = vReal[samplesFFT-2]; vReal[samplesFFT-2] = 0.0f;
xtemp[23] = vReal[samplesFFT-1]; vReal[samplesFFT-1] = 0.0f;
#endif
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.
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()
@ -247,23 +260,23 @@ void FFTcode(void * parameter)
* Multiplier = (End frequency/ Start frequency) ^ 1/16
* Multiplier = 1.320367784
*/
// Range
fftCalc[0] = (fftAdd(3,4)) /2; // 60 - 100
fftCalc[1] = (fftAdd(4,5)) /2; // 80 - 120
fftCalc[2] = (fftAdd(5,7)) /3; // 100 - 160
fftCalc[3] = (fftAdd(7,9)) /3; // 140 - 200
fftCalc[4] = (fftAdd(9,12)) /4; // 180 - 260
fftCalc[5] = (fftAdd(12,16)) /5; // 240 - 340
fftCalc[6] = (fftAdd(16,21)) /6; // 320 - 440
fftCalc[7] = (fftAdd(21,28)) /8; // 420 - 600
fftCalc[8] = (fftAdd(29,37)) /10; // 580 - 760
fftCalc[9] = (fftAdd(37,48)) /12; // 740 - 980
fftCalc[10] = (fftAdd(48,64)) /17; // 960 - 1300
fftCalc[11] = (fftAdd(64,84)) /21; // 1280 - 1700
fftCalc[12] = (fftAdd(84,111)) /28; // 1680 - 2240
fftCalc[13] = (fftAdd(111,147)) /37; // 2220 - 2960
fftCalc[14] = (fftAdd(147,194)) /48; // 2940 - 3900
fftCalc[15] = (fftAdd(194, 255)) /62; // 3880 - 5120
// Range
fftCalc[ 0] = fftAddAvg(3,4); // 60 - 100
fftCalc[ 1] = fftAddAvg(4,5); // 80 - 120
fftCalc[ 2] = fftAddAvg(5,7); // 100 - 160
fftCalc[ 3] = fftAddAvg(7,9); // 140 - 200
fftCalc[ 4] = fftAddAvg(9,12); // 180 - 260
fftCalc[ 5] = fftAddAvg(12,16); // 240 - 340
fftCalc[ 6] = fftAddAvg(16,21); // 320 - 440
fftCalc[ 7] = fftAddAvg(21,28); // 420 - 600
fftCalc[ 8] = fftAddAvg(29,37); // 580 - 760
fftCalc[ 9] = fftAddAvg(37,48); // 740 - 980
fftCalc[10] = fftAddAvg(48,64); // 960 - 1300
fftCalc[11] = fftAddAvg(64,84); // 1280 - 1700
fftCalc[12] = fftAddAvg(84,111); // 1680 - 2240
fftCalc[13] = fftAddAvg(111,147); // 2220 - 2960
fftCalc[14] = fftAddAvg(147,194); // 2940 - 3900
fftCalc[15] = fftAddAvg(194,255); // 3880 - 5120
for (int i=0; i < 16; i++) {
// Noise supression of fftCalc bins using soundSquelch adjustment for different input types.
@ -283,10 +296,14 @@ void FFTcode(void * parameter)
micDataSm = (uint16_t)maxSample2;
micDataReal = maxSample2;
#ifdef WLED_DEBUG
fftTime = ((millis() - start)*3 + fftTime*7)/10;
#endif
#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;
fftResultMax[i] = ((fftResultMax[i] * 63.0f) + fftResult[i]) / 64.0f;
DEBUGSR_PRINT(fftResultMax[i]*fftResultPink[i]); DEBUGSR_PRINT("\t");
}
DEBUGSR_PRINTLN();
@ -397,6 +414,7 @@ class AudioReactive : public Usermod {
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _inputLvl[];
static const char _analogmic[];
static const char _digitalmic[];
static const char UDP_SYNC_HEADER[];
@ -563,16 +581,16 @@ class AudioReactive : public Usermod {
// NOW finally amplify the 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);
if (tmpAgc > 255) tmpAgc = 255; // limit to 8bit
if (tmpAgc < 1) tmpAgc = 0; // just to be sure
if (tmpAgc > 255) tmpAgc = 255.0f; // limit to 8bit
if (tmpAgc < 1) tmpAgc = 0.0f; // just to be sure
// update global vars ONCE - multAgc, sampleAGC, rawSampleAgc
multAgc = multAgcTemp;
rawSampleAgc = 0.8f * tmpAgc + 0.2f * (float)rawSampleAgc;
// 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
else
sampleAgc += agcSampleSmooth[AGC_preset] * (tmpAgc - sampleAgc); // smooth path
@ -613,14 +631,14 @@ class AudioReactive : public Usermod {
expAdjF = (weighting * micInNoDC + (1.0-weighting) * expAdjF);
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;
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 = tmpSample;
@ -647,8 +665,8 @@ class AudioReactive : public Usermod {
uint16_t MinShowDelay = strip.getMinShowDelay();
if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed.
samplePeak = 0;
udpSamplePeak = 0;
samplePeak = false;
udpSamplePeak = false;
}
//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 (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.
samplePeak = 1;
samplePeak = true;
timeOfPeak = millis();
udpSamplePeak = 1;
udpSamplePeak = true;
//userVar1 = samplePeak;
}
} // getSample()
@ -776,9 +794,9 @@ class AudioReactive : public Usermod {
um_data->u_data[ 5] = &samplePeak; //*used (Puddlepeak, Ripplepeak, Waterfall)
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_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_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_type[ 8] = UMT_BYTE_ARR;
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)
{
#ifdef WLED_DEBUG
fftTime = sampleTime = 0;
#endif
if (init) vTaskDelete(FFT_Task); // update is about to begin, remove task to prevent crash
else { // update has failed or create task requested
// Define the FFT Task and lock it to core 0
@ -1021,6 +1042,25 @@ class AudioReactive : public Usermod {
uiDomString += F("\">&#xe08f;</i>");
uiDomString += F("</button>");
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>();
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)
const char AudioReactive::_name[] PROGMEM = "AudioReactive";
const char AudioReactive::_enabled[] PROGMEM = "enabled";
const char AudioReactive::_inputLvl[] PROGMEM = "inputLevel";
const char AudioReactive::_analogmic[] PROGMEM = "analogmic";
const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic";
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
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 */
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);
}
virtual void getSamples(double *buffer, uint16_t num_samples) {
virtual void getSamples(float *buffer, uint16_t num_samples) {
if (_initialized) {
esp_err_t err;
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)
newSamples[i] >>= 16;
#endif
double currSample = 0.0;
float currSample = 0.0f;
if(_shift > 0)
currSample = (double) (newSamples[i] >> _shift);
currSample = (float) (newSamples[i] >> _shift);
else {
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
#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
currSample = (double) newSamples[i];
currSample = (float) newSamples[i];
#endif
}
buffer[i] = currSample;
@ -356,7 +356,7 @@ class I2SAdcSource : public I2SSource {
_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
* after sampling, otherwise Wifi dies
*/

View File

@ -1,10 +1,36 @@
# Usermods API v2 example usermod
# Audioreactive usermod
In this usermod file you can find the documentation on how to take advantage of the new version 2 usermods!
This usermod allows controlling LEDs using audio input. Audio input can be either microphone or analog-in (AUX) using appropriate adapter.
Supported microphones range from analog (MAX4466, MAX9814, ...) to digital (INMP441, ICS-43434, ...).
The usermod does audio processing and provides data structure that specially written effect can use.
The usermod **does not** provide effects or draws anything to LED strip/matrix.
## Installation
Copy `usermod_v2_example.h` to the wled00 directory.
Uncomment the corresponding lines in `usermods_list.cpp` and compile!
_(You shouldn't need to actually install this, it does nothing useful)_
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.
Customised _arduinoFFT_ library for use with this usermod can be found at https://github.com/blazoncek/arduinoFFT.git
## Configuration
All parameters are runtime configurable though some may require hard boot after change (I2S microphone or selected GPIOs).
If you want to define default GPIOs during compile time use the following (default values in parentheses):
- `DMTYPE=x` : defines digital microphone type: 0=analog, 1=generic I2S, 2=ES7243 I2S, 3=SPH0645 I2S, 4=generic I2S with master clock, 5=PDM I2S
- `AUDIOPIN=x` : GPIO for analog microphone/AUX-in (36)
- `I2S_SDPIN=x` : GPIO for SD pin on digital mcrophone (32)
- `I2S_WSPIN=x` : GPIO for WS pin on digital mcrophone (15)
- `I2S_CKPIN=x` : GPIO for SCK pin on digital mcrophone (14)
- `ES7243_SDAPIN` : GPIO for I2C SDA pin on ES7243 microphone (-1)
- `ES7243_SCLPIN` : GPIO for I2C SCL pin on ES7243 microphone (-1)
- `MCLK_PIN=x` : GPIO for master clock pin on digital mcrophone (-1)
**NOTE** Due to the fact that usermod uses I2S peripherial for analog audio sampling, use of analog *buttons* (i.e. potentiometers) is disabled while running this usermod with analog microphone.
## Release notes
2022-06 Ported from [soundreactive](https://github.com/atuline/WLED) by @blazoncek (AKA Blaz Kristan)

View File

@ -3257,7 +3257,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
Spark* sparks = reinterpret_cast<Spark*>(SEGENV.data);
Spark* flare = sparks; //first spark is flare data
float gravity = -0.0004 - (SEGMENT.speed/800000.0); // m/s/s
float gravity = -0.0004f - (SEGMENT.speed/800000.0f); // m/s/s
gravity *= rows;
if (SEGENV.aux0 < 2) { //FLARE
@ -3266,7 +3266,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
flare->posX = isMatrix ? random16(2,cols-1) : (SEGMENT.intensity > random8()); // will enable random firing side on 1D
uint16_t peakHeight = 75 + random8(180); //0-255
peakHeight = (peakHeight * (rows -1)) >> 8;
flare->vel = sqrt(-2.0 * gravity * peakHeight);
flare->vel = sqrt(-2.0f * gravity * peakHeight);
flare->velX = isMatrix ? (random8(8)-4)/32.f : 0; // no X velocity on 1D
flare->col = 255; //brightness
SEGENV.aux0 = 1;
@ -3275,7 +3275,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
// launch
if (flare->vel > 12 * gravity) {
// flare
if (isMatrix) setPixelColorXY(flare->posX, rows - uint16_t(flare->pos) - 1, flare->col, flare->col, flare->col);
if (isMatrix) setPixelColorXY(int(flare->posX), rows - uint16_t(flare->pos) - 1, flare->col, flare->col, flare->col);
else setPixelColor(int(flare->posX) ? rows - int(flare->pos) - 1 : int(flare->pos), flare->col, flare->col, flare->col);
flare->pos += flare->vel;
flare->posX += flare->velX;
@ -3302,7 +3302,7 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
sparks[i].pos = flare->pos;
sparks[i].posX = flare->posX;
sparks[i].vel = (float(random16(0, 20000)) / 10000.0f) - 0.9f; // from -0.9 to 1.1
sparks[i].vel *= rows<32 ? 0.5 : 1; // reduce velocity for smaller strips
sparks[i].vel *= rows<32 ? 0.5f : 1; // reduce velocity for smaller strips
sparks[i].velX = isMatrix ? (float(random16(0, 4000)) / 10000.0f) - 0.2f : 0; // from -0.2 to 0.2
sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright
//sparks[i].col = constrain(sparks[i].col, 0, 345);
@ -3337,12 +3337,12 @@ uint16_t WS2812FX::mode_exploding_fireworks(void)
c.g = qsub8(c.g, cooling);
c.b = qsub8(c.b, cooling * 2);
}
if (isMatrix) setPixelColorXY(sparks[i].posX, rows - int(sparks[i].pos) - 1, c.red, c.green, c.blue);
if (isMatrix) setPixelColorXY(int(sparks[i].posX), rows - int(sparks[i].pos) - 1, c.red, c.green, c.blue);
else setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c.red, c.green, c.blue);
}
}
blur(16);
*dying_gravity *= .8; // as sparks burn out they fall slower
*dying_gravity *= .8f; // as sparks burn out they fall slower
} else {
SEGENV.aux0 = 6 + random8(10); //wait for this many frames
}
@ -5947,7 +5947,7 @@ static const char *_data_FX_MODE_DRIFT_ROSE PROGMEM = "2D Drift Rose@Fade,Blur;;
uint8_t soundAgc = 0, soundSquelch = 10;
bool samplePeak = false;
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;
uint16_t *myVals = 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];
rawSampleAgc = *(uint16_t*)um_data->u_data[ 4];
samplePeak = *(uint8_t*) um_data->u_data[ 5];
FFT_MajorPeak = *(double*) um_data->u_data[ 6];
FFT_Magnitude = *(double*) um_data->u_data[ 7];
FFT_MajorPeak = *(float*) um_data->u_data[ 6];
FFT_Magnitude = *(float*) um_data->u_data[ 7];
fftResult = (uint8_t*) um_data->u_data[ 8];
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
@ -5998,10 +5998,10 @@ uint16_t WS2812FX::mode_ripplepeak(void) { // * Ripple peak. By A
uint8_t *binNum, *maxVol; // just in case assignment
uint8_t samplePeak = 0; // actually a bool
double FFT_MajorPeak = 0.0;
float FFT_MajorPeak = 0.0;
um_data_t *um_data;
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];
maxVol = (uint8_t*)um_data->u_data[9];
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.
if (endBin > startBin) endBin --; // avoid overlapping
double sumBin = 0;
float sumBin = 0;
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
@ -6988,15 +6988,15 @@ uint16_t WS2812FX::mode_freqmap(void) { // Map FFT_MajorPeak t
// Start frequency = 60 Hz and log10(60) = 1.78
// End frequency = 5120 Hz and lo10(5120) = 3.71
double FFT_MajorPeak = 0.0;
double FFT_Magnitude = 0.0;
float FFT_MajorPeak = 0.0;
float FFT_Magnitude = 0.0;
uint8_t soundAgc = 0;
float sampleAvg = 0.0f;
float multAgc = 0.0f;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[6];
FFT_Magnitude = *(double*)um_data->u_data[7];
FFT_MajorPeak = *(float*)um_data->u_data[6];
FFT_Magnitude = *(float*)um_data->u_data[7];
sampleAvg = *(float*)um_data->u_data[0];
soundAgc = *(uint8_t*)um_data->u_data[1];
multAgc = *(float*)um_data->u_data[11];
@ -7027,11 +7027,11 @@ static const char *_data_FX_MODE_FREQMAP PROGMEM = " ♫ Freqmap@Fade rate,Start
// ** Freqmatrix //
///////////////////////
uint16_t WS2812FX::mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung.
double FFT_MajorPeak = 0.0;
float FFT_MajorPeak = 0.0;
float sampleAgc = 0.0f;
um_data_t *um_data;
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];
} else {
// 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.intensity select colour index
uint16_t WS2812FX::mode_freqpixels(void) { // Freqpixel. By Andrew Tuline.
double FFT_MajorPeak = 0.0;
double FFT_Magnitude = 0.0;
float FFT_MajorPeak = 0.0;
float FFT_Magnitude = 0.0;
uint8_t soundAgc = 0;
float sampleAvg = 0.0f;
float multAgc = 0.0f;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[6];
FFT_Magnitude = *(double*)um_data->u_data[7];
FFT_MajorPeak = *(float*)um_data->u_data[6];
FFT_Magnitude = *(float*)um_data->u_data[7];
sampleAvg = *(float*)um_data->u_data[0];
soundAgc = *(uint8_t*)um_data->u_data[1];
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.
// 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.
double FFT_MajorPeak = 0.0;
float FFT_MajorPeak = 0.0;
uint8_t soundAgc = 0;
float sampleAgc = 0.0f, sampleAvg = 0.0f;
um_data_t *um_data;
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];
soundAgc = *(uint8_t*)um_data->u_data[1];
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;
uint8_t soundAgc = 0;
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)) {
FFT_MajorPeak = *(double*)um_data->u_data[6];
FFT_MajorPeak = *(float*)um_data->u_data[6];
soundAgc = *(uint8_t*)um_data->u_data[1];
sampleAgc = *(float*)um_data->u_data[2];
sampleAvg = *(float*)um_data->u_data[0];
@ -7279,15 +7279,15 @@ static const char *_data_FX_MODE_NOISEMOVE PROGMEM = " ♫ Noisemove@Speed of pe
// ** Rocktaves //
//////////////////////
uint16_t WS2812FX::mode_rocktaves(void) { // Rocktaves. Same note from each octave is same colour. By: Andrew Tuline
double FFT_MajorPeak = 0.0;
double FFT_Magnitude = 0.0;
float FFT_MajorPeak = 0.0;
float FFT_Magnitude = 0.0;
uint8_t soundAgc = 0;
float sampleAvg = 0.0f;
float multAgc = 0.0f;
um_data_t *um_data;
if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
FFT_MajorPeak = *(double*)um_data->u_data[6];
FFT_Magnitude = *(double*)um_data->u_data[7];
FFT_MajorPeak = *(float*)um_data->u_data[6];
FFT_Magnitude = *(float*)um_data->u_data[7];
sampleAvg = *(float*)um_data->u_data[0];
soundAgc = *(uint8_t*)um_data->u_data[1];
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 samplePeak = 0;
double FFT_MajorPeak = 0.0;
double FFT_Magnitude = 0.0;
float FFT_MajorPeak = 0.0;
float FFT_Magnitude = 0.0;
uint8_t soundAgc = 0;
float sampleAvg = 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];
samplePeak = *(uint8_t*)um_data->u_data[5];
binNum = (uint8_t*)um_data->u_data[10];
FFT_MajorPeak = *(double*)um_data->u_data[6];
FFT_Magnitude = *(double*)um_data->u_data[7];
FFT_MajorPeak = *(float*)um_data->u_data[6];
FFT_Magnitude = *(float*)um_data->u_data[7];
sampleAvg = *(float*)um_data->u_data[0];
soundAgc = *(uint8_t*)um_data->u_data[1];
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";
/////////////////////////
// ** 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 //
/////////////////////////
@ -7834,7 +7824,7 @@ void WS2812FX::setupEffectData() {
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_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_BLURZ, &WS2812FX::mode_blurz, _data_FX_MODE_BLURZ);
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_DJLIGHT 159
#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_BLURZ 163
#define FX_MODE_2DDRIFT 164 // non audio
@ -605,221 +605,6 @@ class WS2812FX {
WS2812FX() {
WS2812FX::instance = this;
setupEffectData();
/*
//assign each member of the _mode[] array to its respective function reference
_mode[FX_MODE_STATIC] = &WS2812FX::mode_static;
_mode[FX_MODE_BLINK] = &WS2812FX::mode_blink;
_mode[FX_MODE_COLOR_WIPE] = &WS2812FX::mode_color_wipe;
_mode[FX_MODE_COLOR_WIPE_RANDOM] = &WS2812FX::mode_color_wipe_random;
_mode[FX_MODE_RANDOM_COLOR] = &WS2812FX::mode_random_color;
_mode[FX_MODE_COLOR_SWEEP] = &WS2812FX::mode_color_sweep;
_mode[FX_MODE_DYNAMIC] = &WS2812FX::mode_dynamic;
_mode[FX_MODE_RAINBOW] = &WS2812FX::mode_rainbow;
_mode[FX_MODE_RAINBOW_CYCLE] = &WS2812FX::mode_rainbow_cycle;
_mode[FX_MODE_SCAN] = &WS2812FX::mode_scan;
_mode[FX_MODE_DUAL_SCAN] = &WS2812FX::mode_dual_scan;
_mode[FX_MODE_FADE] = &WS2812FX::mode_fade;
_mode[FX_MODE_THEATER_CHASE] = &WS2812FX::mode_theater_chase;
_mode[FX_MODE_THEATER_CHASE_RAINBOW] = &WS2812FX::mode_theater_chase_rainbow;
_mode[FX_MODE_SAW] = &WS2812FX::mode_saw;
_mode[FX_MODE_TWINKLE] = &WS2812FX::mode_twinkle;
_mode[FX_MODE_DISSOLVE] = &WS2812FX::mode_dissolve;
_mode[FX_MODE_DISSOLVE_RANDOM] = &WS2812FX::mode_dissolve_random;
_mode[FX_MODE_SPARKLE] = &WS2812FX::mode_sparkle;
_mode[FX_MODE_FLASH_SPARKLE] = &WS2812FX::mode_flash_sparkle;
_mode[FX_MODE_HYPER_SPARKLE] = &WS2812FX::mode_hyper_sparkle;
_mode[FX_MODE_STROBE] = &WS2812FX::mode_strobe;
_mode[FX_MODE_STROBE_RAINBOW] = &WS2812FX::mode_strobe_rainbow;
_mode[FX_MODE_MULTI_STROBE] = &WS2812FX::mode_multi_strobe;
_mode[FX_MODE_BLINK_RAINBOW] = &WS2812FX::mode_blink_rainbow;
_mode[FX_MODE_ANDROID] = &WS2812FX::mode_android;
_mode[FX_MODE_CHASE_COLOR] = &WS2812FX::mode_chase_color;
_mode[FX_MODE_CHASE_RANDOM] = &WS2812FX::mode_chase_random;
_mode[FX_MODE_CHASE_RAINBOW] = &WS2812FX::mode_chase_rainbow;
_mode[FX_MODE_CHASE_FLASH] = &WS2812FX::mode_chase_flash;
_mode[FX_MODE_CHASE_FLASH_RANDOM] = &WS2812FX::mode_chase_flash_random;
_mode[FX_MODE_CHASE_RAINBOW_WHITE] = &WS2812FX::mode_chase_rainbow_white;
_mode[FX_MODE_COLORFUL] = &WS2812FX::mode_colorful;
_mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light;
_mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random;
_mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color;
_mode[FX_MODE_AURORA] = &WS2812FX::mode_aurora;
_mode[FX_MODE_RUNNING_RANDOM] = &WS2812FX::mode_running_random;
_mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner;
_mode[FX_MODE_COMET] = &WS2812FX::mode_comet;
_mode[FX_MODE_FIREWORKS] = &WS2812FX::mode_fireworks;
_mode[FX_MODE_RAIN] = &WS2812FX::mode_rain;
_mode[FX_MODE_TETRIX] = &WS2812FX::mode_tetrix;
_mode[FX_MODE_FIRE_FLICKER] = &WS2812FX::mode_fire_flicker;
_mode[FX_MODE_GRADIENT] = &WS2812FX::mode_gradient;
_mode[FX_MODE_LOADING] = &WS2812FX::mode_loading;
_mode[FX_MODE_POLICE] = &WS2812FX::mode_police;
_mode[FX_MODE_FAIRY] = &WS2812FX::mode_fairy;
_mode[FX_MODE_TWO_DOTS] = &WS2812FX::mode_two_dots;
_mode[FX_MODE_FAIRYTWINKLE] = &WS2812FX::mode_fairytwinkle;
_mode[FX_MODE_RUNNING_DUAL] = &WS2812FX::mode_running_dual;
_mode[FX_MODE_HALLOWEEN] = &WS2812FX::mode_halloween;
_mode[FX_MODE_TRICOLOR_CHASE] = &WS2812FX::mode_tricolor_chase;
_mode[FX_MODE_TRICOLOR_WIPE] = &WS2812FX::mode_tricolor_wipe;
_mode[FX_MODE_TRICOLOR_FADE] = &WS2812FX::mode_tricolor_fade;
_mode[FX_MODE_BREATH] = &WS2812FX::mode_breath;
_mode[FX_MODE_RUNNING_LIGHTS] = &WS2812FX::mode_running_lights;
_mode[FX_MODE_LIGHTNING] = &WS2812FX::mode_lightning;
_mode[FX_MODE_ICU] = &WS2812FX::mode_icu;
_mode[FX_MODE_MULTI_COMET] = &WS2812FX::mode_multi_comet;
_mode[FX_MODE_DUAL_LARSON_SCANNER] = &WS2812FX::mode_dual_larson_scanner;
_mode[FX_MODE_RANDOM_CHASE] = &WS2812FX::mode_random_chase;
_mode[FX_MODE_OSCILLATE] = &WS2812FX::mode_oscillate;
_mode[FX_MODE_FIRE_2012] = &WS2812FX::mode_fire_2012;
_mode[FX_MODE_PRIDE_2015] = &WS2812FX::mode_pride_2015;
_mode[FX_MODE_BPM] = &WS2812FX::mode_bpm;
_mode[FX_MODE_JUGGLE] = &WS2812FX::mode_juggle;
_mode[FX_MODE_PALETTE] = &WS2812FX::mode_palette;
_mode[FX_MODE_COLORWAVES] = &WS2812FX::mode_colorwaves;
_mode[FX_MODE_FILLNOISE8] = &WS2812FX::mode_fillnoise8;
_mode[FX_MODE_NOISE16_1] = &WS2812FX::mode_noise16_1;
_mode[FX_MODE_NOISE16_2] = &WS2812FX::mode_noise16_2;
_mode[FX_MODE_NOISE16_3] = &WS2812FX::mode_noise16_3;
_mode[FX_MODE_NOISE16_4] = &WS2812FX::mode_noise16_4;
_mode[FX_MODE_COLORTWINKLE] = &WS2812FX::mode_colortwinkle;
_mode[FX_MODE_LAKE] = &WS2812FX::mode_lake;
_mode[FX_MODE_METEOR] = &WS2812FX::mode_meteor;
_mode[FX_MODE_METEOR_SMOOTH] = &WS2812FX::mode_meteor_smooth;
_mode[FX_MODE_RAILWAY] = &WS2812FX::mode_railway;
_mode[FX_MODE_RIPPLE] = &WS2812FX::mode_ripple;
_mode[FX_MODE_TWINKLEFOX] = &WS2812FX::mode_twinklefox;
_mode[FX_MODE_TWINKLECAT] = &WS2812FX::mode_twinklecat;
_mode[FX_MODE_HALLOWEEN_EYES] = &WS2812FX::mode_halloween_eyes;
_mode[FX_MODE_STATIC_PATTERN] = &WS2812FX::mode_static_pattern;
_mode[FX_MODE_TRI_STATIC_PATTERN] = &WS2812FX::mode_tri_static_pattern;
_mode[FX_MODE_SPOTS] = &WS2812FX::mode_spots;
_mode[FX_MODE_SPOTS_FADE] = &WS2812FX::mode_spots_fade;
_mode[FX_MODE_GLITTER] = &WS2812FX::mode_glitter;
_mode[FX_MODE_CANDLE] = &WS2812FX::mode_candle;
_mode[FX_MODE_STARBURST] = &WS2812FX::mode_starburst;
_mode[FX_MODE_EXPLODING_FIREWORKS] = &WS2812FX::mode_exploding_fireworks;
_mode[FX_MODE_BOUNCINGBALLS] = &WS2812FX::mode_bouncing_balls;
_mode[FX_MODE_SINELON] = &WS2812FX::mode_sinelon;
_mode[FX_MODE_SINELON_DUAL] = &WS2812FX::mode_sinelon_dual;
_mode[FX_MODE_SINELON_RAINBOW] = &WS2812FX::mode_sinelon_rainbow;
_mode[FX_MODE_POPCORN] = &WS2812FX::mode_popcorn;
_mode[FX_MODE_DRIP] = &WS2812FX::mode_drip;
_mode[FX_MODE_PLASMA] = &WS2812FX::mode_plasma;
_mode[FX_MODE_PERCENT] = &WS2812FX::mode_percent;
_mode[FX_MODE_RIPPLE_RAINBOW] = &WS2812FX::mode_ripple_rainbow;
_mode[FX_MODE_HEARTBEAT] = &WS2812FX::mode_heartbeat;
_mode[FX_MODE_PACIFICA] = &WS2812FX::mode_pacifica;
_mode[FX_MODE_CANDLE_MULTI] = &WS2812FX::mode_candle_multi;
_mode[FX_MODE_SOLID_GLITTER] = &WS2812FX::mode_solid_glitter;
_mode[FX_MODE_SUNRISE] = &WS2812FX::mode_sunrise;
_mode[FX_MODE_PHASED] = &WS2812FX::mode_phased;
_mode[FX_MODE_TWINKLEUP] = &WS2812FX::mode_twinkleup;
_mode[FX_MODE_NOISEPAL] = &WS2812FX::mode_noisepal;
_mode[FX_MODE_SINEWAVE] = &WS2812FX::mode_sinewave;
_mode[FX_MODE_PHASEDNOISE] = &WS2812FX::mode_phased_noise;
_mode[FX_MODE_FLOW] = &WS2812FX::mode_flow;
_mode[FX_MODE_CHUNCHUN] = &WS2812FX::mode_chunchun;
_mode[FX_MODE_DANCING_SHADOWS] = &WS2812FX::mode_dancing_shadows;
_mode[FX_MODE_WASHING_MACHINE] = &WS2812FX::mode_washing_machine;
_mode[FX_MODE_CANDY_CANE] = &WS2812FX::mode_candy_cane;
_mode[FX_MODE_BLENDS] = &WS2812FX::mode_blends;
_mode[FX_MODE_TV_SIMULATOR] = &WS2812FX::mode_tv_simulator;
_mode[FX_MODE_DYNAMIC_SMOOTH] = &WS2812FX::mode_dynamic_smooth;
_mode[FX_MODE_SPACESHIPS] = &WS2812FX::mode_2Dspaceships;
_mode[FX_MODE_CRAZYBEES] = &WS2812FX::mode_2Dcrazybees;
_mode[FX_MODE_GHOST_RIDER] = &WS2812FX::mode_2Dghostrider;
_mode[FX_MODE_BLOBS] = &WS2812FX::mode_2Dfloatingblobs;
_mode[FX_MODE_SCROLL_TEXT] = &WS2812FX::mode_2Dscrollingtext;
_mode[FX_MODE_DRIFT_ROSE] = &WS2812FX::mode_2Ddriftrose;
#ifndef USERMOD_AUDIOREACTIVE
_mode[FX_MODE_PERLINMOVE] = &WS2812FX::mode_perlinmove;
_mode[FX_MODE_FLOWSTRIPE] = &WS2812FX::mode_FlowStripe;
_mode[FX_MODE_WAVESINS] = &WS2812FX::mode_wavesins;
_mode[FX_MODE_2DJULIA] = &WS2812FX::mode_2DJulia;
_mode[FX_MODE_2DGAMEOFLIFE] = &WS2812FX::mode_2Dgameoflife;
_mode[FX_MODE_2DNOISE] = &WS2812FX::mode_2Dnoise;
_mode[FX_MODE_2DFIRENOISE] = &WS2812FX::mode_2Dfirenoise;
_mode[FX_MODE_2DSQUAREDSWIRL] = &WS2812FX::mode_2Dsquaredswirl;
_mode[FX_MODE_2DDNA] = &WS2812FX::mode_2Ddna;
_mode[FX_MODE_2DMATRIX] = &WS2812FX::mode_2Dmatrix;
_mode[FX_MODE_2DMETABALLS] = &WS2812FX::mode_2Dmetaballs;
_mode[FX_MODE_2DPULSER] = &WS2812FX::mode_2DPulser;
_mode[FX_MODE_2DSUNRADIATION] = &WS2812FX::mode_2DSunradiation;
_mode[FX_MODE_2DWAVERLY] = &WS2812FX::mode_2DWaverly;
_mode[FX_MODE_2DDRIFT] = &WS2812FX::mode_2DDrift;
_mode[FX_MODE_2DCOLOREDBURSTS] = &WS2812FX::mode_2DColoredBursts;
_mode[FX_MODE_2DTARTAN] = &WS2812FX::mode_2Dtartan;
_mode[FX_MODE_2DPOLARLIGHTS] = &WS2812FX::mode_2DPolarLights;
_mode[FX_MODE_2DSWIRL] = &WS2812FX::mode_2DSwirl;
_mode[FX_MODE_2DLISSAJOUS] = &WS2812FX::mode_2DLissajous;
_mode[FX_MODE_2DFRIZZLES] = &WS2812FX::mode_2DFrizzles;
_mode[FX_MODE_2DPLASMABALL] = &WS2812FX::mode_2DPlasmaball;
_mode[FX_MODE_2DHIPHOTIC] = &WS2812FX::mode_2DHiphotic;
_mode[FX_MODE_2DSINDOTS] = &WS2812FX::mode_2DSindots;
_mode[FX_MODE_2DDNASPIRAL] = &WS2812FX::mode_2DDNASpiral;
_mode[FX_MODE_2DBLACKHOLE] = &WS2812FX::mode_2DBlackHole;
_mode[FX_MODE_2DAKEMI] = &WS2812FX::mode_2DAkemi;
#else
// WLED-SR
_mode[FX_MODE_2DJULIA] = &WS2812FX::mode_2DJulia;
_mode[FX_MODE_2DGAMEOFLIFE] = &WS2812FX::mode_2Dgameoflife;
_mode[FX_MODE_PIXELS] = &WS2812FX::mode_pixels;
_mode[FX_MODE_PIXELWAVE] = &WS2812FX::mode_pixelwave;
_mode[FX_MODE_JUGGLES] = &WS2812FX::mode_juggles;
_mode[FX_MODE_MATRIPIX] = &WS2812FX::mode_matripix;
_mode[FX_MODE_GRAVIMETER] = &WS2812FX::mode_gravimeter;
_mode[FX_MODE_PLASMOID] = &WS2812FX::mode_plasmoid;
_mode[FX_MODE_PUDDLES] = &WS2812FX::mode_puddles;
_mode[FX_MODE_MIDNOISE] = &WS2812FX::mode_midnoise;
_mode[FX_MODE_NOISEMETER] = &WS2812FX::mode_noisemeter;
_mode[FX_MODE_FREQWAVE] = &WS2812FX::mode_freqwave;
_mode[FX_MODE_FREQMATRIX] = &WS2812FX::mode_freqmatrix;
_mode[FX_MODE_2DGEQ] = &WS2812FX::mode_2DGEQ;
_mode[FX_MODE_WATERFALL] = &WS2812FX::mode_waterfall;
_mode[FX_MODE_FREQPIXELS] = &WS2812FX::mode_freqpixels;
_mode[FX_MODE_BINMAP] = &WS2812FX::mode_binmap;
_mode[FX_MODE_NOISEFIRE] = &WS2812FX::mode_noisefire;
_mode[FX_MODE_PUDDLEPEAK] = &WS2812FX::mode_puddlepeak;
_mode[FX_MODE_NOISEMOVE] = &WS2812FX::mode_noisemove;
_mode[FX_MODE_2DNOISE] = &WS2812FX::mode_2Dnoise;
_mode[FX_MODE_PERLINMOVE] = &WS2812FX::mode_perlinmove;
_mode[FX_MODE_RIPPLEPEAK] = &WS2812FX::mode_ripplepeak;
_mode[FX_MODE_2DFIRENOISE] = &WS2812FX::mode_2Dfirenoise;
_mode[FX_MODE_2DSQUAREDSWIRL] = &WS2812FX::mode_2Dsquaredswirl;
//_mode[FX_MODE_2DFIRE2012] = &WS2812FX::mode_2Dfire2012;
_mode[FX_MODE_2DDNA] = &WS2812FX::mode_2Ddna;
_mode[FX_MODE_2DMATRIX] = &WS2812FX::mode_2Dmatrix;
_mode[FX_MODE_2DMETABALLS] = &WS2812FX::mode_2Dmetaballs;
_mode[FX_MODE_FREQMAP] = &WS2812FX::mode_freqmap;
_mode[FX_MODE_GRAVCENTER] = &WS2812FX::mode_gravcenter;
_mode[FX_MODE_GRAVCENTRIC] = &WS2812FX::mode_gravcentric;
_mode[FX_MODE_GRAVFREQ] = &WS2812FX::mode_gravfreq;
_mode[FX_MODE_DJLIGHT] = &WS2812FX::mode_DJLight;
_mode[FX_MODE_2DFUNKYPLANK] = &WS2812FX::mode_2DFunkyPlank;
_mode[FX_MODE_2DCENTERBARS] = &WS2812FX::mode_2DCenterBars;
_mode[FX_MODE_2DPULSER] = &WS2812FX::mode_2DPulser;
_mode[FX_MODE_BLURZ] = &WS2812FX::mode_blurz;
_mode[FX_MODE_2DSUNRADIATION] = &WS2812FX::mode_2DSunradiation;
_mode[FX_MODE_2DWAVERLY] = &WS2812FX::mode_2DWaverly;
_mode[FX_MODE_2DDRIFT] = &WS2812FX::mode_2DDrift;
_mode[FX_MODE_2DCOLOREDBURSTS] = &WS2812FX::mode_2DColoredBursts;
_mode[FX_MODE_2DTARTAN] = &WS2812FX::mode_2Dtartan;
_mode[FX_MODE_2DPOLARLIGHTS] = &WS2812FX::mode_2DPolarLights;
_mode[FX_MODE_2DSWIRL] = &WS2812FX::mode_2DSwirl;
_mode[FX_MODE_2DLISSAJOUS] = &WS2812FX::mode_2DLissajous;
_mode[FX_MODE_2DFRIZZLES] = &WS2812FX::mode_2DFrizzles;
_mode[FX_MODE_2DPLASMABALL] = &WS2812FX::mode_2DPlasmaball;
_mode[FX_MODE_FLOWSTRIPE] = &WS2812FX::mode_FlowStripe;
_mode[FX_MODE_2DHIPHOTIC] = &WS2812FX::mode_2DHiphotic;
_mode[FX_MODE_2DSINDOTS] = &WS2812FX::mode_2DSindots;
_mode[FX_MODE_2DDNASPIRAL] = &WS2812FX::mode_2DDNASpiral;
_mode[FX_MODE_2DBLACKHOLE] = &WS2812FX::mode_2DBlackHole;
_mode[FX_MODE_WAVESINS] = &WS2812FX::mode_wavesins;
_mode[FX_MODE_ROCKTAVES] = &WS2812FX::mode_rocktaves;
_mode[FX_MODE_2DAKEMI] = &WS2812FX::mode_2DAkemi;
//_mode[FX_MODE_CUSTOMEFFECT] = &WS2812FX::mode_customEffect; //WLEDSR Custom Effects
#endif
*/
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
targetPalette = CloudColors_p;
@ -853,8 +638,8 @@ class WS2812FX {
resetSegments(),
makeAutoSegments(bool forceReset = false),
fixInvalidSegments(),
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w, bool aa),
setPixelColor(int n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = false),
show(void),
setTargetFps(uint8_t fps),
deserializeMap(uint8_t n=0);
@ -863,8 +648,8 @@ class WS2812FX {
void setupEffectData(void); // defined in FX.cpp
// outsmart the compiler :) by correctly overloading
inline void setPixelColor(int n, uint32_t c) {setPixelColor(n, byte(c>>16), byte(c>>8), byte(c), byte(c>>24));}
inline void setPixelColor(int n, CRGB c) {setPixelColor(n, c.red, c.green, c.blue);}
inline void setPixelColor(int n, uint32_t c) {setPixelColor(n, byte(c>>16), byte(c>>8), byte(c), byte(c>>24));}
inline void setPixelColor(int n, CRGB c) {setPixelColor(n, c.red, c.green, c.blue);}
inline void setPixelColor(float i, uint32_t c, bool aa=true) {setPixelColor(i, byte(c>>16), byte(c>>8), byte(c), byte(c>>24), aa);}
inline void setPixelColor(float i, CRGB c, bool aa=true) {setPixelColor(i, c.red, c.green, c.blue, 0, aa);}
@ -1094,7 +879,7 @@ class WS2812FX {
void
setUpMatrix(),
setPixelColorXY(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
setPixelColorXY(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = false),
blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend),
addPixelColorXY(uint16_t x, uint16_t y, uint32_t color),
@ -1116,8 +901,8 @@ class WS2812FX {
wu_pixel(CRGB *leds, uint32_t x, uint32_t y, CRGB c);
// outsmart the compiler :) by correctly overloading
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColorXY(uint16_t(x), uint16_t(y), byte(c>>16), byte(c>>8), byte(c), byte(c>>24)); }
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(uint16_t(x), uint16_t(y), c.red, c.green, c.blue, 0); }
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColorXY(x, y, byte(c>>16), byte(c>>8), byte(c), byte(c>>24)); }
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, c.red, c.green, c.blue, 0); }
inline void setPixelColorXY(float x, float y, uint32_t c, bool aa=true) { setPixelColorXY(x, y, byte(c>>16), byte(c>>8), byte(c), byte(c>>24), aa); }
inline void setPixelColorXY(float x, float y, CRGB c, bool aa=true) { setPixelColorXY(x, y, c.red, c.green, c.blue, 0, aa); }
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { drawLine(x0, y0, x1, y1, CRGB(byte(c>>16), byte(c>>8), byte(c))); }
@ -1183,7 +968,6 @@ class WS2812FX {
mode_2DAkemi(void);
#else
uint16_t
GEQ_base(bool centered_horizontal, bool centered_vertical, bool color_vertical),
mode_pixels(void),
mode_pixelwave(void),
mode_juggles(void),
@ -1206,7 +990,6 @@ class WS2812FX {
mode_ripplepeak(void),
mode_2Dfirenoise(void),
mode_2Dsquaredswirl(void),
//mode_2Dfire2012(void),
mode_2Ddna(void),
mode_2Dmatrix(void),
mode_2Dmetaballs(void),
@ -1216,7 +999,6 @@ class WS2812FX {
mode_gravfreq(void),
mode_DJLight(void),
mode_2DFunkyPlank(void),
mode_2DCenterBars(void),
mode_2DPulser(void),
mode_blurz(void),
mode_2Dgameoflife(void),
@ -1262,8 +1044,9 @@ class WS2812FX {
_triggered;
uint8_t _modeCount = MODE_COUNT;
// TODO: allocate memory using new or malloc()
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
show_callback _callback = nullptr;

View File

@ -166,7 +166,7 @@ void WS2812FX::service() {
}
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++;
}
@ -211,7 +211,7 @@ void /*IRAM_ATTR*/ WS2812FX::setPixelColor(float i, byte r, byte g, byte b, byte
}
}
void IRAM_ATTR WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
void IRAM_ATTR WS2812FX::setPixelColor(int i, byte r, byte g, byte b, byte w)
{
uint8_t segIdx = SEGLEN ? _segment_index : _mainSegment;
if (isMatrix && SEGLEN) {

View File

@ -531,6 +531,16 @@ button {
z-index: -2;
}
#info .slider {
max-width: 200px;
min-width: 145px;
float: right;
margin: 0;
}
#info .sliderwrap {
width: 200px;
}
#info table, #nodes table {
table-layout: fixed;
width: 100%;
@ -1377,7 +1387,7 @@ TD .checkmark, TD .radiomark {
width: 145px;
}
#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;
isM = mw>0 && mh>0;
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
}
//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)
{
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 + ")")}
</table>`;
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)
@ -1346,15 +1365,16 @@ function setSliderAndColorControl(idx, applyDef=false)
else if (i==1) btn.innerHTML = "Bg";
else btn.innerHTML = "Cs";
hide = false;
if (!cslCnt) selectSlot(i); // select 1st displayed slot
cslCnt++;
} else if (!controlDefined /*|| paOnOff.length>0*/) { // if no controls then all buttons should be shown for color 1..3
btn.style.display = "inline";
btn.innerHTML = `${i+1}`;
hide = false;
if (!cslCnt) selectSlot(i); // select 1st displayed slot
cslCnt++;
} else {
btn.style.display = "none";
if (i>0 && csel==i) selectSlot(0);
}
}
gId("cslLabel").innerHTML = cslLabel;

File diff suppressed because it is too large Load Diff