Custom firmware · Hermetic Modular Alchemy Lab V2 · build e35fad5

Markfor Alchemy Lab

Five loops under two buttons. The first one you record is the bar.

Heard, and still being tested

On 22 September 2026 it ran on a racked module: loops record and play back, the TRACK page works, B2 shows clock lock, and the SD picker switches between Mark, Smack and Belt with each keeping its own settings. Five tracks of 55 seconds each fit the module's SDRAM, and the native tests pass.

Not yet tried on hardware: a long run against a steady clock (drift would be a bug), the J4 / J5 trigger inputs, the CV inputs, a cold power cycle, and the CPU load with five tracks and their effects all running.

12 HP · 6 pots · 3 buttons · 10 jacks · 102 LEDs · drawn at true scale

What it does

01 — The idea

The Boss RC-505's workflow on a Eurorack module: five independent stereo loop tracks, each stepping record → play → overdub under one button, stop under the other, synced to a shared bar, with undo. What you patch into it keeps passing through underneath, and each of the five light rings is that track's display.

The rings

Five track displays

An RC-505 has five columns of coloured lights. This module has five rings around five pots. Each ring is its track: red recording, green playing, yellow overdubbing, white stopped, with a playhead running round it.

The bar

Your first loop sets it

With nothing on the clock jack, the first loop you record is exactly as long as you played it and becomes the bar every later loop snaps to. TEMPO only tells the module how many bars that was. With a clock on J3, everything snaps to that instead.

Two buttons

A track button and a stop button

Pick a track with the TRACK SELECT pot. B1 is that track's REC/PLAY: tap through record, play and overdub, hold for undo, hold longer to clear. B2 stops it; hold B2 for ALL.

It is the same C engine as Mark for the Ableton Move, recompiled for the Alchemy Lab: six pots on three pages, three buttons, six CV jacks that read independently of the pots, and 102 LEDs. Each track's one-shot, reverse, built-in effect and pan are on the TRACK page, a tap of B3 away. The one thing the Move version has that this panel does not is sessions saved to the card; the engine still has them. It also brings firmware swapping from the SD card, so this module can carry several firmwares and change between them from a settings page.

The panel

02 — Drawn at true scale · click any control

Every hole sits where it sits on an Alchemy Lab. The coordinates come from the SDK's own KiCad front-panel template, not from a photo, and the drawing is generated from them. The PLAY page is five track levels and the TRACK selector; the SETUP page appears while B3 is held; a quick tap of B3 swaps PLAY for the selected track's TRACK page and back.

rings as the firmware draws them
Select a control

The panel

6 pots × 3 pages · 3 buttons · 10 jacks · 102 LEDs
Hover or click anything on the drawing. Audio in and out, the front USB-C and the light rings are fixed Alchemy Lab hardware; everything else is what this firmware makes of them.
plate 60.96 × 128.5 mm · 12 HP
pot pitch 35 mm across, 28 mm down · rings 16 LEDs, 13 in the arc
source KiCad template, parsed
J1/J2 sit under the IN legend, J9/J10 under OUT. The six CV jacks between them are numbered here in reading order, which the template does not state: the numbers printed on your panel are the authority.

Playing it

03 — Five steps to the first two loops
1  Patch audio to J1 / J2 (IN). It passes through immediately.
2  Turn TRACK SELECT (P6, bottom right) to 1. The B1 light shows track 1's state: dim, empty.
3  Tap B1. The P1 ring turns red. It is recording, right now,
   because nothing is playing yet and nothing is clocking it.
4  Tap B1 again where the bar should end. The ring turns green
   and the loop plays. That length is now the bar.
5  Turn TRACK SELECT to 2, tap B1. The P2 ring blinks red until
   the bar line, then records for a bar and turns green on the next one.

Tap B1 on a playing track and it overdubs: the ring goes yellow and everything you play is layered onto the loop until you tap again. Tap B2 to stop a track; tap B1 to restart it on the next bar line. Hold B2 for ALL: every playing track stops, or every stopped track starts, on the spot.

Hold B1 past half a second for undo. The last thing you did to the loop, a first recording or an overdub, comes back off; hold again and it comes back on. The B1 light turns white the moment the hold has reached undo, so you know before you let go. Hold two seconds to clear the track.

Taps act when you let go, so a hold never fires the tap first. The cost is a release-time delay on the first loop's downbeat, and the grid then carries that consistently; every later loop lines up with it.

What "the bar" means here

The engine follows one grid. A running clock on J3 wins. Otherwise the first finalized loop anchors the bar. Otherwise, the tempo. So unclocked, your first loop is not quantized at all: it is as long as your two taps, and the module divides it by the TEMPO pot's bar to decide how many bars it was, one at 120 BPM for a two-second loop, two for four seconds. Everything after that snaps to that bar, or to the fraction of it that QUANTIZE picks.

That is the RC-505 with no rhythm running, and it is why the clock jack is handled the way it is.

The five rings, live

04 — The engine's track state machine, on the page

This is the RC's track logic as the firmware runs it: the same states, the same button cycle, the same rule that actions wait for the bar line once something is playing. Click a ring to select that track, then press the buttons. Rings draw exactly as the module draws them.

B1 light: the selected track B2 light: free-running bar: not set yet
Track 1 is empty. Tap B1 to record it; with nothing playing and no clock, recording starts at once.
RingMeans
near darkEmpty. The arc still shows the level, dimly, so a turned-down pot is not mistaken for an empty track.
redRecording. Filling from the start of the arc while the bar counts.
greenPlaying, with a white pip running once around the arc per loop pass.
yellowOverdubbing: playing and layering your input onto the loop at the same time.
whiteStopped, with a loop in it. Tap B1 to start it on the next bar line.
blinkingWaiting for the bar line: a record or a start that QUANTIZE is holding until the base track comes round.

The arc's length is the LEVEL pot, so the ring is doing two jobs. The levels are saved, and a saved level wins over where the pot happens to point: after a power cycle, or after the picker has switched in from another firmware that left the pots somewhere else, each ring shows an amber pip at the saved level until you sweep the pot past it. Then the pot takes over. The pip is amber so it cannot be mistaken for the white playhead.

The other pages

05 — What B3 buys back: hold it, or tap it

B3 does two things. Hold it and the same six pots are the RC-505's system menu: the grid, what a recording ends in, how an overdub lands, whether tracks are sections, the tempo and the master. Tap it and they become the selected track's own page: one-shot, reverse, an effect, its amount and pan. Settings, the SDK's layer, sits behind both.

SETUP — hold B3

The set-once things
PotParameterRangeRing
P1QUANTIZE, the grid a recording's length and a start snap toOff · Bar · Beat · 8th · 16th5 dots
P2REC →, what a recording drops into when you end itPlay · Overdub2 dots
P3DUB, whether an overdub layers onto the loop or replaces itOverdub · Replace2 dots
P4PLAY, Single makes starting one track stop the others: song sectionsMulti · Single2 dots
P5TEMPO, the bar length nothing else has set50–200 BPMlevel
P6MASTER, the loop mix out0–200 %level

Opening the page to look cannot change anything. The SDK's pot catch runs on the way in and on the way out: a SETUP pot only takes effect once you turn it through the value it already holds, and letting go of B3 hands the pots back to the PLAY page without jumping any level. All three pages are saved to flash a few seconds after you stop moving a pot, and come back at the next power-up or the next time the picker switches back to Mark; loop audio is never saved. Saved PLAY levels come back too, and each pot has to catch its saved level before it takes over.

First boot after flashing seeds the page with QUANTIZE Bar, REC → Play, Overdub, Multi, 120 BPM, 100%, and the PLAY page takes the pots where they are.

TRACK — tap B3

The selected track's own page · B3 light amber while it is showing
PotParameterRangeRing
P1ONE-SHOT, whether the track loops or plays once and stopsLoop · One-shot2 dots
P2REVERSE, the track plays backwards. Reversing a track that is overdubbing ends the overdub: the RC's ruleForward · Reverse2 dots
P3FX, the track's built-in insert effectOff · Low-pass · High-pass · Crush · Delay · Phaser · Ring mod7 dots
P4FX AMOUNT0–100 %level
P5PAN, with a small dead zone at centre so the middle is easy to findL50 – R50left · right, from a white centre
P6TRACK SELECT, the same selector as on PLAY, on the same pot1 · 2 · 3 · 4 · 5five dots in the tracks' own state colours, the selected one bright

One page, five tracks. The page always shows the track TRACK points at. Turn P6, or let J6 move it, and the page reloads with that track's values; each pot then has to catch the new track's value before it moves it, so walking through the tracks never drags one track's settings onto the next. B1 and B2 still record and stop here, so you can set a track's effect and keep playing without leaving the page. Every track's five values are saved with the rest of the state.

With the LEVEL rings out of sight, the P6 ring stands in for them: five dots in the five tracks' state colours, blinking while one waits for the bar line, the selected one at full brightness and the rest at a quarter. A tap is a press under 0.3 s that turned nothing and never met B2. The SETUP layer engages on the press, so SETUP flashes on the rings for the length of the tap. The B3 light says where the next tap lands you: dim violet on PLAY, dim amber on TRACK. The swatches here are brightened; on the module both are low-brightness tints.

First boot: every track Loop, Forward, FX off with the amount at 50, pan centre. Not here yet: loop length. The engine only accepts a length of up to one bar, so a pot for it would cut a longer loop down to a bar. Halving a loop needs a small engine change first.

Settings — hold B2 + B3 for two seconds

The SDK's own settings layer; B1 steps through its pages, B2 or B3 leaves
Page 1

Brightness · dry input · presets · clock ratio · USB

P1 ring brightness. P2 DRY INPUT: Through mixes what comes in on J1/J2 into the output, as the RC does; Muted outputs the loops only, for a mixer that already has the dry signal. P3 / P4 preset slot and action. P5 CLOCK RATIO: what one pulse on J3 is worth, ÷2, =1 (a quarter note, the default) or ×2. P6 USB PORT: Mac, Launchpad or Audio, below.

Page 2

Firmware

The SD card picker: P1 file, P2 flash, P3 DFU. The card section is about it.

Where it saves

Slot 13, Mark's own

Each firmware in the family autosaves to a slot of its own: Smack 12, Mark 13, Belt 14, Relay 15, counting from 0 (HostLink counts from 1). So switching to Belt and back leaves Mark as you left it. Slots 0–11 are for presets you save by hand. Saving one by hand into 12–15 overwrites that firmware's working state.

Settings pages at a glance

Page · potControlChoices, range, default
1 · P1BRIGHTNESS5–100% · default 30% · changes as you turn
1 · P2DRY INPUTThrough · Muted · default Through
1 · P3PRESET SLOT16 slots, 0–15 · picks the slot for P4
1 · P4PRESET ACTIONfully left: save · fully right: load · hold 3 s
1 · P5CLOCK RATIO÷2 · =1 · ×2 · default =1
1 · P6USB PORTMac · Launchpad · Audio · default Mac
2 · Firmware · P1FILEthe .bin files in /alchemy · up to 16
2 · Firmware · P2FLASHdip below ~85 %, then past ~95 % · writes and reboots
2 · Firmware · P3DFUdip below ~85 %, then past ~95 % · reboots to the bootloader
2 · Firmware · P4—nothing
2 · Firmware · P5—nothing
2 · Firmware · P6—nothing

B1 steps to the next page when you let go of it and is lit orange while Settings is open; a press of B2 or B3 leaves. DRY INPUT and CLOCK RATIO apply when Settings closes; BRIGHTNESS as you turn; USB PORT at the next power-up. Every Settings value except the picker's three is saved in Mark's preset slot 13 about five seconds after Settings closes; USB PORT is also written to /alchemy/usb.cfg on the card, shared by every firmware on it. The panel drawing has both pages: pick Settings 1 or Settings 2 above it and tap any pot, button or jack.

B2 stands down while B3 is held, so the two seconds of the Settings chord never fire ALL on the way in and letting go stops nothing. A B3 press that met B2 is never taken as a tap, so the chord never flips the page either.

The clock

06 — J3, and why it is quiet until a pulse arrives

Patch a clock to J3 and every loop snaps to it: a recording ends on its bar line, a start waits for its bar line, and CLOCK RATIO says whether one pulse is a half note, a quarter or an eighth. Leave J3 empty and the module makes its own bar from your first loop.

J3 empty

The first loop is the bar

No quantizing until something is playing. Your first recording is as long as your taps, and TEMPO says how many bars it spanned. Later loops snap to it.

J3 clocked

The clock is the bar

Pulses become the 24-pulse-per-quarter clock the engine already speaks. Every record length rounds to the grid, every start waits for the bar line.

Settings P5

Ratio

÷2, =1 or ×2 on what arrives, so a 16th-note clock and a quarter-note clock both make a four-beat bar.

The engine hears the clock jack only after a pulse has arrived on it. The clock adapter this firmware shares with Smack free-runs at the TEMPO when nothing is patched, which is what Smack wants; Mark does not, because a free-running clock would quantize the first loop to the TEMPO pot and take the bar away from your hands. So nothing is forwarded until J3 fires, and when the pulse train stops the module sends the engine a single stop and goes quiet again; the engine then carries on with the bar it already has.

J3 is read raw in the audio callback, not through the SDK's 20 Hz pot filter, which would smear a pulse. It fires on the magnitude of the swing away from the jack's calibrated zero, 1.5 V to assert and 0.5 V to release, so a pulse counts whichever way the front end signs it. The same reader watches J4 and J5 for the two trigger inputs. It reads once per 128-sample block, about every 2.7 ms, so use pulses of 5 ms or longer: shorter ones can be missed.

Loops do not follow the clock's tempo. Playback is always at the speed it was recorded. The clock places record, play and stop on the bar line, rounds loop lengths to whole bars, and times the delay effect. Change the clock's tempo and the loops keep their own. B2 turning blue on a clock has been seen on the module. A long steady-clock run to check for drift has not been done yet.

Jacks and CV

07 — Two triggers, three CV inputs, independent of the pots

The Alchemy Lab reads pots and jacks separately and the SDK adds them in software, per page and per pot. Two of the six jacks are triggers here, because a looper whose record button a sequencer can press is a different instrument from one it cannot.

JackDrivesPage
J3CLOCK — see above—
J4REC trigger — the selected track's B1, from a gate or trigger—
J5STOP trigger — the selected track's B2—
J6TRACK SELECT CVPLAY P6
J7LEVEL 1PLAY P1
J8LEVEL 2PLAY P2

A sequencer into J6 and a trigger into J4 records, plays and overdubs across all five tracks with no hands on the module. The triggers are edge-detected in the audio callback and acted on at the one-millisecond control poll, so the engine's parameter calls never run on the audio thread.

The routing is fixed and provisional; choosing it from the Settings pages is the obvious next version.

Reading the rings

08 — 96 LEDs around the pots, 6 beside the buttons

The five LEVEL rings are the track displays described above. The rest of the panel says what the firmware is doing.

WhereShows
LEVEL rings 1–5The track's state colour as a level arc, blinking while an action waits for the bar line, a white playhead once around per loop pass, and an amber pip at the saved level until the pot catches it.
TRACK ring · PLAYFive dots, the selected track bright.
TRACK ring · TRACK pageFive dots in the five tracks' state colours, the selected one bright and the rest at a quarter, blinking while pending. An empty selected track shows the selector blue.
SETUP · TRACK ringsThe SDK draws every pot's value in its colour, with its catch pip until the pot has caught.
B1 · TRACKThe selected track's state colour: dim blue empty · red · green · yellow · white stopped · blinking pending · white while a hold has reached undo
B2 · CLOCKblue locked to J3 · grey free-running · red = the audio callback is above 80%
B3 · SETUP / TRACKWhere a tap lands: a dim violet tint on PLAY, dim amber on TRACK. The SDK lights it in the page colour while SETUP is held.
P1 ring, first 2.5 sLast session's worst CPU load, as a bar. See below.
All three buttons redThe engine could not allocate its five tracks. The native test proves 55 seconds a track fits the pool with room, so this should be impossible; it fails loudly rather than running silently broken.

The boot report

The load, shown when you can look

You cannot watch a status light with five loops running and both hands on the pots, so the module measures its own worst-case load while you play and shows it on the P1 ring for the first two and a half seconds of the next power-up.

no data
first boot after flashing

A single dim blue LED means it has not measured anything yet. Green is under 75%, amber under 90%, red means it did not fit. Five loops reading and writing from external RAM is far less than Smack asks of the same silicon, so this number is expected to be comfortable. The worst case, five tracks each running a TRACK-page effect, has not been read off the module yet.

Firmware on the card

09 — Carry several firmwares, change between them from the panel

Hermetic's firmware treats the SD card as a place for presets and files. This one also reads .bin files from it, and can write one into the module's firmware slot, verify it, and reboot into it, from a settings page, with the module on and in the rack. Smack and Belt for the Alchemy Lab carry the same page, so any of the three can hand the module to any other.

Prepare the card

FAT32, a folder named alchemy

32 GB or under, MBR partition table, FAT32. Make a folder called alchemy in the root and put firmware images in it: any .bin built for the Alchemy Lab bootloader, this one included. On a Mac, run dot_clean on the card before ejecting so the picker does not list resource forks as files.

Or over USB

Without pulling the card

Files reach the card over USB while the module runs: the web programmer's file panel, or the repository's tools/hostlink-fs.mjs, which makes the folder and puts the images in it from a terminal. Uploads are staged and renamed onto their final name only after the firmware has checked the CRC.

The gesture

Hold B2 + B3 two seconds · tap B1 to the Firmware page
PotDoesRing
P1 · FILEPicks a file. One dot per .bin in the folder, the chosen one bright; turn to move the choice. green dots · red: no card · orange: no folder, or no files
P2 · FLASHWrites the chosen file. Turn it down below 85%, then all the way up. The dip arms it, so a pot that happens to be parked at maximum cannot fire on entry. It first compares the file with the firmware already running. If they are the same, nothing is written and nothing reboots, so your loops keep playing; turn down to go back to the list. teal comparing · solid green: already loaded · orange erasing · blue writing · green verifying · white, then reboot · blinking red: failed, nothing booted; turn down to try again
P3 · DFUSame gesture. Reboots into the bootloader's update mode and stays there for a USB flash: the escape hatch for a firmware that has no picker of its own. violet arming bar

What it refuses, and what it never touches

It checks the image's first eight bytes before erasing anything and refuses one that is not bootable from SRAM. The largest file it will take is the app slot up to the calibration sector, so the board's calibration record and the preset store are never in the erase path. If a write fails, the module blinks red and boots nothing; the bootloader is intact, and hold-B3-at-power-on still gets you a USB flash.

What has run. On 22 September 2026 the picker switched a racked module between Mark, Smack and Belt. It listed the folder, wrote and verified the slot, rebooted, and skipped the write when the chosen file was already loaded. Each firmware came back with its own settings: Mark's are kept in slot 13 and are not touched while another firmware runs. The failure paths (a bad image, a pulled card) have not been exercised.

USB and controllers

10 — One front port, three jobs: the Mac, controllers, or a sound card

The front USB-C does one thing per power-up. By default it talks to the Mac: the web programmer, presets, the card. Switched over, the Lab becomes the USB host for a Launchpad Mini MK3, a Launch Control XL and a Haute42 gamepad, or a two-in, two-out USB audio interface.

The USB port setting

Settings page 1 · P6, bottom right

Hold B2 + B3 for two seconds to open Settings, and turn P6, the bottom-right pot of Settings page 1. It is a three-way selector:

ModeThe front USB-C is
MacHostLink, the default: the web programmer, presets and the card's files, with the module racked.
LaunchpadThe USB host for controllers. The Lab drives a Launchpad Mini MK3, a Launch Control XL and a Haute42, through a powered dongle; see below. No HostLink this boot.
AudioA class-compliant USB audio interface (USB Audio Class 1): 2 channels in from J1/J2, 2 out to J9/J10, 48 kHz, 24-bit, no driver needed on a Mac. The looper is bypassed: what the computer plays comes out of J9/J10, what comes in on J1/J2 goes to the computer. There is no volume control in the path and J9/J10 are DC-coupled, so a DAW can send CV through them. No HostLink and no controllers this boot.

One setting for the whole card, from the next power-up

The mode is kept on the SD card in /alchemy/usb.cfg, shared by every firmware on it: each one adopts the card's value at boot and writes a change back, so switching firmware in the picker keeps the mode. A change takes effect the next time the module powers up.

Hold B1 while powering up for Mac mode for that one boot, whatever the setting says: the way back to the web programmer without opening Settings. The port has one USB role at a time, so Audio mode means no controllers, and neither Launchpad nor Audio mode has HostLink. The bootloader's DFU (hold B3 at power-on) is unaffected.

What B2 says about the port

B2 is borrowed while the USB side starts up
Launchpad mode

The host starting up

dim purpleThe first two seconds after power-up, before the host starts.
blueStarting the USB host.
cyanHost running, nothing on the wire: no dongle seen.
yellowA device is attached and enumerating, or the dongle's hub is up with no controller behind it yet.
redThe host gave up: an abort, an unsupported device, an error.
greenA controller is up. On Mark, B2 stays green for the session in Launchpad mode; it does not go back to the CLOCK colour.
whiteWhile any Haute42 button is held.
Audio mode

The interface

dim purpleNot started yet.
cyanWaiting for a computer.
yellowConnected, no stream open.
greenStreaming, at least one direction.

If the host does not come up, a report of what it saw is written to the card as /lpdiag.txt about 17 seconds after power-up, for reading back in Mac mode.

P1–P4 rings, while B2 is yellow or redHost forensics, Mark only: P1 the last host state before the first abort, P2 the enumeration step at that abort, P3 all green if the device said Novation (all red if it was never read), P4 the number of aborts.

Hooking up controllers

A powered USB-C dongle with a hub inside · up to three controllers at once
Power

The front port has no 5 V

The Lab's USB-C gives no bus power, so a controller needs it from somewhere else: a powered USB-C dongle with a USB hub inside. Power the dongle, plug it into the Lab's front USB-C, and plug the controllers into the dongle. The one it was developed with carries a hub and an Ethernet chip; a device that is not a controller, like the Ethernet chip, is switched off and skipped.

Behind the hub

Three at once, one hub deep

Up to three controllers at a time, full speed. Free ports are rescanned every half second, so a controller can go in after power-up. Unplugging one mid-session is not handled tidily: the host sees errors and may reset, so power down to rearrange. The gamepad is only recognised behind a hub, never plugged straight in.

ControllerUSB IDSet-up
Launchpad Mini MK3Novation 1235:0113None: the Lab puts it in Programmer mode and paints its pads.
Launch Control XLNovation 1235:0061None: factory template 1 is selected automatically at connect, and again if the template is changed on the device. The MIDI channel is ignored.
Haute42045E:028EMust be in XInput mode (GP2040-CE), where it shows up as an Xbox 360 controller.

While Settings is open the controllers do nothing: the pads, buttons and knobs are ignored and any held effect lets go. Knobs and faders move the pages' stored values, so what they set is saved like a pot move, and the panel pot then has to catch the new value before it takes over again.

Launchpad Mini MK3

Rows count from the top · tap or click any pad to see what it does
An example moment: track 1 recording, 2 playing, 3 overdubbing, 4 stopped, 5 empty. Colours approximate the Launchpad's palette.
PadDoesColour
Rows 1–5, pad 1REC/PLAY for tracks 1–5, the track's B1: tap record → play → overdub; hold 0.6 s and let go = UNDO/REDO; hold 2 s = clear the track.red rec · green play · yellow dub · dim green stopped · dim red empty · blinking while a change waits for the bar
Rows 1–5, pad 2STOP the track.dim red when the track holds a loop
Rows 1–5, pads 3–8The track's playhead, six steps per pass.in the track's colour
Rows 6–8Unused.off
Top 1ALL: start / stop every track, B2's job.dim green
Top 2UNDO / REDO.yellow: undo available · green: redo · off: nothing to undo
Top 3–8, right columnUnused.off

Launch Control XL

Factory template 1 · columns count from the left · tap any control
Columns 1–5 are tracks 1–5 (the same example moment as the Launchpad). Lit = in use.
ControlDoesLED
Faders 1–5Track LEVELs 1–5, the PLAY pots.—
Fader 6MASTER (SETUP P6).—
Knob columns 1–5Each column is its track's TRACK-page values: top knob FX type (Off · Low-pass · High-pass · Crush · Delay · Phaser · Ring mod), middle FX AMOUNT, bottom PAN. Column 3 sets track 3 whichever track is selected.dim amber · dim green · dim red
Upper buttons 1–5REC/PLAY/DUB for tracks 1–5, a tap of the track's B1. No hold gestures here: undo and clear are on the Launchpad and the panel.red rec · green play · amber dub · dim green stopped · off empty
Upper button 6ALL start / stop.dim green
Lower buttons 1–5STOP tracks 1–5.dim red when the track holds a loop
Lower button 6UNDO / REDO.amber when there is something to undo or redo
Column 7–8, buttons 7–8Unused.off

Haute42

Every button is hold-to-punch · tap any button

Hold a button and its effect plays; let go and it returns to dry. The last button pressed wins. Let it go while another is still held and that one takes over; with nothing held it is back to dry. The effects are a performance-effects stage on Mark's stereo output, after the looper, tempo-synced to TEMPO (SETUP P5), or to the J3 clock when one is patched.

LeftLow-passDownHigh-passRightCrushUpGateXStutter 1/4YStutter 1/8RBStutter 1/16LBBuzzAReverseBTape StopRTHalf SpeedLTEchoL3Stutter 1/2R3Drive
Left hand: Left, Down, Right. Thumb: Up. Right hand: X Y RB LB on top, A B RT LT below. L3 and R3 are extra buttons; where they sit depends on the controller.
ButtonWhereEffectWhat it does
Xright hand, top row, 1stStutter 1/4Repeats the quarter beat that starts at the moment of the press, for as long as you hold.
Yright hand, top row, 2ndStutter 1/8The same, an eighth of a beat.
RBright hand, top row, 3rdStutter 1/16The same, a sixteenth of a beat.
LBright hand, top row, 4thBuzzA 1/64-beat repeat: the sound frozen into a buzz.
Aright hand, bottom row, 1stReverseThe last two beats, backwards, looping while held.
Bright hand, bottom row, 2ndTape StopSlows to a halt over one beat, then silence until you let go.
RTright hand, bottom row, 3rdHalf SpeedAn octave down at half speed, re-anchored every two beats.
LTright hand, bottom row, 4thEchoA dotted-1/8 ping-pong echo, each side feeding the other. It keeps ringing after you let go: a dub throw.
Leftleft hand, ring fingerLow-passA low-pass filter sweeping down over two beats.
Downleft hand, middle fingerHigh-passA high-pass filter sweeping up over two beats.
Rightleft hand, index fingerCrushSample-rate and bit reduction.
UpthumbGateA 1/16 chop.
L3extra buttonStutter 1/2Repeats the half beat from the press.
R3extra buttonDriveWaveshaper distortion.

The stutters, reverse, tape stop and half speed play from a two-second record of the output that is always running, so they have something to work on the moment you press. Changes fade over about 1.5 ms, so a punch in or out does not click. The same stage and the same map are in Belt. They run in Launchpad mode only.

Button positions

The positions here follow the standard GP2040-CE hitbox mapping. If the controller's button mapping has been changed, the same effects follow the XInput button names (X, Y, RB, LB, A, B, RT, LT, the directions, L3, R3), not the physical positions. Start, Back and Guide do nothing.

Download it

11 — The firmware file, or the source

For the Alchemy Lab V2 only. This is a beta: the hardware tests above are not finished.

Download mark_alchemy.bin  All releases and notes

To build it yourself instead (a few minutes with the ARM toolchain installed):

git clone --recurse-submodules 
cd mark-alchemy
make libdaisy        # once
make                 # build/mark_alchemy.bin, ~346 KB, 55 s per track
make MARK_SECONDS=40 # a smaller capacity; the test proves it fits
make test            # the SDRAM pool, a first loop, the TRACK-page save

Needs arm-none-eabi-gcc, make and dfu-util. libDaisy has nested submodules, so the clone must be recursive or the HAL is missing. make BENCH_USB=1 BUILD_DIR=build-bench builds a variant with HostLink on the Daisy Seed's own micro-USB, for a module out of its case on a bench bootloader; it is not the one to rack.

Installing

12 — Through the front USB-C, and getting back to stock

The Alchemy Lab's bootloader serves DFU on the front-panel USB-C, so the module stays in the rack. Once this firmware is on it, so does every update after.

First time

Hold B3 at power-on

During the two-second boot window the rings run a warm-white comet. Hold B3 through it and they switch to a slow breathe with the B3 lights on: update mode. Then flash the .bin with Hermetic's web programmer, or from the repository:

make program-dfu
Every time after

Live

With Mark running, the module can be asked to reboot into update mode over HostLink and flashed in the same breath, no button held:

make program-live

Or put the new .bin on the card and use the picker.

Back to stock

Same door

Flashing any Alchemy Lab firmware, Hermetic's own included, the same way returns the module to it. Presets in the slots survive; this firmware's working state lives in slot 13 and is schema-guarded, so another firmware will not read it as its own.

Before you flash it

It is custom firmware. Hermetic Modular did not write it, did not test it and cannot support it, so please do not contact them about it. It has been played on one racked module, and the tests listed at the top are still open. If you run it, the things worth reporting are whether loops drift against a steady clock, whether J4 and J5 fire reliably, and what the boot report reads after a hard session with the TRACK-page effects on.

How it is built

13 — The parts worth knowing about

The engine's C file was not touched. Everything below is the layer between it and the Alchemy SDK, and the handful of decisions that shaped that layer.

PieceWhat it is
The engine, at 48 kHzMark's engine, byte-identical to the Move build's, with two edits in its header: the sample rate, because libDaisy offers no 44.1 kHz, and a build-time track capacity. 128-frame blocks, as the engine expects.
Its Move-only needs, stubbedThe engine uses threads for sessions and dynamic loading for external effects, neither of which exists on this board. Four small headers shadow the POSIX ones it includes and a stub file makes every such call fail the way the real one fails without the resource, so those features go inert instead of being cut out of the engine.
Five tracks in SDRAMA bump allocator in external RAM, 62 MiB of 64. The engine's own capacity ladder cannot work on it, because the allocator never gives memory back, so the capacity is fixed at build time and a native test proves it fits on the first attempt: 64.7 MB used, 55 seconds a track.
Three pages, one layerThe SDK's Pager makes SETUP a held layer on B3 with pot catch on the way in and out. Nothing on the PLAY page can jump because you looked at another one. A short B3 press is taken as a tap by the app, not the Pager (the Pager allows one binding per button), and flips PLAY and TRACK with GoToPage.
One TRACK page, five tracksThe Pager keeps one value per page and pot, so the five tracks' values live in the firmware's extras and the page is a window on the selected one. A track change reloads the page and re-arms catch; a preset load pushes all twenty-five values to the engine again. A native test checks the round trip and that one corrupt byte resets only that track.
Clock adapterGate edges become 24 ppqn MIDI clock, the same adapter as Smack, gated so the engine hears it only after a pulse and gets a stop when the pulses end.
Working presetSlot 13 (0-based) is Mark's own live state: all three pages, every track's TRACK-page values, the Settings and the CPU peak. It autosaves five seconds after the last change, PLAY levels included, once hands are off the buttons and the picker is idle, one 4 KB sector per save. At boot the home slot wins; slot 0, where earlier builds saved, is read once so that an older module keeps its settings. Loop audio is never saved. Adding the TRACK page changed the saved format, so the first boot of this build after a v0.1.0 one starts from first-boot defaults. That is the schema check doing its job.
The pickerThree Custom slots on a Settings page: a file scanner, a state machine that compares, erases, writes and verifies one step per frame, and a DFU hand-off. Shared, by copy, with Smack and Belt.
HostLinkProduct "Mark", all three pages, ten jacks, three buttons, a manual and the SD filesystem, over the front USB-C.
Budget~346 KB image. SRAM 72%, DTCM 76,300 B, SDRAM 97%. CPU: not yet read with the TRACK-page effects running.

Found something, or want it to do something it doesn't? Open an issue. A report from someone playing it is worth more than anything measurable on a laptop.

Specifications

Appendix
Platform

Alchemy Lab V2

Daisy Seed2 DFM: STM32H750 at 480 MHz, 64 MB SDRAM. 12 HP. Hermetic Modular's Alchemy SDK, beta.

Audio

48 kHz · 128

Stereo in on J1/J2, stereo out on J9/J10; the dry input passes to the output unless Settings mutes it.

Tracks

5 × 55 s

Five stereo loop tracks and an undo buffer, 64.7 MB of a 62 MiB SDRAM pool.

Grid

Bar · beat · 8th · 16th

Measure-quantized sync from a J3 clock or the first loop; polymetric loops on the finer grids.

Controls

6 × 3 · 3 · 6

Six pots on three pages, three buttons, a clock, two triggers and three CV inputs, 102 LEDs.

Storage

16 slots + card

Sixteen preset slots in QSPI flash, slot 13 Mark's working state; firmware images and files on a FAT32 microSD.

Per track

One-shot · reverse · FX · pan

Six insert effects: low-pass, high-pass, crush, delay, phaser, ring mod.

The rest of them

14 — The same engine, and its siblings

Mark started on the Ableton Move under Schwung. This is its second body, and one of three firmwares for this module that share the picker, the allocator and the shape of the code.

All of Tim's Alchemy Lab instruments, on one page →