mi-alchemy
Mutable Instruments Clouds, Elements, Marbles, Plaits,
Warps and Beads (Emilie Gillet, MIT), plus Meld (Warps with stock Warps as a
tenth mode and a coincidence clock and envelope CVs, from ~/tim-os/meld), as firmwares for the Hermetic Modular
Alchemy Lab V2, on the Alchemy SDK. The DSP is vendored from
pichenettes/eurorack at 08460a6,
and for Warps from Matthias Puech's
Parasites at 32fa66f; Beads,
whose source was released on 2026-10-12, is from eurorack d8f4739. It is
unmodified except two marked fixes and one upstream flag (Beads' 48 kHz
path); Meld's stock-Warps copy is a mechanical
namespace rename (vendor/VENDOR.md). Each
firmware's shim does what the original's cv_scaler/ui code did, on six
pots, three buttons and ten jacks.
| Firmware | Rate | Autosave (slot until v0.1.0) | Image (of 480 KB) | Panel + jacks |
|---|---|---|---|---|
| Clouds | 32 kHz / 32 | clouds.st (was 8) | 387 KB | src/clouds/DESIGN.md |
| Elements | 32 kHz / 16 | elements.st (was 9) | 366 KB, plus a 338 KB samples file on the card | src/elements/DESIGN.md |
| Marbles | 32 kHz / 16 | marbles.st (was 10) | 399 KB | src/marbles/DESIGN.md |
| Plaits | 48 kHz / 24 (2×12) | plaits.st (was 11) | 451 KB (engine at -Os) | src/plaits/DESIGN.md |
| Warps (Parasites) | 96 kHz / 60 | warps.st (was 7) | 393 KB | src/warps/DESIGN.md |
| Meld | 96 kHz / 60 | meld.st (was 6) | 457 KB (engines at -O2) | src/meld/DESIGN.md |
| Beads | 48 kHz / 12 (Clouds quality resampled to 32 kHz) | beads.st (never had one) | 474 KB (engine at -Os), plus 768 KB of SDRAM | src/beads/DESIGN.md |
All seven are siblings of smack/mark/belt/relay-alchemy. They include the
same SD-card firmware picker (Settings page 1), keep their working state in
their own file on the card (/alchemy/state/<fw>.st), autosave 5 s after the last change, catch pots
after a firmware switch, and show last session's CPU peak on the P1 ring at
boot.
Build
git submodule update --init && git -C lib/libDaisy submodule update --init --recursive
make libdaisy once
make FW=clouds build-clouds/clouds_alchemy.bin (FW = clouds | elements | marbles | plaits | warps | meld | beads)
make every all seven
make size image sizes against the 480 KB SRAM region
make test native suites for all seven (host compiler, ASan/UBSan)
make stage copy bins (+ elements.smp) to ../daisy-sdk/alchemy-lab/
Never build with a module attached in DFU. Flashing is a manual step:
use the SD picker, or make FW=x program-live DFU_SERIAL=<serial>.
Card layout
/alchemy/clouds_alchemy.bin elements_alchemy.bin marbles_alchemy.bin plaits_alchemy.bin warps_alchemy.bin meld_alchemy.bin beads_alchemy.bin
/mi/elements.smp Elements' exciter samples (build-elements/elements.smp)
/alchemy/state/<fw>.st each firmware's autosaved panel (written by the firmware)
Without /mi/elements.smp, Elements still runs. Its strike samples and
blow noise are silent, B1 rests dim amber, and the P2 ring shows red at
boot.
Where the panel is saved
Every firmware here autosaves its panel to its own file on the card,
/alchemy/state/<fw>.st (src/common/home_state.h; format in
state_file.h, tested by make -C test test-state-file). It writes 5 s
after the last change, hands off, never while Settings or the picker is
busy, as a .tmp then renamed. A file named after the firmware can't
collide with another's, so there is no slot map to keep.
Up to v0.1.0 they autosaved to QSPI preset slots instead: Meld 6, Warps 7,
Clouds 8, Elements 9, Marbles 10, Plaits 11. The SDK has 16 slots for the
whole module, and by 2026-10-13 sibling repos held the rest (Hypjolin 1,
Tally 2, Stencil 3, Break 4, Seq 5, Smack 12, Mark 13, Belt 14, Relay 15),
with Beads still to place. Each firmware now names its old slot as
legacy_slot. When the card has no <fw>.st, that slot is read once
(schema-checked, so another firmware's state is never misread) and written
to the card at the first autosave. The slot itself is never written again,
so 6–11 are free for presets saved by hand. Their old contents sit there
until something overwrites them.
Rules the helper keeps:
- No card: nothing is saved (it retries every 30 s), and the next boot falls back to the legacy slot or defaults.
- If the card wasn't readable at boot, autosave won't replace an existing file that session, so a late-mounting card never loses its saved panel to defaults.
host.BootSlotis left at the SDK default of 0, which is what the web programmer sees. Slot 0 still loads first at boot (BootLoad), then the card file overrides it, as a home slot did.
The manuals in docs/ describe v0.1.0 and its slots; they change with the
release that ships this.
Counting Beads, there are 17 Lab firmwares, one more than the picker's 16
bins (kMaxFiles), so one stays off any given card.
v0.1 scope
- HostLink only. No Launchpad, no USB-audio mode, and
/alchemy/usb.cfgis never written, so a card set to Launchpad keeps that setting for the other firmwares. - Nothing has been flashed or heard. Hardware checks are listed in each DESIGN.md.
Layout
src/common/ picker (shared by copy with the sibling repos), mi_family.h, linker script
src/<fw>/ fw.mk, <fw>_alchemy.cpp, DESIGN.md
src/shim/ stand-ins for upstream headers that pull in STM32F drivers
vendor/ eurorack subset + VENDOR.md
test/ native suites; test/<fw>.mk per firmware
