# M2: edit operations Branch: `m2-edit-operations` → `main` ## What changed - **`internal/project`**: the domain model (build plan 4.2, 4.3). It has no Wails code. - `New(name)` builds from `DemoBlank.xpj`, embedded with `go:embed` (copy in `internal/project/template/`; a test checks it still matches `testdata/device/DemoBlank.xpj`). - `Load(path)` reads a project, takes the name from the file name, maps each pool file to `_[ProjectData]/`, and warns when the firmware header or `data.version` differ from the tested 1.3.0.12 / 28. - Pads: `AssignSample`, `ClearPad`, `CopyPad`, `MovePad`, `SwapPads`, `SetTune` (clamped to ±24 st / ±90 ct, pitch rounded to 32-bit), `SetMuteGroup`, `PadHasNotes`, plus a read-only `Pad(slot)` view. - Sequences: `AddSequence`, `RemoveSequence`, `SetSequence` (name, BPM, bars; writes all 26 length fields), plus `Sequences()` in slot order. - `SetName`, `ValidName` (no empty names, no `<>:"/\|?*` or control characters, no trailing dot/space, no Windows reserved names), `SlotName` (0 → A1, 17 → B2). - Pool rules: the same source file on several pads gives one entry; a different file with a taken name gets `001`, `002`, compared without case; an entry is dropped when its last pad is cleared; 128-sample limit. - **`internal/wav`**: WAV header reader (format, channels, rate, bits, frames), moved forward from M3 because `AssignSample` needs the frame count. It handles extensible headers and extra chunks, and `Validate()` applies the 1.0 rule: 8/16/24/32-bit PCM or 32-bit float, mono/stereo, at most 20 minutes. The preview decoder and export stay in M3. - **Docs**: corrected the pitch example (see notes); added open question 7 on `currentSequence`. ## Notes - **Device ordering, copied exactly**: new pool entries are appended to `samples[]` but inserted first in `tracks[0].samples[]`, and a new sequence goes first in `sequences[]`. The T1 golden match depends on both. - **Pitch text**: the device wrote 12.4 as `12.399999618530274`. Our writer prints `12.399999618530273`, the same float64 in shortest form, which is what the device-accepted T1/T3 files use. The docs said the device wrote `…273`; corrected. - **`currentSequence`**: treated as a slot number, as the plan says. The files cannot tell slot from array index (always 0, and slot 0 is stored second), so I added it as open question 7 for checkpoint B4. - **Limits not yet confirmed on the device**: mute groups 0–32 (checkpoint A3) and at most 999 bars (A5). Both are constants in the code (`MaxMuteGroup`, `MaxBars`) and easy to change. - **128-sample limit**: with one sample per pad the pool can't overflow through the API, since every pad replaced frees its entry. The limit only matters for loaded projects with unused or multi-layer entries, and the test covers that case. - Loaded pool entries keep their metadata; new ones use loadImpl 0, tempo 0.0, root 60, tune 0.0, key "C Natural Minor". ## Testing `go vet ./...` and `go test ./...` pass (coverage: project 90%, wav 94%, xpj 89%). M2 done-when: - **T1 and T3**: building from the blank template with the prototype's edits gives output **byte-identical** to `testdata/accepted/MpckitT1.xpj` and `MpckitT3.xpj` (decompressed). - **Demo02 rebuild**: matches the device's file except `tracks[0].colour`, `assignableEnvelopeFollowerAssignments.currentControlIndex`, recorded events, the pad-5 `LoopCrossfadeLength` (device value on its trimmed pad vs our -1, as the format doc already records) and the pitch spelling above. Trim (a 2.0 feature) is set straight on the tree in the test to complete the rebuild. - **Unit tests**: clear, copy, move, swap, pool reuse, name collision, the 128 limit, sequence add/remove/length (all 26 fields), `PadHasNotes` against `DemoFile` (true for A1–A4 only), loading DemoFile and writing it back unchanged, bad WAVs, range checks. - **WAV reader**: all 10 files in the WAV test pack and the 7 device-saved samples give the frame counts the projects record (`sliceInfo.End + 1`); synthetic extensible, ADPCM, 3-channel, 64-bit float, RF64, truncated and zero-size-data files. ## Next M3: export to folder and zip, the preview decoder, and the small CLI for device checkpoint A.