A mod loader for Elektron firmware. You pick mods and supply the stock OS file Elektron publishes for your device. elekloader builds a custom OS file on your own machine, and you flash it the way you flash any OS update.
- Nothing from Elektron is distributed. A mod (
.elemod) carries only its author's bytes, the short instruction fragments needed to hook the OS, and hashes of the stock bytes it expects. Every build starts from your own stock file, recognised by its hash. - The bootloader is never touched. Mods can only change the main OS: the file format has no way to say anything else. Each output file is re-read and verified before it is written. So the stock OS file always recovers the device.
- Mods are checked against each other before anything is built. Two mods may not touch the same bytes, claim the same memory or the same named resource, or leave a requirement unmet.
| Device | OS | Status |
|---|---|---|
| Digitakt (mk1) | 1.53, 1.54 | supported |
| Digitone (mk1) and Digitone Keys | 1.43, 1.44 | supported |
| Octatrack (MKI and MKII) | 1.40C | supported: whole builds (format-1 mods); linkable mods with its own core, checked in an emulator, not yet on a unit |
| other Elektron devices | planned: see docs/DEVICES.md |
In your browser, nothing to install: https://irpina.github.io/elekloader/.
Drop in your stock OS file, add your mods or browse the mod shop, tick them,
build, and download the .syx (and, for the Octatrack, the .bin). The build runs in the page, in
Python compiled to WebAssembly (Pyodide), with
elekloader's own code, unchanged. The page shows its version and commit, and
whether that is the latest release's. Your files are never uploaded, the
site hosts no firmware, and it fetches nothing from any other site. The
latest release's core for your device is listed and ticked for you. See
docs/WEB.md.
Windows: download elekloader-<version>-windows.exe from
Releases and run it.
There is nothing to install and no Python needed. The first time, it asks
for your stock OS file (below). The core mod is built in: it is listed in the window, and ticked for you
with any mod that needs it. The exe is not signed, so Windows may say it
protected your PC: choose More info, then Run anyway.
macOS: download elekloader-<version>-macos.dmg from
Releases, open it,
and drag elekloader to Applications. It runs on Apple silicon and
Intel Macs, with no Python needed, and it is signed and notarized by Apple.
As on Windows, the first time it asks for your stock OS file, and core is
built in.
Any system, from source: Python 3.9 or newer, nothing else to install
(on Linux, Tkinter may be a separate package, such as python3-tk).
Download or clone this repository, then:
python -m elekloader # the window
python -m elekloader.patch --stock Digitakt_OS1.53.syx --mod core-2.1.elemod --mod a.elemod --out custom.syx --version 2.0a
python -m elekloader.patch --stock Digitakt_OS1.53.syx --mod core-2.1.elemod --mod a.elemod --checkWith pip install . the same commands are elekloader and elekpatch.
From source, core is not built in. Take your device's from
Releases (or build
it, below), and install it like any mod. There is one per device and OS:
| device | OS | core |
|---|---|---|
| Digitakt mk1 | 1.53 | core-2.1.elemod |
| Digitakt mk1 | 1.54 | core-2.1-os1.54.elemod |
| Digitone mk1, Digitone Keys | 1.43 | core-dn1-2.0a.elemod |
| Digitone mk1, Digitone Keys | 1.44 | core-dn1-2.0a-os1.44.elemod |
A mod is made for one OS version: one built for 1.53 is refused with a 1.54 stock file, and its author has to build it for 1.54 (docs/ADAPTING.md, "Another OS version").
You also need the stock OS file for your device, exactly as Elektron publishes it:
- Digitakt mk1:
Digitakt_OS1.54.syxorDigitakt_OS1.53.syx, from Elektron's Digitakt downloads; - Digitone mk1 or Digitone Keys:
Digitone_and_Digitone_Keys_OS1.44.syxor..._OS1.43.syx(one file serves both), from Elektron's Digitone downloads; - Octatrack MKI or MKII:
OCTATRACK_OS1.40C.syxorOCTATRACK_OS1.40C.bin(one file serves both), from Elektron's Octatrack downloads.
The .zip Elektron's site gives you works as it is. elekloader recognises
the file by its hash.
- Your stock OS file: the first time, elekloader asks for it (a
.syx, a.binor Elektron's.zip); Change stock firmware... (top right) picks another. The header then shows the device and OS version with a tick. Mods made for another device or OS version are hidden unless you tick Show mods for other firmware. - + Install from file...: add the
.elemodfiles of the mods you want. They are copied into your library. - Tick the mods (or double-click them). Each mod's status shows as you go: Enabled, Conflict, Needs another mod, or made for other firmware. The check below the list says when the set combines: "No conflicts ... Ready to build".
- OS version shown: what the unit will show as its OS version: 4 characters on the Digitakt mk1 and the Digitone mk1, 1 to 10 on the Octatrack.
- BUILD FIRMWARE: choose where to save the
.syx. elekloader builds it, verifies it (see below), and shows its sha256. For the Octatrack it also writes the card file, the.binbeside it.
The details pane shows each mod's description, every change it makes
(patch sites, the events it handles, its memory) and what it requires.
Profiles save a set of ticked mods. Your library, profiles and the stock
file you chose last are kept in %APPDATA%\elekloader (Windows) or
~/.elekloader.
Send the .syx to the unit the way Elektron describes for OS updates
(How to update your device).
For the Digitakt mk1 and the Digitone mk1:
- Connect it over USB and open Elektron Transfer.
- Select the unit and Connect.
- Drag the
.syxonto Drop files here. - Press YES on the unit.
Don't turn the unit off until the upgrade is done.
For the Octatrack, from the card (back it up first):
- PROJECT > SYSTEM > USB DISK MODE, and copy the
.binto the root of the card. - Eject the card on the computer, then leave USB DISK MODE on the unit.
- PROJECT > SYSTEM > OS UPGRADE, and confirm.
- When it restarts, power-cycle it once more before judging anything.
Recovery: the bootloader is never changed, so the stock OS file always
restores the unit. If a custom OS will not start on a Digitakt mk1 or a
Digitone mk1, hold FUNC while powering on for the startup menu, and
press TRIG 4 for OS UPGRADE.
Then send the stock .syx with Transfer's legacy OS upgrade mode. On the
Octatrack: hold FUNC while powering on, press TRIG 3 for MIDI
UPGRADE, and send the stock .syx over 5-pin DIN MIDI (USB MIDI does not
work for this).
The output is refused unless every one of these holds:
- It is your stock file with only the main OS section changed. The other sections, bootloader included, are byte for byte stock. The header differs only in its 4-character version field; the framing only in its message count.
- Every message checksum, counter and the content checksum are right, and the container fits the device's flash budget.
- The main OS unpacks to exactly the patched image, simulated the way the bootloader does it: in place, over its own staged copy.
For the Digitakt mk1, the writer produces the same bytes as elektron-firmware-tool when given the same main OS stream. For the Digitone mk1 (the same file family, with seven sections), it reproduces the stock file from its own main OS stream.
The Octatrack's files are checked the same way: the container header
differs only in its 10-character version field, every SysEx message's
checksum and the card file's checksum are right, and the .syx and .bin
carry the same container. The copy of the bootloader that the OS can
re-flash (0x400de1e0-0x400e21e0) must stay stock. The in-place unpack is
not simulated there: where its bootloader stages the image is not known
yet. From their own main OS stream, the writer reproduces Elektron's
.syx and .bin byte for byte.
Users install mods from their .elemod files.
docs/FORMAT.md describes both kinds:
- format 1: a whole custom build as one file;
- format 2: separate, linkable mods. A
coremod provides a hook bus; other mods subscribe to its events and add entries to each other's tables. The loader's linker places them, resolves their symbols and checks them.
Every set of format-2 mods needs the core mod for its device. The
Windows and macOS apps have them built in, and each release carries them:
one source, mods/core/core.s, built with each device's addresses
(mods/core for the Digitakt mk1, mods/core-dn1
for the Digitone mk1). Each mod.json gives the addresses of every OS it
supports (its os, and its ports): the stock file you build with picks
them. The Octatrack's, mods/core-ot, is
only the boot copier, with no hook bus: it reserves RAM for mods and copies
their code there. To build one yourself, use the SDK (below):
python -m elekloader.sdk.build mods/core --stock Digitakt_OS1.54.syx # the Digitakt mk1's (or 1.53)
python -m elekloader.sdk.build mods/core-dn1 --stock Digitone_and_Digitone_Keys_OS1.44.syx # the Digitone mk1's (or 1.43)
python -m elekloader.sdk.build mods/core-ot --stock OCTATRACK_OS1.40C.syx # the Octatrack'sFiles from before version 0.2 used the .dtmod extension; they still load.
See docs/ADAPTING.md: the path to take, the rules, each command with the output it should print, a table from every refusal to its fix, and a definition of done. Coding agents: start with AGENTS.md.
The tools, in brief:
python -m elekloader.sdk.build examples/hello-marker --stock Digitakt_OS1.53.syx # sources -> .elemod
python -m elekloader.lint my-mod-1.0.elemod --stock Digitakt_OS1.53.syx --with core-2.1.elemod
python -m elekloader.mkmod ... # a whole build -> .elemod
python -m elekloader.sdk.octabam --octabam octabam --stock OCTATRACK_OS1.40C.syx # octabam modules -> .elemodFor the Octatrack, elekloader.sdk.octabam converts
sambanks/octabam's ColdFire modules
into linkable mods. It checks each one against octabam's own account of
its bytes. See docs/ADAPTING.md, section 4b.
examples/hello-marker/ is a complete mod to start from. It is one C
function on the draw event, and it puts a small square in the corner of
every screen. Building code needs the device's cross toolchain; for the
Digitakt mk1 that is m68k binutils and gcc.
packaging/build_windows.py --core core-2.1.elemod [core-dn1-2.0a.elemod ...] builds
elekloader.exe with PyInstaller (packaging/requirements-build.txt). The
exe carries the cores in elekloader/bundled. The script checks the exe with
its --selftest (the version, Tk, the built-in cores and their hashes, the
devices it supports), then writes elekloader-<version>-windows.exe and
SHA256SUMS.txt.
The windows-build workflow (Actions, run by hand with a release's tag)
does the same on GitHub's Windows runner. It takes every core*.elemod from that
release and attaches the exe and SHA256SUMS.txt to it. core is built where
the stock OS file is and attached to the release first. No firmware
reaches the workflow.
packaging/build_macos.py --core core-2.1.elemod [...] builds
elekloader.app the same way, universal2 (Apple silicon and Intel; it needs
a universal2 Python, such as python.org's). With --identity (a Developer
ID Application certificate in your keychain) every binary in it is signed
with the hardened runtime; without, it is signed ad hoc, for trying on
your own Mac. It runs the app's --selftest as it will ship, signed, then
writes elekloader-<version>-macos.dmg and SHA256SUMS.txt. --notarize
has Apple notarize the app and the .dmg and staples both, with an App Store
Connect API key in NOTARY_KEY (the .p8 file), NOTARY_KEY_ID and
NOTARY_ISSUER.
The macos-build workflow (Actions, run by hand with a release's tag, like
windows-build) does all of that on GitHub's macOS runner and attaches the
.dmg to the release, adding its line to SHA256SUMS.txt. With test
ticked, it builds the branch it is run on with the given release's cores,
signs, notarizes and self-tests it the same way, and keeps the .dmg as the
run's artifact instead of attaching it: a check of the signing before a
release. It needs these repository secrets:
| secret | what |
|---|---|
MACOS_CERTIFICATE |
the Developer ID Application certificate with its private key, exported from Keychain Access as a .p12, base64-encoded |
MACOS_CERTIFICATE_PASSWORD |
the password the .p12 was exported with |
NOTARY_KEY |
an App Store Connect API key's AuthKey_<id>.p8, its text as it is |
NOTARY_KEY_ID |
that key's ID |
NOTARY_ISSUER |
the Issuer ID shown above the keys in App Store Connect |
python tests/test_units.py # needs nothing
ELEKLOADER_STOCK=Digitakt_OS1.53.syx ELEKLOADER_MODS=path/to/mods python tests/test_link.py
ELEKLOADER_STOCK=... ELEKLOADER_STOCK_154=Digitakt_OS1.54.syx ELEKLOADER_MODS=... python tests/test_sdk.py # the example needs the cross compiler
ELEKLOADER_RELEASES=folder/of/stock/files python tests/test_releases.py # every known release, and its cores
ELEKLOADER_STOCK=... ELEKLOADER_BUNDLE=bundle.elemod ELEKLOADER_CTOOL_SYX=its-build.syx python tests/test_patcher.py
ELEKLOADER_OT_SYX=OCTATRACK_OS1.40C.syx ELEKLOADER_OT_BIN=OCTATRACK_OS1.40C.bin python tests/test_octatrack.py
ELEKLOADER_OT_SYX=... ELEKLOADER_OCTABAM=path/to/octabam python tests/test_octabam.py # octabam optional
ELEKLOADER_DN_SYX=Digitone_and_Digitone_Keys_OS1.43.syx python tests/test_digitone.py
ELEKLOADER_STOCK=... ELEKLOADER_STOCK_154=... ELEKLOADER_OT_SYX=... ELEKLOADER_MODS=... python tests/test_gui.py # the window, hidden (Tk)
node tests/test_web.mjs build/site # the web page's engine, in Pyodide (packaging/build_web.py first)A test whose input files are not given is skipped, not passed. Firmware files never go in this repository.
GPL-2.0-or-later. See LICENSE, and NOTICE for the code that comes from digikit and for the credits. elekloader is not affiliated with Elektron. Flashing custom firmware is at your own risk.