Skip to content

feat(moneo): recorder + main sketch (single-file WAV, reliable touch)#6

Open
Ricky1207-sen wants to merge 3 commits into
debloper:mainfrom
Ricky1207-sen:feat/moneo-recorder
Open

feat(moneo): recorder + main sketch (single-file WAV, reliable touch)#6
Ricky1207-sen wants to merge 3 commits into
debloper:mainfrom
Ricky1207-sen:feat/moneo-recorder

Conversation

@Ricky1207-sen

@Ricky1207-sen Ricky1207-sen commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Adds the moneo recorder and the main sketch that drives it.

Recorder (Recorder.cpp/.h)

  • Captures audio into a single continuous WAV on the SD card (no chunks).
  • Writes each ~10s segment with open → append → close, so a power loss can corrupt at most the last segment, not the whole recording. Header is finalized with the real length on stop.
  • Datetime filenames (rec_YYYYMMDD_HHMMSS.wav) via NTP, millis-based fallback.
  • 8-bit / 16kHz mono.

Touch reliability

  • Confirmation read in the touch handler to reject spurious interrupt noise
    (was causing phantom start/stop and auto-restarts).
  • Config.h: TOUCH_THRESHOLD 22000 → 50000, DEBOUNCE_DELAY 2000 → 5000.

Main sketch (moneo.ino)

  • Wires touch → record → stop → WiFi (WiFiMulti) together.
  • AIClient (audio → notes) is commented out / marked TODO since AIClient isn't
    in the repo yet — enabled in a follow-up PR.

@Ricky1207-sen Ricky1207-sen changed the title feat(moneo): add recorder — single-file continuous WAV file capture to SD feat(moneo): recorder + main sketch (single-file WAV, reliable touch) Jun 24, 2026

@debloper debloper left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Some changes are necessary, some are good to have and rest of them are comments/FYI.

Comment thread moneo/Config.h
const int TOUCH_THRESHOLD = 22000;
const unsigned long DEBOUNCE_DELAY = 2000;
const int TOUCH_THRESHOLD = 50000;
const unsigned long DEBOUNCE_DELAY = 5000;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

That's too long IMO; but not a blocker.

Comment thread moneo/moneo.ino Outdated
void setup() {
Serial.begin(115200);
unsigned long t = millis();
while (!Serial && millis() - t < 500) delay(10);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

By the time you're counting the millis() it may already be over 500ms (as in, it's not a deterministic timeout).

A better way could be:

    unsigned long serialTimeout = millis() + 500;
    while (!Serial && millis() < serialTimeout) { delay(10); }

In this way the timeout starts when we start waiting for Serial, and waits for 500ms (however, I think 100ms is more than enough). Also, probably should put the waiting duration inside the Config.h instead of putting the raw values here.

Comment thread moneo/moneo.ino Outdated

touchAttachInterrupt(TOUCH_PIN, onTouch, TOUCH_THRESHOLD);

Serial.println("[Moneo] Ready. Touch pin D1 to start recording.");

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Redundant consecutive instructions to touch pin to start recording (recorder.begin already logs this just above). One of those is not necessary.

Comment thread moneo/moneo.ino
}
_wasRecording = nowRecording;

delay(10);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Too short interval I think... checking each 0.1sec (100ms) is more than sufficient. Even 1s/1000ms would be snappy enough for any practical purposes.

Comment thread moneo/Recorder.cpp
{}

bool Recorder::begin() {
if (!SD.begin(SD_CARD_PIN)) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Would work as SD.h etc. are included in the Recorder.h file, but the best practice is to include the headers where they're being used... so in this file.

Not a blocker/must.

Comment thread moneo/Recorder.cpp Outdated
DLOG("[Recorder] I2S init failed!");
return false;
}
DLOG("[Recorder] I2S initialized (16kHz, 8-bit).");

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Don't hardcode config parameters in log.

It can be misleading while debugging (if the config values changed, and then forgotten).

Comment thread moneo/Recorder.cpp Outdated
Comment on lines +66 to +68
void Recorder::requestToggle() {
_toggleRequested = true;
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The nested wrapping of onTouch -> requestToggle -> toggleRequested seems a bit too deep fried.

It will work, so not a blocker... but perhaps not the most elegant way.

Comment thread moneo/Recorder.cpp
_psramWritten = 0;

// Try NTP time sync
configTime(19800, 0, "pool.ntp.org"); // UTC+5:30 for IST

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

NTP sync should be in main INO file's setup section (as with any runtime blocking/stalling subroutine), and kept alongside the lastTimeSync as millis() value when it was sync'd, so that current time can always be calculated without needing to make another network request (by adding the elapsed time sinch the last sync, with the last sync'd timestamp).

As it currently is, nothing is even ensuring the WiFi is connected (most likely isn't) so the request would just fail.

Comment thread moneo/Recorder.cpp
Comment on lines +167 to +170
xTaskCreatePinnedToCore(_captureTaskEntry, "Capture", 4096,
this, 5, &_captureTask_h, 1);
xTaskCreatePinnedToCore(_writerTaskEntry, "Writer", 8192,
this, 3, &_writerTask_h, 1);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This is nice to use the second core for compute heavy non-management task. Will have to check how it works out in terms of real world impact.

Comment thread moneo/Recorder.cpp Outdated
File f = SD.open(_wavPath.c_str(), FILE_APPEND);
if (!f) {
// Keep the buffer and retry on the next cycle rather than dropping audio.
DLOG("[Writer] Append open failed; will retry next segment.");

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

NOPE... that's gonna be a corrupt/incomplete recording (with parts missing).

Log the failure and close the recording. Blink error.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds the Stage 2 moneo recording pipeline: a PSRAM-buffered recorder that appends audio into a single WAV on SD in periodic segments, plus a main sketch that drives touch-to-record and WiFi connect-on-stop behavior.

Changes:

  • Introduces Recorder (FreeRTOS capture/writer tasks) that writes one WAV per session with periodic append/close cycles.
  • Adds moneo.ino main sketch wiring touch interrupt → recorder lifecycle → WiFi connection after recording completes.
  • Adjusts touch threshold and debounce constants in Config.h for improved touch stability.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
moneo/Recorder.h Declares the recorder API and task/buffer state for PSRAM-based capture + periodic SD append.
moneo/Recorder.cpp Implements WAV header writing, capture/writer tasks, segment flushing, and start/stop lifecycle.
moneo/moneo.ino Main Arduino sketch wiring touch interrupt handling, recording state transitions, and WiFi processing on stop.
moneo/Config.h Updates touch threshold/debounce values for noise rejection and stability.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread moneo/Recorder.cpp
Comment on lines +52 to +56
// Confirm a real touch is still present. The interrupt can fire on brief
// electrical noise; a genuine press is still held when we reach here (reads
// above threshold), while a noise spike has already decayed and is rejected.
if (touchRead(TOUCH_PIN) < TOUCH_THRESHOLD) return;

Comment thread moneo/Recorder.h
Comment on lines +29 to +32
bool begin();
void loop();
void requestToggle();

Comment thread moneo/Recorder.cpp Outdated
Comment on lines +66 to +68
void Recorder::requestToggle() {
_toggleRequested = true;
}
Comment thread moneo/Recorder.cpp Outdated
Comment on lines +130 to +135
size_t written = f.write(_psramBuf, _psramWritten);
f.close();

_dataLength += written;
_psramWritten = 0;
DLOGF("[Writer] Appended %u bytes (total: %u)\n", written, _dataLength);
Comment thread moneo/Recorder.cpp Outdated
Comment on lines +189 to +191
// Append whatever is left in the buffer. The tasks have stopped, so no
// mutex is needed here.
_flushSegment();
Comment thread moneo/Recorder.cpp
Comment on lines +146 to +150
// Try NTP time sync
configTime(19800, 0, "pool.ntp.org"); // UTC+5:30 for IST
delay(500);

_wavPath = _generateFilename();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants