Skip to content

Commit b084c0b

Browse files
bwhitmanclaude
andauthored
hwci: audition AMYboard World sketches over the SysEx control API (#1071)
Expand the AMYboard HW CI beyond the built-in reference tones: after the tones, download real AMYboard World sketches (shorepine's acid_generator, house_generator, universal_hair, woodpiano), push each onto the board over the SysEx "write to sketch" flow (docs/amyboard/control_api.md), drive it with a simple MIDI arpeggio, record it, and spectral-compare to a committed reference. This covers far more of AMY than the tones — the drum-heavy generators exercise the path PR #1067's drums regression broke, which the tone-only test missed. The World sketches are fetched with stdlib urllib (the Pi CI venv has no requests) and transferred with proper AK flow control — a stdbuf -oL `amidi -d` reader on the Pi / mido input callback on mac, one frame in flight. Without it the larger sketches' chunked transfers overflow the board's SysEx ring buffer and corrupt sketch.py, which self-heals to the silent default; the generative sketches recorded as silence until this was added. The random *_generator sketches still reproduce at ~0.98 spectral similarity run-to-run (timbre is stable even when the notes aren't), so they compare with the existing timing/phase-invariant avg-spectrum metric. References captured on the bench against the rolling amyboard release and listened-to before commit. Disable the suite with --no-flash's sibling --no-world. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 9fc8c68 commit b084c0b

6 files changed

Lines changed: 344 additions & 34 deletions

File tree

.github/workflows/amyboard-hwci.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ name: HW CI (AMYboard + Tulip)
55
# spectral-compare the audio to a committed reference. The hardware analogue of
66
# amy/test.py, for BOTH boards that share the bench:
77
# * AMYboard — driven over USB-MIDI + AMY zP sysex; firmware from the per-PR
8-
# Vercel preview (amyboard-pr-<N>.vercel.app). See hwci.py.
8+
# Vercel preview (amyboard-pr-<N>.vercel.app). Runs the built-in reference
9+
# tones, then pushes real AMYboard World sketches (acid/house/universal_hair/
10+
# woodpiano) onto the board over the SysEx control API and records each.
11+
# See hwci.py + docs/amyboard/control_api.md.
912
# * Tulip (TULIP4_R11) — driven over the MicroPython serial REPL (no USB-MIDI);
1013
# firmware from the 'tulip-firmware' artifact the preview workflow builds.
1114
# See tulip_hwci.py.
@@ -200,6 +203,10 @@ jobs:
200203
if-no-files-found: warn
201204
path: |
202205
hwci/hwci_basic-recording.wav
206+
hwci/acid_generator-recording.wav
207+
hwci/house_generator-recording.wav
208+
hwci/universal_hair-recording.wav
209+
hwci/woodpiano-recording.wav
203210
hwci/hwci_basic-serial.log
204211
hwci/hwci-run.log
205212
hwci/tulip_basic-recording.wav
@@ -236,13 +243,13 @@ jobs:
236243
marker,
237244
...head,
238245
'',
239-
`**AMYboard** (USB-MIDI + AMY \`zP\` → audio): ${line(amyPass)}`,
246+
`**AMYboard** (USB-MIDI + AMY \`zP\` → audio; built-in tones + AMYboard World sketches acid/house/universal_hair/woodpiano over the SysEx control API): ${line(amyPass)}`,
240247
'',
241248
`**Tulip** (TULIP4_R11; serial-REPL audio + WiFi screenshot): ${line(tulipPass)}`,
242249
'',
243250
`**[⬇️ Artifacts: recordings · screenshot · serial logs · run logs](${runUrl})**`,
244251
'',
245-
'<sub>Self-hosted bench. Audio spectral-compared to `ref/hwci_basic.wav` + `ref/tulip_basic.wav`; Tulip screenshot pixel-compared to `ref/tulip_screenshot.png`. Both analog outs share one capture card, so the tests run sequentially.</sub>',
252+
'<sub>Self-hosted bench. Audio spectral-compared to `ref/hwci_basic.wav`, the AMYboard World sketch refs (`ref/{acid_generator,house_generator,universal_hair,woodpiano}.wav`) + `ref/tulip_basic.wav`; Tulip screenshot pixel-compared to `ref/tulip_screenshot.png`. Both analog outs share one capture card, so the tests run sequentially.</sub>',
246253
].join('\n');
247254
const { data: comments } = await github.rest.issues.listComments({ owner, repo, issue_number: pr });
248255
const existing = comments.find(c => c.body && c.body.includes(marker));

0 commit comments

Comments
 (0)