You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
soundmodule on a classic ESP32: the engine's Reverb can't keep up at 48 kHz #44
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.
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.
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.
Activity
bdbarnett commentedon Nov 10, 2026
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.bdbarnett commentedon Nov 10, 2026
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.