Merge branch 'MoonModules:mdev' into mdev

This commit is contained in:
tonyxforce
2023-08-24 21:12:01 +02:00
committed by GitHub
4 changed files with 189 additions and 80 deletions

View File

@@ -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.
Inline comments are OK if they describe that line only and are not exceedingly wide.

View File

@@ -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

View File

@@ -1,14 +1,15 @@
#pragma once
#include "wled.h"
#ifdef ARDUINO_ARCH_ESP32
#include <driver/i2s.h>
#include <driver/adc.h>
#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 <esp_timer.h>
#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(" /><div class=\"sliderdisplay\"></div></div></div>"); //<output class=\"sliderbubble\"></output>
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<bool>();
if (prevEnabled != enabled) onUpdateBegin(!enabled);
}
#ifdef ARDUINO_ARCH_ESP32
if (usermod[FPSTR(_inputLvl)].is<int>()) {
inputLevel = min(255,max(0,usermod[FPSTR(_inputLvl)].as<int>()));
}
#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,'<button onclick=\"location.href=&quot;https://mm.kno.wled.ge/soundreactive/Sound-Settings&quot;\" type=\"button\">?</button>');"));
#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,'<br> Sync audio data with other WLEDs');"));
oappend(SET_F("addInfo('AudioReactive:digitalmic:type',1,'<i>requires reboot!</i>');")); // 0 is field type, 1 is actual field
#ifdef ARDUINO_ARCH_ESP32
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',0,'<i>sd/data/dout</i>','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
}

View File

@@ -1,5 +1,5 @@
#pragma once
#ifdef ARDUINO_ARCH_ESP32
#include <Wire.h>
#include "wled.h"
#include <driver/i2s.h>
@@ -893,3 +893,4 @@ class SPH0654 : public I2SSource {
#endif
}
};
#endif