M1: Firmware recording core #1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/fw-recorder-core"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
M1: Firmware recording core
Feature
The device now records. Short-press the button to start/stop capturing microphone audio to
a WAV file on the microSD card, with the status LED showing idle/recording/error and a
sidecar JSON metadata file written per recording.
What was achieved
From a bare scaffold, the firmware gained a working capture pipeline: mic -> 16-bit PCM ->
streaming WAV file on SD, plus button control, LED feedback, and metadata that matches the
Recordingschema inapi/openapi.yaml. Both board profiles are supported (external I2Smic on the dev board; onboard PDM mic on the XIAO).
How to verify
.forgejo/workflows/ci.yml) builds both profiles on push:pio run -e esp32s3_devandpio run -e xiao_esp32s3.the button. Expect "Recording started/stopped" logs and a
rec_*.wav+rec_*.jsonpair under
/recordingson the SD card, with the WAV playable.Not yet compiled locally (no PlatformIO on the dev host) or hardware-verified - see
Follow-ups.
Tools used
C++ (Arduino-ESP32 3.x), PlatformIO, the core-bundled
ESP_I2SandSD/FSlibraries.No extra dependencies.
How it works
audio(src/audio.{h,cpp}) - brings up the mic viaESP_I2S'sI2SClass. Dev board:I2S_MODE_STDfor INMP441/ICS-43434. XIAO:I2S_MODE_PDM_RXfor the onboard mic.Presents 16-bit PCM mono to callers regardless of board.
storage(src/storage.{h,cpp}) - mounts the SD card on a dedicated HSPI bus andprovides
WavWriter, which writes a 44-byte PCM WAV header, streams samples, and patchesthe RIFF/data sizes on close. Also writes sidecar JSON metadata.
recorder(src/recorder.{h,cpp}) - the idle/recording state machine: creates/recordings/<id>.wav, pumps mic chunks into it onupdate(), and on stop finalises thefile and writes
<id>.json(Recording schema).ux(src/ux.{h,cpp}) - debounced button (short press = toggle) and status LEDpatterns (idle heartbeat, recording blink, error fast-blink), active-low aware.
main.cppwires them:ux::begin()+recorder::begin()in setup;loop()toggles onbutton and calls
recorder::update().include/audio_config.h(16 kHz mono 16-bit, chunk size, paths); pins ininclude/pins.hper board.State updated
state/TODO.md(M1 in PR; audio-calibration + real-timestamp follow-ups)state/ARCHITECTURE.md(M1 modules marked landed)state/NOTES.md(firmware specifics)state/DECISIONS.md(no new decision beyond those recorded at M0)Follow ups
If so, capture 32-bit and right-shift into int16 in
audio.cpp.started_atare uptime-based until NTP arrives in M2.device paths in
api/openapi.yaml.Implements the first working feature: the device records audio to the microSD card, toggled by the button, with LED status and per-recording JSON metadata. What changed: - firmware/src/audio.{h,cpp}: mic capture via the core-bundled ESP_I2S. Dev board uses I2S standard mode (INMP441/ICS-43434); XIAO uses PDM mode (onboard mic). Presents 16-bit PCM mono to callers regardless of board. - firmware/src/storage.{h,cpp}: microSD on a dedicated HSPI bus + a streaming WavWriter that writes a 44-byte PCM header and patches RIFF/data sizes on close; plus sidecar JSON metadata writer. - firmware/src/recorder.{h,cpp}: idle/recording state machine; creates /recordings/<id>.wav, pumps mic chunks in on update(), finalises + writes <id>.json (Recording schema from api/openapi.yaml) on stop. - firmware/src/ux.{h,cpp}: debounced button (short press toggles) + status LED patterns (idle/recording/error), active-low aware. - firmware/src/main.cpp: wires ux + recorder; loop toggles on button and drains the mic while recording. - firmware/include/audio_config.h: 16 kHz mono 16-bit, chunk size, rec dir. - firmware/include/pins.h: added XIAO PDM mic + onboard SD pins, LED active-low flag. - state/: TODO, ARCHITECTURE, NOTES updated for M1 and the deferred follow-ups. Why: - Recording is the foundation every later milestone (transfer, upload, transcription) builds on. Kept dependency-free (only core-bundled ESP_I2S + SD) for simple CI builds. Notes: - Not compiled locally (no PlatformIO on the dev host) or hardware-verified; Forgejo Actions CI builds both board profiles. Follow-ups tracked in state/TODO.md: INMP441 16-bit level calibration, and real NTP timestamps (ids are uptime-based until M2 brings WiFi/NTP). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>