m5-pads-tab.md 4.5 KB

M5: Pads tab

Branch: m5-pads-tab → main

What changed

Go service (internal/app), new methods:

  • SetName, AssignSampleDialog, AssignSamplePath (used by file drop), ClearPad, SetTune, SetMuteGroup.
  • Export: ChooseExportFolder / ExportFolder(dir, overwrite) and ChooseZipPath / ExportZip(path, overwrite).
    • If the target exists, nothing is written and exists lists it; the frontend asks, then calls again with overwrite.
    • A zip path without .zip gets it added.
    • A successful export clears the unsaved-changes flag.
  • Every edit returns the new state, even when it fails. The frontend refetches the state when a call is rejected.
  • internal/app still imports nothing from Wails, so its tests run anywhere. The native dialogs are behind a small Dialogs interface; dialogs.go implements it with Wails.

Preview audio (internal/app/audio.go, frontend/src/lib/audio.ts), build plan 4.5:

  • Go serves each pad's source WAV at /audio/<slot>?k=… through the asset server's middleware. The key changes with the source file, so the preview never plays a stale cached sample.
  • The frontend decodes with Web Audio. If the webview can't decode a format, it fetches /audio/<slot>?pcm=1, which Go decodes (the M3 decoder).
  • Tuning is applied as detune (coarse × 100 + fine cents), so pitch and speed change together as on the device. Only the slice region is played.
  • Pads are monophonic: a new click restarts the pad. Starting a pad cuts off every sounding pad in the same non-zero mute group with an 8 ms fade.

File drop (main.go): the window accepts files. Pad cells and the empty-pad panel are drop targets carrying data-slot, and they highlight while a file is over them. Go assigns the first .wav dropped and sends the new state as a state event; problems come as an error event. Dropping a non-WAV file shows a message.

Frontend:

  • Project name is editable (Enter or leaving the field saves; a refused name goes back).
  • Export zip and Export to folder work, with a confirm dialog before replacing files.
  • Clicking a pad selects it and plays it.
  • The pad panel is live: Choose WAV file, Play, Replace, Clear, tuning sliders (they play the pad when let go), mute group (Off, 1–16).
  • Errors show in a dismissable banner. The footer shows "Unsaved changes" and where the last export went.
  • Move/Copy stay disabled until M6. Load stays disabled until M8.

tools/xpjdiff: go run ./tools/xpjdiff A.xpj B.xpj compares two projects (the .xpj values and the data-folder files) and prints the differing paths, or identical. It's for checking this milestone.

Testing

On the server:

  • go vet and go test ./... pass (Linux with -tags purego, and GOOS=windows go vet).
  • The service tests cover the dialog-cancel path, assign/clear/tune/mute through the service, name validation, folder and zip export with the overwrite round-trip, an export through the service that matches the model byte for byte, and the audio route (WAV bytes, decoded PCM header and peak, 404s, other paths passed through).
  • xpjdiff is tested against T1/T2/T3.

The server has no Node, so the frontend is untested here. On the laptop, from the repo root (create C:\temp\m5 first). Use quotes as shown; in PowerShell an unquoted comma splits an argument.

  1. npm run check in frontend: 0 errors, 0 warnings.
  2. wails3 dev. In the app:
    • Name the project UiKit.
    • A01: Choose WAV file → testdata\device\DemoFile_[ProjectData]\PadLp-London Cm114 SA.wav.
    • A02: drag testdata\device\DemoFile_[ProjectData]\Bass-Pure C.wav from Explorer onto the A02 cell.
    • A02: Semitones −12, Cents +50.
    • A01 and A02: mute group 1.
    • Export to folder → C:\temp\m5.
  3. The same edits with the CLI:

    go run ./cmd/mpckit-cli -name CliKit -out C:\temp\m5 -pad "A1=testdata\device\DemoFile_[ProjectData]\PadLp-London Cm114 SA.wav" -pad "A2=testdata\device\DemoFile_[ProjectData]\Bass-Pure C.wav" -tune "A2=-12,50" -mute "A1=1" -mute "A2=1"
    
  4. go run ./tools/xpjdiff C:\temp\m5\UiKit.xpj C:\temp\m5\CliKit.xpj prints identical. (M5 done-when, part 1.)

  5. Preview: click A01 (a long pad sound), then A02 while it plays: A01 stops. Set A02's group to Off and repeat: both play together. A02 sounds 11.5 semitones lower than untuned (just under an octave). (M5 done-when, part 2.)

  6. Export again to the same folder: a dialog asks before replacing; Cancel writes nothing. Export zip saves UiKit.zip.

  7. Clear A02: the pad empties and the footer drops to 1 sample. Rename to a/b: an error shows and the name goes back.