Skip to content

soundmodule on a classic ESP32: the engine's Reverb can't keep up at 48 kHz #44

Closed
PyDevices/micropython-pydevices
#375

Description

@bdbarnett

On an ESP32 (Ai-Thinker ESP32-Audio-Kit V2.2, classic ESP32 with PSRAM), `soundmodule.engine.Module(48000, 2, bank=...)` plays with its default effects (Reverb on and chorus off, as on any board), and the output has a gap about every 10 ms. With `effects=False` the same notes play clean.

What was run: firmware with audioeffects' chorus and reverb, audioinstruments' `soundfont`, and soundmodule and midiports frozen. A one-sample sine SoundFont, seven notes 800 ms apart on channel 1, played through the board config's `audio_out(AudioFormat(48000, 2, 16))` while the main loop called `out.service()` every 5 ms. The speaker was recorded on a USB microphone.

Run Dropouts the analyzer counted What the waveform shows
`effects=False` 0 a steady sine
default (Reverb) 3 a gap about every 10 ms in the tone
default, `latency="buffered"` 4 the same gaps

The main thread spent 565 ms of 9 s in `out.service()` with the Reverb, and 428 ms without, so the main loop isn't what falls behind. The Reverb's render in the audio pump doesn't keep up at 48 kHz on this chip, and a bigger output buffer doesn't help.

So midiEngine on a classic ESP32 stutters with its defaults. Ways out could be a lighter reverb on a board this size, a lower rate there, or Reverb off by default where the chip can't carry it.

Activity

  1. bdbarnett commented on Nov 10, 2026

    @bdbarnett
    ContributorAuthor

    The Reverb's tank took 4.7 ms of each 5.3 ms block at 48 kHz on a 160 MHz ESP32, and with the voices beside it the pump fell behind. Two changes fix it on the Audio Kit: PyDevices/audiodsp#399 compiles the tank at -O2 in size-optimised firmware (bit-exact, 4.0 ms at 160 MHz), and PyDevices/micropython-pydevices#374 boots the Audio Kit at 240 MHz (Reverb about 3.6 ms per block). With both, the seven-note run from this issue records 0 dropouts with the Reverb on. Other classic ESP32 builds that stay at 160 MHz can call machine.freq(240000000) before starting the synth.

  2. bdbarnett commented on Nov 10, 2026

    @bdbarnett
    ContributorAuthor

    Fixed by PyDevices/audiodsp#399, where the reverb tank compiles for speed in size-optimised firmware, and PyDevices/micropython-pydevices#374, where the Audio Kit's firmware runs its CPU at 240 MHz. micropython-pydevices#375 carries the audiodsp fix into firmware builds. On the Audio Kit, the seven-note run above plays with the Reverb on and no dropouts or starved blocks. Another classic ESP32 that boots at 160 MHz needs machine.freq(240000000) until its board's build sets 240.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions