# Acapella v2 — From-Scratch Implementation Plan

Companion to [SPEC.md](SPEC.md). Ordered so that **the risky core (timing) is
proven first with tests, before any UI exists**, and every phase ends with
something demonstrably working.

Ground rules:
- New Xcode project `AcapellaV2/`, new git repo, commit per work item.
- Core layers (`MusicModel`, `AudioCore`, `Layout`) are platform-independent
  Swift packages with unit tests; the app target is thin.
- Nothing from v1 is copied except: the YIN pitch detector (ported + fixed
  window-center alignment), the four sample songs (converted), and the music
  theory tables (key signatures / circle of fifths) after review.

---

## Phase 0 — Scaffold (½ day)

- Create repo, Xcode project, three local Swift packages: `MusicModel`,
  `AudioCore`, `ScoreLayout`. App target `Acapella` (iOS 17, iPhone+iPad).
- CI-ish script: `Scripts/test.sh` runs all package tests + builds the app
  for simulator. CLAUDE.md documenting build/test commands.
- **Done when:** empty app boots in simulator; `test.sh` green.

## Phase 1 — MusicModel: ticks, score, native format (2–3 days)

- `Tick` arithmetic (PPQ 960), `TempoMap` (tick↔seconds), `TimeSignature`,
  `KeySignature`, spelled `Pitch` (+ MIDI/frequency), `NoteEvent`, `Part`,
  `Score`, derived `Measure` slicing with **strict barline validation**.
- `.acasong` parser + serializer (version header, ties, dots, tuplets,
  pickup, barline check tokens, part headers with clefs, lyric lines,
  tempo-change lines). Errors carry line/column.
- Converter for v1 files; migrate the four existing samples into
  `Resources/Library/`.
- Tests: round-trip property tests, validation rejection cases, tempo-map
  math (incl. mid-song change), tuplet/dot exactness, 10k-measure drift test.
- **Done when:** all sample songs parse, validate, round-trip byte-identical.

## Phase 2 — AudioCore: transport + sample-accurate tone playback (4–5 days)
*The heart. No UI — verified by offline rendering.*

- `TransportClock` + `ConductorNode` (AVAudioSourceNode): master
  `songSamplePosition`, lock-free transport snapshot for readers.
- Schedule compiler: `Score` + tempo map + range + count-in →
  per-part `[(startSample, endSample, freq)]` + metronome event list.
- Tone voice (band-limited soft synth, per-sample AR envelope), per-part
  gain/mute/solo with smoothing; count-in as negative sample positions.
- **Offline manual-render mode** from day one (same node, no device).
- Tests (the payoff): render a known score offline → detect note onsets in
  the buffer → assert onsets at *exact* expected samples (0 jitter); loop
  boundary continuity; tempo-change correctness; envelope click-freedom
  (no discontinuities > threshold).
- Thin `PlaybackDemo` debug screen (play/stop/tempo slider) to hear it.
- **Done when:** offline-render tests prove sample-exact scheduling; demo
  plays a 4-part sample smoothly on device with live mute/solo.

## Phase 3 — Recording, alignment, takes (4–5 days)
*The other half of the heart.*

- Session setup (.playAndRecord, 5 ms buffers, route/interruption handlers).
- Always-on armed input tap → `.caf` writer; hardware-timestamp capture;
  `alignmentOffsetSamples` computation (§5.3 of spec).
- Project package (`.acaproj`) + `manifest.json` (Codable, versioned);
  take CRUD; active-take selection; per-take manual nudge (ms).
- Take playback inside ConductorNode (PCM in memory, SRC on load,
  index-based alignment); tempo-mismatch detection (warn/lock slider).
- Calibration: route-reported defaults; guided loopback measurement via
  cross-correlation (vDSP); per-route `calibrationTrim` storage.
- Tests: simulated-timestamp alignment math; offline "record" of a rendered
  tone track re-mixed against the original → cross-correlate → < 1 sample
  offset; manifest round-trip; interruption-during-recording preserves file.
- Device validation ritual (manual, scripted steps): record the guide tones
  acoustically (speaker→mic), play back together, listen for flam; repeat
  wired + Bluetooth.
- **Done when:** on-device recorded click track aligns within spec
  (±10 ms wired) with zero manual nudging.

## Phase 4 — ScoreLayout + engraving (5–7 days)

- Embed Bravura + SMuFL metadata loader (glyph metrics, no magic numbers).
- `LayoutEngine`: measures → systems (width-aware wrapping), shared
  cross-part horizontal spacing from union-of-onsets, clef-correct pitch
  placement, ledger lines, key/time signatures per system, accidental
  carry rules, dots, ties (intra- and inter-system), beam grouping by time
  signature, tuplet brackets, rests.
- `ScoreCanvasView` (UIView + CALayer tiles): static render first;
  separate cursor + highlight layers; pinch zoom (re-layout);
  tap/drag measure selection.
- Tests: layout snapshot tests (render to image, compare), pitch-placement
  table tests for all four clefs, beaming unit tests, spacing monotonicity.
- **Done when:** all library songs render correctly (visually reviewed),
  bass part actually on bass clef, simultaneous notes vertically aligned.

## Phase 5 — App assembly: the real UX loop (4–6 days)

- LibraryView (bundled + documents), ProjectView composition: ScoreView,
  MixerStrip, TransportBar, TakeSheet, SettingsSheet (per SPEC §7).
- Transport wiring: cursor via CADisplayLink + snapshot extrapolation,
  onset-interpolated x-position, auto-scroll (follow + page-flip modes).
- Full record flow: arm from part chip → count-in → sing → review →
  keep/retake; punch range = current selection; monitoring options.
- Route-change / interruption / background UX; mic permission flow.
- **Done when:** the complete "load song → record 4 parts → hear yourself
  in 4-part harmony" loop works end-to-end on a real iPhone. **This is the
  emotional milestone — schedule a real singing session and dogfood.**

## Phase 6 — Mixdown & export (2 days)

- Offline mixdown via manual-render ConductorNode; include/omit unrecorded
  parts; limiter + loudness normalize; `.m4a`/`.wav`; share sheet;
  project-package export/import.
- Tests: offline mix equals live mix (render both, cross-correlate);
  loudness target; export of partially-recorded project.
- **Done when:** exported file of a full recording sounds identical to
  in-app playback.

## Phase 7 — MusicXML import + starter library (3–4 days)

- `.musicxml`/`.mxl` importer → internal model → saved as `.acasong`
  (subset per SPEC §4.2), with an import report sheet.
- Build the starter library: source ≥ 8 public-domain arrangements, import,
  hand-verify/fix, tag (difficulty, voices, duration).
- Tests: importer against a corpus of real files (CPDL/MuseScore exports),
  tie/tuplet/pickup edge cases, chord-collapse warning.
- **Done when:** a MuseScore SATB export sings correctly in-app within
  a minute of downloading it.

## Phase 8 — Pitch indicator + polish (3–4 days)

- Port YIN (fix window-center alignment); live cents-vs-target needle on
  the cursor while recording; simple post-take "accuracy trail" overlay
  (display only — this seeds v2's future pitch correction).
- Settings: metronome volume, count-in length, monitoring toggles,
  calibration UI, follow mode, theme.
- iPad layout pass (side mixer panel), Dynamic Type where sane, app icon,
  onboarding (headphones! calibration!), haptics on count-in.
- Performance pass against SPEC §9 budgets; fix hot spots.
- **Done when:** SPEC §9 acceptance criteria all pass; TestFlight build.

---

## Sequencing notes & risks

- **Phases 2–3 are the project.** If sample-accurate alignment works, all
  the v1 misery is structurally gone; everything after is normal app work.
  Do not start Phase 4 until Phase 3's device validation passes.
- Biggest unknowns, front-loaded on purpose: (a) hardware-timestamp
  alignment accuracy across routes — mitigated by the calibration routine
  and per-take nudge; (b) engraving spacing quality — mitigated by
  snapshot tests and keeping scope to SPEC's pragmatic list.
- Total: roughly 4–6 weeks of focused solo work, or considerably less
  wall-clock with Claude Code doing the typing and you doing the singing.
- Suggested rhythm per phase: plan → implement with tests → run `test.sh` →
  device check → commit → dogfood note in `NOTES.md`.

## v2.x roadmap (after 1.0)

Pitch correction done right (correct anchor, PSOLA or phase-vocoder shifter,
per-take strength), lyrics rendering, per-part reverb/blend, time-stretch for
tempo-flexible take reuse, punch-in at note granularity, macOS (Catalyst or
native), watch remote for hands-free record start.
