Firmware

ep-series-sysex

Hype41/100

Unofficial open-source EP-133 and EP-40 SysEx protocol documentation and tooling

ep-series-sysex is custom firmware for the Teenage Engineering EP-133 K.O. II, by @kmorrill. Open source under MIT, 12 stars on GitHub.

forTeenage Engineering EP-133 K.O. II·by@kmorrill

Unclaimed. Is this yours? Sign in with GitHub as @kmorrill to claim it.

Downloads
0
Stars
12
Forks
0
Commits
3
Last commit
Get the source

No release files yet. Build from source.

MIT· kmorrill/ep-series-sysex·downloads come from the creator’s GitHub releases

3
Commits
0
Releases
3 commits and 0 releases in the last year
Activity · last 12 months

EP SysEx

Reverse-engineered documentation and tooling for the shared EP SysEx protocol and saved-project format. Transport and firmware claims are currently verified on EP-133 and EP-40 hardware; Riddim-only structures are identified explicitly.

Everything here was derived from capture-verified experiments against real hardware: single-variable device changes, full-archive before/after byte diffs, firmware-stamped hashed captures, and (for audio behavior) a closed loop that captures the device's own USB audio and measures it. Claims carry confidence markers — verified (round-trip or audio-proven), observed, or inferred — and open questions are catalogued rather than papered over. See docs/coverage.md for the provenance model and the current frontier.

Firmware of record: OS 2.5.1. Byte layouts can change across firmware releases; model-specific evidence is identified where it matters.

Unofficial. This project is not affiliated with or endorsed by Teenage Engineering. EP-133, K.O. II, and EP-40 are trademarks of Teenage Engineering. This documentation exists for interoperability. Writing to a device can corrupt projects if you violate the documented invariants — read docs/errors.md before sending anything, and keep backups.

The 60-second tour

  • A project exports as a .pak/.ppak — a ZIP with leading-slash entries (/meta.json, /projects/PNN.tar, /sounds/NNN name.wav).
  • /projects/PNN.tar is a stripped-header TAR whose members hold the project: pad records, pattern events + fader automation, scenes/song, settings, master FX.
  • Over the wire it's TE SysEx: F0 00 20 76 <product> 40 <flags|reqid> <cmd> <packed7> F7 — product byte 0x33 (EP-133) or 0x3C (EP-40) — with a filesystem-over-SysEx FILE protocol on top (read/write/list/metadata), which also exposes non-project state: the sample library, slot metadata, and active project/group/pad switching.

Documentation

DocCovers
docs/sysex-protocol.mdWire frame, packed7 encoding, request ids, GREET, status/rejections, debug frames, live events, identity
docs/file-protocol.mdFILE sub-commands, fid/node tree, read/write/metadata flows, project activation, non-project capabilities
docs/project-format.mdThe project TAR, byte-by-byte: pads, patterns, scenes, settings, fx_settings; safety invariants
docs/pak-container.mdThe .pak/.ppak ZIP outer container
docs/project-json.mdThe JSON project-description schema the compiler accepts
docs/hardware-testing.mdJSON→device HIL suite, MIDI/audio oracles, artifacts and recovery
docs/live-deployment.mdLow-overhead project writes during playback, measured tradeoffs and research flags
docs/ep40.mdRiddim-only loop mode, live, supertone engines and knob semantics
docs/midi-reference.mdMIDI note→pad maps, CCs, clock, device limits, fader parameter and FX enums
docs/errors.mdDevice error taxonomy, what causes each, and recovery
docs/measured-curves.mdAudio-measured response laws: amp, velocity, attack/release, pan, pitch
docs/coverage.mdWhat's verified vs believed vs unknown; open questions — contributions welcome

Tooling

epsysex/ is a self-contained Python package (stdlib-only core; mido needed only for talking to a device):

pip install -e .            # offline: compile, parse, diff
pip install -e ".[device]"  # + mido/python-rtmidi for device I/O
pip install -e ".[hil]"     # + NumPy/sounddevice for USB-audio hardware tests
# Compile a JSON project description into a project TAR (or a .ppak)
python3 tools/compile_project.py examples/example-project.json --out out.tar
python3 tools/compile_project.py examples/example-project.json --out out.tar --ppak out.ppak

# Talk to a connected device
python3 tools/identity.py                              # firmware/device info
python3 tools/read_project.py --project 1 --out p1.tar
python3 tools/send_project.py --tar out.tar --project 2  # checkpoints, writes, verifies, reloads
python3 tools/send_project.py --json project.json --project 2  # patches the live checkpoint
python3 tools/send_project.py --json project.json --project 2 --upload-missing-sounds

# Opt-in low-overhead live write (requires a captured baseArchive in the JSON)
python3 tools/send_project.py --json project.json --project 2 \
  --fast-live --trust-sound-slots --put-page-delay-ms 0

# Measure inactive-slot upload followed by a boundary-timed project switch
python3 tools/double_buffer_capture.py --tar out.tar --project 2 \
  --wav double-buffer.wav --report double-buffer-report.json --bpm 112

# Manage the shared sample library (slots 1–999, not part of any project)
python3 tools/sound_tool.py list
python3 tools/sound_tool.py put 56 --in kick.pcm --name kick --verify
python3 tools/sound_tool.py delete 56 --acknowledge-delete "DELETE SOUND 56"

# Inspect
python3 tools/diff_tars.py before.tar after.tar    # member-by-member changed byte ranges

The sample library is global — shared across all projects and never part of a project TAR. tools/sound_tool.py exposes list/stat/get/put/meta/play/delete on it (see docs/file-protocol.md). Destructive ops (delete, replacing an occupied slot) require an explicit acknowledgement string. Select the model-specific transport product only when the connected device requires it.

tools/send_project.py defaults to the safe path: it checkpoints the existing project, byte-verifies the write by reading it back, and runs the activation dance so the device actually loads it. JSON mode uses that checkpoint as a safe base, preserves unknown members, preflights referenced sound slots, and can upload declared missing WAV dependencies explicitly.

Run the test suite (no device needed):

python3 tests/test_roundtrip.py

Run the JSON-to-device hardware suite against a connected Riddim (this overwrites and then restores one explicitly acknowledged scratch slot):

python3 tools/test_device_json.py --list
python3 tools/test_device_json.py --run --project 9 \
  --acknowledge-overwrite "ERASE PROJECT 9"

The runner checkpoints the slot, compiles the authored JSON matrix, writes and byte-verifies every TAR, reloads it, drives playback with external MIDI clock, captures returned note events and stereo USB audio, writes a machine-readable report plus WAV evidence, and restores the checkpoint and previously active project. See docs/hardware-testing.md for setup, coverage, failure recovery, and the separately gated settings-member probe.

Offline tests generate their project archives from authored JSON. Device captures, OEM projects, samples, checkpoints, and live-test audio are intentionally excluded from source control.

Safety, briefly

Device FILE I/O must be serialized (the library takes a lock file for you — never run two device tools in parallel). A nonzero status with an ASCII reason is a clean, safe rejection. An unsolicited debug SysEx frame is not — stop, power-cycle, restore from your checkpoint. Never write a nonzero pattern-header byte 0, and don't fabricate a settings member from scratch. Details in docs/errors.md and docs/project-format.md.

Contributing

The highest-value contributions are captures that close entries in docs/coverage.md: remaining unknown byte ranges, OS 2.5 arpeggiator persistence, song-list repeat semantics, and the scale/root scope question. The methodology that produced everything here is described there too — one variable per capture, firmware-stamped, byte-diffed.

Prior art

Community projects that independently reverse-engineered parts of this protocol were used to cross-check findings (all re-verified against device captures; no third-party code is included): ep133-ppak, ep133-krate, knockout, and ep133-export-to-daw. Details and licenses in docs/coverage.md.

License

MIT — see LICENSE.