Add world.amyboard.download: run AMYboard World sketches on Tulip too#1125
Conversation
world.amyboard.download("eno_ambient", "dpwe") fetches the latest sketch.py
from AMYboard World into user/current/ and starts it the AMYboard way
(synths reset, _auto_generated_knobs applied, loop() on the sequencer);
world.amyboard.ls() browses recent sketches. Implemented in world.py
(AMYboard/Tulip hardware + desktop, via tuliprequests) and world_web.py
(both web ports, via js.fetch). Sketches are resolved through the existing
/api/amyboardworld/files listing (q= narrows server-side, exact filename
match client-side, newest first), so no server change is needed and this
works against production as-is.
To make sketches run on Tulip, amyboard.py is now frozen into the Tulip
esp32s3/macos/linux/web builds: cv_in()/cv_out()/set_cv_out() no-op off
AMYboard hardware, get_i2c() raises OSError on ports without machine.I2C so
the accessory helpers' missing-hardware paths apply, and run_sketch() lazily
probes the I2C OLED so amyboard.display works. I2C accessories (OLED,
rotary encoders) work unchanged on Tulip hardware.
Tested end-to-end on Tulip Desktop against the production API (download of
dpwe's eno_ambient with and without username, knob apply, loop() running on
the sequencer, CV no-ops, stop_sketch, missing-sketch error); Tulip Web and
TULIP4_R11 firmware builds verified.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🔌 AMYboard PR previewEditor + flasher: https://amyboard-pr-1125.vercel.app/editor/ This preview bundles this PR's firmware — its flasher only flashes this build (not the release). Rebuilt on every push; removed when the PR closes. The hardware CI has been kicked off and should return within a few minutes, stand by! |
🌷 Tulip Web PR previewTulip Web: https://tulip-pr-1125.vercel.app/run/ Flash a Tulip to this build: on-device run Rebuilt on every push; removed when the PR closes. |
🎛️ HW CI (physical bench)AMYboard (USB-MIDI + AMY Tulip (TULIP4_R11; serial-REPL audio + WiFi screenshot): ✅ PASS — flashed this PR’s firmware; all checks matched the references. ⬇️ Artifacts: recordings · screenshot · serial logs · run logs Self-hosted bench. Audio spectral-compared to |
What
world.amyboard.download("eno_ambient", "dpwe")fetches the latest sketch.py from AMYboard World intouser/current/and starts it the AMYboard way — synths reset,_auto_generated_knobsapplied,loop(step)scheduled on the bar-locked sequencer grid.world.amyboard.ls()browses recent sketches,start=Falsedownloads without running, andamyboard.stop_sketch()stops a running loop.Works in all four places:
world.pysync via tuliprequests,world_web.pyasync via js.fetch).amyboard.pyis now frozen into those builds (esp32s3, macos, linux, web manifests), so the sketch-start path is identical to AMYboard's, not a reimplementation.Tulip compatibility (
tulip/shared/amyboard-py/amyboard.py)cv_capable()check:cv_in()returns 0.0 andcv_out()/set_cv_out()no-op on non-AMYboard boards.get_i2c()converts a missingmachine.I2C(Desktop/web) intoOSError, which the accessory helpers already treat as "device absent" — so I2C accessories (OLED, all three encoder types, neopixels) work unchanged on Tulip hardware and degrade to safe defaults elsewhere.run_sketch()lazily probes the I2C OLED on Tulip (AMYboard inits it at boot), soamyboard.displayis always usable.No behavior change on AMYboard boards —
cv_capable()is true there and all paths are unchanged.Server
No server changes. Sketches are resolved through the existing
/api/amyboardworld/fileslisting (q=narrows server-side, exact filename match client-side, newest-first → first hit is the latest revision), so this works against production as-is.Testing
eno_ambient(with and without username), knobs applied (1419 bytes),loop()running and sequencing notes, CV calls no-op'd,stop_sketch()works, missing sketch prints a friendly error.amyboardfrozen in), TULIP4_R11 esp32s3 firmware (13% app-partition headroom remaining).Docs updated in
docs/tulip_api.mdanddocs/amyboard/online.md.🤖 Generated with Claude Code