SpectraLab-P4 — a professional real-time audio measurement instrument for the ESP32-P4 Function EV Board.
Status: Stable Public Release – v1.3.2
The animation below was generated from the actual hardware demonstration video.
The animation demonstrates live spectrum analysis, waterfall display, oscilloscope mode, display mode switching and the touchscreen user interface.
Eight modes, cycled from the Settings screen or from the optional front-panel keycap.
Most analyzer views support two-finger pinch zoom for frequency span and display range.
Eight schemes. Since v1.3.1 the selected one applies to every screen, not just the analyzer view. HIGH CONTRAST is the only light scheme. RAINBOW is the odd one out: instead of colouring a bar by how loud it is, it gives every band its own hue, sweeping red to violet across the frequency axis.
All eight, same view and same signal so only the palette differs:
| Dark Default |
Classic Green phosphor |
High Contrast Light, for bright rooms |
Amber Warm retro CRT |
![]() |
![]() |
![]() |
|
| Blue Neon Electric blue |
Matrix Deep green on black |
Red Neon Hot red |
Rainbow Hue by frequency |
![]() |
![]() |
![]() |
![]() |
The app icon is the browser tab icon on every page, and the badge in front of the title on the dashboard.
The analyzer includes a fully integrated responsive web interface. No additional software is required—any modern browser on your local network can access the device.
Features include:
- Analyzer status dashboard
- Device settings page — every measurement, display, auto-gain and startup setting, configurable from the browser
- Shared navigation bar across all five pages
- Dark and Light themes
- Wi-Fi configuration, including per-network static IP and access-point mode
- SD card file browser — download screenshots, presets and calibration files
- Take a screenshot of the analyzer's display from the browser
- Microphone calibration upload
- Clock and timezone
- Works over the analyzer's own access point, with no network required
| Dark Theme | Light Theme |
![]() |
![]() |
| Dark Theme | Light Theme |
![]() |
![]() |
| Dark Theme | Light Theme |
![]() |
![]() |
This project began as a personal engineering challenge while I was undergoing treatment for acute myeloid leukemia (AML). During an extended hospital stay I wanted to continue learning, solving problems and building something real — work I could pick up and put down around treatment, and that would still be there when I came back to it.
Engineering has always been one of the ways I make sense of complex problems, and this project became an opportunity to keep learning while facing a very different kind of challenge.
The ESP32-P4 is a remarkably capable embedded platform, yet most audio examples stop at demonstrating individual peripherals or basic FFT processing. What started as an exploration of the ESP32-P4 and real-time DSP gradually evolved into a much more capable audio measurement instrument. Every new feature was added with the same goal in mind: to make it behave like a real piece of laboratory equipment rather than a technology demonstration.
It combines modern embedded graphics, DSP, USB Audio Class support, persistent configuration, touchscreen interaction and web-based configuration into a single standalone application.
I am releasing the project as open source in the hope that other engineers, students, makers, and audio enthusiasts will find it useful, learn from it, and perhaps extend it in directions I never anticipated.
| Document | Description |
|---|---|
| User Guide | How to operate the analyzer, feature by feature |
| Hardware Setup | Wiring, front-panel keycaps, signal chain |
| Known-Good Config | Verified toolchain, component and C6 firmware versions |
| Quick Start | Build and flash the analyzer |
| Display Modes | Supported on-device analyzer views |
| Embedded Web Interface | Browser dashboard, Wi-Fi setup and calibration upload |
| Roadmap | Planned future enhancements |
| Release Notes | GitHub releases |
| Changelog | Version history, release-by-release |
- Real-time FFT analysis (512–16384 point)
- Multiple window functions
- Multiple averaging modes
- Spectrum, Waterfall, Oscilloscope, Mirror, VU and 1/3 Octave displays
- USB Audio Class (UAC1) support
- ES8311 onboard audio support
- Runtime USB stereo-to-mono selection
- Touchscreen pinch zoom
- Microphone calibration support
- Automatic Gain Control (AGC) with manual override
- Noise-floor capture and subtraction
- Presets with full runtime persistence
- Named settings profiles
- A-weighted SPL and mic sensitivity entry
- Peak readout cursor — long-press a peak for exact frequency, level, band and note
- Screenshot capture to SD card (PNG)
- SD card configuration storage
- Wi-Fi provisioning
- Multiple remembered Wi-Fi networks with automatic reconnect
- Access-point mode with a captive portal — full web interface with no network at all
- Automatic clock (NTP, or your browser) so recordings and screenshots carry real dates
- Embedded web interface
- Responsive browser interface
- Dark and Light themes
- Browser-based Wi-Fi configuration
- Browser-based microphone calibration upload
- Browser-based SD card file browser, downloads and screenshot capture
- Browser-based static IP configuration
- Remote analyzer configuration
- PlatformIO and ESP-IDF compatible
Everything the analyzer can do is configurable on the device itself. Settings apply as you leave the screen — there is no Apply button — and are written to the SD card automatically.
Boot opens on a splash screen carrying the logo above, in the active colour scheme; Settings sets it to anything from off to 15 seconds.
| Saved network Password, addressing, forget |
IP settings DHCP or per-network static address |
![]() |
![]() |
| Save preset Named settings profiles on SD |
Wi-Fi QR scan Camera provisioning |
![]() |
![]() |
Touch drives everything. The one exception is the Wi-Fi QR scanner: the camera and the touch controller share an I2C bus, so touch pauses while the camera is live. Optional front-panel keycaps cover that gap and add a hardware display-mode shortcut — see hardware-setup.md.
The camera can also only be started once per boot, which is why the scanner screen above offers a restart rather than a second scan; use Manual to type the network details instead if you would rather not reboot.
Many embedded FFT projects answer the question:
"Can an ESP32 perform an FFT?"
This project asks a different question:
"How capable can an ESP32-P4 become as a standalone audio measurement instrument?"
Every feature is evaluated against one goal:
Does it make the instrument more useful?
| Capability | Status |
|---|---|
| FFT Analyzer | ✅ |
| Oscilloscope | ✅ |
| Waterfall Display | ✅ |
| 1/3 Octave Analyzer | ✅ |
| USB Audio | ✅ |
| ES8311 Audio | ✅ |
| Touch Gestures | ✅ |
| Embedded Web UI | ✅ |
| Dark / Light Themes | ✅ |
| Wi-Fi Configuration | ✅ |
| Calibration Upload | ✅ |
| Remote Configuration | ✅ |
| Presets | ✅ |
| Calibration | ✅ |
| Noise Floor Capture | ✅ |
| Automatic Gain Control | ✅ |
| Wi-Fi Provisioning | ✅ |
| Multiple Saved Wi-Fi Networks | ✅ |
| Saved Network Management (view / forget) | ✅ |
| Static IP Configuration (device + browser) | ✅ |
| Named Settings Profiles | ✅ |
| A-Weighting / Mic Sensitivity | ✅ |
| Peak Readout Cursor | ✅ |
| Screenshot Capture (PNG to SD) | ✅ |
| SD File Browser & Download | ✅ |
| Access-Point Mode + Captive Portal | ✅ |
| Automatic Clock (NTP / browser) | ✅ |
| Selectable Timezone | ✅ |
| Camera QR Wi-Fi Setup | ✅ |
| Front-Panel Keycaps (optional) | ✅ |
| Distributed Stereo Analyzer | 🚧 Planned for v2.0 |
- An ESP32-P4 Function EV Board — either revision:
- ESP32-P4-Function-EV-Board v1.5.2 — P4 silicon rev 1.x
- ESP32-P4X-Function-EV-Board v1.6 — P4 silicon rev 3.x
- USB-C cable
- microSD card
- Optional USB UAC1 interface, such as the Behringer UCA222
- Optional calibrated USB measurement microphone
- Optional 1-2 x Seeed Grove-Mech Keycap — front-panel keys whose RGB LEDs show what each key selects: one cycles the colour theme (and cancels a camera QR scan while touch is suspended, or restarts the board on a 2 s hold), the other cycles the spectrum display mode (wiring in hardware-setup.md — power them from 3V3, never 5V)
git clone https://github.com/JFG3rd/SpectraLab-P4.git
cd SpectraLab-P4The two boards are peripheral-identical — same LCD, ES8311 codec, ESP32-C6,
SD slot — and differ only in P4 silicon revision. Revision 3.x is a breaking
major revision, so one binary cannot run on both. Each board therefore has
its own build environment and its own sdkconfig:
| Board | Silicon | PlatformIO env | sdkconfig |
|---|---|---|---|
| ESP32-P4-Function-EV-Board v1.5.2 | rev 1.x | esp32-p4-evboard |
sdkconfig.esp32-p4-evboard |
| ESP32-P4X-Function-EV-Board v1.6 | rev 3.x | esp32-p4x-evboard |
sdkconfig.esp32-p4x-evboard |
If you are not sure which you have, plug it in and ask it:
esptool.py chip_id # or: python -m esptool chip_idLook for Chip is ESP32-P4 (revision v1.x) or (revision v3.x).
Flashing the wrong image leaves the board unbootable until it is reflashed
correctly. The PlatformIO upload path guards against this automatically
(tools/check_chip_rev.py probes the connected chip before every upload and
aborts on a mismatch); the raw ESP-IDF path does not.
This is the supported path — it applies the correct sdkconfig, the OTA
partition table, the camera ISP tuning generation and the chip-revision guard
for you.
# Build both board images at once (no board needs to be connected)
pio run
# Build and flash ONE board — pick the env that matches your hardware
pio run -e esp32-p4-evboard -t upload # v1.5.2 board (silicon rev 1.x)
pio run -e esp32-p4x-evboard -t upload # P4X v1.6 board (silicon rev 3.x)
# Serial monitor (115200 baud)
pio run -e esp32-p4-evboard -t monitor
pio run -e esp32-p4x-evboard -t monitorDo not run a bare pio run -t upload: with two environments defined it
tries to flash both images to the same board, and the chip-revision guard will
abort one of them. Always pass -e.
If the upload cannot find the board, name the port explicitly:
pio run -e esp32-p4x-evboard -t upload --upload-port /dev/cu.usbmodem1101After changing the partition table, erase the chip first:
pio run -e esp32-p4x-evboard -t eraseAlso supported, but you have to supply by hand what PlatformIO otherwise
infers. Three things are mandatory and the build silently does the wrong thing
without them: the target, the per-board sdkconfig, and a separate
build directory per board (the two boards cannot share one, and a stale
build/ from an earlier attempt will fail with confusing toolchain errors).
Set up the toolchain once — the ESP-IDF that PlatformIO already downloaded works fine:
~/.platformio/packages/framework-espidf/install.sh esp32p4 # once, ever
. ~/.platformio/packages/framework-espidf/export.sh # each new shellOr use your own ESP-IDF v5.5.3 or newer — rev-3 silicon needs it.
For the v1.5.2 board (silicon rev 1.x):
idf.py -B build.p4 \
-D SDKCONFIG_DEFAULTS=sdkconfig.esp32-p4-evboard \
-D SDKCONFIG=build.p4/sdkconfig \
build
idf.py -B build.p4 \
-D SDKCONFIG_DEFAULTS=sdkconfig.esp32-p4-evboard \
-D SDKCONFIG=build.p4/sdkconfig \
-p /dev/cu.usbmodem1101 flash monitorFor the P4X v1.6 board (silicon rev 3.x) — same commands, p4x everywhere:
idf.py -B build.p4x \
-D SDKCONFIG_DEFAULTS=sdkconfig.esp32-p4x-evboard \
-D SDKCONFIG=build.p4x/sdkconfig \
build
idf.py -B build.p4x \
-D SDKCONFIG_DEFAULTS=sdkconfig.esp32-p4x-evboard \
-D SDKCONFIG=build.p4x/sdkconfig \
-p /dev/cu.usbmodem1101 flash monitorNotes on this path:
- Both
SDKCONFIG_DEFAULTSandSDKCONFIGare needed. The first supplies the board's configuration; the second keeps the generated copy inside the build directory. Passing onlySDKCONFIG=sdkconfig.esp32-p4x-evboardalso builds correctly, but ESP-IDF rewrites that tracked file on every build (it strips PlatformIO's# default:comments), leaving the working tree dirty for no reason. idf.py set-targetis not needed and should not be run — the target and the silicon-revision keys already live in eachsdkconfig.*, and it would overwrite them.- A separate
-Bbuild directory per board is required, not just tidy: the two configurations cannot share one, and a stalebuild/from an earlier attempt fails with confusing "compiler not found" errors about the wrong architecture. - Nothing here checks that the image matches the connected silicon. Confirm the revision yourself before flashing, or use the PlatformIO path, which does.
- Flash over USB-Serial/JTAG, which is the default. Do not flash the P4X board via OpenOCD — on rev-3 silicon it writes without overlap checks and produces "Checksum failure" boot loops.
- The serial port differs by machine:
/dev/cu.usbmodem*on macOS,/dev/ttyACM*on Linux,COM*on Windows. Omit-pto let idf.py guess.
Insert the SD card and reboot. The analyzer starts in the spectrum view; the web interface address is shown on the on-device Wi-Fi screen once it joins a network.
The analyzer does not need infrastructure. Switch it to access-point mode
and it becomes its own Wi-Fi network: join SpectraLab-P4-XXXX and the portal
opens by itself, with the complete web interface — file browser, screenshot
capture and download, settings, calibration upload.
The only thing that changes is where the clock comes from. With no route to a time server the analyzer takes the time from whichever browser opens a page, so captures still carry correct timestamps.
Switch modes on the device under Wi-Fi Setup → Mode, or from the browser.
SpectraLab-P4 is suitable for loudspeaker development, audio amplifier analysis, AVR setup and testing, USB audio debugging, DSP development, educational demonstrations, embedded audio design, room acoustics and noise-floor measurement.
Ideal for development and testing.
Supports external USB audio interfaces.
Runtime options:
- Average L+R
- Left only
- Right only
No recompilation required.
Audio Sources
┌────────────────────────────┐
│ ES8311 │ USB Audio │ Future│
└──────────────┬─────────────┘
│
▼
Audio Source Manager
│
▼
DSP Processing
FFT │ Averaging │ Calibration
│
▼
Visualization Engine
Spectrum │ Scope │ Waterfall │ VU
│
┌──────────┴──────────┐
▼ ▼
LCD Display Web Interface
The firmware is intentionally organized into independent components including audio capture, DSP, networking, settings management and display rendering.
components/
audio_source/ ES8311 I2S + USB UAC1 host, hot-swap
dsp_engine/ FFT, windows, averaging, SPL, noise floor, calibration
agc/ software automatic gain control
display_ui/ LVGL 9 screens, screenshot capture
settings_mgr/ SD + NVS persistence, presets, file listing
net_mgr/ Wi-Fi join, setup AP, static IP, mDNS
web_server/ HTTP portal, REST API, file browser
qr_scan/ MIPI-CSI capture + QR decode for Wi-Fi provisioning
panel_button/ optional Grove-Mech Keycaps
Docu/
images/
web/ browser assets (baked into web_server by tools/)
tools/
src/
UserGuide.md
hardware-setup.md
CHANGELOG.md
ROADMAP.md
- Complete embedded spectrum analyzer
- Multiple display modes
- USB Audio
- Touch interface
- Calibration
- Web interface
- ✅ Multiple remembered Wi-Fi networks with automatic reconnect to whichever known network is in range
- ✅ Robust on-device Wi-Fi scanning and provisioning, with a "Show password" toggle
- ✅ Per-device mDNS name (
spectralab-p4-xxxx.local) so multiple units coexist on one network - ✅ Camera QR-code Wi-Fi provisioning — point the on-board camera at a router's Wi-Fi QR code to auto-fill SSID/password from the on-device Wi-Fi setup flow
- ✅ QR scanner stability — real camera errors are shown instead of a bare "Scanner stopped", touch and audio survive a scan, the UI is never blocked while stopping, and an idle scan gives up after 45 s
- ✅ Optional front-panel Grove-Mech Keycaps — a colour-theme/scan-abort/restart key usable while touch is suspended for a camera scan, plus a display-mode key; each LED glows the colour of what its key currently selects
Operate two ESP32-P4 analyzers as a synchronized pair.
Planned features include Primary / Secondary operating modes, stereo channel split, low latency PCM streaming, preset synchronization, automatic pairing, shared configuration and synchronized displays.
Potential future capabilities include transfer-function measurements, THD analysis, impulse response, data logging, CSV export, browser-based remote displays and additional display themes.
If you build the project, I would enjoy hearing about it.
Bug reports, suggestions and pull requests are welcome.
If the project proves useful, please consider giving it a ⭐ on GitHub to help others discover it.
Apache 2.0





























