Branch: m2-edit-operations → main
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 <name>_[ProjectData]/, and warns when the firmware header or data.version differ from the tested 1.3.0.12 / 28.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.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).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.currentSequence.samples[] but inserted first in tracks[0].samples[], and a new sequence goes first in sequences[]. The T1 golden match depends on both.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.MaxMuteGroup, MaxBars) and easy to change.go vet ./... and go test ./... pass (coverage: project 90%, wav 94%, xpj 89%).
M2 done-when:
testdata/accepted/MpckitT1.xpj and MpckitT3.xpj (decompressed).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.PadHasNotes against DemoFile (true for A1–A4 only), loading DemoFile and writing it back unchanged, bad WAVs, range checks.sliceInfo.End + 1); synthetic extensible, ADPCM, 3-channel, 64-bit float, RF64, truncated and zero-size-data files.M3: export to folder and zip, the preview decoder, and the small CLI for device checkpoint A.