|
@@ -1,4 +1,4 @@
|
|
|
-# mpckit: MPC Sample project format and 1.0 / 2.0 scope
|
|
|
|
|
|
|
+# mpckit: MPC Sample project format and 0.5.0 / 2.0 scope
|
|
|
|
|
|
|
|
Sources: three projects saved on an MPC Sample, in `testdata/device/` of `bajdev/mpckit` (first committed as `demo-projects/`), analysed 2026-11-10.
|
|
Sources: three projects saved on an MPC Sample, in `testdata/device/` of `bajdev/mpckit` (first committed as `demo-projects/`), analysed 2026-11-10.
|
|
|
|
|
|
|
@@ -15,7 +15,7 @@ Everything below is observed in those files unless marked as an open question. T
|
|
|
- The `.xpj` reader/writer is its own Go package with no UI code.
|
|
- The `.xpj` reader/writer is its own Go package with no UI code.
|
|
|
- New projects are built from the blank project as a template; edits change only known fields.
|
|
- New projects are built from the blank project as a template; edits change only known fields.
|
|
|
|
|
|
|
|
-## 1.0 scope (agreed 2026-11-10)
|
|
|
|
|
|
|
+## 0.5.0 scope (agreed 2026-11-10 as the 1.0 scope; renamed 2026-11-11: 0.5.0 is a beta release for testing)
|
|
|
|
|
|
|
|
Intended use: set up new kits on the desktop, then move to the device to create sequences and tracks.
|
|
Intended use: set up new kits on the desktop, then move to the device to create sequences and tracks.
|
|
|
|
|
|
|
@@ -35,7 +35,7 @@ UI (mockup agreed 2026-11-10, "mpckit main screen mockup" artifact):
|
|
|
- Pads: click to select and play; drag to move, drag onto a filled pad to swap, Alt-drag to copy; drop a WAV to assign.
|
|
- Pads: click to select and play; drag to move, drag onto a filled pad to swap, Alt-drag to copy; drop a WAV to assign.
|
|
|
|
|
|
|
|
2.0 or later:
|
|
2.0 or later:
|
|
|
-- Start and end trim, together with a waveform view (moved out of 1.0: not useful without the waveform). The file fields are already verified (section 3).
|
|
|
|
|
|
|
+- Start and end trim, together with a waveform view (moved out of 0.5.0: not useful without the waveform). The file fields are already verified (section 3).
|
|
|
- Level and pan (fields not yet confirmed from a device file).
|
|
- Level and pan (fields not yet confirmed from a device file).
|
|
|
- Trigger and loop modes, envelopes, filters, effects, pad colours.
|
|
- Trigger and loop modes, envelopes, filters, effects, pad colours.
|
|
|
- Sequence editing (notes), including making notes follow a moved pad.
|
|
- Sequence editing (notes), including making notes follow a moved pad.
|
|
@@ -91,7 +91,7 @@ A pad's settings hold nothing that depends on its slot: all 128 blank pads are i
|
|
|
- Move: copy, then reset the source slot to the blank pad.
|
|
- Move: copy, then reset the source slot to the blank pad.
|
|
|
- Swap: exchange the two `pad[n]` objects.
|
|
- Swap: exchange the two `pad[n]` objects.
|
|
|
|
|
|
|
|
-Recorded notes follow the slot, not the sample (a note stores 36 + n). Moving a pad that has notes in a sequence changes what those notes play. Decided for 1.0: warn before moving a pad that has recorded notes, and leave the notes untouched. Rewriting notes to follow the pad belongs with sequence editing, a later feature.
|
|
|
|
|
|
|
+Recorded notes follow the slot, not the sample (a note stores 36 + n). Moving a pad that has notes in a sequence changes what those notes play. Decided for 0.5.0: warn before moving a pad that has recorded notes, and leave the notes untouched. Rewriting notes to follow the pad belongs with sequence editing, a later feature.
|
|
|
|
|
|
|
|
### Tune a pad
|
|
### Tune a pad
|
|
|
Three fields on the layer, written together:
|
|
Three fields on the layer, written together:
|
|
@@ -131,7 +131,7 @@ Copy the blank sequence, set `sequences[].key` to the slot (0-based), then name,
|
|
|
|
|
|
|
|
| Property | Path | Seen | Proposed |
|
|
| Property | Path | Seen | Proposed |
|
|
|
|---|---|---|---|
|
|
|---|---|---|---|
|
|
|
-| Project name | file name and `_[ProjectData]` folder name | DemoFile | 1.0 |
|
|
|
|
|
|
|
+| Project name | file name and `_[ProjectData]` folder name | DemoFile | 0.5.0 |
|
|
|
| Master tempo | `masterTempo`, `masterTempoEnabled` | 128.0, false in all three | 2.0 (sequences carry their own BPM) |
|
|
| Master tempo | `masterTempo`, `masterTempoEnabled` | 128.0, false in all three | 2.0 (sequences carry their own BPM) |
|
|
|
| Project key | `key` | "C Major" | 2.0 |
|
|
| Project key | `key` | "C Major" | 2.0 |
|
|
|
| Info tags | `info.title`, `artist`, `originalArtist`, `album`, `year`, `genre`, `copyright`, `notes` | all empty | 2.0 |
|
|
| Info tags | `info.title`, `artist`, `originalArtist`, `album`, `year`, `genre`, `copyright`, `notes` | all empty | 2.0 |
|
|
@@ -144,28 +144,28 @@ Copy the blank sequence, set `sequences[].key` to the slot (0-based), then name,
|
|
|
|
|
|
|
|
| Property | Path | Seen | Proposed |
|
|
| Property | Path | Seen | Proposed |
|
|
|
|---|---|---|---|
|
|
|---|---|---|---|
|
|
|
-| Name | `samples[].name` | "Linn 9000 kick" | 1.0 |
|
|
|
|
|
-| File | `samples[].path` | "Linn 9000 kick.wav" | 1.0 |
|
|
|
|
|
-| Load mode | `samples[].loadImpl` | 0 for one-shots and the user sample; 1 for three factory loops | 1.0, write 0 |
|
|
|
|
|
-| Tempo | `samples[].metadata.tempo` | 0.0 for the user sample; 20-114 for factory | 1.0, write 0.0 |
|
|
|
|
|
-| Root note, tune | `samples[].metadata.rootNote`, `tune` | 60, 0.0 | 1.0, defaults |
|
|
|
|
|
-| Key | `samples[].metadata.key` | "C Natural Minor" on the user sample | 1.0, default |
|
|
|
|
|
|
|
+| Name | `samples[].name` | "Linn 9000 kick" | 0.5.0 |
|
|
|
|
|
+| File | `samples[].path` | "Linn 9000 kick.wav" | 0.5.0 |
|
|
|
|
|
+| Load mode | `samples[].loadImpl` | 0 for one-shots and the user sample; 1 for three factory loops | 0.5.0, write 0 |
|
|
|
|
|
+| Tempo | `samples[].metadata.tempo` | 0.0 for the user sample; 20-114 for factory | 0.5.0, write 0.0 |
|
|
|
|
|
+| Root note, tune | `samples[].metadata.rootNote`, `tune` | 60, 0.0 | 0.5.0, defaults |
|
|
|
|
|
+| Key | `samples[].metadata.key` | "C Natural Minor" on the user sample | 0.5.0, default |
|
|
|
|
|
|
|
|
### Pad: assignment, tuning, trim (verified)
|
|
### Pad: assignment, tuning, trim (verified)
|
|
|
|
|
|
|
|
| Property | Path | Proposed |
|
|
| Property | Path | Proposed |
|
|
|
|---|---|---|
|
|
|---|---|---|
|
|
|
-| Sample | `layer.sampleName`, `layer.sampleFile` | 1.0 |
|
|
|
|
|
-| Slice end | `layer.sliceInfo.End` | 1.0, computed |
|
|
|
|
|
-| Pad tempo | `pad[n].tempo` | 1.0, computed |
|
|
|
|
|
-| Tune | `layer.coarseTune`, `fineTune`, `pitch` | 1.0 |
|
|
|
|
|
|
|
+| Sample | `layer.sampleName`, `layer.sampleFile` | 0.5.0 |
|
|
|
|
|
+| Slice end | `layer.sliceInfo.End` | 0.5.0, computed |
|
|
|
|
|
+| Pad tempo | `pad[n].tempo` | 0.5.0, computed |
|
|
|
|
|
+| Tune | `layer.coarseTune`, `fineTune`, `pitch` | 0.5.0 |
|
|
|
| Start, end | `layer.sliceInfo.Start`, `LoopStart`, `End` | 2.0, with waveform view |
|
|
| Start, end | `layer.sliceInfo.Start`, `LoopStart`, `End` | 2.0, with waveform view |
|
|
|
|
|
|
|
|
### Pad: playback
|
|
### Pad: playback
|
|
|
|
|
|
|
|
| Property | Path | Seen | Proposed |
|
|
| Property | Path | Seen | Proposed |
|
|
|
|---|---|---|---|
|
|
|---|---|---|---|
|
|
|
-| Mute group | `pad[n].whichMuteGroup` | 0 none; 1 on both hats in DemoFile; device offers 0-16 | 1.0 |
|
|
|
|
|
|
|
+| Mute group | `pad[n].whichMuteGroup` | 0 none; 1 on both hats in DemoFile; device offers 0-16 | 0.5.0 |
|
|
|
| Level, pan | `pad[n].mixable.volume`, `pan` | 0.7079 (unity), 0.5 centre | 2.0 (not yet seen changed) |
|
|
| Level, pan | `pad[n].mixable.volume`, `pan` | 0.7079 (unity), 0.5 centre | 2.0 (not yet seen changed) |
|
|
|
| Trigger mode | `pad[n].triggerMode` | 0; 3 on the looped pad | 2.0 until mapped |
|
|
| Trigger mode | `pad[n].triggerMode` | 0; 3 on the looped pad | 2.0 until mapped |
|
|
|
| Layer loop | `layer.loopMode`, `sliceInfo.LoopMode` | 0/1 | 2.0 until mapped |
|
|
| Layer loop | `layer.loopMode`, `sliceInfo.LoopMode` | 0/1 | 2.0 until mapped |
|
|
@@ -193,10 +193,10 @@ Copy the blank sequence, set `sequences[].key` to the slot (0-based), then name,
|
|
|
|
|
|
|
|
| Property | Path | Seen | Proposed |
|
|
| Property | Path | Seen | Proposed |
|
|
|
|---|---|---|---|
|
|
|---|---|---|---|
|
|
|
-| Slot | `sequences[].key` | 0, 1 | 1.0 |
|
|
|
|
|
-| Name | `seq.name` | "Intro", "Sequence 02" | 1.0 |
|
|
|
|
|
-| BPM | `seq.bpm`, `seq.tempoEnable` | 105, 110, 128; true | 1.0 |
|
|
|
|
|
-| Length | `seq.lengthBars` plus the 25 dependent fields | 2, 4 | 1.0 |
|
|
|
|
|
|
|
+| Slot | `sequences[].key` | 0, 1 | 0.5.0 |
|
|
|
|
|
+| Name | `seq.name` | "Intro", "Sequence 02" | 0.5.0 |
|
|
|
|
|
+| BPM | `seq.bpm`, `seq.tempoEnable` | 105, 110, 128; true | 0.5.0 |
|
|
|
|
|
+| Length | `seq.lengthBars` plus the 25 dependent fields | 2, 4 | 0.5.0 |
|
|
|
| Time signature | `seq.timeSignatureTrack.timeSignatures[]` | 4/4 | 2.0 |
|
|
| Time signature | `seq.timeSignatureTrack.timeSignatures[]` | 4/4 | 2.0 |
|
|
|
| Transpose | `seq.transposition` | 0 | 2.0 |
|
|
| Transpose | `seq.transposition` | 0 | 2.0 |
|
|
|
| Notes | `...eventList.events[]` type 3: `time`, `note`, `velocity`, `length`, `probability`, `ratchet` | up to 32 notes | preserve |
|
|
| Notes | `...eventList.events[]` type 3: `time`, `note`, `velocity`, `length`, `probability`, `ratchet` | up to 32 notes | preserve |
|
|
@@ -247,7 +247,7 @@ Four projects written by the Go writer (`tools/checkpoint-a`, built from commit
|
|
|
- **Tempo** (`MpckitTempo`): sequences at 20, 30, 300 and 999 BPM all work. The device's tempo control runs from 20 to 999, and mpckit uses the same range.
|
|
- **Tempo** (`MpckitTempo`): sequences at 20, 30, 300 and 999 BPM all work. The device's tempo control runs from 20 to 999, and mpckit uses the same range.
|
|
|
- **WAV headers** (`MpckitWav`): 48 kHz 24-bit stereo, 44.1 kHz 16-bit stereo and mono, all with the extensible header, play the same as a plain-header control.
|
|
- **WAV headers** (`MpckitWav`): 48 kHz 24-bit stereo, 44.1 kHz 16-bit stereo and mono, all with the extensible header, play the same as a plain-header control.
|
|
|
|
|
|
|
|
-Every item on the original 1.0 list (project name, pad sample assignment, sequence name, BPM, bar length, adding a sequence) plus pad tuning has now been written by these recipes and accepted by the device.
|
|
|
|
|
|
|
+Every item on the original 0.5.0 list (project name, pad sample assignment, sequence name, BPM, bar length, adding a sequence) plus pad tuning has now been written by these recipes and accepted by the device.
|
|
|
|
|
|
|
|
## 8. Open questions
|
|
## 8. Open questions
|
|
|
|
|
|
|
@@ -256,6 +256,6 @@ Every item on the original 1.0 list (project name, pad sample assignment, sequen
|
|
|
2. Level and pan have not been seen changed; confirm they are written to `pad[n].mixable`.
|
|
2. Level and pan have not been seen changed; confirm they are written to `pad[n].mixable`.
|
|
|
3. `triggerMode` values (0 and 3 seen) and how they pair with `loopMode`.
|
|
3. `triggerMode` values (0 and 3 seen) and how they pair with `loopMode`.
|
|
|
4. When a sequence with notes is shortened, are notes past the new end kept or removed?
|
|
4. When a sequence with notes is shortened, are notes past the new end kept or removed?
|
|
|
-5. Sample rates outside 22.05-96 kHz and 64-bit float are untested. (The extensible header was confirmed in checkpoint A; other WAV bit depths and sample rates are confirmed; non-WAV formats are out of 1.0.)
|
|
|
|
|
|
|
+5. Sample rates outside 22.05-96 kHz and 64-bit float are untested. (The extensible header was confirmed in checkpoint A; other WAV bit depths and sample rates are confirmed; non-WAV formats are out of 0.5.0.)
|
|
|
6. What key and tempo to write for a sample mpckit imports (the device detects them; mpckit cannot yet).
|
|
6. What key and tempo to write for a sample mpckit imports (the device detects them; mpckit cannot yet).
|
|
|
7. Is `currentSequence` a slot number or an index into `sequences[]`? Every file seen has 0, and slot 0 is stored second, so the files cannot tell. mpckit treats it as a slot (build plan 4.3); checkpoint B4 should remove the current sequence and check which one the device opens.
|
|
7. Is `currentSequence` a slot number or an index into `sequences[]`? Every file seen has 0, and slot 0 is stored second, so the files cannot tell. mpckit treats it as a slot (build plan 4.3); checkpoint B4 should remove the current sequence and check which one the device opens.
|