kopia lustrzana https://github.com/Aircoookie/WLED
				
				
				
			Merge branch 'dev' of https://github.com/blazoncek/WLED into 0_14
- remove conditional audio compile - Random Cycle bugfix - AudioReactive updates - global gamma flagspull/2771/head
						commit
						51d3268eed
					
				| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
// #define MIC_LOGGER                   // MIC sampling & sound input debugging (serial plotter)
 | 
			
		||||
// #define FFT_SAMPLING_LOG             // FFT result debugging
 | 
			
		||||
// #define SR_DEBUG                     // generic SR DEBUG messages
 | 
			
		||||
// #define NO_MIC_LOGGER                // exclude MIC_LOGGER from SR_DEBUG
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef SR_DEBUG
 | 
			
		||||
  #define DEBUGSR_PRINT(x) Serial.print(x)
 | 
			
		||||
| 
						 | 
				
			
			@ -85,41 +85,51 @@ const float agcSampleSmooth[AGC_NUM_PRESETS]  = {  1/12.f,   1/6.f,  1/16.f}; //
 | 
			
		|||
static AudioSource *audioSource = nullptr;
 | 
			
		||||
static volatile bool disableSoundProcessing = false;      // if true, sound processing (FFT, filters, AGC) will be suspended. "volatile" as its shared between tasks.
 | 
			
		||||
 | 
			
		||||
// audioreactive variables shared with FFT task
 | 
			
		||||
static float    micDataReal = 0.0f;             // MicIn data with full 24bit resolution - lowest 8bit after decimal point
 | 
			
		||||
static float    sampleReal = 0.0f;	            // "sampleRaw" as float, to provide bits that are lost otherwise (before amplification by sampleGain or inputLevel). Needed for AGC.
 | 
			
		||||
static float    multAgc = 1.0f;                 // sample * multAgc = sampleAgc. Our AGC multiplier
 | 
			
		||||
static float    sampleAvg = 0.0f;               // Smoothed Average sample - sampleAvg < 1 means "quiet" (simple noise gate)
 | 
			
		||||
 | 
			
		||||
// peak detection
 | 
			
		||||
static bool samplePeak = false;      // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
 | 
			
		||||
static uint8_t maxVol = 10;          // Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
 | 
			
		||||
static uint8_t binNum = 8;           // Used to select the bin for FFT based beat detection  (deprecated)
 | 
			
		||||
static bool udpSamplePeak = false;   // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData
 | 
			
		||||
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
 | 
			
		||||
static void detectSamplePeak(void);  // peak detection function (needs scaled FFT reasults in vReal[])
 | 
			
		||||
static void autoResetPeak(void);     // peak auto-reset function
 | 
			
		||||
 | 
			
		||||
static int16_t  sampleRaw = 0;                  // Current sample. Must only be updated ONCE!!! (amplified mic value by sampleGain and inputLevel)
 | 
			
		||||
static int16_t  rawSampleAgc = 0;               // not smoothed AGC sample
 | 
			
		||||
static float    sampleAvg = 0.0f;               // Smoothed Average sampleRaw
 | 
			
		||||
static float    sampleAgc = 0.0f;               // Smoothed AGC sample
 | 
			
		||||
 | 
			
		||||
////////////////////
 | 
			
		||||
// Begin FFT Code //
 | 
			
		||||
////////////////////
 | 
			
		||||
 | 
			
		||||
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
 | 
			
		||||
// lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2
 | 
			
		||||
#define FFT_SPEED_OVER_PRECISION     // enables use of reciprocals (1/x etc), and an a few other speedups
 | 
			
		||||
#define FFT_SQRT_APPROXIMATION       // enables "quake3" style inverse sqrt
 | 
			
		||||
#define sqrt(x) sqrtf(x)             // little hack that reduces FFT time by 50% on ESP32 (as alternative to FFT_SQRT_APPROXIMATION)
 | 
			
		||||
#else
 | 
			
		||||
// lib_deps += https://github.com/blazoncek/arduinoFFT.git
 | 
			
		||||
#endif
 | 
			
		||||
#include "arduinoFFT.h"
 | 
			
		||||
 | 
			
		||||
// FFT Variables
 | 
			
		||||
// FFT Output variables shared with animations
 | 
			
		||||
#define NUM_GEQ_CHANNELS 16                     // number of frequency channels. Don't change !!
 | 
			
		||||
static float FFT_MajorPeak = 1.0f;              // FFT: strongest (peak) frequency
 | 
			
		||||
static float FFT_Magnitude = 0.0f;              // FFT: volume (magnitude) of peak frequency
 | 
			
		||||
static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects
 | 
			
		||||
 | 
			
		||||
// FFT Constants
 | 
			
		||||
constexpr uint16_t samplesFFT = 512;            // Samples in an FFT batch - This value MUST ALWAYS be a power of 2
 | 
			
		||||
constexpr uint16_t samplesFFT_2 = 256;          // meaningfull part of FFT results - only the "lower half" contains useful information.
 | 
			
		||||
 | 
			
		||||
static float FFT_MajorPeak = 1.0f;
 | 
			
		||||
static float FFT_Magnitude = 0.0f;
 | 
			
		||||
 | 
			
		||||
// These are the input and output vectors.  Input vectors receive computed results from FFT.
 | 
			
		||||
static float vReal[samplesFFT] = {0.0f};
 | 
			
		||||
static float vImag[samplesFFT] = {0.0f};
 | 
			
		||||
static float fftBin[samplesFFT_2] = {0.0f};
 | 
			
		||||
static float vReal[samplesFFT] = {0.0f};       // FFT sample inputs / freq output -  these are our raw result bins
 | 
			
		||||
static float vImag[samplesFFT] = {0.0f};       // imaginary parts
 | 
			
		||||
 | 
			
		||||
// the following are observed values, supported by a bit of "educated guessing"
 | 
			
		||||
//#define FFT_DOWNSCALE 0.65f                             // 20kHz - downscaling factor for FFT results - "Flat-Top" window @20Khz, old freq channels 
 | 
			
		||||
 | 
			
		||||
#define FFT_DOWNSCALE 0.46f                             // downscaling factor for FFT results - for "Flat-Top" window @22Khz, new freq channels
 | 
			
		||||
#define LOG_256  5.54517744
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -128,13 +138,11 @@ static float windowWeighingFactors[samplesFFT] = {0.0f};
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
static float   fftCalc[16] = {0.0f};
 | 
			
		||||
static uint8_t fftResult[16] = {0};                     // Our calculated result table, which we feed to the animations.
 | 
			
		||||
static float   fftCalc[NUM_GEQ_CHANNELS] = {0.0f};
 | 
			
		||||
static float   fftAvg[NUM_GEQ_CHANNELS] = {0.0f};                     // Calculated frequency channel results, with smoothing (used if dynamics limiter is ON)
 | 
			
		||||
#ifdef SR_DEBUG
 | 
			
		||||
static float   fftResultMax[16] = {0.0f};               // A table used for testing to determine how our post-processing is working.
 | 
			
		||||
static float   fftResultMax[NUM_GEQ_CHANNELS] = {0.0f};               // A table used for testing to determine how our post-processing is working.
 | 
			
		||||
#endif
 | 
			
		||||
static float   fftAvg[16] = {0.0f};
 | 
			
		||||
 | 
			
		||||
#ifdef WLED_DEBUG
 | 
			
		||||
static unsigned long fftTime = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +150,7 @@ static unsigned long sampleTime = 0;
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
// Table of multiplication factors so that we can even out the frequency response.
 | 
			
		||||
static float fftResultPink[16] = { 1.70f, 1.71f, 1.73f, 1.78f, 1.68f, 1.56f, 1.55f, 1.63f, 1.79f, 1.62f, 1.80f, 2.06f, 2.47f, 3.35f, 6.83f, 9.55f };
 | 
			
		||||
static float fftResultPink[NUM_GEQ_CHANNELS] = { 1.70f, 1.71f, 1.73f, 1.78f, 1.68f, 1.56f, 1.55f, 1.63f, 1.79f, 1.62f, 1.80f, 2.06f, 2.47f, 3.35f, 6.83f, 9.55f };
 | 
			
		||||
 | 
			
		||||
// Create FFT object
 | 
			
		||||
#ifdef UM_AUDIOREACTIVE_USE_NEW_FFT
 | 
			
		||||
| 
						 | 
				
			
			@ -161,12 +169,12 @@ static float mapf(float x, float in_min, float in_max, float out_min, float out_
 | 
			
		|||
static float fftAddAvg(int from, int to) {
 | 
			
		||||
  float result = 0.0f;
 | 
			
		||||
  for (int i = from; i <= to; i++) {
 | 
			
		||||
    result += fftBin[i];
 | 
			
		||||
    result += vReal[i];
 | 
			
		||||
  }
 | 
			
		||||
  return result / float(to - from + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FFT main code
 | 
			
		||||
// FFT main task
 | 
			
		||||
void FFTcode(void * parameter)
 | 
			
		||||
{
 | 
			
		||||
  DEBUGSR_PRINT("FFT started on core: "); DEBUGSR_PRINTLN(xPortGetCoreID());
 | 
			
		||||
| 
						 | 
				
			
			@ -237,9 +245,9 @@ void FFTcode(void * parameter)
 | 
			
		|||
#endif
 | 
			
		||||
    FFT_MajorPeak = constrain(FFT_MajorPeak, 1.0f, 11025.0f);   // restrict value to range expected by effects
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < samplesFFT_2; i++) {          // Values for bins 0 and 1 are WAY too large. Might as well start at 3.
 | 
			
		||||
    for (int i = 0; i < samplesFFT; i++) {
 | 
			
		||||
      float t = fabsf(vReal[i]);                      // just to be sure - values in fft bins should be positive any way
 | 
			
		||||
      fftBin[i] = t / 16.0f;                          // Reduce magnitude. Want end result to be linear and ~4096 max.
 | 
			
		||||
      vReal[i] = t / 16.0f;                           // Reduce magnitude. Want end result to be scaled linear and ~4096 max.
 | 
			
		||||
    } // for()
 | 
			
		||||
 | 
			
		||||
    // mapping of FFT result bins to frequency channels
 | 
			
		||||
| 
						 | 
				
			
			@ -292,14 +300,14 @@ void FFTcode(void * parameter)
 | 
			
		|||
      // don't use the last bins from 216 to 255. They are usually contaminated by aliasing (aka noise) 
 | 
			
		||||
#endif
 | 
			
		||||
    } else {  // noise gate closed - just decay old values
 | 
			
		||||
      for (int i=0; i < 16; i++) {
 | 
			
		||||
      for (int i=0; i < NUM_GEQ_CHANNELS; i++) {
 | 
			
		||||
        fftCalc[i] *= 0.85f;  // decay to zero
 | 
			
		||||
        if (fftCalc[i] < 4.0f) fftCalc[i] = 0.0f;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // post-processing of frequency channels (pink noise adjustment, AGC, smooting, scaling)
 | 
			
		||||
    for (int i=0; i < 16; i++) {
 | 
			
		||||
    for (int i=0; i < NUM_GEQ_CHANNELS; i++) {
 | 
			
		||||
 | 
			
		||||
      if (sampleAvg > 1) { // noise gate open
 | 
			
		||||
        // Adjustment for frequency curves.
 | 
			
		||||
| 
						 | 
				
			
			@ -378,11 +386,43 @@ void FFTcode(void * parameter)
 | 
			
		|||
      fftTime  = (fftTimeInMillis*3 + fftTime*7)/10; // smooth
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    // run peak detection
 | 
			
		||||
    autoResetPeak();
 | 
			
		||||
    detectSamplePeak();
 | 
			
		||||
 | 
			
		||||
  } // for(;;)
 | 
			
		||||
} // FFTcode()
 | 
			
		||||
  } // for(;;)ever
 | 
			
		||||
} // FFTcode() task end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////
 | 
			
		||||
// Peak detection //
 | 
			
		||||
////////////////////
 | 
			
		||||
 | 
			
		||||
// peak detection is called from FFT task when vReal[] contains valid FFT results
 | 
			
		||||
static void detectSamplePeak(void) {
 | 
			
		||||
  // Poor man's beat detection by seeing if sample > Average + some value.
 | 
			
		||||
  if ((sampleAvg > 1) && (maxVol > 0) && (binNum > 1) && (vReal[binNum] > maxVol) && ((millis() - timeOfPeak) > 100)) {
 | 
			
		||||
    // This goes through ALL of the 255 bins - but ignores stupid settings
 | 
			
		||||
    // 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    = true;
 | 
			
		||||
    timeOfPeak    = millis();
 | 
			
		||||
    udpSamplePeak = true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void autoResetPeak(void) {
 | 
			
		||||
  uint16_t MinShowDelay = MAX(50, strip.getMinShowDelay());  // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC
 | 
			
		||||
  if (millis() - timeOfPeak > MinShowDelay) {          // Auto-reset of samplePeak after a complete frame has passed.
 | 
			
		||||
    samplePeak = false;
 | 
			
		||||
    if (audioSyncEnabled == 0) udpSamplePeak = false;  // this is normally reset by transmitAudioData
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////
 | 
			
		||||
// usermod class  //
 | 
			
		||||
////////////////////
 | 
			
		||||
 | 
			
		||||
//class name. Use something descriptive and leave the ": public Usermod" part :)
 | 
			
		||||
class AudioReactive : public Usermod {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -453,40 +493,36 @@ class AudioReactive : public Usermod {
 | 
			
		|||
      double FFT_MajorPeak;   //  08 Bytes
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    WiFiUDP fftUdp;
 | 
			
		||||
 | 
			
		||||
    // set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
 | 
			
		||||
    bool     enabled = false;
 | 
			
		||||
    bool     initDone = false;
 | 
			
		||||
 | 
			
		||||
    const uint16_t delayMs = 10;        // I don't want to sample too often and overload WLED
 | 
			
		||||
    // variables  for UDP sound sync
 | 
			
		||||
    WiFiUDP fftUdp;               // UDP object for sound sync (from WiFi UDP, not Async UDP!) 
 | 
			
		||||
    bool udpSyncConnected = false;// UDP connection status -> true if connected to multicast group
 | 
			
		||||
    unsigned long lastTime = 0;   // last time of running UDP Microphone Sync
 | 
			
		||||
    const uint16_t delayMs = 10;  // I don't want to sample too often and overload WLED
 | 
			
		||||
    uint16_t audioSyncPort= 11988;// default port for UDP sound sync
 | 
			
		||||
 | 
			
		||||
    // used for AGC
 | 
			
		||||
    int      last_soundAgc = -1;   // used to detect AGC mode change (for resetting AGC internal error buffers)
 | 
			
		||||
    double   control_integrated = 0.0;   // persistent across calls to agcAvg(); "integrator control" = accumulated error
 | 
			
		||||
 | 
			
		||||
    // variables used by getSample() and agcAvg()
 | 
			
		||||
    int16_t  micIn = 0;           // Current sample starts with negative values and large values, which is why it's 16 bit signed
 | 
			
		||||
    double   sampleMax = 0.0;     // Max sample over a few seconds. Needed for AGC controler.
 | 
			
		||||
    float    micLev = 0.0f;       // Used to convert returned value to have '0' as minimum. A leveller
 | 
			
		||||
    float    expAdjF = 0.0f;      // Used for exponential filter.
 | 
			
		||||
    float    sampleReal = 0.0f;	  // "sampleRaw" as float, to provide bits that are lost otherwise (before amplification by sampleGain or inputLevel). Needed for AGC.
 | 
			
		||||
    int16_t  sampleRaw = 0;       // Current sample. Must only be updated ONCE!!! (amplified mic value by sampleGain and inputLevel)
 | 
			
		||||
    int16_t  rawSampleAgc = 0;    // not smoothed AGC sample
 | 
			
		||||
    float    sampleAgc = 0.0f;    // Smoothed AGC sample
 | 
			
		||||
 | 
			
		||||
    // variables used in effects
 | 
			
		||||
    uint8_t  maxVol = 10;         // Reasonable value for constant volume for 'peak detector', as it won't always trigger (deprecated)
 | 
			
		||||
    uint8_t  binNum = 8;          // Used to select the bin for FFT based beat detection  (deprecated)
 | 
			
		||||
    bool     samplePeak = 0;      // Boolean flag for peak. Responding routine must reset this flag
 | 
			
		||||
    float    volumeSmth = 0.0f;   // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample
 | 
			
		||||
    int16_t  volumeRaw = 0;       // either sampleRaw or rawSampleAgc depending on soundAgc
 | 
			
		||||
    float my_magnitude =0.0f;     // FFT_Magnitude, scaled by multAgc
 | 
			
		||||
 | 
			
		||||
    bool     udpSamplePeak = 0;   // Boolean flag for peak. Set at the same tiem as samplePeak, but reset by transmitAudioData
 | 
			
		||||
    int16_t  micIn = 0;           // Current sample starts with negative values and large values, which is why it's 16 bit signed
 | 
			
		||||
    double   sampleMax = 0.0;     // Max sample over a few seconds. Needed for AGC controler.
 | 
			
		||||
    uint32_t timeOfPeak = 0;
 | 
			
		||||
    unsigned long lastTime = 0;   // last time of running UDP Microphone Sync
 | 
			
		||||
    float    micLev = 0.0f;       // Used to convert returned value to have '0' as minimum. A leveller
 | 
			
		||||
    float    expAdjF = 0.0f;      // Used for exponential filter.
 | 
			
		||||
 | 
			
		||||
    bool     udpSyncConnected = false;
 | 
			
		||||
    uint16_t audioSyncPort = 11988;
 | 
			
		||||
 | 
			
		||||
    // used for AGC
 | 
			
		||||
    uint8_t  lastMode = 0;        // last known effect mode
 | 
			
		||||
    int      last_soundAgc = -1;
 | 
			
		||||
    double   control_integrated = 0.0;   // persistent across calls to agcAvg(); "integrator control" = accumulated error
 | 
			
		||||
    unsigned long last_update_time = 0;
 | 
			
		||||
    unsigned long last_kick_time = 0;
 | 
			
		||||
    uint8_t  last_user_inputLevel = 0;
 | 
			
		||||
 | 
			
		||||
    // used to feed "Info" Page
 | 
			
		||||
    unsigned long last_UDPTime = 0;    // time of last valid UDP sound sync datapacket
 | 
			
		||||
    float maxSample5sec = 0.0f;        // max sample (after AGC) in last 5 seconds 
 | 
			
		||||
| 
						 | 
				
			
			@ -503,6 +539,10 @@ class AudioReactive : public Usermod {
 | 
			
		|||
    static const char UDP_SYNC_HEADER_v1[];
 | 
			
		||||
 | 
			
		||||
    // private methods
 | 
			
		||||
 | 
			
		||||
    ////////////////////
 | 
			
		||||
    // Debug support  //
 | 
			
		||||
    ////////////////////
 | 
			
		||||
    void logAudio()
 | 
			
		||||
    {
 | 
			
		||||
    #ifdef MIC_LOGGER
 | 
			
		||||
| 
						 | 
				
			
			@ -525,7 +565,7 @@ class AudioReactive : public Usermod {
 | 
			
		|||
 | 
			
		||||
    #ifdef FFT_SAMPLING_LOG
 | 
			
		||||
      #if 0
 | 
			
		||||
        for(int i=0; i<16; i++) {
 | 
			
		||||
        for(int i=0; i<NUM_GEQ_CHANNELS; i++) {
 | 
			
		||||
          Serial.print(fftResult[i]);
 | 
			
		||||
          Serial.print("\t");
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -551,11 +591,11 @@ class AudioReactive : public Usermod {
 | 
			
		|||
 | 
			
		||||
      int maxVal = minimumMaxVal;
 | 
			
		||||
      int minVal = 0;
 | 
			
		||||
      for(int i = 0; i < 16; i++) {
 | 
			
		||||
      for(int i = 0; i < NUM_GEQ_CHANNELS; i++) {
 | 
			
		||||
        if(fftResult[i] > maxVal) maxVal = fftResult[i];
 | 
			
		||||
        if(fftResult[i] < minVal) minVal = fftResult[i];
 | 
			
		||||
      }
 | 
			
		||||
      for(int i = 0; i < 16; i++) {
 | 
			
		||||
      for(int i = 0; i < NUM_GEQ_CHANNELS; i++) {
 | 
			
		||||
        Serial.print(i); Serial.print(":");
 | 
			
		||||
        Serial.printf("%04ld ", map(fftResult[i], 0, (scaleValuesFromCurrentMaxVal ? maxVal : defaultScalingFromHighValue), (mapValuesToPlotterSpace*i*scalingToHighValue)+0, (mapValuesToPlotterSpace*i*scalingToHighValue)+scalingToHighValue-1));
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -574,6 +614,10 @@ class AudioReactive : public Usermod {
 | 
			
		|||
    } // logAudio()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //////////////////////
 | 
			
		||||
    // Audio Processing //
 | 
			
		||||
    //////////////////////
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    * A "PI controller" multiplier to automatically adjust sound sensitivity.
 | 
			
		||||
    * 
 | 
			
		||||
| 
						 | 
				
			
			@ -668,7 +712,7 @@ class AudioReactive : public Usermod {
 | 
			
		|||
      last_soundAgc = soundAgc;
 | 
			
		||||
    } // agcAvg()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // post-processing and filtering of MIC sample (micDataReal) from FFTcode()
 | 
			
		||||
    void getSample()
 | 
			
		||||
    {
 | 
			
		||||
      float    sampleAdj;           // Gain adjusted sample value
 | 
			
		||||
| 
						 | 
				
			
			@ -729,24 +773,6 @@ class AudioReactive : public Usermod {
 | 
			
		|||
      if (sampleMax < 0.5f) sampleMax = 0.0f;
 | 
			
		||||
 | 
			
		||||
      sampleAvg = ((sampleAvg * 15.0f) + sampleAdj) / 16.0f;   // Smooth it out over the last 16 samples.
 | 
			
		||||
 | 
			
		||||
      // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC
 | 
			
		||||
      uint16_t MinShowDelay = strip.getMinShowDelay();
 | 
			
		||||
 | 
			
		||||
      if (millis() - timeOfPeak > MinShowDelay) {   // Auto-reset of samplePeak after a complete frame has passed.
 | 
			
		||||
        samplePeak = false;
 | 
			
		||||
        udpSamplePeak = false;
 | 
			
		||||
      }
 | 
			
		||||
      //if (userVar1 == 0) samplePeak = 0;
 | 
			
		||||
 | 
			
		||||
      // Poor man's beat detection by seeing if sample > Average + some value.
 | 
			
		||||
      if ((maxVol > 0) && (binNum > 1) && (fftBin[binNum] > maxVol) && (millis() > (timeOfPeak + 100))) {
 | 
			
		||||
        // This goes through ALL of the 255 bins - but ignores stupid settings
 | 
			
		||||
        // 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    = true;
 | 
			
		||||
        timeOfPeak    = millis();
 | 
			
		||||
        udpSamplePeak = true;
 | 
			
		||||
      }
 | 
			
		||||
    } // getSample()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -781,6 +807,26 @@ class AudioReactive : public Usermod {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //////////////////////
 | 
			
		||||
    // UDP Sound Sync   //
 | 
			
		||||
    //////////////////////
 | 
			
		||||
 | 
			
		||||
    // try to establish UDP sound sync connection
 | 
			
		||||
    void connectUDPSoundSync(void) {
 | 
			
		||||
      // This function tries to establish a UDP sync connection if needed
 | 
			
		||||
      // necessary as we also want to transmit in "AP Mode", but the standard "connected()" callback only reacts on STA connection
 | 
			
		||||
      static unsigned long last_connection_attempt = 0;
 | 
			
		||||
 | 
			
		||||
      if ((audioSyncPort <= 0) || ((audioSyncEnabled & 0x03) == 0)) return;  // Sound Sync not enabled
 | 
			
		||||
      if (udpSyncConnected) return;                                          // already connected
 | 
			
		||||
      if (!(apActive || interfacesInited)) return;                           // neither AP nor other connections availeable
 | 
			
		||||
      if (millis() - last_connection_attempt < 15000) return;                // only try once in 15 seconds
 | 
			
		||||
 | 
			
		||||
      // if we arrive here, we need a UDP connection but don't have one
 | 
			
		||||
      last_connection_attempt = millis();
 | 
			
		||||
      connected(); // try to start UDP
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void transmitAudioData()
 | 
			
		||||
    {
 | 
			
		||||
      if (!udpSyncConnected) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -795,7 +841,7 @@ class AudioReactive : public Usermod {
 | 
			
		|||
      udpSamplePeak            = false;           // Reset udpSamplePeak after we've transmitted it
 | 
			
		||||
      transmitData.reserved1   = 0;
 | 
			
		||||
 | 
			
		||||
      for (int i = 0; i < 16; i++) {
 | 
			
		||||
      for (int i = 0; i < NUM_GEQ_CHANNELS; i++) {
 | 
			
		||||
        transmitData.fftResult[i] = (uint8_t)constrain(fftResult[i], 0, 254);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -808,12 +854,10 @@ class AudioReactive : public Usermod {
 | 
			
		|||
      return;
 | 
			
		||||
    } // transmitAudioData()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    static bool isValidUdpSyncVersion(const char *header) {
 | 
			
		||||
      return strncmp_P(header, PSTR(UDP_SYNC_HEADER), 6) == 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    bool receiveAudioData()   // check & process new data. return TRUE in case that new audio data was received. 
 | 
			
		||||
    {
 | 
			
		||||
      if (!udpSyncConnected) return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -839,13 +883,7 @@ class AudioReactive : public Usermod {
 | 
			
		|||
          sampleAgc    = volumeSmth;
 | 
			
		||||
          multAgc      = 1.0f;
 | 
			
		||||
 | 
			
		||||
          // auto-reset sample peak. Need to do it here, because getSample() is not running
 | 
			
		||||
          uint16_t MinShowDelay = strip.getMinShowDelay();
 | 
			
		||||
          if (millis() - timeOfPeak > MinShowDelay) {   // Auto-reset of samplePeak after a complete frame has passed.
 | 
			
		||||
            samplePeak = false;
 | 
			
		||||
            udpSamplePeak = false;
 | 
			
		||||
          }
 | 
			
		||||
          //if (userVar1 == 0) samplePeak = 0;
 | 
			
		||||
          autoResetPeak();
 | 
			
		||||
          // Only change samplePeak IF it's currently false.
 | 
			
		||||
          // If it's true already, then the animation still needs to respond.
 | 
			
		||||
          if (!samplePeak) {
 | 
			
		||||
| 
						 | 
				
			
			@ -855,7 +893,7 @@ class AudioReactive : public Usermod {
 | 
			
		|||
          }
 | 
			
		||||
 | 
			
		||||
          //These values are only available on the ESP32
 | 
			
		||||
          for (int i = 0; i < 16; i++) fftResult[i] = receivedPacket->fftResult[i];
 | 
			
		||||
          for (int i = 0; i < NUM_GEQ_CHANNELS; i++) fftResult[i] = receivedPacket->fftResult[i];
 | 
			
		||||
 | 
			
		||||
          my_magnitude  = fmaxf(receivedPacket->FFT_Magnitude, 0.0f);
 | 
			
		||||
          FFT_Magnitude = my_magnitude;
 | 
			
		||||
| 
						 | 
				
			
			@ -869,6 +907,10 @@ class AudioReactive : public Usermod {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //////////////////////
 | 
			
		||||
    // usermod functions//
 | 
			
		||||
    //////////////////////
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    //Functions called by WLED or other usermods
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -961,6 +1003,7 @@ class AudioReactive : public Usermod {
 | 
			
		|||
        disableSoundProcessing = true;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (enabled) connectUDPSoundSync();
 | 
			
		||||
      initDone = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -971,6 +1014,11 @@ class AudioReactive : public Usermod {
 | 
			
		|||
     */
 | 
			
		||||
    void connected()
 | 
			
		||||
    {
 | 
			
		||||
      if (udpSyncConnected) {   // clean-up: if open, close old UDP sync connection
 | 
			
		||||
        udpSyncConnected = false;
 | 
			
		||||
        fftUdp.stop();
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      if (audioSyncPort > 0 && (audioSyncEnabled & 0x03)) {
 | 
			
		||||
      #ifndef ESP8266
 | 
			
		||||
        udpSyncConnected = fftUdp.beginMulticast(IPAddress(239, 0, 0, 1), audioSyncPort);
 | 
			
		||||
| 
						 | 
				
			
			@ -1004,7 +1052,7 @@ class AudioReactive : public Usermod {
 | 
			
		|||
      if (strip.isUpdating() && (millis() - lastUMRun < 2)) return;   // be nice, but not too nice
 | 
			
		||||
 | 
			
		||||
      // suspend local sound processing when "real time mode" is active (E131, UDP, ADALIGHT, ARTNET)
 | 
			
		||||
      if (  (realtimeOverride == REALTIME_OVERRIDE_NONE)  // please odd other orrides here if needed
 | 
			
		||||
      if (  (realtimeOverride == REALTIME_OVERRIDE_NONE)  // please add other overrides here if needed
 | 
			
		||||
          &&( (realtimeMode == REALTIME_MODE_GENERIC)
 | 
			
		||||
            ||(realtimeMode == REALTIME_MODE_E131)
 | 
			
		||||
            ||(realtimeMode == REALTIME_MODE_UDP)
 | 
			
		||||
| 
						 | 
				
			
			@ -1067,9 +1115,13 @@ class AudioReactive : public Usermod {
 | 
			
		|||
        if (soundAgc) my_magnitude *= multAgc;
 | 
			
		||||
        if (volumeSmth < 1 ) my_magnitude = 0.001f;  // noise gate closed - mute
 | 
			
		||||
 | 
			
		||||
        limitSampleDynamics();  // optional - makes volumeSmth very smooth and fluent
 | 
			
		||||
      }
 | 
			
		||||
        limitSampleDynamics();
 | 
			
		||||
      }  // if (!disableSoundProcessing)
 | 
			
		||||
 | 
			
		||||
      autoResetPeak();          // auto-reset sample peak after strip minShowDelay
 | 
			
		||||
      if (!udpSyncConnected) udpSamplePeak = false;  // reset UDP samplePeak while UDP is unconnected
 | 
			
		||||
 | 
			
		||||
      connectUDPSoundSync();  // ensure we have a connection - if needed
 | 
			
		||||
 | 
			
		||||
      // UDP Microphone Sync  - receive mode
 | 
			
		||||
      if ((audioSyncEnabled & 0x02) && udpSyncConnected) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1092,7 +1144,7 @@ class AudioReactive : public Usermod {
 | 
			
		|||
       }
 | 
			
		||||
      #endif
 | 
			
		||||
 | 
			
		||||
      // peak sample from last 5 seconds
 | 
			
		||||
      // Info Page: keep max sample from last 5 seconds
 | 
			
		||||
      if ((millis() -  sampleMaxTimer) > CYCLE_SAMPLEMAX) {
 | 
			
		||||
        sampleMaxTimer = millis();
 | 
			
		||||
        maxSample5sec = (0.15 * maxSample5sec) + 0.85 *((soundAgc) ? sampleAgc : sampleAvg); // reset, and start with some smoothing
 | 
			
		||||
| 
						 | 
				
			
			@ -1100,6 +1152,7 @@ class AudioReactive : public Usermod {
 | 
			
		|||
      } else {
 | 
			
		||||
         if ((sampleAvg >= 1)) maxSample5sec = fmaxf(maxSample5sec, (soundAgc) ? rawSampleAgc : sampleRaw); // follow maximum volume
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      //UDP Microphone Sync  - transmit mode
 | 
			
		||||
      if ((audioSyncEnabled & 0x01) && (millis() - lastTime > 20)) {
 | 
			
		||||
        // Only run the transmit code IF we're in Transmit mode
 | 
			
		||||
| 
						 | 
				
			
			@ -1137,8 +1190,9 @@ class AudioReactive : public Usermod {
 | 
			
		|||
      memset(fftCalc, 0, sizeof(fftCalc)); 
 | 
			
		||||
      memset(fftAvg, 0, sizeof(fftAvg)); 
 | 
			
		||||
      memset(fftResult, 0, sizeof(fftResult)); 
 | 
			
		||||
      for(int i=(init?0:1); i<16; i+=2) fftResult[i] = 16; // make a tiny pattern
 | 
			
		||||
      for(int i=(init?0:1); i<NUM_GEQ_CHANNELS; i+=2) fftResult[i] = 16; // make a tiny pattern
 | 
			
		||||
      inputLevel = 128;                                    // resset level slider to default
 | 
			
		||||
      autoResetPeak();
 | 
			
		||||
 | 
			
		||||
      if (init && FFT_Task) {
 | 
			
		||||
        vTaskSuspend(FFT_Task);   // update is about to begin, disable task to prevent crash
 | 
			
		||||
| 
						 | 
				
			
			@ -1186,6 +1240,10 @@ class AudioReactive : public Usermod {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ////////////////////////////
 | 
			
		||||
    // Settings and Info Page //
 | 
			
		||||
    ////////////////////////////
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
 | 
			
		||||
     * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										393
									
								
								wled00/FX.cpp
								
								
								
								
							
							
						
						
									
										393
									
								
								wled00/FX.cpp
								
								
								
								
							| 
						 | 
				
			
			@ -30,6 +30,7 @@
 | 
			
		|||
 | 
			
		||||
#define IBN 5100
 | 
			
		||||
#define PALETTE_SOLID_WRAP (strip.paletteBlend == 1 || strip.paletteBlend == 3)
 | 
			
		||||
#define indexToVStrip(index, stripNr) ((index) | (int((stripNr)+1)<<16))
 | 
			
		||||
 | 
			
		||||
// effect utility functions
 | 
			
		||||
uint8_t sin_gap(uint16_t in) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1926,10 +1927,7 @@ uint16_t mode_palette()
 | 
			
		|||
  for (int i = 0; i < SEGLEN; i++)
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t colorIndex = (i * 255 / SEGLEN) - counter;
 | 
			
		||||
    
 | 
			
		||||
    if (noWrap) colorIndex = map(colorIndex, 0, 255, 0, 240); //cut off blend at palette "end"
 | 
			
		||||
    
 | 
			
		||||
    SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, true, 255));
 | 
			
		||||
    SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, noWrap, 255));
 | 
			
		||||
  }
 | 
			
		||||
  return FRAMETIME;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1966,59 +1964,59 @@ static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed,;1,2,3;
 | 
			
		|||
// in step 3 above) (Effect Intensity = Sparking).
 | 
			
		||||
uint16_t mode_fire_2012()
 | 
			
		||||
{
 | 
			
		||||
  const uint16_t cols = strip.isMatrix ? SEGMENT.virtualWidth() : 1;
 | 
			
		||||
  const uint16_t rows = strip.isMatrix ? SEGMENT.virtualHeight() : SEGMENT.virtualLength();
 | 
			
		||||
 | 
			
		||||
  uint32_t it = strip.now >> 5; //div 32
 | 
			
		||||
  //uint16_t q  = cols>>2; // a quarter of flames
 | 
			
		||||
 | 
			
		||||
  if (!SEGENV.allocateData(cols*rows)) return mode_static(); //allocation failed
 | 
			
		||||
  
 | 
			
		||||
  uint16_t strips = SEGMENT.nrOfVStrips();
 | 
			
		||||
  if (!SEGENV.allocateData(strips * SEGLEN)) return mode_static(); //allocation failed
 | 
			
		||||
  byte* heat = SEGENV.data;
 | 
			
		||||
 | 
			
		||||
  if (it != SEGENV.step) {
 | 
			
		||||
    SEGENV.step = it;
 | 
			
		||||
    uint8_t ignition = max(3,rows/10);  // ignition area: 10% of segment length or minimum 3 pixels
 | 
			
		||||
  uint32_t it = strip.now >> 5; //div 32
 | 
			
		||||
 | 
			
		||||
    for (int f = 0; f < cols; f++) {
 | 
			
		||||
      // Step 1.  Cool down every cell a little
 | 
			
		||||
      for (int i = 0; i < rows; i++) {
 | 
			
		||||
        uint8_t cool = (((20 + SEGMENT.speed/3) * 16) / rows);
 | 
			
		||||
        /*
 | 
			
		||||
        // 2D enhancement: cool sides of the flame a bit more
 | 
			
		||||
        if (cols>5) {
 | 
			
		||||
          if (f < q)   cool = qadd8(cool, 2*(uint16_t)((cool *    (q-f))/cols)); // cool segment sides a bit more
 | 
			
		||||
          if (f > 3*q) cool = qadd8(cool, 2*(uint16_t)((cool * (cols-f))/cols)); // cool segment sides a bit more
 | 
			
		||||
  struct virtualStrip {
 | 
			
		||||
    static void runStrip(uint16_t stripNr, byte* heat, uint32_t it) {
 | 
			
		||||
 | 
			
		||||
      if (it != SEGENV.step)
 | 
			
		||||
      {
 | 
			
		||||
        uint8_t ignition = max(3,SEGLEN/10);  // ignition area: 10% of segment length or minimum 3 pixels
 | 
			
		||||
 | 
			
		||||
        // Step 1.  Cool down every cell a little
 | 
			
		||||
        for (int i = 0; i < SEGLEN; i++) {
 | 
			
		||||
          uint8_t cool = random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2);
 | 
			
		||||
          uint8_t minTemp = 0;
 | 
			
		||||
          if (i<ignition) {
 | 
			
		||||
            cool /= (ignition-i); // ignition area cools slower
 | 
			
		||||
            minTemp = 4*(ignition-i) + 8; // and should not become black
 | 
			
		||||
          }
 | 
			
		||||
          uint8_t temp = qsub8(heat[i], cool);
 | 
			
		||||
          heat[i] = i<ignition && temp<minTemp ? minTemp : temp; // prevent ignition area from becoming black
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Step 2.  Heat from each cell drifts 'up' and diffuses a little
 | 
			
		||||
        for (int k = SEGLEN -1; k > 1; k--) {
 | 
			
		||||
          heat[k] = (heat[k - 1] + (heat[k - 2]<<1) ) / 3;  // heat[k-2] multiplied by 2
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
 | 
			
		||||
        if (random8() <= SEGMENT.intensity) {
 | 
			
		||||
          uint8_t y = random8(ignition);
 | 
			
		||||
          heat[y] = qadd8(heat[y], random8(160,255));
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
        uint8_t temp = qsub8(heat[i+rows*f], random8(0, cool + 2));
 | 
			
		||||
        heat[i+rows*f] = (temp==0 && i<ignition) ? random8(1,16) : temp; // prevent ignition area from becoming black
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Step 2.  Heat from each cell drifts 'up' and diffuses a little
 | 
			
		||||
      for (int k = rows -1; k > 1; k--) {
 | 
			
		||||
        heat[k+rows*f] = (heat[k+rows*f - 1] + (heat[k+rows*f - 2]<<1) ) / 3;  // heat[k-2] multiplied by 2
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
 | 
			
		||||
      if (random8() <= SEGMENT.intensity) {
 | 
			
		||||
        uint8_t y = random8(ignition);
 | 
			
		||||
        heat[y+rows*f] = qadd8(heat[y+rows*f], random8(160,255));
 | 
			
		||||
      // Step 4.  Map from heat cells to LED colors
 | 
			
		||||
      for (int j = 0; j < SEGLEN; j++) {
 | 
			
		||||
        SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, MIN(heat[j],240), 255, NOBLEND));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  for (int stripNr=0; stripNr<strips; stripNr++)
 | 
			
		||||
    virtualStrip::runStrip(stripNr, &heat[stripNr * SEGLEN], it);
 | 
			
		||||
 | 
			
		||||
  if (it != SEGENV.step)
 | 
			
		||||
    SEGENV.step = it;
 | 
			
		||||
 | 
			
		||||
  for (int f = 0; f < cols; f++) {
 | 
			
		||||
    // Step 4.  Map from heat cells to LED colors
 | 
			
		||||
    for (int j = 0; j < rows; j++) {
 | 
			
		||||
      CRGB color = ColorFromPalette(SEGPALETTE, /*MIN(*/heat[j+rows*f]/*,240)*/, 255, LINEARBLEND);
 | 
			
		||||
      if (strip.isMatrix) SEGMENT.setPixelColorXY(f, rows -j -1, color);
 | 
			
		||||
      else                SEGMENT.setPixelColor(j, color);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return FRAMETIME;
 | 
			
		||||
}
 | 
			
		||||
static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate;1,2,3;!;sx=120,ix=64,1d,2d";
 | 
			
		||||
static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate;1,2,3;!;sx=120,ix=64,mp12=1,1d"; //bars
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
 | 
			
		||||
| 
						 | 
				
			
			@ -2849,7 +2847,7 @@ uint16_t mode_bouncing_balls(void) {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        int pos = roundf(balls[i].height * (SEGLEN - 1));
 | 
			
		||||
        if (SEGLEN<32) SEGMENT.setPixelColor(pos | int((stripNr+1)<<16), color); // encode virtual strip into index
 | 
			
		||||
        if (SEGLEN<32) SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color); // encode virtual strip into index
 | 
			
		||||
        else           SEGMENT.setPixelColor(balls[i].height + (stripNr+1)*10.0f, color);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -2942,68 +2940,68 @@ typedef struct Spark {
 | 
			
		|||
  uint8_t colIndex;
 | 
			
		||||
} spark;
 | 
			
		||||
 | 
			
		||||
#define maxNumPopcorn 21 // max 21 on 16 segment ESP8266
 | 
			
		||||
/*
 | 
			
		||||
*  POPCORN
 | 
			
		||||
*  modified from https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Popcorn.h
 | 
			
		||||
*/
 | 
			
		||||
uint16_t mode_popcorn(void) {
 | 
			
		||||
  const uint16_t cols = strip.isMatrix ? SEGMENT.virtualWidth() : 1;
 | 
			
		||||
  const uint16_t rows = strip.isMatrix ? SEGMENT.virtualHeight() : SEGMENT.virtualLength();
 | 
			
		||||
 | 
			
		||||
  //allocate segment data
 | 
			
		||||
  uint16_t maxNumPopcorn = 21; // max 21 on 16 segment ESP8266
 | 
			
		||||
  uint16_t strips = SEGMENT.nrOfVStrips();
 | 
			
		||||
  uint16_t dataSize = sizeof(spark) * maxNumPopcorn;
 | 
			
		||||
  if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
 | 
			
		||||
  
 | 
			
		||||
  Spark* popcorn = reinterpret_cast<Spark*>(SEGENV.data);
 | 
			
		||||
  if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
 | 
			
		||||
 | 
			
		||||
  float gravity = -0.0001 - (SEGMENT.speed/200000.0); // m/s/s
 | 
			
		||||
  gravity *= rows; //SEGLEN
 | 
			
		||||
  Spark* popcorn = reinterpret_cast<Spark*>(SEGENV.data);
 | 
			
		||||
 | 
			
		||||
  bool hasCol2 = SEGCOLOR(2);
 | 
			
		||||
  SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1));
 | 
			
		||||
 | 
			
		||||
  uint8_t numPopcorn = SEGMENT.intensity*maxNumPopcorn/255;
 | 
			
		||||
  if (numPopcorn == 0) numPopcorn = 1;
 | 
			
		||||
  struct virtualStrip {
 | 
			
		||||
    static void runStrip(uint16_t stripNr, Spark* popcorn) {
 | 
			
		||||
      float gravity = -0.0001 - (SEGMENT.speed/200000.0); // m/s/s
 | 
			
		||||
      gravity *= SEGLEN;
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < numPopcorn; i++) {
 | 
			
		||||
    if (popcorn[i].pos >= 0.0f) { // if kernel is active, update its position
 | 
			
		||||
      popcorn[i].pos += popcorn[i].vel;
 | 
			
		||||
      popcorn[i].vel += gravity;
 | 
			
		||||
    } else { // if kernel is inactive, randomly pop it
 | 
			
		||||
      if (random8() < 2) { // POP!!!
 | 
			
		||||
        popcorn[i].pos = 0.01f;
 | 
			
		||||
        popcorn[i].posX = random16(cols);
 | 
			
		||||
        
 | 
			
		||||
        uint16_t peakHeight = 128 + random8(128); //0-255
 | 
			
		||||
        peakHeight = (peakHeight * (rows -1)) >> 8;
 | 
			
		||||
        popcorn[i].vel = sqrt(-2.0 * gravity * peakHeight);
 | 
			
		||||
        popcorn[i].velX = 0;
 | 
			
		||||
        
 | 
			
		||||
        if (SEGMENT.palette) {
 | 
			
		||||
          popcorn[i].colIndex = random8();
 | 
			
		||||
        } else {
 | 
			
		||||
          byte col = random8(0, NUM_COLORS);
 | 
			
		||||
          if (!hasCol2 || !SEGCOLOR(col)) col = 0;
 | 
			
		||||
          popcorn[i].colIndex = col;
 | 
			
		||||
      uint8_t numPopcorn = SEGMENT.intensity*maxNumPopcorn/255;
 | 
			
		||||
      if (numPopcorn == 0) numPopcorn = 1;
 | 
			
		||||
 | 
			
		||||
      for(int i = 0; i < numPopcorn; i++) {
 | 
			
		||||
        if (popcorn[i].pos >= 0.0f) { // if kernel is active, update its position
 | 
			
		||||
          popcorn[i].pos += popcorn[i].vel;
 | 
			
		||||
          popcorn[i].vel += gravity;
 | 
			
		||||
        } else { // if kernel is inactive, randomly pop it
 | 
			
		||||
          if (random8() < 2) { // POP!!!
 | 
			
		||||
            popcorn[i].pos = 0.01f;
 | 
			
		||||
 | 
			
		||||
            uint16_t peakHeight = 128 + random8(128); //0-255
 | 
			
		||||
            peakHeight = (peakHeight * (SEGLEN -1)) >> 8;
 | 
			
		||||
            popcorn[i].vel = sqrt(-2.0 * gravity * peakHeight);
 | 
			
		||||
 | 
			
		||||
            if (SEGMENT.palette)
 | 
			
		||||
            {
 | 
			
		||||
              popcorn[i].colIndex = random8();
 | 
			
		||||
            } else {
 | 
			
		||||
              byte col = random8(0, NUM_COLORS);
 | 
			
		||||
              if (!SEGCOLOR(2) || !SEGCOLOR(col)) col = 0;
 | 
			
		||||
              popcorn[i].colIndex = col;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        if (popcorn[i].pos >= 0.0f) { // draw now active popcorn (either active before or just popped)
 | 
			
		||||
          uint32_t col = SEGMENT.color_wheel(popcorn[i].colIndex);
 | 
			
		||||
          if (!SEGMENT.palette && popcorn[i].colIndex < NUM_COLORS) col = SEGCOLOR(popcorn[i].colIndex);
 | 
			
		||||
          uint16_t ledIndex = popcorn[i].pos;
 | 
			
		||||
          if (ledIndex < SEGLEN) SEGMENT.setPixelColor(indexToVStrip(ledIndex, stripNr), col);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (popcorn[i].pos >= 0.0f) { // draw now active popcorn (either active before or just popped)
 | 
			
		||||
      uint32_t col = SEGMENT.color_wheel(popcorn[i].colIndex);
 | 
			
		||||
      if (!SEGMENT.palette && popcorn[i].colIndex < NUM_COLORS) col = SEGCOLOR(popcorn[i].colIndex);
 | 
			
		||||
      
 | 
			
		||||
      uint16_t ledIndex = popcorn[i].pos;
 | 
			
		||||
      if (ledIndex < rows) {
 | 
			
		||||
        if (strip.isMatrix) SEGMENT.setPixelColorXY(uint16_t(popcorn[i].posX), rows - 1 - ledIndex, col);
 | 
			
		||||
        else                SEGMENT.setPixelColor(ledIndex, col);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  for (int stripNr=0; stripNr<strips; stripNr++)
 | 
			
		||||
    virtualStrip::runStrip(stripNr, &popcorn[stripNr * maxNumPopcorn]);
 | 
			
		||||
 | 
			
		||||
  return FRAMETIME;
 | 
			
		||||
}
 | 
			
		||||
static const char _data_FX_MODE_POPCORN[] PROGMEM = "Popcorn@!,!;!,!,!;!;1d,2d";
 | 
			
		||||
static const char _data_FX_MODE_POPCORN[] PROGMEM = "Popcorn@!,!;!,!,!;!;mp12=1,1d"; //bar
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//values close to 100 produce 5Hz flicker, which looks very candle-y
 | 
			
		||||
| 
						 | 
				
			
			@ -3375,91 +3373,84 @@ static const char _data_FX_MODE_EXPLODING_FIREWORKS[] PROGMEM = "Fireworks 1D@Gr
 | 
			
		|||
 */
 | 
			
		||||
uint16_t mode_drip(void)
 | 
			
		||||
{
 | 
			
		||||
  const uint16_t cols = strip.isMatrix ? SEGMENT.virtualWidth() : 1;
 | 
			
		||||
  const uint16_t rows = strip.isMatrix ? SEGMENT.virtualHeight() : SEGMENT.virtualLength();
 | 
			
		||||
 | 
			
		||||
  //allocate segment data
 | 
			
		||||
  uint8_t numDrops = 4; 
 | 
			
		||||
  uint16_t dataSize = sizeof(spark) * numDrops;
 | 
			
		||||
  if (!SEGENV.allocateData(dataSize * cols)) return mode_static(); //allocation failed
 | 
			
		||||
  uint16_t strips = SEGMENT.nrOfVStrips();
 | 
			
		||||
  const int maxNumDrops = 4; 
 | 
			
		||||
  uint16_t dataSize = sizeof(spark) * maxNumDrops;
 | 
			
		||||
  if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed
 | 
			
		||||
  Spark* drops = reinterpret_cast<Spark*>(SEGENV.data);
 | 
			
		||||
 | 
			
		||||
  SEGMENT.fill(SEGCOLOR(1));
 | 
			
		||||
  
 | 
			
		||||
  Spark* drops = reinterpret_cast<Spark*>(SEGENV.data);
 | 
			
		||||
  struct virtualStrip {
 | 
			
		||||
    static void runStrip(uint16_t stripNr, Spark* drops) {
 | 
			
		||||
 | 
			
		||||
  numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
 | 
			
		||||
      uint8_t numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3
 | 
			
		||||
 | 
			
		||||
  float gravity = -0.0005 - (SEGMENT.speed/50000.0);
 | 
			
		||||
  gravity *= rows-1;
 | 
			
		||||
  int sourcedrop = 12;
 | 
			
		||||
      float gravity = -0.0005 - (SEGMENT.speed/50000.0);
 | 
			
		||||
      gravity *= SEGLEN-1;
 | 
			
		||||
      int sourcedrop = 12;
 | 
			
		||||
 | 
			
		||||
  for (int k=0; k < cols; k++) {
 | 
			
		||||
    for (size_t j=0; j < numDrops; j++) {
 | 
			
		||||
      uint16_t idx = k*numDrops + j;
 | 
			
		||||
 | 
			
		||||
      if (drops[idx].colIndex == 0) { //init
 | 
			
		||||
        drops[idx].pos = rows-1;       // start at end
 | 
			
		||||
        drops[idx].vel = 0;           // speed
 | 
			
		||||
        drops[idx].col = sourcedrop;  // brightness
 | 
			
		||||
        drops[idx].colIndex = 1;      // drop state (0 init, 1 forming, 2 falling, 5 bouncing) 
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      uint32_t col = color_blend(BLACK, SEGCOLOR(0), sourcedrop);
 | 
			
		||||
      if (strip.isMatrix) SEGMENT.setPixelColorXY(k, 0, col);
 | 
			
		||||
      else                SEGMENT.setPixelColor(rows-1, col);// water source
 | 
			
		||||
 | 
			
		||||
      if (drops[idx].colIndex == 1) {
 | 
			
		||||
        if (drops[idx].col > 255) drops[idx].col = 255;
 | 
			
		||||
        col = color_blend(BLACK,SEGCOLOR(0),drops[idx].col);
 | 
			
		||||
        if (strip.isMatrix) SEGMENT.setPixelColorXY(k, rows - 1 - uint16_t(drops[idx].pos), col);
 | 
			
		||||
        else                SEGMENT.setPixelColor(uint16_t(drops[idx].pos), col);
 | 
			
		||||
        
 | 
			
		||||
        drops[idx].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling
 | 
			
		||||
        
 | 
			
		||||
        if (random8() < drops[idx].col/10) {   // random drop
 | 
			
		||||
          drops[idx].colIndex = 2;             //fall
 | 
			
		||||
          drops[idx].col = 255;
 | 
			
		||||
      for (int j=0;j<numDrops;j++) {
 | 
			
		||||
        if (drops[j].colIndex == 0) { //init
 | 
			
		||||
          drops[j].pos = SEGLEN-1;    // start at end
 | 
			
		||||
          drops[j].vel = 0;           // speed
 | 
			
		||||
          drops[j].col = sourcedrop;  // brightness
 | 
			
		||||
          drops[j].colIndex = 1;      // drop state (0 init, 1 forming, 2 falling, 5 bouncing)
 | 
			
		||||
        }
 | 
			
		||||
      }  
 | 
			
		||||
      if (drops[idx].colIndex > 1) {           // falling
 | 
			
		||||
        if (drops[idx].pos > 0) {              // fall until end of segment
 | 
			
		||||
          drops[idx].pos += drops[idx].vel;
 | 
			
		||||
          if (drops[idx].pos < 0) drops[idx].pos = 0;
 | 
			
		||||
          drops[idx].vel += gravity;           // gravity is negative
 | 
			
		||||
 | 
			
		||||
          for (int i = 1; i < 7 - drops[idx].colIndex; i++) { // some minor math so we don't expand bouncing droplets
 | 
			
		||||
            uint16_t pos = constrain(uint16_t(drops[idx].pos) +i, 0, rows-1); //this is BAD, returns a pos >= SEGLEN occasionally
 | 
			
		||||
            col = color_blend(BLACK, SEGCOLOR(0), drops[idx].col/i);
 | 
			
		||||
            if (strip.isMatrix) SEGMENT.setPixelColorXY(k, rows - 1 - pos, col);
 | 
			
		||||
            else                SEGMENT.setPixelColor(pos, col); //spread pixel with fade while falling
 | 
			
		||||
        SEGMENT.setPixelColor(indexToVStrip(SEGLEN-1, stripNr), color_blend(BLACK,SEGCOLOR(0), sourcedrop));// water source
 | 
			
		||||
        if (drops[j].colIndex==1) {
 | 
			
		||||
          if (drops[j].col>255) drops[j].col=255;
 | 
			
		||||
          SEGMENT.setPixelColor(indexToVStrip(uint16_t(drops[j].pos), stripNr), color_blend(BLACK,SEGCOLOR(0),drops[j].col));
 | 
			
		||||
 | 
			
		||||
          drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling
 | 
			
		||||
 | 
			
		||||
          if (random8() < drops[j].col/10) {               // random drop
 | 
			
		||||
            drops[j].colIndex=2;               //fall
 | 
			
		||||
            drops[j].col=255;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        if (drops[j].colIndex > 1) {           // falling
 | 
			
		||||
          if (drops[j].pos > 0) {              // fall until end of segment
 | 
			
		||||
            drops[j].pos += drops[j].vel;
 | 
			
		||||
            if (drops[j].pos < 0) drops[j].pos = 0;
 | 
			
		||||
            drops[j].vel += gravity;           // gravity is negative
 | 
			
		||||
 | 
			
		||||
          if (drops[idx].colIndex > 2) {         // during bounce, some water is on the floor
 | 
			
		||||
            col = color_blend(SEGCOLOR(0), BLACK, drops[idx].col);
 | 
			
		||||
            if (strip.isMatrix) SEGMENT.setPixelColorXY(k, rows - 1, col);
 | 
			
		||||
            else                SEGMENT.setPixelColor(0, col);
 | 
			
		||||
          }
 | 
			
		||||
        } else {                                 // we hit bottom
 | 
			
		||||
          if (drops[idx].colIndex > 2) {         // already hit once, so back to forming
 | 
			
		||||
            drops[idx].colIndex = 0;
 | 
			
		||||
            drops[idx].col = sourcedrop;
 | 
			
		||||
            
 | 
			
		||||
          } else {
 | 
			
		||||
            for (int i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets
 | 
			
		||||
              uint16_t pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally
 | 
			
		||||
              SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (drops[idx].colIndex == 2) {      // init bounce
 | 
			
		||||
              drops[idx].vel = -drops[idx].vel/4;// reverse velocity with damping 
 | 
			
		||||
              drops[idx].pos += drops[idx].vel;
 | 
			
		||||
            } 
 | 
			
		||||
            drops[idx].col = sourcedrop*2;
 | 
			
		||||
            drops[idx].colIndex = 5;             // bouncing
 | 
			
		||||
            if (drops[j].colIndex > 2) {       // during bounce, some water is on the floor
 | 
			
		||||
              SEGMENT.setPixelColor(indexToVStrip(0, stripNr), color_blend(SEGCOLOR(0),BLACK,drops[j].col));
 | 
			
		||||
            }
 | 
			
		||||
          } else {                             // we hit bottom
 | 
			
		||||
            if (drops[j].colIndex > 2) {       // already hit once, so back to forming
 | 
			
		||||
              drops[j].colIndex = 0;
 | 
			
		||||
              drops[j].col = sourcedrop;
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
 | 
			
		||||
              if (drops[j].colIndex==2) {      // init bounce
 | 
			
		||||
                drops[j].vel = -drops[j].vel/4;// reverse velocity with damping
 | 
			
		||||
                drops[j].pos += drops[j].vel;
 | 
			
		||||
              }
 | 
			
		||||
              drops[j].col = sourcedrop*2;
 | 
			
		||||
              drops[j].colIndex = 5;           // bouncing
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  for (int stripNr=0; stripNr<strips; stripNr++)
 | 
			
		||||
    virtualStrip::runStrip(stripNr, &drops[stripNr*maxNumDrops]);
 | 
			
		||||
 | 
			
		||||
  return FRAMETIME;
 | 
			
		||||
}
 | 
			
		||||
static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips;!,!;!;1d,2d";
 | 
			
		||||
static const char _data_FX_MODE_DRIP[] PROGMEM = "Drip@Gravity,# of drips;!,!;!;mp12=1,1d"; //bar
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -3493,7 +3484,7 @@ uint16_t mode_tetrix(void) {
 | 
			
		|||
      if (SEGENV.call == 0) {
 | 
			
		||||
        drop->stack = 0;                  // reset brick stack size
 | 
			
		||||
        drop->step = 0;
 | 
			
		||||
        //for (int i=0; i<SEGLEN; i++) SEGMENT.setPixelColor(i | int((stripNr+1)<<16), SEGCOLOR(1));  // will fill virtual strip only
 | 
			
		||||
        //for (int i=0; i<SEGLEN; i++) SEGMENT.setPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1));  // will fill virtual strip only
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      if (drop->step == 0) {              // init brick
 | 
			
		||||
| 
						 | 
				
			
			@ -3518,11 +3509,8 @@ uint16_t mode_tetrix(void) {
 | 
			
		|||
      if (drop->step == 2) {              // falling
 | 
			
		||||
        if (drop->pos > drop->stack) {    // fall until top of stack
 | 
			
		||||
          drop->pos -= drop->speed;       // may add gravity as: speed += gravity
 | 
			
		||||
          if (uint16_t(drop->pos) < drop->stack) drop->pos = drop->stack;
 | 
			
		||||
          for (int i=int(drop->pos); i<SEGLEN; i++) {
 | 
			
		||||
            uint32_t col = i<int(drop->pos)+drop->brick ? SEGMENT.color_from_palette(drop->col, false, false, 0) : SEGCOLOR(1);
 | 
			
		||||
            SEGMENT.setPixelColor(i | int((stripNr+1)<<16), col);
 | 
			
		||||
          }
 | 
			
		||||
          if (uint16_t(drop->pos) < drop->aux1) drop->pos = drop->aux1;
 | 
			
		||||
          for (int i=int(drop->pos); i<SEGLEN; i++) SEGMENT.setPixelColor(i | int((stripNr+1)<<16), i<int(drop->pos)+drop->aux0 ? drop->col : SEGCOLOR(1));
 | 
			
		||||
        } else {                          // we hit bottom
 | 
			
		||||
          drop->step = 0;                 // proceed with next brick, go back to init
 | 
			
		||||
          drop->stack += drop->brick;     // increase the stack size
 | 
			
		||||
| 
						 | 
				
			
			@ -3534,7 +3522,7 @@ uint16_t mode_tetrix(void) {
 | 
			
		|||
        drop->brick = 0;                  // reset brick size (no more growing)
 | 
			
		||||
        if (drop->step > millis()) {
 | 
			
		||||
          // allow fading of virtual strip
 | 
			
		||||
          for (int i=0; i<SEGLEN; i++) SEGMENT.blendPixelColor(i | int((stripNr+1)<<16), SEGCOLOR(1), 25); // 10% blend with Bg color
 | 
			
		||||
          for (int i=0; i<SEGLEN; i++) SEGMENT.blendPixelColor(i | int((stripNr+1)<<16), SEGCOLOR(1), 25); // 10% blend
 | 
			
		||||
        } else {
 | 
			
		||||
          drop->stack = 0;                // reset brick stack size
 | 
			
		||||
          drop->step = 0;                 // proceed with next brick
 | 
			
		||||
| 
						 | 
				
			
			@ -5931,7 +5919,6 @@ static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur;;;
 | 
			
		|||
#endif // WLED_DISABLE_2D
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef WLED_DISABLE_AUDIO
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
/********************     audio enhanced routines     ************************/
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -6258,7 +6245,7 @@ uint16_t mode_gravcentric(void) {                     // Gravcentric. By Andrew
 | 
			
		|||
 | 
			
		||||
  return FRAMETIME;
 | 
			
		||||
} // mode_gravcentric()
 | 
			
		||||
static const char _data_FX_MODE_GRAVCENTRIC[] PROGMEM = "Gravcentric@Rate of fall,Sensitivity;!;!;ix=128,mp12=2,ssim=0,1d,vo"; // Circle, Beatsin
 | 
			
		||||
static const char _data_FX_MODE_GRAVCENTRIC[] PROGMEM = "Gravcentric@Rate of fall,Sensitivity;!;!;ix=128,mp12=3,ssim=0,1d,vo"; // Corner, Beatsin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -6394,7 +6381,7 @@ uint16_t mode_midnoise(void) {                  // Midnoise. By Andrew Tuline.
 | 
			
		|||
 | 
			
		||||
  return FRAMETIME;
 | 
			
		||||
} // mode_midnoise()
 | 
			
		||||
static const char _data_FX_MODE_MIDNOISE[] PROGMEM = "Midnoise@Fade rate,Maximum length;,!;!;ix=128,mp12=2,ssim=0,1d,vo"; // Circle, Beatsin
 | 
			
		||||
static const char _data_FX_MODE_MIDNOISE[] PROGMEM = "Midnoise@Fade rate,Maximum length;,!;!;ix=128,mp12=1,ssim=0,1d,vo"; // Bar, Beatsin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -6519,7 +6506,7 @@ uint16_t mode_plasmoid(void) {                  // Plasmoid. By Andrew Tuline.
 | 
			
		|||
  }
 | 
			
		||||
  float   volumeSmth   = *(float*)  um_data->u_data[0];
 | 
			
		||||
 | 
			
		||||
  SEGMENT.fadeToBlackBy(64);
 | 
			
		||||
  SEGMENT.fadeToBlackBy(32);
 | 
			
		||||
 | 
			
		||||
  plasmoip->thisphase += beatsin8(6,-4,4);                          // You can change direction and speed individually.
 | 
			
		||||
  plasmoip->thatphase += beatsin8(7,-4,4);                          // Two phase values to make a complex pattern. By Andrew Tuline.
 | 
			
		||||
| 
						 | 
				
			
			@ -6615,11 +6602,6 @@ uint16_t mode_puddles(void) {                   // Puddles. By Andrew Tuline.
 | 
			
		|||
static const char _data_FX_MODE_PUDDLES[] PROGMEM = "Puddles@Fade rate,Puddle size;!,!;!;mp12=0,ssim=0,1d,vo"; // Pixels, Beatsin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
/********************       audio only routines       ************************/
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
#ifdef USERMOD_AUDIOREACTIVE
 | 
			
		||||
 | 
			
		||||
//////////////////////
 | 
			
		||||
//     * PIXELS     //
 | 
			
		||||
//////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -6671,7 +6653,8 @@ uint16_t mode_blurz(void) {                    // Blurz. By Andrew Tuline.
 | 
			
		|||
    SEGENV.aux0 = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SEGMENT.fade_out(SEGMENT.speed);
 | 
			
		||||
  int fadeoutDelay = (256 - SEGMENT.speed) / 32; 
 | 
			
		||||
  if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(SEGMENT.speed);
 | 
			
		||||
 | 
			
		||||
  SEGENV.step += FRAMETIME;
 | 
			
		||||
  if (SEGENV.step > SPEED_FORMULA_L) {
 | 
			
		||||
| 
						 | 
				
			
			@ -6739,7 +6722,9 @@ uint16_t mode_freqmap(void) {                   // Map FFT_MajorPeak to SEGLEN.
 | 
			
		|||
  float   my_magnitude  = *(float*)   um_data->u_data[5] / 4.0f; 
 | 
			
		||||
  if (FFT_MajorPeak < 1) FFT_MajorPeak = 1;                                         // log10(0) is "forbidden" (throws exception)
 | 
			
		||||
 | 
			
		||||
  SEGMENT.fade_out(SEGMENT.speed);
 | 
			
		||||
  if (SEGENV.call == 0) SEGMENT.fill(BLACK);
 | 
			
		||||
  int fadeoutDelay = (256 - SEGMENT.speed) / 32; 
 | 
			
		||||
  if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(SEGMENT.speed);
 | 
			
		||||
 | 
			
		||||
  int locn = (log10f((float)FFT_MajorPeak) - 1.78f) * (float)SEGLEN/(MAX_FREQ_LOG10 - 1.78f);  // log10 frequency range is from 1.78 to 3.71. Let's scale to SEGLEN.
 | 
			
		||||
  if (locn < 1) locn = 0; // avoid underflow
 | 
			
		||||
| 
						 | 
				
			
			@ -6754,7 +6739,7 @@ uint16_t mode_freqmap(void) {                   // Map FFT_MajorPeak to SEGLEN.
 | 
			
		|||
 | 
			
		||||
  return FRAMETIME;
 | 
			
		||||
} // mode_freqmap()
 | 
			
		||||
static const char _data_FX_MODE_FREQMAP[] PROGMEM = "Freqmap@Fade rate,Starting color;,!;!;mp12=2,ssim=0,1d,fr"; // Circle, Beatsin
 | 
			
		||||
static const char _data_FX_MODE_FREQMAP[] PROGMEM = "Freqmap@Fade rate,Starting color;,!;!;mp12=0,ssim=0,1d,fr"; // Pixels, Beatsin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -6809,7 +6794,7 @@ uint16_t mode_freqmatrix(void) {                // Freqmatrix. By Andreas Plesch
 | 
			
		|||
 | 
			
		||||
  return FRAMETIME;
 | 
			
		||||
} // mode_freqmatrix()
 | 
			
		||||
static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Time delay,Sound effect,Low bin,High bin,Sensivity;;;mp12=0,ssim=0,1d,fr"; // Pixels, Beatsin
 | 
			
		||||
static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Time delay,Sound effect,Low bin,High bin,Sensivity;;;mp12=3,ssim=0,1d,fr"; // Corner, Beatsin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -6830,7 +6815,10 @@ uint16_t mode_freqpixels(void) {                // Freqpixel. By Andrew Tuline.
 | 
			
		|||
  if (FFT_MajorPeak < 1) FFT_MajorPeak = 1;                                         // log10(0) is "forbidden" (throws exception)
 | 
			
		||||
 | 
			
		||||
  uint16_t fadeRate = 2*SEGMENT.speed - SEGMENT.speed*SEGMENT.speed/255;    // Get to 255 as quick as you can.
 | 
			
		||||
  SEGMENT.fade_out(fadeRate);
 | 
			
		||||
 | 
			
		||||
  if (SEGENV.call == 0) SEGMENT.fill(BLACK);
 | 
			
		||||
  int fadeoutDelay = (256 - SEGMENT.speed) / 64; 
 | 
			
		||||
  if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(fadeRate);
 | 
			
		||||
 | 
			
		||||
  for (int i=0; i < SEGMENT.intensity/32+1; i++) {
 | 
			
		||||
    uint16_t locn = random16(0,SEGLEN);
 | 
			
		||||
| 
						 | 
				
			
			@ -6962,7 +6950,7 @@ uint16_t mode_gravfreq(void) {                  // Gravfreq. By Andrew Tuline.
 | 
			
		|||
 | 
			
		||||
  return FRAMETIME;
 | 
			
		||||
} // mode_gravfreq()
 | 
			
		||||
static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sensivity;,!;!;ix=128,mp12=2,ssim=0,1d,fr"; // Circle, Beatsin
 | 
			
		||||
static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sensivity;,!;!;ix=128,mp12=0,ssim=0,1d,fr"; // Pixels, Beatsin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -6976,7 +6964,10 @@ uint16_t mode_noisemove(void) {                 // Noisemove.    By: Andrew Tuli
 | 
			
		|||
  }
 | 
			
		||||
  uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
 | 
			
		||||
 | 
			
		||||
  SEGMENT.fade_out(224);                                          // Just in case something doesn't get faded.
 | 
			
		||||
  if (SEGENV.call == 0) SEGMENT.fill(BLACK);
 | 
			
		||||
  //SEGMENT.fade_out(224);                                          // Just in case something doesn't get faded.
 | 
			
		||||
  int fadeoutDelay = (256 - SEGMENT.speed) / 96; 
 | 
			
		||||
  if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(4+ SEGMENT.speed/4);
 | 
			
		||||
 | 
			
		||||
  uint8_t numBins = map(SEGMENT.intensity,0,255,0,16);    // Map slider to fftResult bins.
 | 
			
		||||
  for (int i=0; i<numBins; i++) {                         // How many active bins are we using.
 | 
			
		||||
| 
						 | 
				
			
			@ -7002,13 +6993,16 @@ uint16_t mode_rocktaves(void) {                 // Rocktaves. Same note from eac
 | 
			
		|||
  float   FFT_MajorPeak = *(float*)  um_data->u_data[4];
 | 
			
		||||
  float   my_magnitude  = *(float*)   um_data->u_data[5] / 16.0f; 
 | 
			
		||||
 | 
			
		||||
  SEGMENT.fadeToBlackBy(64);                        // Just in case something doesn't get faded.
 | 
			
		||||
  if (SEGENV.call == 0) SEGMENT.fill(BLACK);
 | 
			
		||||
  SEGMENT.fadeToBlackBy(16);                        // Just in case something doesn't get faded.
 | 
			
		||||
 | 
			
		||||
  float frTemp = FFT_MajorPeak;
 | 
			
		||||
  uint8_t octCount = 0;                                   // Octave counter.
 | 
			
		||||
  uint8_t volTemp = 0;
 | 
			
		||||
 | 
			
		||||
  if (my_magnitude > 32) volTemp = 255;                 // We need to squelch out the background noise.
 | 
			
		||||
  volTemp = 32.0f + my_magnitude * 1.5f;                  // brightness = volume (overflows are handled in next lines)
 | 
			
		||||
  if (my_magnitude < 48) volTemp = 0;                     // We need to squelch out the background noise.
 | 
			
		||||
  if (my_magnitude > 144) volTemp = 255;                  // everything above this is full brightness
 | 
			
		||||
 | 
			
		||||
  while ( frTemp > 249 ) {
 | 
			
		||||
    octCount++;                                           // This should go up to 5.
 | 
			
		||||
| 
						 | 
				
			
			@ -7024,7 +7018,7 @@ uint16_t mode_rocktaves(void) {                 // Rocktaves. Same note from eac
 | 
			
		|||
 | 
			
		||||
  return FRAMETIME;
 | 
			
		||||
} // mode_rocktaves()
 | 
			
		||||
static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;,!;!;mp12=0,ssim=0,1d,fr"; // Pixels, Beatsin
 | 
			
		||||
static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;,!;!;mp12=1,ssim=0,1d,fr"; // Bar, Beatsin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -7108,10 +7102,13 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma.
 | 
			
		|||
    rippleTime = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SEGMENT.fadeToBlackBy(SEGMENT.speed);
 | 
			
		||||
  if (SEGENV.call == 0) SEGMENT.fill(BLACK);
 | 
			
		||||
  int fadeoutDelay = (256 - SEGMENT.speed) / 64; 
 | 
			
		||||
  if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(SEGMENT.speed);
 | 
			
		||||
 | 
			
		||||
  for (int x=0; x < cols; x++) {
 | 
			
		||||
    uint8_t  band       = map(x, 0, cols-1, 0, NUM_BANDS - 1);
 | 
			
		||||
    if (NUM_BANDS < 16) band = map(band, 0, NUM_BANDS - 1, 0, 15); // always use full range. comment out this line to get the previous behaviour.
 | 
			
		||||
    band = constrain(band, 0, 15);
 | 
			
		||||
    uint16_t colorIndex = band * 17;
 | 
			
		||||
    uint16_t barHeight  = map(fftResult[band], 0, 255, 0, rows); // do not subtract -1 from rows here
 | 
			
		||||
| 
						 | 
				
			
			@ -7193,14 +7190,7 @@ uint16_t mode_2DFunkyPlank(void) {              // Written by ??? Adapted by Wil
 | 
			
		|||
} // mode_2DFunkyPlank
 | 
			
		||||
static const char _data_FX_MODE_2DFUNKYPLANK[] PROGMEM = "Funky Plank@Scroll speed,,# of bands;;;ssim=0,2d,fr"; // Beatsin
 | 
			
		||||
 | 
			
		||||
#endif // WLED_DISABLE_2D
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//end audio only routines
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef WLED_DISABLE_2D
 | 
			
		||||
/////////////////////////
 | 
			
		||||
//     2D Akemi        //
 | 
			
		||||
/////////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -7305,7 +7295,6 @@ uint16_t mode_2DAkemi(void) {
 | 
			
		|||
static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Head palette,Arms & Legs,Eyes & Mouth;Face palette;ssim=0,2d,fr"; //beatsin
 | 
			
		||||
#endif // WLED_DISABLE_2D
 | 
			
		||||
 | 
			
		||||
#endif // WLED_DISABLE_AUDIO
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// mode data
 | 
			
		||||
| 
						 | 
				
			
			@ -7487,16 +7476,14 @@ void WS2812FX::setupEffectData() {
 | 
			
		|||
  addEffect(FX_MODE_2DMETABALLS, &mode_2Dmetaballs, _data_FX_MODE_2DMETABALLS);
 | 
			
		||||
  addEffect(FX_MODE_2DPULSER, &mode_2DPulser, _data_FX_MODE_2DPULSER);
 | 
			
		||||
  addEffect(FX_MODE_2DDRIFT, &mode_2DDrift, _data_FX_MODE_2DDRIFT);
 | 
			
		||||
 | 
			
		||||
  // --- 2D audio effects ---
 | 
			
		||||
  #ifndef WLED_DISABLE_AUDIO
 | 
			
		||||
  addEffect(FX_MODE_2DWAVERLY, &mode_2DWaverly, _data_FX_MODE_2DWAVERLY);
 | 
			
		||||
  addEffect(FX_MODE_2DSWIRL, &mode_2DSwirl, _data_FX_MODE_2DSWIRL);
 | 
			
		||||
  addEffect(FX_MODE_2DAKEMI, &mode_2DAkemi, _data_FX_MODE_2DAKEMI);
 | 
			
		||||
  #endif
 | 
			
		||||
  addEffect(FX_MODE_2DGEQ, &mode_2DGEQ, _data_FX_MODE_2DGEQ);
 | 
			
		||||
  addEffect(FX_MODE_2DFUNKYPLANK, &mode_2DFunkyPlank, _data_FX_MODE_2DFUNKYPLANK);
 | 
			
		||||
#endif // WLED_DISABLE_2D
 | 
			
		||||
 | 
			
		||||
#ifndef WLED_DISABLE_AUDIO
 | 
			
		||||
  // --- 1D audio effects ---
 | 
			
		||||
  addEffect(FX_MODE_PIXELWAVE, &mode_pixelwave, _data_FX_MODE_PIXELWAVE);
 | 
			
		||||
  addEffect(FX_MODE_JUGGLES, &mode_juggles, _data_FX_MODE_JUGGLES);
 | 
			
		||||
| 
						 | 
				
			
			@ -7511,29 +7498,15 @@ void WS2812FX::setupEffectData() {
 | 
			
		|||
  addEffect(FX_MODE_RIPPLEPEAK, &mode_ripplepeak, _data_FX_MODE_RIPPLEPEAK);
 | 
			
		||||
  addEffect(FX_MODE_GRAVCENTER, &mode_gravcenter, _data_FX_MODE_GRAVCENTER);
 | 
			
		||||
  addEffect(FX_MODE_GRAVCENTRIC, &mode_gravcentric, _data_FX_MODE_GRAVCENTRIC);
 | 
			
		||||
#endif // WLED_DISABLE_AUDIO
 | 
			
		||||
 | 
			
		||||
#ifdef USERMOD_AUDIOREACTIVE
 | 
			
		||||
  // --- WLED-SR audio reactive usermod only effects ---
 | 
			
		||||
  #ifdef WLED_DISABLE_AUDIO
 | 
			
		||||
    #error Incompatible options: WLED_DISABLE_AUDIO and USERMOD_AUDIOREACTIVE
 | 
			
		||||
  #endif
 | 
			
		||||
  #ifdef WLED_DISABLE_2D
 | 
			
		||||
    #error AUDIOREACTIVE usermod requires 2D support.
 | 
			
		||||
  #endif
 | 
			
		||||
  addEffect(FX_MODE_PIXELS, &mode_pixels, _data_FX_MODE_PIXELS);
 | 
			
		||||
  addEffect(FX_MODE_FREQWAVE, &mode_freqwave, _data_FX_MODE_FREQWAVE);
 | 
			
		||||
  addEffect(FX_MODE_FREQMATRIX, &mode_freqmatrix, _data_FX_MODE_FREQMATRIX);
 | 
			
		||||
  addEffect(FX_MODE_2DGEQ, &mode_2DGEQ, _data_FX_MODE_2DGEQ);
 | 
			
		||||
  addEffect(FX_MODE_WATERFALL, &mode_waterfall, _data_FX_MODE_WATERFALL);
 | 
			
		||||
  addEffect(FX_MODE_FREQPIXELS, &mode_freqpixels, _data_FX_MODE_FREQPIXELS);
 | 
			
		||||
  addEffect(FX_MODE_NOISEMOVE, &mode_noisemove, _data_FX_MODE_NOISEMOVE);
 | 
			
		||||
  addEffect(FX_MODE_FREQMAP, &mode_freqmap, _data_FX_MODE_FREQMAP);
 | 
			
		||||
  addEffect(FX_MODE_GRAVFREQ, &mode_gravfreq, _data_FX_MODE_GRAVFREQ);
 | 
			
		||||
  addEffect(FX_MODE_DJLIGHT, &mode_DJLight, _data_FX_MODE_DJLIGHT);
 | 
			
		||||
  addEffect(FX_MODE_2DFUNKYPLANK, &mode_2DFunkyPlank, _data_FX_MODE_2DFUNKYPLANK);
 | 
			
		||||
  addEffect(FX_MODE_BLURZ, &mode_blurz, _data_FX_MODE_BLURZ);
 | 
			
		||||
  addEffect(FX_MODE_ROCKTAVES, &mode_rocktaves, _data_FX_MODE_ROCKTAVES);
 | 
			
		||||
  //addEffect(FX_MODE_CUSTOMEFFECT, &mode_customEffect, _data_FX_MODE_CUSTOMEFFECT); //WLEDSR Custom Effects
 | 
			
		||||
#endif // USERMOD_AUDIOREACTIVE
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										96
									
								
								wled00/FX.h
								
								
								
								
							
							
						
						
									
										96
									
								
								wled00/FX.h
								
								
								
								
							| 
						 | 
				
			
			@ -275,67 +275,39 @@
 | 
			
		|||
  #define FX_MODE_2DMETABALLS            142 // non audio
 | 
			
		||||
  #define FX_MODE_2DPULSER               143 // non audio
 | 
			
		||||
  #define FX_MODE_2DDRIFT                144 // non audio
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef WLED_DISABLE_AUDIO
 | 
			
		||||
  #ifndef WLED_DISABLE_2D
 | 
			
		||||
    #define FX_MODE_2DWAVERLY              145 // audio enhanced
 | 
			
		||||
    #define FX_MODE_2DSWIRL                146 // audio enhanced
 | 
			
		||||
    #define FX_MODE_2DAKEMI                147 // audio enhanced
 | 
			
		||||
    // 148 & 149 reserved
 | 
			
		||||
  #endif
 | 
			
		||||
  #define FX_MODE_PIXELWAVE              150 // audio enhanced
 | 
			
		||||
  #define FX_MODE_JUGGLES                151 // audio enhanced
 | 
			
		||||
  #define FX_MODE_MATRIPIX               152 // audio enhanced
 | 
			
		||||
  #define FX_MODE_GRAVIMETER             153 // audio enhanced
 | 
			
		||||
  #define FX_MODE_PLASMOID               154 // audio enhanced
 | 
			
		||||
  #define FX_MODE_PUDDLES                155 // audio enhanced
 | 
			
		||||
  #define FX_MODE_MIDNOISE               156 // audio enhanced
 | 
			
		||||
  #define FX_MODE_NOISEMETER             157 // audio enhanced
 | 
			
		||||
  #define FX_MODE_NOISEFIRE              158 // audio enhanced
 | 
			
		||||
  #define FX_MODE_PUDDLEPEAK             159 // audio enhanced
 | 
			
		||||
  #define FX_MODE_RIPPLEPEAK             160 // audio enhanced
 | 
			
		||||
  #define FX_MODE_GRAVCENTER             161 // audio enhanced
 | 
			
		||||
  #define FX_MODE_GRAVCENTRIC            162 // audio enhanced
 | 
			
		||||
#endif
 | 
			
		||||
  #define FX_MODE_2DWAVERLY              145 // audio enhanced
 | 
			
		||||
  #define FX_MODE_2DSWIRL                146 // audio enhanced
 | 
			
		||||
  #define FX_MODE_2DAKEMI                147 // audio enhanced
 | 
			
		||||
  #define FX_MODE_2DGEQ                  148 // audio enhanced
 | 
			
		||||
  #define FX_MODE_2DFUNKYPLANK           149 // audio enhanced
 | 
			
		||||
#endif //WLED_DISABLE_2D
 | 
			
		||||
#define FX_MODE_PIXELWAVE              150 // audio enhanced
 | 
			
		||||
#define FX_MODE_JUGGLES                151 // audio enhanced
 | 
			
		||||
#define FX_MODE_MATRIPIX               152 // audio enhanced
 | 
			
		||||
#define FX_MODE_GRAVIMETER             153 // audio enhanced
 | 
			
		||||
#define FX_MODE_PLASMOID               154 // audio enhanced
 | 
			
		||||
#define FX_MODE_PUDDLES                155 // audio enhanced
 | 
			
		||||
#define FX_MODE_MIDNOISE               156 // audio enhanced
 | 
			
		||||
#define FX_MODE_NOISEMETER             157 // audio enhanced
 | 
			
		||||
#define FX_MODE_NOISEFIRE              158 // audio enhanced
 | 
			
		||||
#define FX_MODE_PUDDLEPEAK             159 // audio enhanced
 | 
			
		||||
#define FX_MODE_RIPPLEPEAK             160 // audio enhanced
 | 
			
		||||
#define FX_MODE_GRAVCENTER             161 // audio enhanced
 | 
			
		||||
#define FX_MODE_GRAVCENTRIC            162 // audio enhanced
 | 
			
		||||
#define FX_MODE_PIXELS                 163 // audio enhanced
 | 
			
		||||
#define FX_MODE_FREQWAVE               164 // audio enhanced
 | 
			
		||||
#define FX_MODE_FREQMATRIX             165 // audio enhanced
 | 
			
		||||
#define FX_MODE_WATERFALL              166 // audio enhanced
 | 
			
		||||
#define FX_MODE_FREQPIXELS             167 // audio enhanced
 | 
			
		||||
#define FX_MODE_BINMAP                 168 // audio enhanced
 | 
			
		||||
#define FX_MODE_NOISEMOVE              169 // audio enhanced
 | 
			
		||||
#define FX_MODE_FREQMAP                170 // audio enhanced
 | 
			
		||||
#define FX_MODE_GRAVFREQ               171 // audio enhanced
 | 
			
		||||
#define FX_MODE_DJLIGHT                172 // audio enhanced
 | 
			
		||||
#define FX_MODE_BLURZ                  173 // audio enhanced
 | 
			
		||||
#define FX_MODE_ROCKTAVES              174 // audio enhanced
 | 
			
		||||
 | 
			
		||||
#ifndef USERMOD_AUDIOREACTIVE
 | 
			
		||||
 | 
			
		||||
  #ifndef WLED_DISABLE_AUDIO
 | 
			
		||||
  #define MODE_COUNT                   163
 | 
			
		||||
  #else
 | 
			
		||||
    #ifndef WLED_DISABLE_2D
 | 
			
		||||
  #define MODE_COUNT                   145
 | 
			
		||||
    #else
 | 
			
		||||
  #define MODE_COUNT                   118
 | 
			
		||||
    #endif
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
  #ifdef WLED_DISABLE_AUDIO
 | 
			
		||||
    #error Incompatible options: WLED_DISABLE_AUDIO and USERMOD_AUDIOREACTIVE
 | 
			
		||||
  #endif
 | 
			
		||||
  #ifdef WLED_DISABLE_2D
 | 
			
		||||
    #error AUDIOREACTIVE usermod requires 2D support.
 | 
			
		||||
  #endif
 | 
			
		||||
  #define FX_MODE_2DGEQ                  148
 | 
			
		||||
  #define FX_MODE_2DFUNKYPLANK           149
 | 
			
		||||
  #define FX_MODE_PIXELS                 163
 | 
			
		||||
  #define FX_MODE_FREQWAVE               164
 | 
			
		||||
  #define FX_MODE_FREQMATRIX             165
 | 
			
		||||
  #define FX_MODE_WATERFALL              166
 | 
			
		||||
  #define FX_MODE_FREQPIXELS             167
 | 
			
		||||
  #define FX_MODE_BINMAP                 168
 | 
			
		||||
  #define FX_MODE_NOISEMOVE              169
 | 
			
		||||
  #define FX_MODE_FREQMAP                170
 | 
			
		||||
  #define FX_MODE_GRAVFREQ               171
 | 
			
		||||
  #define FX_MODE_DJLIGHT                172
 | 
			
		||||
  #define FX_MODE_BLURZ                  173
 | 
			
		||||
  #define FX_MODE_ROCKTAVES              174
 | 
			
		||||
  //#define FX_MODE_CUSTOMEFFECT           175 //WLEDSR Custom Effects
 | 
			
		||||
 | 
			
		||||
  #define MODE_COUNT                     175
 | 
			
		||||
#endif
 | 
			
		||||
#define MODE_COUNT                     175
 | 
			
		||||
 | 
			
		||||
typedef enum mapping1D2D {
 | 
			
		||||
  M12_Pixels = 0,
 | 
			
		||||
| 
						 | 
				
			
			@ -647,8 +619,6 @@ class WS2812FX {  // 96 bytes
 | 
			
		|||
  public:
 | 
			
		||||
 | 
			
		||||
    WS2812FX() :
 | 
			
		||||
      gammaCorrectBri(false),
 | 
			
		||||
      gammaCorrectCol(true),
 | 
			
		||||
      paletteFade(0),
 | 
			
		||||
      paletteBlend(0),
 | 
			
		||||
      milliampsPerLed(55),
 | 
			
		||||
| 
						 | 
				
			
			@ -747,8 +717,6 @@ class WS2812FX {  // 96 bytes
 | 
			
		|||
    inline void appendSegment(const Segment &seg = Segment()) { _segments.push_back(seg); }
 | 
			
		||||
 | 
			
		||||
    bool
 | 
			
		||||
      gammaCorrectBri,
 | 
			
		||||
      gammaCorrectCol,
 | 
			
		||||
      checkSegmentAlignment(void),
 | 
			
		||||
      hasRGBWBus(void),
 | 
			
		||||
      hasCCTBus(void),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -208,6 +208,7 @@ void Segment::setUpLeds() {
 | 
			
		|||
 | 
			
		||||
CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
 | 
			
		||||
  static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment
 | 
			
		||||
  static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR);
 | 
			
		||||
  byte tcp[72];
 | 
			
		||||
  if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0;
 | 
			
		||||
  if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -229,30 +230,31 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
 | 
			
		|||
      targetPalette = PartyColors_p; break;
 | 
			
		||||
    case 1: //periodically replace palette with a random one. Doesn't work with multiple FastLED segments
 | 
			
		||||
      if (millis() - _lastPaletteChange > 5000 /*+ ((uint32_t)(255-intensity))*100*/) {
 | 
			
		||||
        targetPalette = CRGBPalette16(
 | 
			
		||||
                        CHSV(random8(), 255, random8(128, 255)),
 | 
			
		||||
                        CHSV(random8(), 255, random8(128, 255)),
 | 
			
		||||
                        CHSV(random8(), 192, random8(128, 255)),
 | 
			
		||||
                        CHSV(random8(), 255, random8(128, 255)));
 | 
			
		||||
        randomPalette = CRGBPalette16(
 | 
			
		||||
                        CHSV(random8(), random8(160, 255), random8(128, 255)),
 | 
			
		||||
                        CHSV(random8(), random8(160, 255), random8(128, 255)),
 | 
			
		||||
                        CHSV(random8(), random8(160, 255), random8(128, 255)),
 | 
			
		||||
                        CHSV(random8(), random8(160, 255), random8(128, 255)));
 | 
			
		||||
        _lastPaletteChange = millis();
 | 
			
		||||
      } break;
 | 
			
		||||
      }
 | 
			
		||||
      targetPalette = randomPalette; break;
 | 
			
		||||
    case 2: {//primary color only
 | 
			
		||||
      CRGB prim = strip.gammaCorrectCol ? gamma32(colors[0]) : colors[0];
 | 
			
		||||
      CRGB prim = gamma32(colors[0]);
 | 
			
		||||
      targetPalette = CRGBPalette16(prim); break;}
 | 
			
		||||
    case 3: {//primary + secondary
 | 
			
		||||
      CRGB prim = strip.gammaCorrectCol ? gamma32(colors[0]) : colors[0];
 | 
			
		||||
      CRGB sec  = strip.gammaCorrectCol ? gamma32(colors[1]) : colors[1];
 | 
			
		||||
      CRGB prim = gamma32(colors[0]);
 | 
			
		||||
      CRGB sec  = gamma32(colors[1]);
 | 
			
		||||
      targetPalette = CRGBPalette16(prim,prim,sec,sec); break;}
 | 
			
		||||
    case 4: {//primary + secondary + tertiary
 | 
			
		||||
      CRGB prim = strip.gammaCorrectCol ? gamma32(colors[0]) : colors[0];
 | 
			
		||||
      CRGB sec  = strip.gammaCorrectCol ? gamma32(colors[1]) : colors[1];
 | 
			
		||||
      CRGB ter  = strip.gammaCorrectCol ? gamma32(colors[2]) : colors[2];
 | 
			
		||||
      CRGB prim = gamma32(colors[0]);
 | 
			
		||||
      CRGB sec  = gamma32(colors[1]);
 | 
			
		||||
      CRGB ter  = gamma32(colors[2]);
 | 
			
		||||
      targetPalette = CRGBPalette16(ter,sec,prim); break;}
 | 
			
		||||
    case 5: {//primary + secondary (+tert if not off), more distinct
 | 
			
		||||
      CRGB prim = strip.gammaCorrectCol ? gamma32(colors[0]) : colors[0];
 | 
			
		||||
      CRGB sec  = strip.gammaCorrectCol ? gamma32(colors[1]) : colors[1];
 | 
			
		||||
      CRGB prim = gamma32(colors[0]);
 | 
			
		||||
      CRGB sec  = gamma32(colors[1]);
 | 
			
		||||
      if (colors[2]) {
 | 
			
		||||
        CRGB ter = strip.gammaCorrectCol ? gamma32(colors[2]) : colors[2];
 | 
			
		||||
        CRGB ter = gamma32(colors[2]);
 | 
			
		||||
        targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,ter,ter,ter,ter,ter,prim);
 | 
			
		||||
      } else {
 | 
			
		||||
        targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,sec,sec,sec);
 | 
			
		||||
| 
						 | 
				
			
			@ -823,7 +825,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_
 | 
			
		|||
  // default palette or no RGB support on segment
 | 
			
		||||
  if ((palette == 0 && mcol < NUM_COLORS) || !(_capabilities & 0x01)) {
 | 
			
		||||
    uint32_t color = (transitional && _t) ? _t->_colorT[mcol] : colors[mcol];
 | 
			
		||||
    color = strip.gammaCorrectCol ? gamma32(color) : color;
 | 
			
		||||
    color = gamma32(color);
 | 
			
		||||
    if (pbri == 255) return color;
 | 
			
		||||
    return RGBW32(scale8_video(R(color),pbri), scale8_video(G(color),pbri), scale8_video(B(color),pbri), scale8_video(W(color),pbri));
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -302,10 +302,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
 | 
			
		|||
 | 
			
		||||
  float light_gc_bri = light["gc"]["bri"];
 | 
			
		||||
  float light_gc_col = light["gc"]["col"]; // 2.8
 | 
			
		||||
  if (light_gc_bri > 1.5) strip.gammaCorrectBri = true;
 | 
			
		||||
  else if (light_gc_bri > 0.5) strip.gammaCorrectBri = false;
 | 
			
		||||
  if (light_gc_col > 1.5) strip.gammaCorrectCol = true;
 | 
			
		||||
  else if (light_gc_col > 0.5) strip.gammaCorrectCol = false;
 | 
			
		||||
  if      (light_gc_bri > 1.5) gammaCorrectBri = true;
 | 
			
		||||
  else if (light_gc_bri > 0.5) gammaCorrectBri = false;
 | 
			
		||||
  if      (light_gc_col > 1.5) gammaCorrectCol = true;
 | 
			
		||||
  else if (light_gc_col > 0.5) gammaCorrectCol = false;
 | 
			
		||||
 | 
			
		||||
  JsonObject light_tr = light["tr"];
 | 
			
		||||
  CJSON(fadeTransition, light_tr["mode"]);
 | 
			
		||||
| 
						 | 
				
			
			@ -759,8 +759,8 @@ void serializeConfig() {
 | 
			
		|||
  light[F("aseg")] = autoSegments;
 | 
			
		||||
 | 
			
		||||
  JsonObject light_gc = light.createNestedObject("gc");
 | 
			
		||||
  light_gc["bri"] = (strip.gammaCorrectBri) ? 2.8 : 1.0;
 | 
			
		||||
  light_gc["col"] = (strip.gammaCorrectCol) ? 2.8 : 1.0;
 | 
			
		||||
  light_gc["bri"] = (gammaCorrectBri) ? 2.8 : 1.0;
 | 
			
		||||
  light_gc["col"] = (gammaCorrectCol) ? 2.8 : 1.0;
 | 
			
		||||
 | 
			
		||||
  JsonObject light_tr = light.createNestedObject("tr");
 | 
			
		||||
  light_tr["mode"] = fadeTransition;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -358,7 +358,7 @@ uint8_t gamma8(uint8_t b)
 | 
			
		|||
 | 
			
		||||
uint32_t gamma32(uint32_t color)
 | 
			
		||||
{
 | 
			
		||||
  //if (!strip.gammaCorrectCol) return color;
 | 
			
		||||
  if (!gammaCorrectCol) return color;
 | 
			
		||||
  uint8_t w = W(color);
 | 
			
		||||
  uint8_t r = R(color);
 | 
			
		||||
  uint8_t g = G(color);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -611,13 +611,13 @@ function parseInfo(i) {
 | 
			
		|||
		//gId("filter2D").classList.add("hide");
 | 
			
		||||
		hideModes("2D");
 | 
			
		||||
	}
 | 
			
		||||
	if (i.noaudio) {
 | 
			
		||||
		gId("filterVol").classList.add("hide");
 | 
			
		||||
		gId("filterFreq").classList.add("hide");
 | 
			
		||||
	}
 | 
			
		||||
//	if (i.noaudio) {
 | 
			
		||||
//		gId("filterVol").classList.add("hide");
 | 
			
		||||
//		gId("filterFreq").classList.add("hide");
 | 
			
		||||
//	}
 | 
			
		||||
//	if (!i.u || !i.u.AudioReactive) {
 | 
			
		||||
		//gId("filterVol").classList.add("hide"); hideModes(" ♪"); // hide volume reactive effects
 | 
			
		||||
		//gId("filterFreq").classList.add("hide"); hideModes(" ♫"); // hide frequency reactive effects
 | 
			
		||||
//		gId("filterVol").classList.add("hide"); hideModes(" ♪"); // hide volume reactive effects
 | 
			
		||||
//		gId("filterFreq").classList.add("hide"); hideModes(" ♫"); // hide frequency reactive effects
 | 
			
		||||
//	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -654,11 +654,11 @@ function populateInfo(i)
 | 
			
		|||
	}
 | 
			
		||||
	var vcn = "Kuuhaku";
 | 
			
		||||
	if (i.ver.startsWith("0.14.")) vcn = "Hoshi";
 | 
			
		||||
	if (i.ver.includes("-bl")) vcn = "Ryujin";
 | 
			
		||||
	if (i.cn) vcn = i.cn;
 | 
			
		||||
 | 
			
		||||
	cn += `v${i.ver} "${vcn}"<br><br><table>
 | 
			
		||||
${urows}
 | 
			
		||||
${urows===""?'':'<tr><td colspan=2><hr style="height:1px;border-width:0;color:gray;background-color:gray"></td></tr>'}
 | 
			
		||||
${inforow("Build",i.vid)}
 | 
			
		||||
${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")}
 | 
			
		||||
${inforow("Uptime",getRuntimeStr(i.uptime))}
 | 
			
		||||
| 
						 | 
				
			
			@ -714,7 +714,7 @@ function populateSegments(s)
 | 
			
		|||
		}
 | 
			
		||||
		let map2D = `<div id="seg${i}map2D" data-map="map2D" class="lbl-s hide">Expand 1D FX<br>
 | 
			
		||||
			<div class="sel-p"><select class="sel-p" id="seg${i}mp12" onchange="setMp12(${i})">
 | 
			
		||||
				<option value="0" ${inst.mp12==0?' selected':''}>Strip</option>
 | 
			
		||||
				<option value="0" ${inst.mp12==0?' selected':''}>Pixels</option>
 | 
			
		||||
				<option value="1" ${inst.mp12==1?' selected':''}>Bar</option>
 | 
			
		||||
				<option value="2" ${inst.mp12==2?' selected':''}>Arc</option>
 | 
			
		||||
				<option value="3" ${inst.mp12==3?' selected':''}>Corner</option>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -506,7 +506,6 @@ function populateInfo(i)
 | 
			
		|||
	}
 | 
			
		||||
	var vcn = "Kuuhaku";
 | 
			
		||||
	if (i.ver.startsWith("0.14.")) vcn = "Hoshi";
 | 
			
		||||
	if (i.ver.includes("-bl")) vcn = "Ryujin";
 | 
			
		||||
	if (i.cn) vcn = i.cn;
 | 
			
		||||
 | 
			
		||||
	cn += `v${i.ver} "${vcn}"<br><br><table>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1498
									
								
								wled00/html_other.h
								
								
								
								
							
							
						
						
									
										1498
									
								
								wled00/html_other.h
								
								
								
								
							
										
											
												Plik diff jest za duży
												Load Diff
											
										
									
								
							
							
								
								
									
										2233
									
								
								wled00/html_simple.h
								
								
								
								
							
							
						
						
									
										2233
									
								
								wled00/html_simple.h
								
								
								
								
							
										
											
												Plik diff jest za duży
												Load Diff
											
										
									
								
							
							
								
								
									
										3740
									
								
								wled00/html_ui.h
								
								
								
								
							
							
						
						
									
										3740
									
								
								wled00/html_ui.h
								
								
								
								
							
										
											
												Plik diff jest za duży
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -84,8 +84,8 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
 | 
			
		|||
 | 
			
		||||
  if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps
 | 
			
		||||
 | 
			
		||||
  seg.map1D2D  = map1D2D & 0x07;
 | 
			
		||||
  seg.soundSim = soundSim & 0x03;
 | 
			
		||||
  seg.map1D2D  = constrain(map1D2D, 0, 7);
 | 
			
		||||
  seg.soundSim = constrain(soundSim, 0, 7);
 | 
			
		||||
 | 
			
		||||
  uint16_t len = 1;
 | 
			
		||||
  if (stop > start) len = stop - start;
 | 
			
		||||
| 
						 | 
				
			
			@ -162,12 +162,12 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
 | 
			
		|||
  }
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  seg.selected  = elem["sel"]   | seg.selected;
 | 
			
		||||
  seg.reverse   = elem["rev"]   | seg.reverse;
 | 
			
		||||
  seg.mirror    = elem["mi"] | seg.mirror;
 | 
			
		||||
  seg.selected  = elem["sel"] | seg.selected;
 | 
			
		||||
  seg.reverse   = elem["rev"] | seg.reverse;
 | 
			
		||||
  seg.mirror    = elem["mi"]  | seg.mirror;
 | 
			
		||||
  #ifndef WLED_DISABLE_2D
 | 
			
		||||
  seg.reverse_y = elem["rY"] | seg.reverse_y;
 | 
			
		||||
  seg.mirror_y  = elem["mY"] | seg.mirror_y;
 | 
			
		||||
  seg.reverse_y = elem["rY"]  | seg.reverse_y;
 | 
			
		||||
  seg.mirror_y  = elem["mY"]  | seg.mirror_y;
 | 
			
		||||
  seg.transpose = elem[F("tp")] | seg.transpose;
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -190,8 +190,8 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
 | 
			
		|||
    sOpt = extractModeDefaults(fx, "c1");   if (sOpt >= 0) seg.custom1   = sOpt;
 | 
			
		||||
    sOpt = extractModeDefaults(fx, "c2");   if (sOpt >= 0) seg.custom2   = sOpt;
 | 
			
		||||
    sOpt = extractModeDefaults(fx, "c3");   if (sOpt >= 0) seg.custom3   = sOpt;
 | 
			
		||||
    sOpt = extractModeDefaults(fx, "mp12"); if (sOpt >= 0) seg.map1D2D   = sOpt & 0x07;
 | 
			
		||||
    sOpt = extractModeDefaults(fx, "ssim"); if (sOpt >= 0) seg.soundSim  = sOpt & 0x03;
 | 
			
		||||
    sOpt = extractModeDefaults(fx, "mp12"); if (sOpt >= 0) seg.map1D2D   = constrain(sOpt, 0, 7);
 | 
			
		||||
    sOpt = extractModeDefaults(fx, "ssim"); if (sOpt >= 0) seg.soundSim  = constrain(sOpt, 0, 7);
 | 
			
		||||
    sOpt = extractModeDefaults(fx, "rev");  if (sOpt >= 0) seg.reverse   = (bool)sOpt;
 | 
			
		||||
    sOpt = extractModeDefaults(fx, "mi");   if (sOpt >= 0) seg.mirror    = (bool)sOpt; // NOTE: setting this option is a risky business
 | 
			
		||||
    sOpt = extractModeDefaults(fx, "rY");   if (sOpt >= 0) seg.reverse_y = (bool)sOpt;
 | 
			
		||||
| 
						 | 
				
			
			@ -219,7 +219,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
 | 
			
		|||
  getVal(elem["c2"], &seg.custom2);
 | 
			
		||||
  uint8_t cust3 = seg.custom3;
 | 
			
		||||
  getVal(elem["c3"], &cust3); // we can't pass reference to bifield
 | 
			
		||||
  seg.custom3 = cust3;
 | 
			
		||||
  seg.custom3 = constrain(cust3, 0, 31);
 | 
			
		||||
 | 
			
		||||
  seg.check1 = elem["o1"] | seg.check1;
 | 
			
		||||
  seg.check2 = elem["o2"] | seg.check2;
 | 
			
		||||
| 
						 | 
				
			
			@ -265,12 +265,9 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        if (set < 2) stop = start + 1;
 | 
			
		||||
        uint32_t c = gamma32(RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
 | 
			
		||||
        for (int i = start; i < stop; i++) {
 | 
			
		||||
          if (strip.gammaCorrectCol) {
 | 
			
		||||
            seg.setPixelColor(i, gamma8(rgbw[0]), gamma8(rgbw[1]), gamma8(rgbw[2]), gamma8(rgbw[3]));
 | 
			
		||||
          } else {
 | 
			
		||||
            seg.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
 | 
			
		||||
          }
 | 
			
		||||
          seg.setPixelColor(i, c);
 | 
			
		||||
        }
 | 
			
		||||
        if (!set) start++;
 | 
			
		||||
        set = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -496,26 +493,26 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b
 | 
			
		|||
  strcat(colstr, "]");
 | 
			
		||||
  root["col"] = serialized(colstr);
 | 
			
		||||
 | 
			
		||||
  root["fx"]     = seg.mode;
 | 
			
		||||
  root["fx"]  = seg.mode;
 | 
			
		||||
  root["sx"]  = seg.speed;
 | 
			
		||||
  root["ix"]  = seg.intensity;
 | 
			
		||||
  root["pal"]    = seg.palette;
 | 
			
		||||
  root["pal"] = seg.palette;
 | 
			
		||||
  root["c1"]  = seg.custom1;
 | 
			
		||||
  root["c2"]  = seg.custom2;
 | 
			
		||||
  root["c3"]  = seg.custom3;
 | 
			
		||||
  root["sel"] = seg.isSelected();
 | 
			
		||||
  root["rev"]    = seg.reverse;
 | 
			
		||||
  root["rev"] = seg.reverse;
 | 
			
		||||
  root["mi"]  = seg.mirror;
 | 
			
		||||
  if (strip.isMatrix) {
 | 
			
		||||
    root["rY"] = seg.reverse_y;
 | 
			
		||||
    root["mY"] = seg.mirror_y;
 | 
			
		||||
    root[F("tp")] = seg.transpose;
 | 
			
		||||
  }
 | 
			
		||||
  root["o1"]  = seg.check1;
 | 
			
		||||
  root["o2"]  = seg.check2;
 | 
			
		||||
  root["o3"]  = seg.check3;
 | 
			
		||||
  root["ssim"]  = seg.soundSim;
 | 
			
		||||
  root["mp12"]  = seg.map1D2D;
 | 
			
		||||
  root["o1"]   = seg.check1;
 | 
			
		||||
  root["o2"]   = seg.check2;
 | 
			
		||||
  root["o3"]   = seg.check3;
 | 
			
		||||
  root["ssim"] = seg.soundSim;
 | 
			
		||||
  root["mp12"] = seg.map1D2D;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segmentBounds)
 | 
			
		||||
| 
						 | 
				
			
			@ -615,10 +612,6 @@ void serializeInfo(JsonObject root)
 | 
			
		|||
  leds[F("wv")]   = totalLC & 0x02;     // deprecated, true if white slider should be displayed for any segment
 | 
			
		||||
  leds["cct"]     = totalLC & 0x04;     // deprecated, use info.leds.lc
 | 
			
		||||
 | 
			
		||||
  #ifdef WLED_DISABLE_AUDIO
 | 
			
		||||
  root[F("noaudio")] = true;
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #ifdef WLED_DEBUG
 | 
			
		||||
  JsonArray i2c = root.createNestedArray(F("i2c"));
 | 
			
		||||
  i2c.add(i2c_sda);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -184,8 +184,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
 | 
			
		|||
    turnOnAtBoot = request->hasArg(F("BO"));
 | 
			
		||||
    t = request->arg(F("BP")).toInt();
 | 
			
		||||
    if (t <= 250) bootPreset = t;
 | 
			
		||||
    strip.gammaCorrectBri = request->hasArg(F("GB"));
 | 
			
		||||
    strip.gammaCorrectCol = request->hasArg(F("GC"));
 | 
			
		||||
    gammaCorrectBri = request->hasArg(F("GB"));
 | 
			
		||||
    gammaCorrectCol = request->hasArg(F("GC"));
 | 
			
		||||
 | 
			
		||||
    fadeTransition = request->hasArg(F("TF"));
 | 
			
		||||
    t = request->arg(F("TD")).toInt();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -564,7 +564,7 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
 | 
			
		|||
{
 | 
			
		||||
  uint16_t pix = i + arlsOffset;
 | 
			
		||||
  if (pix < strip.getLengthTotal()) {
 | 
			
		||||
    if (!arlsDisableGammaCorrection && strip.gammaCorrectCol) {
 | 
			
		||||
    if (!arlsDisableGammaCorrection && gammaCorrectCol) {
 | 
			
		||||
      r = gamma8(r);
 | 
			
		||||
      g = gamma8(g);
 | 
			
		||||
      b = gamma8(b);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -133,9 +133,6 @@
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USERMOD_AUDIOREACTIVE
 | 
			
		||||
  #ifdef WLED_DISABLE_AUDIO
 | 
			
		||||
    #error Incompatible options: WLED_DISABLE_AUDIO and USERMOD_AUDIOREACTIVE
 | 
			
		||||
  #endif
 | 
			
		||||
#include "../usermods/audioreactive/audio_reactive.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -260,9 +257,6 @@ void registerUsermods()
 | 
			
		|||
  #endif
 | 
			
		||||
  
 | 
			
		||||
  #ifdef USERMOD_AUDIOREACTIVE
 | 
			
		||||
    #ifdef WLED_DISABLE_AUDIO
 | 
			
		||||
      #error Incompatible options: WLED_DISABLE_AUDIO and USERMOD_AUDIOREACTIVE
 | 
			
		||||
    #endif
 | 
			
		||||
  usermods.add(new AudioReactive());
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -390,7 +390,6 @@ uint16_t crc16(const unsigned char* data_p, size_t length) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef WLED_DISABLE_AUDIO
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
// Begin simulateSound (to enable audio enhanced effects to display something)
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -402,7 +401,6 @@ typedef enum UM_SoundSimulations {
 | 
			
		|||
  UMS_14_3
 | 
			
		||||
} um_soundSimulations_t;
 | 
			
		||||
 | 
			
		||||
// this is still work in progress
 | 
			
		||||
um_data_t* simulateSound(uint8_t simulationId) 
 | 
			
		||||
{
 | 
			
		||||
  static uint8_t samplePeak;
 | 
			
		||||
| 
						 | 
				
			
			@ -507,7 +505,6 @@ um_data_t* simulateSound(uint8_t simulationId)
 | 
			
		|||
 | 
			
		||||
  return um_data;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void enumerateLedmaps() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
// version code in format yymmddb (b = daily build)
 | 
			
		||||
#define VERSION 2209020
 | 
			
		||||
#define VERSION 220950
 | 
			
		||||
 | 
			
		||||
//uncomment this if you have a "my_config.h" file you'd like to use
 | 
			
		||||
//#define WLED_USE_MY_CONFIG
 | 
			
		||||
| 
						 | 
				
			
			@ -287,9 +287,11 @@ WLED_GLOBAL byte bootPreset   _INIT(0);                   // save preset to load
 | 
			
		|||
//if true, a segment per bus will be created on boot and LED settings save
 | 
			
		||||
//if false, only one segment spanning the total LEDs is created,
 | 
			
		||||
//but not on LED settings save if there is more than one segment currently
 | 
			
		||||
WLED_GLOBAL bool autoSegments _INIT(false);
 | 
			
		||||
WLED_GLOBAL bool correctWB _INIT(false); //CCT color correction of RGB color
 | 
			
		||||
WLED_GLOBAL bool cctFromRgb _INIT(false); //CCT is calculated from RGB instead of using seg.cct
 | 
			
		||||
WLED_GLOBAL bool autoSegments    _INIT(false);
 | 
			
		||||
WLED_GLOBAL bool correctWB       _INIT(false); // CCT color correction of RGB color
 | 
			
		||||
WLED_GLOBAL bool cctFromRgb      _INIT(false); // CCT is calculated from RGB instead of using seg.cct
 | 
			
		||||
WLED_GLOBAL bool gammaCorrectCol _INIT(false); // use gamma correction on colors
 | 
			
		||||
WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness
 | 
			
		||||
 | 
			
		||||
WLED_GLOBAL byte col[]    _INIT_N(({ 255, 160, 0, 0 }));  // current RGB(W) primary color. col[] should be updated if you want to change the color.
 | 
			
		||||
WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 }));      // current RGB(W) secondary color
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -140,8 +140,8 @@ void loadSettingsFromEEPROM()
 | 
			
		|||
  ntpEnabled = EEPROM.read(327);
 | 
			
		||||
  currentTimezone = EEPROM.read(328);
 | 
			
		||||
  useAMPM = EEPROM.read(329);
 | 
			
		||||
  strip.gammaCorrectBri = EEPROM.read(330);
 | 
			
		||||
  strip.gammaCorrectCol = EEPROM.read(331);
 | 
			
		||||
  gammaCorrectBri = EEPROM.read(330);
 | 
			
		||||
  gammaCorrectCol = EEPROM.read(331);
 | 
			
		||||
  overlayCurrent = EEPROM.read(332);
 | 
			
		||||
 | 
			
		||||
  alexaEnabled = EEPROM.read(333);
 | 
			
		||||
| 
						 | 
				
			
			@ -414,10 +414,10 @@ void deEEP() {
 | 
			
		|||
          for (byte j = 0; j < numChannels; j++) colX.add(EEPROM.read(memloc + j));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        segObj["fx"]    = EEPROM.read(i+10);
 | 
			
		||||
        segObj["sx"] = EEPROM.read(i+11);
 | 
			
		||||
        segObj["ix"] = EEPROM.read(i+16);
 | 
			
		||||
        segObj["pal"]   = EEPROM.read(i+17);
 | 
			
		||||
        segObj["fx"]  = EEPROM.read(i+10);
 | 
			
		||||
        segObj["sx"]  = EEPROM.read(i+11);
 | 
			
		||||
        segObj["ix"]  = EEPROM.read(i+16);
 | 
			
		||||
        segObj["pal"] = EEPROM.read(i+17);
 | 
			
		||||
      } else {
 | 
			
		||||
        Segment* seg = strip.getSegments();
 | 
			
		||||
        memcpy(seg, EEPROM.getDataPtr() +i+2, 240);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -394,8 +394,8 @@ void getSettingsJS(byte subPage, char* dest)
 | 
			
		|||
    sappend('c',SET_F("BO"),turnOnAtBoot);
 | 
			
		||||
    sappend('v',SET_F("BP"),bootPreset);
 | 
			
		||||
 | 
			
		||||
    sappend('c',SET_F("GB"),strip.gammaCorrectBri);
 | 
			
		||||
    sappend('c',SET_F("GC"),strip.gammaCorrectCol);
 | 
			
		||||
    sappend('c',SET_F("GB"),gammaCorrectBri);
 | 
			
		||||
    sappend('c',SET_F("GC"),gammaCorrectCol);
 | 
			
		||||
    sappend('c',SET_F("TF"),fadeTransition);
 | 
			
		||||
    sappend('v',SET_F("TD"),transitionDelayDefault);
 | 
			
		||||
    sappend('c',SET_F("PF"),strip.paletteFade);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue