Update script for stand-alone ppak generation#2
Conversation
Continue to reverse engineer the ppak format on a 128 mb EP-133 K.O. II with OS 2.0.5. The goal is to generate a stand-alone ppak file without relying on copying settings from a backup. EP-133 Format Findings Error Clock 43 — BPM Must Be Non-Zero The settings file (222 bytes) stores BPM as a float32 LE at bytes 4–7. A zero BPM causes "Error Clock 43" on load. Always write a valid BPM there, and also at bytes 12–15 of every pad file. Pads Silent After Loading Four separate root causes, discovered in order: 1. Per-pad volume (byte 16) defaults to 0 Pad file byte 16 is volume (0–100). An uninitialized bytearray(27) leaves it at 0 = silent. Fix: set data[16] = 100. 2. Group project volume defaults to 0 The settings file has four group volume floats at offsets 24, 72, 120, 168. An uninitialized settings buffer leaves them at 0.0 = silent. Fix: write float32(1.0) at those offsets. 3. Settings sentinel value is -1.0, not 0.0 All other float slots in the settings group blocks (48 bytes × 4 groups) must be filled with -1.0 (0x000080bf), which the device treats as "use default." Writing 0.0 is interpreted as zero and silences those parameters. 4. Sample ROM ID (bytes 8–9) — the critical one Bytes 8–9 of each pad file are a uint16 LE that the device uses to locate the sample's audio data in ROM. Without the correct value, the pad shows the right sample name in the UI but produces no sound. Zero is not a valid stand-in. These are not derivable from the sample number — they are firmware ROM addresses discovered empirically: ┌────────┬───────────────┬────────┐ │ Sample │ Name │ ROM ID │ ├────────┼───────────────┼────────┤ │ 1 │ MICRO KICK │ 22412 │ ├────────┼───────────────┼────────┤ │ 31 │ BOOMER KICK │ 30133 │ ├────────┼───────────────┼────────┤ │ 126 │ SNARE OPEN │ 18697 │ ├────────┼───────────────┼────────┤ │ 203 │ CLOSED HAT LO │ 7558 │ ├────────┼───────────────┼────────┤ │ 221 │ OPEN HAT REAL │ 14798 │ └────────┴───────────────┴────────┘ Discovery method: assign the sample on-device (or reassign away and back), take a project backup, extract bytes 8–9 from the pad file in the backup tar. ROM ID Structure Internal storage order is hats → snares → kicks — opposite of the user-facing 200s/100s/1s numbering. Within each category, higher sample number = higher ROM offset. The slope differs by category (~402 ROM units/sample for hats, ~257 for kicks), reflecting different average sample lengths. Labeled Pad Numbers ≠ File Numbers The numbers printed on the device do not match the p01–p12 file numbers in the tar. The bottom two rows are swapped: Row 3 (labeled 1-3) → files p07-p09 Row 1 (labeled 7-9) → files p01-p03 Rows 2, 4 (labeled 4-6, 10-12) → files p04-p06, p10-p12 (direct) Pattern events reference pad file numbers via row_byte = (file_num - 1) * 8. Using labeled numbers directly sends events to the wrong pads. Two Separate Volume Controls - Byte 16 of the pad file: per-pad volume (0–100). Fixed at write time; the sound-edit volume knob on the device does not update this. - Group project volume float in the settings file: what the volume knob actually controls (0.0–1.0). Both must be non-zero for sound to play.
|
Hey this is a pretty big diff so don't feel pressured to take this PR. I just wanted to post an update somewhere about some additional reverse engineering discoveries. Notably: setting non-zero volumes and BPM, the pad labels being flipped from their internal IDs, and the necessary ROM offset values for samples. This last one is kind of a blocker. There's no real way to pre-calculate the ROM offset. |
|
Hey, dropping in from EP-PatchStudio (https://ep-patch.studio). Spotted this PR while looking at the same pad-byte questions and wanted to share some data in case it helps. I ran the analysis across a few real backups from my EP-133 K.O. II and EP-40 Riddim and the bytes 8-11 value is not a ROM offset. It is the assigned WAV's frame count. Numbers checked exactly:
The two EP-40 outliers were both the same pad with a user-trimmed sample (the value sat at 67% of the WAV's full length, exactly what you would expect if someone trimmed the sample end on the device). Your own table corroborates it once you divide by 44100:
Every one of those is a plausible drum-hit duration for the named sample. So the interpretation that fits the data:
Bytes 4-7 and 8-11 together describe a playback window into the sample. Your "assign on device, take backup, extract bytes 8-9" discovery method worked because the device needs the playback end frame to be correct. When it is zero the device plays zero frames and you get silence. When you copy from a real backup you are copying the device's already-correct end frame. For the standalone .ppak use case this is much better news. To reference factory sample N from scratch you only need:
No lookup table required, no firmware-version dependency, and the backup format stays self-describing which is the nice architectural property the .pak format seems to lean into anyway. Two more bits in case useful:
Happy to share the analysis script and the raw extract if it would help. I have several more backups across EP-133, EP-40 and EP-1320 if there are other byte interpretations you would like to settle. Joe |
Continue to reverse engineer the ppak format on a 128 mb EP-133 K.O. II with OS 2.0.5. The goal is to generate a stand-alone ppak file without relying on copying settings from a backup.
EP-133 Format Findings
Error Clock 43 — BPM Must Be Non-Zero
The settings file (222 bytes) stores BPM as a float32 LE at bytes 4–7. A zero BPM causes "Error Clock 43" on load. Always write
a valid BPM there, and also at bytes 12–15 of every pad file.
Pads Silent After Loading
Four separate root causes, discovered in order:
Per-pad volume (byte 16) defaults to 0 Pad file byte 16 is volume (0–100). An uninitialized bytearray(27) leaves it at 0 = silent. Fix: set data[16] = 100.
Group project volume defaults to 0 The settings file has four group volume floats at offsets 24, 72, 120, 168. An uninitialized settings buffer leaves them at 0.0 = silent. Fix: write float32(1.0) at those offsets.
Settings sentinel value is -1.0, not 0.0 All other float slots in the settings group blocks (48 bytes × 4 groups) must be filled with -1.0 (0x000080bf), which the device treats as "use default." Writing 0.0 is interpreted as zero and silences those parameters.
Sample ROM ID (bytes 8–9) — the critical one Bytes 8–9 of each pad file are a uint16 LE that the device uses to locate the sample's audio data in ROM. Without the correct value, the pad shows the right sample name in the UI but produces no sound. Zero is not a valid stand-in.
These are not derivable from the sample number — they are firmware ROM addresses discovered empirically:
┌────────┬───────────────┬────────┐
│ Sample │ Name │ ROM ID │
├────────┼───────────────┼────────┤
│ 1 │ MICRO KICK │ 22412 │
├────────┼───────────────┼────────┤
│ 31 │ BOOMER KICK │ 30133 │
├────────┼───────────────┼────────┤
│ 126 │ SNARE OPEN │ 18697 │
├────────┼───────────────┼────────┤
│ 203 │ CLOSED HAT LO │ 7558 │
├────────┼───────────────┼────────┤
│ 221 │ OPEN HAT REAL │ 14798 │
└────────┴───────────────┴────────┘
Discovery method: assign the sample on-device (or reassign away and back), take a project backup, extract bytes 8–9 from the pad
file in the backup tar.
ROM ID Structure
Internal storage order is hats → snares → kicks — opposite of the user-facing 200s/100s/1s numbering. Within each category,
higher sample number = higher ROM offset. The slope differs by category (~402 ROM units/sample for hats, ~257 for kicks),
reflecting different average sample lengths.
Labeled Pad Numbers ≠ File Numbers
The numbers printed on the device do not match the p01–p12 file numbers in the tar. The bottom two rows are swapped:
Row 3 (labeled 1-3) → files p07-p09
Row 1 (labeled 7-9) → files p01-p03
Rows 2, 4 (labeled 4-6, 10-12) → files p04-p06, p10-p12 (direct)
Pattern events reference pad file numbers via row_byte = (file_num - 1) * 8. Using labeled numbers directly sends events to the
wrong pads.
Two Separate Volume Controls