Skip to content

Conversation

@DedeHai
Copy link
Collaborator

@DedeHai DedeHai commented Jul 9, 2025

DRAFT, only for reference, this needs to go upstream to MM first.

uses DMA sampling in the background, not compatible with analog buttons.

Summary by CodeRabbit

  • New Features

    • Added support for analog microphone input on additional ESP32 variants (ESP32S2, ESP32C3, ESP32S3) using a new ADC sampling method.
    • The "Generic Analog" microphone option is now always available in the UI for all ESP32 boards.
  • Improvements

    • Unified and simplified configuration options for analog microphones across all ESP32 variants.
    • Enhanced reliability and performance for analog audio input on newer ESP32 boards.

DedeHai added 2 commits July 7, 2025 21:15
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 9, 2025

Walkthrough

The changes unify and extend analog microphone input support across ESP32, ESP32S2, ESP32C3, and ESP32S3 targets. A new DMAadcSource class is introduced for ADC audio sampling on newer ESP32 variants. Conditional compilation and runtime logic are updated to consistently handle analog mic configuration, type detection, and UI presentation for all ESP32 platforms.

Changes

File(s) Change Summary
usermods/audioreactive/audio_reactive.cpp Updated conditional logic and runtime handling for analog mic input, configuration, and UI on all ESP32 variants.
usermods/audioreactive/audio_source.h Renamed enum Type_I2SAdc to Type_Adc; added new DMAadcSource class for ADC DMA sampling on newer ESP32 chips.
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@DedeHai DedeHai marked this pull request as draft July 9, 2025 06:36
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
usermods/audioreactive/audio_source.h (3)

549-553: Consider removing commented-out code instead of keeping it.

Since analog sound input support is now being added for these MCU variants, these warnings are obsolete. Consider removing the commented lines entirely for cleaner code.

-//#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
-//#if !defined(SOC_I2S_SUPPORTS_ADC) && !defined(SOC_I2S_SUPPORTS_ADC_DAC)
-//  #warning this MCU does not support analog sound input
-//#endif
-//#endif

757-757: Address TODO: Use dynamic timeout calculation.

The hardcoded ADC_TIMEOUT of 30ms should be replaced with a dynamic calculation based on FFT_MIN_CYCLE as suggested in the TODO comment. This would ensure the timeout adapts to the configured FFT cycle time.

Consider moving the FFT_MIN_CYCLE definition before this file's inclusion in the cpp file, or pass the timeout as a parameter to the class.


855-859: Optimize DC offset removal for better performance.

The DC offset removal is currently performed using floating-point arithmetic. As noted in the TODO comment, this could be optimized using integer arithmetic on ESP32-C3 and ESP32-S2 for better performance.

Would you like me to implement the integer-based DC offset removal optimization for C3 and S2 targets?

usermods/audioreactive/audio_reactive.cpp (1)

395-397: Clarify the rationale for excluding ADC sources from the delay.

The comment mentions that the "delay trick" doesn't help for analog ADC, but it would be helpful to document why this is the case. Is this due to different timing characteristics of DMA-based ADC sampling versus I2S sampling?

Consider expanding the comment to explain the timing differences between I2S and ADC DMA sampling methods.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 929a5a8 and cfbb7da.

📒 Files selected for processing (2)
  • usermods/audioreactive/audio_reactive.cpp (5 hunks)
  • usermods/audioreactive/audio_source.h (5 hunks)
🧰 Additional context used
🧠 Learnings (1)
usermods/audioreactive/audio_reactive.cpp (2)
Learnt from: DedeHai
PR: wled/WLED#4750
File: usermods/audioreactive/audio_reactive.cpp:311-321
Timestamp: 2025-06-27T06:04:44.652Z
Learning: In WLED's AudioReactive usermod, FFT buffer memory (valFFT, windowFFT) is allocated once during initialization and never deallocated, following typical embedded system design where core functionality buffers persist for the application lifetime. Raw buffer pointers for aligned allocations don't need to be tracked in the current implementation since deallocation is never performed.
Learnt from: KrX3D
PR: wled/WLED#4585
File: usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h:121-136
Timestamp: 2025-04-27T09:37:28.415Z
Learning: Using PROGMEM for the seven-segment font array (umSSDRNumbers) in the WLED SSDR usermod causes compilation problems, so it should be left as a regular array.
🧬 Code Graph Analysis (1)
usermods/audioreactive/audio_reactive.cpp (1)
usermods/audioreactive/audio_source.h (6)
  • Type_Adc (587-587)
  • Type_Adc (800-800)
  • audioPin (589-645)
  • audioPin (589-589)
  • audioPin (802-824)
  • audioPin (802-802)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32_wrover)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (esp32dev_V4)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32c3dev)
  • GitHub Check: wled_build / Build Environments (esp32_eth)
  • GitHub Check: wled_build / Build Environments (esp32dev)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_compat)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_compat)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_160)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_compat)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_160)
  • GitHub Check: wled_build / Build Environments (nodemcuv2)
  • GitHub Check: wled_build / Build Environments (esp8266_2m)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_160)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full)
🔇 Additional comments (6)
usermods/audioreactive/audio_source.h (2)

143-143: LGTM! Consistent naming for ADC sources.

The rename from Type_I2SAdc to Type_Adc unifies the naming convention for all ADC audio sources, making the code more maintainable.


826-865: Robust error handling in sample acquisition.

The implementation correctly handles:

  • Partial frame returns from DMA
  • Buffer overflow detection and recovery
  • Invalid state recovery with ADC reset

Good defensive programming practice!

usermods/audioreactive/audio_reactive.cpp (4)

1176-1236: Well-structured platform-specific audio source selection.

The code correctly:

  • Falls through PDM case for S2/C3 targets (which don't support PDM)
  • Uses I2SAdcSource for classic ESP32
  • Uses DMAadcSource for S2/C3/S3 targets
  • Applies band-pass filtering consistently for analog inputs

1614-1614: Correct usage of unified ADC type.

The change to use Type_Adc is consistent with the enum rename and properly identifies all ADC audio sources.


1849-1851: Good validation of platform capabilities.

The code properly prevents selection of PDM mode on ESP32-S2 and ESP32-C3, which don't support PDM microphones. This prevents runtime errors from invalid configuration.


1886-1886: UI correctly reflects analog support for all ESP32 variants.

Now that analog input is supported on all ESP32 variants, the UI appropriately shows the "Generic Analog" option universally.

Comment on lines +1221 to +1236
#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
DEBUGSR_PRINTLN(F("AR: Analog Microphone (left channel only)."));
audioSource = new I2SAdcSource(SAMPLE_RATE, BLOCK_SIZE);
delay(100);
useBandPassFilter = true; // PDM bandpass filter seems to help for bad quality analog
if (audioSource) audioSource->initialize(audioPin);
break;
#else
// use ADC DMA on ESP32S2, ESP32C3, ESP32S3
DEBUGSR_PRINTLN(F("AR: Analog Microphone"));
audioSource = new DMAadcSource(SAMPLE_RATE, samplesFFT);
delay(10); // might help with proper initialization
useBandPassFilter = true; // PDM bandpass filter seems to help for bad quality analog
if (audioSource) audioSource->initialize(audioPin);
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Document the analog button incompatibility.

According to the PR objectives, the DMA sampling approach is incompatible with analog buttons. This important limitation should be documented in the code comments to prevent user confusion.

         case 0:
         default:
 #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
           DEBUGSR_PRINTLN(F("AR: Analog Microphone (left channel only)."));
           audioSource = new I2SAdcSource(SAMPLE_RATE, BLOCK_SIZE);
           delay(100);
           useBandPassFilter = true;  // PDM bandpass filter seems to help for bad quality analog
           if (audioSource) audioSource->initialize(audioPin);
           break;
 #else
         // use ADC DMA on ESP32S2, ESP32C3, ESP32S3
+          // WARNING: DMA ADC sampling is incompatible with analog buttons due to continuous ADC usage
           DEBUGSR_PRINTLN(F("AR: Analog Microphone"));
           audioSource = new DMAadcSource(SAMPLE_RATE, samplesFFT);
           delay(10); // might help with proper initialization
           useBandPassFilter = true;  // PDM bandpass filter seems to help for bad quality analog
           if (audioSource) audioSource->initialize(audioPin);
           break;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#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
DEBUGSR_PRINTLN(F("AR: Analog Microphone (left channel only)."));
audioSource = new I2SAdcSource(SAMPLE_RATE, BLOCK_SIZE);
delay(100);
useBandPassFilter = true; // PDM bandpass filter seems to help for bad quality analog
if (audioSource) audioSource->initialize(audioPin);
break;
#else
// use ADC DMA on ESP32S2, ESP32C3, ESP32S3
DEBUGSR_PRINTLN(F("AR: Analog Microphone"));
audioSource = new DMAadcSource(SAMPLE_RATE, samplesFFT);
delay(10); // might help with proper initialization
useBandPassFilter = true; // PDM bandpass filter seems to help for bad quality analog
if (audioSource) audioSource->initialize(audioPin);
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
DEBUGSR_PRINTLN(F("AR: Analog Microphone (left channel only)."));
audioSource = new I2SAdcSource(SAMPLE_RATE, BLOCK_SIZE);
delay(100);
useBandPassFilter = true; // PDM bandpass filter seems to help for bad quality analog
if (audioSource) audioSource->initialize(audioPin);
break;
#else
// use ADC DMA on ESP32S2, ESP32C3, ESP32S3
// WARNING: DMA ADC sampling is incompatible with analog buttons due to continuous ADC usage
DEBUGSR_PRINTLN(F("AR: Analog Microphone"));
audioSource = new DMAadcSource(SAMPLE_RATE, samplesFFT);
delay(10); // might help with proper initialization
useBandPassFilter = true; // PDM bandpass filter seems to help for bad quality analog
if (audioSource) audioSource->initialize(audioPin);
break;
🤖 Prompt for AI Agents
In usermods/audioreactive/audio_reactive.cpp around lines 1221 to 1236, add a
comment explaining that the DMAadcSource sampling method used for ESP32S2,
ESP32C3, and ESP32S3 targets is incompatible with analog buttons. This
documentation should be placed near the conditional code block where
DMAadcSource is instantiated to clearly inform users of this limitation and
prevent confusion.

@netmindz
Copy link
Member

netmindz commented Jul 9, 2025

Not a criticism, just curious as to why you have started with a pr against here Vs MM, was it just that you had already written this code and so sharing here for the benefit of others who might want to pick up before the updated AR mod gets applied here?

@DedeHai
Copy link
Collaborator Author

DedeHai commented Jul 9, 2025

I have problems working with MM: I can't compile unless I base it directly off of MM, but then I can not do any commits. If I make a branch in my fork of AC, it will give me lots of compile errors when I set base to MM. So I did the development in AC and thought I might as well do a draft PR to see the diff and what the rabbit has to say. MM PR is next.

@blazoncek
Copy link
Contributor

@netmindz it might be in best interest of WLED to expedite migrating MM's version of AR into upstream. If that is desired at all and if there is someone that will do the migration.

Otherwise the amount of differences will only grow with time making it more difficult to migrate with each commit.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Jul 9, 2025

now that I have a better grasp on AR code and @softhack007 is not available, I can take a stab at it. How would one go about this? cherry pick all the commits or is there a better way of grabbing the current state of only the AR files and merging them in?

I do however not approve of all features in MM AR, some are just too technical for the non-audio-people, like having 5 different FFT windows selectable at runtime for example. But that is easy to wrap in some #ifdefs

@blazoncek
Copy link
Contributor

I totally agree with you!

KIS - keep it simple
I would extend this to the code itself.

@DedeHai
Copy link
Collaborator Author

DedeHai commented Jul 9, 2025

I would be happy to do a sweeping cleanup of that code, but I do not want to step on anyones toes.

@netmindz
Copy link
Member

netmindz commented Jul 9, 2025

@netmindz it might be in best interest of WLED to expedite migrating MM's version of AR into upstream. If that is desired at all and if there is someone that will do the migration.

Otherwise the amount of differences will only grow with time making it more difficult to migrate with each commit.

It's basically a 3 step process

  1. Copy current MM version to here
  2. Hide experimental features
  3. Add back in the AC approach for the AR palettes

That's why I don't want any extra "downstream" features added to the version in this repo or otherwise we are adding more steps to the process

@netmindz
Copy link
Member

netmindz commented Jul 9, 2025

I have problems working with MM: I can't compile unless I base it directly off of MM, but then I can not do any commits. If I make a branch in my fork of AC, it will give me lots of compile errors when I set base to MM.

Let's try and jump on a call at some point and we can look at these issues together. I'm always swapping between the two

@DedeHai
Copy link
Collaborator Author

DedeHai commented Jul 9, 2025

It's basically a 3 step process

  1. Copy current MM version to here
  2. Hide experimental features
  3. Add back in the AC approach for the AR palettes

That's why I don't want any extra "downstream" features added to the version in this repo or otherwise we are adding more steps to the process

fully agree that there should only be one "upstream" version that gets features added.
Untangling the current state is a bit of a challenge. Copying the MM version will remove any git history, not fond of that. I'll check if I can do a merge of just the AR UM. Maybe git subtree is an option?

@netmindz
Copy link
Member

I agree in principle that we should use git as much as possible, however I fear that the commits might not be clean enough, so while in theory we can cherry-pick the commits, I think we might face some significant challenges.

This would of course be much simpler if we had out of tree usermods, should we perhaps split it out entirely making it a library rather than being in the source itself ?

@willmmiles
Copy link
Member

This would of course be much simpler if we had out of tree usermods, should we perhaps split it out entirely making it a library rather than being in the source itself ?

Theoretically, the current build scripts should already support this, though I haven't tested it fully: any lib_dep with a name starting with "wled-" should be treated the same as an in-tree usermod for the purposes of build flags and include paths and whatnot.

@willmmiles
Copy link
Member

Following up: I just tested it with a quick rip of the example usermod, seems like it works OK:

[env:esp32_wrover_usermods]
extends = env:esp32_wrover
custom_usermods = audioreactive
lib_deps = ${env:esp32_wrover.lib_deps}
  wled-usermod-example =  https://github.com/willmmiles/wled-usermod-example.git

..builds for me with two usermods reported by the validation script. (I'm out of town this weekend and can't test an upload, though.) Hope this helps!

@github-actions
Copy link

github-actions bot commented Nov 8, 2025

Hey! This pull request has been open for quite some time without any new comments now. It will be closed automatically in a week if no further activity occurs.
Thank you for contributing to WLED! ❤️

@github-actions github-actions bot added the stale This issue will be closed soon because of prolonged inactivity label Nov 8, 2025
@DedeHai DedeHai added the keep This issue will never become stale/closed automatically label Nov 8, 2025
@softhack007 softhack007 mentioned this pull request Nov 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement keep This issue will never become stale/closed automatically stale This issue will be closed soon because of prolonged inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants