From 5381119f9e6f4acfa6932150220c2be88e1dbed9 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 8 Oct 2024 19:00:59 +0200 Subject: [PATCH] AR: new input type 'None' for network receive only --- usermods/audioreactive/audio_reactive.h | 47 +++++++++++++++++-------- usermods/audioreactive/audio_source.h | 20 ++++++----- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 1c46e33a..a6fcbd7c 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -199,7 +199,6 @@ static uint8_t binNum = 8; // Used to select the bin for FFT based bea // 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 !) constexpr int BLOCK_SIZE = 128; // I2S buffer size (samples) // globals @@ -1083,6 +1082,11 @@ class AudioReactive : public Usermod { private: #ifdef ARDUINO_ARCH_ESP32 +// HUB75 workaround - audio receive only +#ifdef WLED_ENABLE_HUB75MATRIX +#undef SR_DMTYPE +#define SR_DMTYPE 254 // "network receive only" +#endif #ifndef AUDIOPIN int8_t audioPin = -1; #else @@ -1907,12 +1911,14 @@ class AudioReactive : public Usermod { #ifdef ARDUINO_ARCH_ESP32 - // Reset I2S peripheral for good measure + // Reset I2S peripheral for good measure - not needed in esp-idf v4.4.x and later. + #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 0) 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) delay(100); periph_module_reset(PERIPH_I2S0_MODULE); // not possible on -C3 #endif + #endif delay(100); // Give that poor microphone some time to setup. #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) @@ -2026,6 +2032,14 @@ class AudioReactive : public Usermod { if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); break; + case 255: // falls through + case 254: // dummy "network receive only" driver + if (audioSource) delete audioSource; + audioSource = nullptr; + disableSoundProcessing = true; + audioSyncEnabled = AUDIOSYNC_REC; // force udp sound receive mode + break; + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) // ADC over I2S is only possible on "classic" ESP32 case 0: @@ -2040,18 +2054,16 @@ class AudioReactive : public Usermod { } delay(250); // give microphone enough time to initialise - if (!audioSource) enabled = false; // audio failed to initialise + if (!audioSource && (dmType < 254)) enabled = false; // audio failed to initialise #endif - if (enabled) onUpdateBegin(false); // create FFT task, and initialize network + if (enabled) onUpdateBegin(false); // create FFT task, and initialize network #ifdef ARDUINO_ARCH_ESP32 - if (FFT_Task == nullptr) enabled = false; // FFT task creation failed + if (audioSource && FFT_Task == nullptr) enabled = false; // FFT task creation failed 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.")); - #else - USER_PRINTLN(F("AR: Failed to initialize sound input driver. Please check input PIN settings.")); - #endif + + if (dmType < 254) { USER_PRINTLN(F("AR: Failed to initialize sound input driver. Please check input PIN settings."));} + else { USER_PRINTLN(F("AR: No sound input driver configured - network receive only."));} disableSoundProcessing = true; } else { USER_PRINTLN(F("AR: sound input driver initialized successfully.")); @@ -2191,7 +2203,7 @@ class AudioReactive : public Usermod { if (audioSyncEnabled == AUDIOSYNC_REC) disableSoundProcessing = true; // make sure everything is disabled IF in audio Receive mode if (audioSyncEnabled == AUDIOSYNC_SEND) disableSoundProcessing = false; // keep running audio IF we're in audio Transmit mode #ifdef ARDUINO_ARCH_ESP32 - if (!audioSource->isInitialized()) { // no audio source + if (!audioSource || !audioSource->isInitialized()) { // no audio source disableSoundProcessing = true; if (audioSyncEnabled > AUDIOSYNC_SEND) useNetworkAudio = true; } @@ -2404,7 +2416,8 @@ class AudioReactive : public Usermod { if (FFT_Task) { vTaskResume(FFT_Task); connected(); // resume UDP - } else + } else { + if (audioSource) // WLEDMM only create FFT task if we have a valid audio source // xTaskCreatePinnedToCore( // xTaskCreate( // no need to "pin" this task to core #0 xTaskCreateUniversal( @@ -2416,9 +2429,10 @@ class AudioReactive : public Usermod { &FFT_Task // Task handle , 0 // Core where the task should run ); + } } micDataReal = 0.0f; // just to be sure - if (enabled) disableSoundProcessing = false; + if (enabled && audioSource) disableSoundProcessing = false; updateIsRunning = init; #if defined(ARDUINO_ARCH_ESP32) && defined(SR_DEBUG) @@ -2573,7 +2587,7 @@ class AudioReactive : public Usermod { } else { // error during audio source setup infoArr.add(F("not initialized")); - infoArr.add(F(" - check pin settings")); + if (dmType < 254) infoArr.add(F(" - check pin settings")); } } @@ -2880,6 +2894,11 @@ class AudioReactive : public Usermod { #endif oappend(SET_F("dd=addDropdown(ux,'digitalmic:type');")); + #if SR_DMTYPE==254 + oappend(SET_F("addOption(dd,'None - network receive only (⎌)',254);")); + #else + oappend(SET_F("addOption(dd,'None - network receive only',254);")); + #endif #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) #if SR_DMTYPE==0 oappend(SET_F("addOption(dd,'Generic Analog (⎌)',0);")); diff --git a/usermods/audioreactive/audio_source.h b/usermods/audioreactive/audio_source.h index 77111446..f78a3358 100644 --- a/usermods/audioreactive/audio_source.h +++ b/usermods/audioreactive/audio_source.h @@ -37,6 +37,8 @@ #define SRate_t int #endif +constexpr i2s_port_t AR_I2S_PORT = I2S_NUM_0; // I2S port to use (do not change ! I2S_NUM_1 possible but this has limitation -> no MCLK routing, no ADC support) + //#include //#include //#include @@ -326,7 +328,7 @@ class I2SSource : public AudioSource { //DEBUGSR_PRINTF("[AR] I2S: SD=%d, WS=%d, SCK=%d, MCLK=%d\n", i2ssdPin, i2swsPin, i2sckPin, mclkPin); - esp_err_t err = i2s_driver_install(I2S_NUM_0, &_config, 0, nullptr); + esp_err_t err = i2s_driver_install(AR_I2S_PORT, &_config, 0, nullptr); if (err != ESP_OK) { ERRORSR_PRINTF("AR: Failed to install i2s driver: %d\n", err); return; @@ -344,18 +346,18 @@ class I2SSource : public AudioSource { DEBUGSR_PRINTLN(F("AR: I2S#0 driver installed in SLAVE mode.")); } - err = i2s_set_pin(I2S_NUM_0, &_pinConfig); + err = i2s_set_pin(AR_I2S_PORT, &_pinConfig); if (err != ESP_OK) { ERRORSR_PRINTF("AR: Failed to set i2s pin config: %d\n", err); - i2s_driver_uninstall(I2S_NUM_0); // uninstall already-installed driver + i2s_driver_uninstall(AR_I2S_PORT); // uninstall already-installed driver return; } #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) - err = i2s_set_clk(I2S_NUM_0, _sampleRate, I2S_SAMPLE_RESOLUTION, I2S_CHANNEL_MONO); // set bit clocks. Also takes care of MCLK routing if needed. + err = i2s_set_clk(AR_I2S_PORT, _sampleRate, I2S_SAMPLE_RESOLUTION, I2S_CHANNEL_MONO); // set bit clocks. Also takes care of MCLK routing if needed. if (err != ESP_OK) { ERRORSR_PRINTF("AR: Failed to configure i2s clocks: %d\n", err); - i2s_driver_uninstall(I2S_NUM_0); // uninstall already-installed driver + i2s_driver_uninstall(AR_I2S_PORT); // uninstall already-installed driver return; } #endif @@ -364,7 +366,7 @@ class I2SSource : public AudioSource { virtual void deinitialize() { _initialized = false; - esp_err_t err = i2s_driver_uninstall(I2S_NUM_0); + esp_err_t err = i2s_driver_uninstall(AR_I2S_PORT); if (err != ESP_OK) { DEBUGSR_PRINTF("Failed to uninstall i2s driver: %d\n", err); return; @@ -385,7 +387,7 @@ class I2SSource : public AudioSource { I2S_datatype *newSamples = newSampleBuffer; // use global input buffer if (num_samples > I2S_SAMPLES_MAX) num_samples = I2S_SAMPLES_MAX; // protect the buffer from overflow - err = i2s_read(I2S_NUM_0, (void *)newSamples, num_samples * sizeof(I2S_datatype), &bytes_read, portMAX_DELAY); + err = i2s_read(AR_I2S_PORT, (void *)newSamples, num_samples * sizeof(I2S_datatype), &bytes_read, portMAX_DELAY); if (err != ESP_OK) { DEBUGSR_PRINTF("Failed to get samples: %d\n", err); return; @@ -1056,8 +1058,8 @@ class SPH0654 : public I2SSource { I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin); #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) // these registers are only existing in "classic" ESP32 - REG_SET_BIT(I2S_TIMING_REG(I2S_NUM_0), BIT(9)); - REG_SET_BIT(I2S_CONF_REG(I2S_NUM_0), I2S_RX_MSB_SHIFT); + REG_SET_BIT(I2S_TIMING_REG(AR_I2S_PORT), BIT(9)); + REG_SET_BIT(I2S_CONF_REG(AR_I2S_PORT), I2S_RX_MSB_SHIFT); #else #warning FIX ME! Please. #endif