diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 560a7097..b4fbef51 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,9 +20,16 @@ Good: ```cpp if (a == b) { doStuff(a); +} else { + doOtherStuff(b); } ``` +```cpp +if (a == b) doStuff(a); +``` + +less readable, but acceptable in some cases: ```cpp if (a == b) { @@ -30,9 +37,6 @@ if (a == b) } ``` -```cpp -if (a == b) doStuff(a); -``` There should always be a space between a keyword and its condition and between the condition and brace. Within the condition, no space should be between the paranthesis and variables. @@ -75,4 +79,4 @@ Good: There is no set character limit for a comment within a line, though as a rule of thumb you should wrap your comment if it exceeds the width of your editor window. -Inline comments are OK if they describe that line only and are not exceedingly wide. \ No newline at end of file +Inline comments are OK if they describe that line only and are not exceedingly wide. diff --git a/platformio.ini b/platformio.ini index d8b54d27..0622e9a3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -45,15 +45,16 @@ default_envs = ; esp32_4MB_S ;; experimental, optimized for speed - esp32_4MB_M ; recommended default + esp32_4MB_M ;; esp32 recommended default esp32_4MB_M_eth esp32_4MB_M_debug esp32_4MB_XL ; esp32_16MB_S ;; experimental, optimized for speed - esp32_16MB_M + esp32_16MB_M ;; esp32 recommended for boards with 16MB flash ; esp32_16MB_M_debug ; esp32_16MB_XL - esp8266_4MB_S + esp8266_2MB_S + esp8266_4MB_S ;; recommended for 8266 with audio sync esp8266_4MB_M wemos_shield_esp32_4MB_M ; wemos_shield_esp32_4MB_ICS4343x_M @@ -266,6 +267,7 @@ build_flags = -DVTABLES_IN_FLASH ; restrict to minimal mime-types -DMIMETYPE_MINIMAL + -D USERMOD_AUDIOREACTIVE lib_deps = #https://github.com/lorol/LITTLEFS.git @@ -1230,6 +1232,27 @@ build_flags = ${esp32_4MB_M_base.build_flags} ; RAM: [== ] 24.5% (used 80348 bytes from 327680 bytes) ; Flash: [======= ] 69.4% (used 1455233 bytes from 2097152 bytes) + +[env:esp8266_2MB_S] +extends = env:esp8266_2m +upload_speed = 460800 ;115200 +board_build.f_cpu = 160000000L ;; we want 160Mhz (default = 80Mhz) +build_flags = ${common.build_flags_esp8266} + -D WLED_RELEASE_NAME=esp8266_2MB_S + -D WLED_DISABLE_ALEXA + -D WLED_DISABLE_HUESYNC + -D WLED_DISABLE_ESPNOW ;; might help in case of WiFi connectivity problems + -D WLED_DISABLE_LOXONE ; FLASH 1272 bytes + ;; -D WLED_DISABLE_MQTT ; RAM 216 bytes; FLASH 16496 bytes + ;; -D WLED_DISABLE_INFRARED ;RAM 136 bytes; FLASH 24492 bytes + ; -D WLED_DISABLE_2D + ; -UWLED_USE_MY_CONFIG + ; -D WLED_DEBUG +; monitor_filters = esp8266_exception_decoder +;; lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation +; RAM: [====== ] 60.8% (used 49836 bytes from 81920 bytes) +; Flash: [======== ] 83.3% (used 869783 bytes from 1044464 bytes) + [env:esp8266_4MB_S] extends = env:d1_mini upload_speed = 460800 ;115200 @@ -1238,13 +1261,17 @@ build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=esp8266_4MB_S -D WLED_DISABLE_ALEXA -D WLED_DISABLE_HUESYNC + -D WLED_DISABLE_ESPNOW ;; might help in case of WiFi connectivity problems + -D WLED_DISABLE_LOXONE ; FLASH 1272 bytes + ;; -D WLED_DISABLE_MQTT ; RAM 216 bytes; FLASH 16496 bytes + ;; -D WLED_DISABLE_INFRARED ;RAM 136 bytes; FLASH 24492 bytes ; -D WLED_DISABLE_2D ; -UWLED_USE_MY_CONFIG ; -D WLED_DEBUG ; monitor_filters = esp8266_exception_decoder -; RAM: [====== ] 59.3% (used 48608 bytes from 81920 bytes) -; Flash: [======== ] 77.0% (used 804176 bytes from 1044464 bytes) - +;; lib_ignore = IRremoteESP8266 ; use with WLED_DISABLE_INFRARED for faster compilation +; RAM: [====== ] 60.8% (used 49824 bytes from 81920 bytes) +; Flash: [======== ] 83.3% (used 869779 bytes from 1044464 bytes) [env:esp8266_4MB_M] extends = env:d1_mini upload_speed = 460800 ;115200 @@ -1368,8 +1395,8 @@ lib_deps = ${esp8266.lib_deps} OneWire@~2.3.5 ; used for USERMOD_FOUR_LINE_DISPLAY and USERMOD_DALLASTEMPERATURE olikraus/U8g2 @ ^2.28.8 ; used for USERMOD_FOUR_LINE_DISPLAY ElectronicCats/MPU6050 @ 0.6.0 ; used for USERMOD_MPU6050_IMU -; RAM: [====== ] 62.4% (used 51092 bytes from 81920 bytes) -; Flash: [========= ] 85.5% (used 893056 bytes from 1044464 bytes) +; RAM: [====== ] 63.8% (used 52272 bytes from 81920 bytes) +; Flash: [========= ] 90.4% (used 944487 bytes from 1044464 bytes) [env:esp01_1MB_S] board = esp01_1m diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 75fbba23..ca364d10 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -1,14 +1,15 @@ #pragma once #include "wled.h" + +#ifdef ARDUINO_ARCH_ESP32 + #include #include -#ifndef ARDUINO_ARCH_ESP32 - #error This audio reactive usermod does not support the ESP8266. #endif -#if defined(WLED_DEBUG) || defined(SR_DEBUG) +#if defined(ARDUINO_ARCH_ESP32) && (defined(WLED_DEBUG) || defined(SR_DEBUG)) #include #endif @@ -85,6 +86,46 @@ #define PLOT_FLUSH() #endif +static volatile bool disableSoundProcessing = false; // if true, sound processing (FFT, filters, AGC) will be suspended. "volatile" as its shared between tasks. +static uint8_t audioSyncEnabled = 0; // bit field: bit 0 - send, bit 1 - receive (config value) +static bool udpSyncConnected = false; // UDP connection status -> true if connected to multicast group + +#define NUM_GEQ_CHANNELS 16 // number of frequency channels. Don't change !! + +// audioreactive variables +#ifdef ARDUINO_ARCH_ESP32 +static float micDataReal = 0.0f; // MicIn data with full 24bit resolution - lowest 8bit after decimal point +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) +static float sampleAgc = 0.0f; // Smoothed AGC sample +static uint8_t soundAgc = 0; // Automagic gain control: 0 - none, 1 - normal, 2 - vivid, 3 - lazy (config value) +#endif +static float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample +static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency +static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of peak frequency +static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay() +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 uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects + +// TODO: probably best not used by receive nodes +static float agcSensitivity = 128; // AGC sensitivity estimation, based on agc gain (multAgc). calculated by getSensitivity(). range 0..255 + +// user settable parameters for limitSoundDynamics() +static bool limiterOn = true; // bool: enable / disable dynamics limiter +static uint16_t attackTime = 50; // int: attack time in milliseconds. Default 0.08sec +static uint16_t decayTime = 300; // int: decay time in milliseconds. New default 300ms. Old default was 1.40sec + +// peak detection +#ifdef ARDUINO_ARCH_ESP32 +static void detectSamplePeak(void); // peak detection function (needs scaled FFT reasults in vReal[]) - no used for 8266 receive-only mode +#endif +static void autoResetPeak(void); // peak auto-reset function +static uint8_t maxVol = 31; // (was 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) + +#ifdef ARDUINO_ARCH_ESP32 + // use audio source class (ESP32 specific) #include "audio_source.h" constexpr i2s_port_t I2S_PORT = I2S_NUM_0; // I2S port to use (do not change !) @@ -102,14 +143,7 @@ static uint8_t inputLevel = 128; // UI slider value #else uint8_t sampleGain = SR_GAIN; // sample gain (config value) #endif -static uint8_t soundAgc = 1; // Automagic gain control: 0 - none, 1 - normal, 2 - vivid, 3 - lazy (config value) -static uint8_t audioSyncEnabled = 0; // bit field: bit 0 - send, bit 1 - receive (config value) -static bool udpSyncConnected = false; // UDP connection status -> true if connected to multicast group -// user settable parameters for limitSoundDynamics() -static bool limiterOn = true; // bool: enable / disable dynamics limiter -static uint16_t attackTime = 50; // int: attack time in milliseconds. Default 0.08sec -static uint16_t decayTime = 300; // int: decay time in milliseconds. New default 300ms. Old default was 1.40sec // user settable options for FFTResult scaling static uint8_t FFTScalingMode = 3; // 0 none; 1 optimized logarithmic; 2 optimized linear; 3 optimized sqare root #ifndef SR_FREQ_PROF @@ -139,7 +173,6 @@ const float agcSampleSmooth[AGC_NUM_PRESETS] = { 1/12.f, 1/6.f, 1/16.f}; // // AGC presets end 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. static uint8_t useInputFilter = 0; // enables low-cut filtering. Applies before FFT. //WLEDMM add experimental settings @@ -151,26 +184,11 @@ static uint8_t averageByRMS = true; // false: use mean val #endif static uint8_t freqDist = 0; // 0=old 1=rightshift mode -// audioreactive variables shared with FFT task -static float micDataReal = 0.0f; // MicIn data with full 24bit resolution - lowest 8bit after decimal point -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) -static float sampleAgc = 0.0f; // Smoothed AGC sample // variables used in effects -static float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample //static int16_t volumeRaw = 0; // either sampleRaw or rawSampleAgc depending on soundAgc //static float my_magnitude =0.0f; // FFT_Magnitude, scaled by multAgc -// 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 = 31; // (was 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 - // shared vars for debugging #ifdef MIC_LOGGER static volatile float micReal_min = 0.0f; // MicIn data min from last batch of samples @@ -193,7 +211,6 @@ void FFTcode(void * parameter); // audio processing task: read samples, run static void runMicFilter(uint16_t numSamples, float *sampleBuffer); // pre-filtering of raw samples (band-pass) static void postProcessFFTResults(bool noiseGateOpen, int numberOfChannels); // post-processing and post-amp of GEQ channels -#define NUM_GEQ_CHANNELS 16 // number of frequency channels. Don't change !! static TaskHandle_t FFT_Task = nullptr; @@ -249,10 +266,7 @@ static const float fftResultPink[MAX_PINK+1][NUM_GEQ_CHANNELS] = { */ // globals and FFT Output variables shared with animations -static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency -static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of peak frequency static float FFT_MajPeakSmth = 1.0f; // FFT: (peak) frequency, smooth -static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects #if defined(WLED_DEBUG) || defined(SR_DEBUG) || defined(SR_STATS) static float fftTaskCycle = 0; // avg cycle time for FFT task static float fftTime = 0; // avg time for single FFT @@ -870,6 +884,8 @@ static void detectSamplePeak(void) { } } +#endif + 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. @@ -878,7 +894,6 @@ static void autoResetPeak(void) { } } - //////////////////// // usermod class // //////////////////// @@ -887,6 +902,8 @@ static void autoResetPeak(void) { class AudioReactive : public Usermod { private: +#ifdef ARDUINO_ARCH_ESP32 + #ifndef AUDIOPIN int8_t audioPin = -1; #else @@ -928,7 +945,7 @@ class AudioReactive : public Usermod { #else int8_t mclkPin = MCLK_PIN; #endif - +#endif // new "V2" audiosync struct - 40 Bytes struct audioSyncPacket { char header[6]; // 06 Bytes @@ -974,6 +991,7 @@ class AudioReactive : public Usermod { 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 +#ifdef ARDUINO_ARCH_ESP32 // 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. @@ -982,11 +1000,11 @@ class AudioReactive : public Usermod { 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 +#endif // variables used in effects int16_t volumeRaw = 0; // either sampleRaw or rawSampleAgc depending on soundAgc float my_magnitude =0.0f; // FFT_Magnitude, scaled by multAgc - float agcSensitivity = 128; // AGC sensitivity estimation, based on agc gain (multAgc). calculated by getSensitivity(). range 0..255 float soundPressure = 0; // Sound Pressure estimation, based on microphone raw readings. 0 ->5db, 255 ->105db // used to feed "Info" Page @@ -1017,13 +1035,15 @@ class AudioReactive : public Usermod { if (disableSoundProcessing && (!udpSyncConnected || ((audioSyncEnabled & 0x02) == 0))) return; // no audio availeable #ifdef MIC_LOGGER // Debugging functions for audio input and sound processing. Comment out the values you want to see + PLOT_PRINT("volumeSmth:"); PLOT_PRINT(volumeSmth + 256.0f); PLOT_PRINT("\t"); // +256 to move above other lines + //PLOT_PRINT("volumeRaw:"); PLOT_PRINT(volumeRaw + 256.0f); PLOT_PRINT("\t"); // +256 to move above other lines + //PLOT_PRINT("samplePeak:"); PLOT_PRINT((samplePeak!=0) ? 128:0); PLOT_PRINT("\t"); + #ifdef ARDUINO_ARCH_ESP32 PLOT_PRINT("micMin:"); PLOT_PRINT(0.5f * micReal_min); PLOT_PRINT("\t"); // scaled down to 50%, for better readability PLOT_PRINT("micMax:"); PLOT_PRINT(0.5f * micReal_max); PLOT_PRINT("\t"); // scaled down to 50% //PLOT_PRINT("micAvg:"); PLOT_PRINT(0.5f * micReal_avg); PLOT_PRINT("\t"); // scaled down to 50% //PLOT_PRINT("micDC:"); PLOT_PRINT(0.5f * (micReal_min + micReal_max)/2.0f);PLOT_PRINT("\t"); // scaled down to 50% PLOT_PRINT("micReal:"); PLOT_PRINT(micDataReal + 256.0f); PLOT_PRINT("\t"); // +256 to move above other lines - PLOT_PRINT("volumeSmth:"); PLOT_PRINT(volumeSmth + 256.0f); PLOT_PRINT("\t"); // +256 to move above other lines - //PLOT_PRINT("volumeRaw:"); PLOT_PRINT(volumeRaw + 256.0f); PLOT_PRINT("\t"); // +256 to move above other lines PLOT_PRINT("DC_Level:"); PLOT_PRINT(micLev + 256.0f); PLOT_PRINT("\t"); // +256 to move above other lines // //PLOT_PRINT("filtmicMin:"); PLOT_PRINT(0.5f * micReal_min2); PLOT_PRINT("\t"); // scaled down to 50% // //PLOT_PRINT("filtmicMax:"); PLOT_PRINT(0.5f * micReal_max2); PLOT_PRINT("\t"); // scaled down to 50% @@ -1033,8 +1053,8 @@ class AudioReactive : public Usermod { //PLOT_PRINT("micIn:"); PLOT_PRINT(micIn); PLOT_PRINT("\t"); //PLOT_PRINT("sample:"); PLOT_PRINT(sample); PLOT_PRINT("\t"); //PLOT_PRINT("sampleMax:"); PLOT_PRINT(sampleMax); PLOT_PRINT("\t"); - //PLOT_PRINT("samplePeak:"); PLOT_PRINT((samplePeak!=0) ? 128:0); PLOT_PRINT("\t"); //PLOT_PRINT("multAgc:"); PLOT_PRINT(multAgc, 4); PLOT_PRINT("\t"); + #endif PLOT_PRINTLN(); PLOT_FLUSH(); #endif @@ -1090,6 +1110,7 @@ class AudioReactive : public Usermod { #endif // FFT_SAMPLING_LOG } // logAudio() +#ifdef ARDUINO_ARCH_ESP32 ////////////////////// // Audio Processing // @@ -1355,6 +1376,7 @@ class AudioReactive : public Usermod { scaledvalue = (scaledvalue - logMinSample) / (logMaxSample - logMinSample); // 0...1 return fminf(fmaxf(256.0*scaledvalue, 0), 255.0); // scaled value } +#endif /* Limits the dynamics of volumeSmth (= sampleAvg or sampleAgc). @@ -1387,7 +1409,6 @@ class AudioReactive : public Usermod { last_time = millis(); } - ////////////////////// // UDP Sound Sync // ////////////////////// @@ -1415,7 +1436,7 @@ class AudioReactive : public Usermod { last_connection_attempt = millis(); connected(); // try to start UDP } - +#ifdef ARDUINO_ARCH_ESP32 void transmitAudioData() { if (!udpSyncConnected) return; @@ -1443,12 +1464,12 @@ class AudioReactive : public Usermod { } return; } // transmitAudioData() - +#endif static bool isValidUdpSyncVersion(const char *header) { - return strncmp_P(header, PSTR(UDP_SYNC_HEADER), 6) == 0; + return strncmp_P(header, UDP_SYNC_HEADER, 6) == 0; } static bool isValidUdpSyncVersion_v1(const char *header) { - return strncmp_P(header, PSTR(UDP_SYNC_HEADER_v1), 6) == 0; + return strncmp_P(header, UDP_SYNC_HEADER_v1, 6) == 0; } void decodeAudioData(int packetSize, uint8_t *fftBuff) { @@ -1456,12 +1477,14 @@ class AudioReactive : public Usermod { // update samples for effects volumeSmth = fmaxf(receivedPacket->sampleSmth, 0.0f); volumeRaw = fmaxf(receivedPacket->sampleRaw, 0.0f); +#ifdef ARDUINO_ARCH_ESP32 // update internal samples sampleRaw = volumeRaw; sampleAvg = volumeSmth; rawSampleAgc = volumeRaw; sampleAgc = volumeSmth; - multAgc = 1.0f; + multAgc = 1.0f; +#endif // Only change samplePeak IF it's currently false. // If it's true already, then the animation still needs to respond. autoResetPeak(); @@ -1470,7 +1493,7 @@ class AudioReactive : public Usermod { if (samplePeak) timeOfPeak = millis(); //userVar1 = samplePeak; } - //These values are only available on the ESP32 + //These values are only computed by ESP32 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; @@ -1482,12 +1505,14 @@ class AudioReactive : public Usermod { // update samples for effects volumeSmth = fmaxf(receivedPacket->sampleAgc, 0.0f); volumeRaw = volumeSmth; // V1 format does not have "raw" AGC sample +#ifdef ARDUINO_ARCH_ESP32 // update internal samples sampleRaw = fmaxf(receivedPacket->sampleRaw, 0.0f); sampleAvg = fmaxf(receivedPacket->sampleAvg, 0.0f);; sampleAgc = volumeSmth; rawSampleAgc = volumeRaw; multAgc = 1.0f; +#endif // Only change samplePeak IF it's currently false. // If it's true already, then the animation still needs to respond. autoResetPeak(); @@ -1525,7 +1550,9 @@ class AudioReactive : public Usermod { packetSize = fftUdp.parsePacket(); #endif +#ifdef ARDUINO_ARCH_ESP32 if ((packetSize > 0) && ((packetSize < 5) || (packetSize > UDPSOUND_MAX_PACKET))) fftUdp.flush(); // discard invalid packets (too small or too big) +#endif if ((packetSize > 5) && (packetSize <= UDPSOUND_MAX_PACKET)) { static uint8_t fftUdpBuffer[UDPSOUND_MAX_PACKET+1] = { 0 }; // static buffer for receiving, to reuse the same memory and avoid heap fragmentation //DEBUGSR_PRINTLN("Received UDP Sync Packet"); @@ -1584,6 +1611,7 @@ class AudioReactive : public Usermod { um_data->u_type[4] = UMT_FLOAT; um_data->u_data[5] = &my_magnitude; // used (New) um_data->u_type[5] = UMT_FLOAT; +#ifdef ARDUINO_ARCH_ESP32 um_data->u_data[6] = &maxVol; // assigned in effect function from UI element!!! (Puddlepeak, Ripplepeak, Waterfall) um_data->u_type[6] = UMT_BYTE; um_data->u_data[7] = &binNum; // assigned in effect function from UI element!!! (Puddlepeak, Ripplepeak, Waterfall) @@ -1594,8 +1622,25 @@ class AudioReactive : public Usermod { um_data->u_type[9] = UMT_FLOAT; um_data->u_data[10] = &agcSensitivity; // used (New) um_data->u_type[10] = UMT_FLOAT; +#else + // ESP8266 + // See https://github.com/MoonModules/WLED/pull/60#issuecomment-1666972133 for explaination of these alternative sources of data + + um_data->u_data[6] = &maxVol; // assigned in effect function from UI element!!! (Puddlepeak, Ripplepeak, Waterfall) + um_data->u_type[6] = UMT_BYTE; + um_data->u_data[7] = &binNum; // assigned in effect function from UI element!!! (Puddlepeak, Ripplepeak, Waterfall) + um_data->u_type[7] = UMT_BYTE; + um_data->u_data[8] = &FFT_MajorPeak; // new - substitute for FFT_MajPeakSmth + um_data->u_type[8] = UMT_FLOAT; + um_data->u_data[9] = &volumeSmth; // used (New) - substitute for soundPressure + um_data->u_type[9] = UMT_FLOAT; + um_data->u_data[10] = &agcSensitivity; // used (New) - dummy value (128 => 50%) + um_data->u_type[10] = UMT_FLOAT; +#endif } +#ifdef ARDUINO_ARCH_ESP32 + // Reset I2S peripheral for good measure i2s_driver_uninstall(I2S_NUM_0); // E (696) I2S: i2s_driver_uninstall(2006): I2S port 0 has not installed #if !defined(CONFIG_IDF_TARGET_ESP32C3) @@ -1679,10 +1724,11 @@ class AudioReactive : public Usermod { delay(250); // give microphone enough time to initialise if (!audioSource) enabled = false; // audio failed to initialise - if (enabled) onUpdateBegin(false); // create FFT task if (FFT_Task == nullptr) enabled = false; // FFT task creation failed +#endif + if (enabled) onUpdateBegin(false); // create FFT task if (enabled) disableSoundProcessing = false; // all good - enable audio processing - +#ifdef ARDUINO_ARCH_ESP32 if((!audioSource) || (!audioSource->isInitialized())) { // audio source failed to initialize. Still stay "enabled", as there might be input arriving via UDP Sound Sync #ifdef WLED_DEBUG DEBUG_PRINTLN(F("AR: Failed to initialize sound input driver. Please check input PIN settings.")); @@ -1693,7 +1739,7 @@ class AudioReactive : public Usermod { } else { USER_PRINTLN(F("AR: sound input driver initialized successfully.")); } - +#endif // try to start UDP last_UDPTime = 0; receivedFormat = 0; @@ -1717,7 +1763,7 @@ class AudioReactive : public Usermod { } if (audioSyncPort > 0 && (audioSyncEnabled & 0x03)) { - #ifndef ESP8266 + #ifdef ARDUINO_ARCH_ESP32 udpSyncConnected = fftUdp.beginMulticast(IPAddress(239, 0, 0, 1), audioSyncPort); #else udpSyncConnected = fftUdp.beginMulticast(WiFi.localIP(), IPAddress(239, 0, 0, 1), audioSyncPort); @@ -1771,7 +1817,7 @@ class AudioReactive : public Usermod { #endif disableSoundProcessing = true; } else { - #ifdef WLED_DEBUG + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DEBUG) if ((disableSoundProcessing == true) && (audioSyncEnabled == 0) && audioSource->isInitialized()) { // we just switched to "enabled" DEBUG_PRINTLN("[AR userLoop] realtime mode ended - audio processing resumed."); DEBUG_PRINTF( " RealtimeMode = %d; RealtimeOverride = %d\n", int(realtimeMode), int(realtimeOverride)); @@ -1783,6 +1829,7 @@ class AudioReactive : public Usermod { if (audioSyncEnabled & 0x02) disableSoundProcessing = true; // make sure everything is disabled IF in audio Receive mode if (audioSyncEnabled & 0x01) disableSoundProcessing = false; // keep running audio IF we're in audio Transmit mode +#ifdef ARDUINO_ARCH_ESP32 if (!audioSource->isInitialized()) disableSoundProcessing = true; // no audio source @@ -1836,6 +1883,7 @@ class AudioReactive : public Usermod { } limitSampleDynamics(); } // if (!disableSoundProcessing) +#endif autoResetPeak(); // auto-reset sample peak after strip minShowDelay if (!udpSyncConnected) udpSamplePeak = false; // reset UDP samplePeak while UDP is unconnected @@ -1873,7 +1921,9 @@ class AudioReactive : public Usermod { volumeSmth =0.0f; volumeRaw =0; my_magnitude = 0.1; FFT_Magnitude = 0.01; FFT_MajorPeak = 2; +#ifdef ARDUINO_ARCH_ESP32 multAgc = 1; +#endif DEBUGSR_PRINTLN(F("AR loop(): UDP closed due to inactivity.")); } @@ -1886,6 +1936,7 @@ class AudioReactive : public Usermod { #endif // Info Page: keep max sample from last 5 seconds +#ifdef ARDUINO_ARCH_ESP32 if ((millis() - sampleMaxTimer) > CYCLE_SAMPLEMAX) { sampleMaxTimer = millis(); maxSample5sec = (0.15 * maxSample5sec) + 0.85 *((soundAgc) ? sampleAgc : sampleAvg); // reset, and start with some smoothing @@ -1893,14 +1944,25 @@ class AudioReactive : public Usermod { } else { if ((sampleAvg >= 1)) maxSample5sec = fmaxf(maxSample5sec, (soundAgc) ? rawSampleAgc : sampleRaw); // follow maximum volume } +#else // similar functionality for 8266 receive only - use VolumeSmth instead of raw sample data + if ((millis() - sampleMaxTimer) > CYCLE_SAMPLEMAX) { + sampleMaxTimer = millis(); + maxSample5sec = (0.15 * maxSample5sec) + 0.85 * volumeSmth; // reset, and start with some smoothing + if (volumeSmth < 1.0f) maxSample5sec = 0; // noise gate + if (maxSample5sec < 0.0f) maxSample5sec = 0; // avoid negative values + } else { + if (volumeSmth >= 1.0f) maxSample5sec = fmaxf(maxSample5sec, volumeRaw); // follow maximum volume + } +#endif +#ifdef ARDUINO_ARCH_ESP32 //UDP Microphone Sync - transmit mode if ((audioSyncEnabled & 0x01) && (millis() - lastTime > 20)) { // Only run the transmit code IF we're in Transmit mode transmitAudioData(); lastTime = millis(); } - +#endif } @@ -1912,6 +1974,7 @@ class AudioReactive : public Usermod { } +#ifdef ARDUINO_ARCH_ESP32 void onUpdateBegin(bool init) { #ifdef WLED_DEBUG @@ -1983,7 +2046,7 @@ class AudioReactive : public Usermod { } return false; } - +#endif //////////////////////////// // Settings and Info Page // @@ -1996,7 +2059,9 @@ class AudioReactive : public Usermod { */ void addToJsonInfo(JsonObject& root) { - char myStringBuffer[16]; // buffer for snprintf() +#ifdef ARDUINO_ARCH_ESP32 + char myStringBuffer[16]; // buffer for snprintf() - not used yet on 8266 +#endif JsonObject user = root["u"]; if (user.isNull()) user = root.createNestedObject("u"); @@ -2014,6 +2079,7 @@ class AudioReactive : public Usermod { infoArr.add(uiDomString); if (enabled) { +#ifdef ARDUINO_ARCH_ESP32 // Input Level Slider if (disableSoundProcessing == false) { // only show slider when audio processing is running if (soundAgc > 0) { @@ -2036,9 +2102,8 @@ class AudioReactive : public Usermod { uiDomString += F(" />
"); // infoArr.add(uiDomString); } - +#endif // The following can be used for troubleshooting user errors and is so not enclosed in #ifdef WLED_DEBUG - // current Audio input infoArr = user.createNestedArray(F("Audio Source")); if (audioSyncEnabled & 0x02) { @@ -2052,6 +2117,11 @@ class AudioReactive : public Usermod { } else { infoArr.add(F(" - no connection")); } +#ifndef ARDUINO_ARCH_ESP32 // substitute for 8266 + } else { + infoArr.add(F("sound sync Off")); + } +#else // ESP32 only } else { // Analog or I2S digital input if (audioSource && (audioSource->isInitialized())) { @@ -2099,7 +2169,7 @@ class AudioReactive : public Usermod { infoArr.add(roundf(multAgc*100.0f) / 100.0f); infoArr.add("x"); } - +#endif // UDP Sound Sync status infoArr = user.createNestedArray(F("UDP Sound Sync")); if (audioSyncEnabled) { @@ -2118,6 +2188,7 @@ class AudioReactive : public Usermod { } #if defined(WLED_DEBUG) || defined(SR_DEBUG) || defined(SR_STATS) + #ifdef ARDUINO_ARCH_ESP32 infoArr = user.createNestedArray(F("I2S cycle time")); infoArr.add(roundf(fftTaskCycle)/100.0f); infoArr.add(" ms"); @@ -2139,6 +2210,7 @@ class AudioReactive : public Usermod { DEBUGSR_PRINTF("AR Sampling time : %5.2f ms\n", roundf(sampleTime)/100.0f); DEBUGSR_PRINTF("AR FFT time : %5.2f ms\n", roundf(fftTime)/100.0f); #endif + #endif } } @@ -2172,9 +2244,11 @@ class AudioReactive : public Usermod { enabled = usermod[FPSTR(_enabled)].as(); if (prevEnabled != enabled) onUpdateBegin(!enabled); } +#ifdef ARDUINO_ARCH_ESP32 if (usermod[FPSTR(_inputLvl)].is()) { inputLevel = min(255,max(0,usermod[FPSTR(_inputLvl)].as())); } +#endif } } @@ -2218,7 +2292,7 @@ class AudioReactive : public Usermod { { JsonObject top = root.createNestedObject(FPSTR(_name)); top[FPSTR(_enabled)] = enabled; - +#ifdef ARDUINO_ARCH_ESP32 #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) JsonObject amic = top.createNestedObject(FPSTR(_analogmic)); amic["pin"] = audioPin; @@ -2244,16 +2318,16 @@ class AudioReactive : public Usermod { poweruser[F("micLev")] = micLevelMethod; poweruser[F("freqDist")] = freqDist; poweruser[F("freqRMS")] = averageByRMS; - + + JsonObject freqScale = top.createNestedObject("frequency"); + freqScale[F("scale")] = FFTScalingMode; + freqScale[F("profile")] = pinkIndex; //WLEDMM +#endif JsonObject dynLim = top.createNestedObject("dynamics"); dynLim[F("limiter")] = limiterOn; dynLim[F("rise")] = attackTime; dynLim[F("fall")] = decayTime; - JsonObject freqScale = top.createNestedObject("frequency"); - freqScale[F("scale")] = FFTScalingMode; - freqScale[F("profile")] = pinkIndex; //WLEDMM - JsonObject sync = top.createNestedObject("sync"); sync[F("port")] = audioSyncPort; sync[F("mode")] = audioSyncEnabled; @@ -2281,7 +2355,7 @@ class AudioReactive : public Usermod { bool configComplete = !top.isNull(); configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled); - +#ifdef ARDUINO_ARCH_ESP32 #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) configComplete &= getJsonValue(top[FPSTR(_analogmic)]["pin"], audioPin); #else @@ -2316,13 +2390,13 @@ class AudioReactive : public Usermod { configComplete &= getJsonValue(top["experiments"][F("freqDist")], freqDist); configComplete &= getJsonValue(top["experiments"][F("freqRMS")], averageByRMS); + configComplete &= getJsonValue(top["frequency"][F("scale")], FFTScalingMode); + configComplete &= getJsonValue(top["frequency"][F("profile")], pinkIndex); //WLEDMM +#endif configComplete &= getJsonValue(top["dynamics"][F("limiter")], limiterOn); configComplete &= getJsonValue(top["dynamics"][F("rise")], attackTime); configComplete &= getJsonValue(top["dynamics"][F("fall")], decayTime); - configComplete &= getJsonValue(top["frequency"][F("scale")], FFTScalingMode); - configComplete &= getJsonValue(top["frequency"][F("profile")], pinkIndex); //WLEDMM - configComplete &= getJsonValue(top["sync"][F("port")], audioSyncPort); configComplete &= getJsonValue(top["sync"][F("mode")], audioSyncEnabled); @@ -2333,7 +2407,7 @@ class AudioReactive : public Usermod { void appendConfigData() { oappend(SET_F("addInfo('AudioReactive:help',0,'');")); - +#ifdef ARDUINO_ARCH_ESP32 //WLEDMM: add defaults #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) // -S3/-S2/-C3 don't support analog audio #ifdef AUDIOPIN @@ -2489,15 +2563,17 @@ class AudioReactive : public Usermod { oappend(SET_F("addOption(dd,'userdefined #2',9);")); #endif oappend(SET_F("addInfo('AudioReactive:frequency:profile',1,'☾');")); - +#endif oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');")); oappend(SET_F("addOption(dd,'Off',0);")); +#ifdef ARDUINO_ARCH_ESP32 oappend(SET_F("addOption(dd,'Send',1);")); +#endif oappend(SET_F("addOption(dd,'Receive',2);")); oappend(SET_F("addInfo('AudioReactive:sync:mode',1,'
Sync audio data with other WLEDs');")); oappend(SET_F("addInfo('AudioReactive:digitalmic:type',1,'requires reboot!');")); // 0 is field type, 1 is actual field - +#ifdef ARDUINO_ARCH_ESP32 oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',0,'sd/data/dout','I2S SD');")); #ifdef I2S_SDPIN oappend(SET_F("xOpt('AudioReactive:digitalmic:pin[]',0,' ⎌',")); oappendi(I2S_SDPIN); oappend(");"); @@ -2537,6 +2613,7 @@ class AudioReactive : public Usermod { oappend(SET_F("xOpt('AudioReactive:digitalmic:pin[]',5,' ⎌',")); oappendi(ES7243_SCLPIN); oappend(");"); #endif oappend(SET_F("dRO('AudioReactive:digitalmic:pin[]',5);")); // disable read only pins +#endif } diff --git a/usermods/audioreactive/audio_source.h b/usermods/audioreactive/audio_source.h index e02c3107..3c257d78 100644 --- a/usermods/audioreactive/audio_source.h +++ b/usermods/audioreactive/audio_source.h @@ -1,5 +1,5 @@ #pragma once - +#ifdef ARDUINO_ARCH_ESP32 #include #include "wled.h" #include @@ -893,3 +893,4 @@ class SPH0654 : public I2SSource { #endif } }; +#endif \ No newline at end of file