A fork of the Synthux Academy Spotykach firmware, restructured so the instrument is a fixed hardware and UI platform with a swappable DSP engine. Each firmware build replaces only the engine and its parameters.
The panel does not change when you flash a different engine. The same controls mean the same things, so what you learn once keeps working — and an engine is free to be a looper, an effect, a sampler or a whole scripting language behind it.
Browse the engines
Every engine has a page: what it does, what it expects on the card, and how to get it onto the device.
What stays the same across every engine
- Encoders with pickup behaviour and LED ring feedback
- Pad gestures and transport controls
- CV and gate I/O, and MIDI
- SD-card storage, and a clock every engine can sync to
The platform is decoupled from any engine by construction — the hardware, UI, memory and transport code carries no engine-specific dependency, and a build-time check fails the build if one is introduced.
Engines are written three ways
In C++ against the engine interface; in Faust, from a .dsp source and a small
manifest with no hand-written C++ at all; or in Max/MSP gen~, translated to
C++. The generated paths are not toys — the reverb and several others ship from them.
One firmware image each: flash the one you want, and the device becomes that instrument. Pick one to see what it does and what it expects on the card.
Makes an empty card the firmware can read. Format it FAT32 first.
Unpack it so the folders sit at the card's root. Then add audio on Convert, and if anything misbehaves later, point Verify at the card.
What it creates — the files, the folders
Every folder the firmware looks for, a README in each one restating that folder's rules,
the default SK/config.txt, radio/rate.txt,
bard/BARD.CFG, and the example chuck and csound patches. Byte for byte the
card sk_card.py init --no-demo builds, and it passes Verify with nothing to
report.
Want demo audio too?
The released sk-card-<version>.zip is a complete card with synthesized
audio for every engine, and it is checksummed. This page builds the skeleton only rather
than regenerating that content, so what you download from the release is what everyone
else has.
Get
it from the latest release.
Converts your audio to exactly what the target engine reads. mp3, flac, wav, ogg, m4a.
On resampling, and why this is not the CLI
The browser's resampler is not bit-identical to libsox's or ffmpeg's. None of the three agree with each other today, so this is not a regression — but it does mean this page cannot reproduce a particular card byte for byte. For a 50x pstretch source, where artefacts have a long time to become audible, converting with ffmpeg is worth comparing against.
The upside is the reason this screen exists: decoding happens in the browser's own audio engine, so there is no install and no format-support lottery. The CLI needs ffmpeg, or cysox plus a libsox built with the right handlers.
Checks a card and explains anything that will not work.
Why a bad card gives no error on the device
Engines read this card using several folder layouts and several incompatible audio formats, and the firmware converts nothing. A file in the wrong format is not rejected, it is read as raw bytes and plays as noise; a filename over a few characters is skipped by the directory scan with no error shown. The hardware's only feedback is an LED, so every one of these fails silently. This finds all of it.
Every engine, what it does, and what it expects on the card.
Where these facts come from
The card rules are generated from the same table the firmware and the command-line tools
read, so this page cannot disagree with
python3 scripts/sk_card.py layout. The engine descriptions are the opening
paragraph of each docs/engines/<name>.md, so they cannot drift from the
documentation either.
make ENGINE=<engine> TERMINAL=1.
Why released firmware has no terminal, and what it costs
scripts/build_release.py never passes TERMINAL=1, so every binary
in dist/ lacks the command channel and this screen finds nothing to talk to.
Shipping terminal-enabled releases is an open firmware decision: it costs ~19-25 KB of
SRAM_EXEC everywhere, and on the QSPI engines (chuck, csound, mosc) it costs USB MIDI,
which claims the same OTG core.
The control surface above is generated from the device's own describe reply
— every control is one this build actually advertises, and nothing appears for the
enum entries it ignores. Destructive verbs ask before firing.
Why this is safe to interrupt, and what it will not do
This page writes one address and one only: the application region at
the app region, in QSPI. The bootloader lives somewhere
else entirely — internal flash at 0x08000000 — and nothing here
can address it.
So the worst case is a device with a half-written app and a working bootloader. Hold Reset for about 3 seconds until the pad LEDs breathe white, and flash it again. That is a retry, not a brick.
Installing a bootloader is the operation that genuinely can brick a device, it is done
once per unit, and it is not offered here. Use dfu-util for it.
Where the device allows it, the image is read back and compared byte for byte after writing, so a successful flash is measured rather than assumed.
If the device does not appear
The device must be in bootloader mode first: hold Reset for about 3 seconds until the pad
LEDs breathe white. It then enumerates as 0483:df11.
WebUSB is Chromium-only — Chrome or Edge. Firefox and Safari do not implement it and will not; the command-line path works everywhere:
dfu-util
On Linux, a udev rule is needed for a non-root browser to claim the interface — the
same rule dfu-util needs.