Adds the "Recording" category to the Settings page so the recording mode is
selectable from the UI (config + core wiring already existed from Stage 2).
- AppMessage::RecordingModeSelected → persists config + sends SetRecordingMode
(takes effect on the next recording start). recording_mode_hint copy.
- iced 0.14 pick_list can't host per-option tooltips, so the three modes are
RADIO BUTTONS each wrapped in a `tooltip` (hover explains that mode) — chosen
over a dropdown so each option is self-documenting. Placed after Microphone,
using the shared section_header; output-dir note below.
- +1 config test (recording_mode round-trip + is_multitrack classification).
User-verified live (Both mode writes the expected WAVs; radios + tooltips
approved). Senior-written — Gemini's unsanctioned Stage 3 attempt was discarded.
179 tests (169 lib +1 ign, 6 reconnect, 4 transport), clippy --all-targets clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Scopes the differentiating "record every peer to their own synced track"
feature and lands its pure, isolated core (no live-audio wiring yet).
- docs/multitrack-recording-plan.md: scope contract + locked decisions
(raw stems pre-volume/mute, stems + a mixed track, silence-pad late joiners).
- src/audio/multitrack.rs: MultitrackRecorder over the existing WavWriter.
One master clock = the mixer cycle; every end_cycle() appends exactly
FRAME_SAMPLES to every track (silence where idle) so all stems stay
sample-aligned. add_peer back-pads a late joiner to cycle 0; track_filename
gives fs-safe `<slug>-<shortid>.wav` (reuses sanitize_name). Optional mix
track for "Both" mode.
- +5 unit tests: equal length across tracks, late-joiner leading silence,
stems-only omits mix, fit() pad/truncate, filename slugging/disambiguation.
Stage 2 (wire into the mixer) is next, behind a checkpoint. 168 lib tests,
clippy --all-targets clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>