Skip to content

Commit 7e5b52a

Browse files
authored
Merge pull request #1100 from shorepine/hwci-world-suite-fixes
hwci: record generative sketches clean; fix cross-sketch audio contamination
2 parents 9953133 + 82b851d commit 7e5b52a

3 files changed

Lines changed: 32 additions & 9 deletions

File tree

tulip/amyboard/hwci/hwci.py

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,9 @@
8181
# from loop() (started by the sequencer that environment_transfer_done() kicks off)
8282
# and use random() — so run-to-run they differ in the notes but not the timbre, and
8383
# the timing/phase-invariant avg-spectrum compare still matches. `woodpiano` is a
84-
# bare DX7 patch that only sounds when we send it MIDI notes. We send the simple
85-
# MIDI pattern to every sketch (it also proves the USB-MIDI note path per sketch).
84+
# bare DX7 patch that only sounds when we send it MIDI notes. Only non-generative
85+
# sketches get the simple MIDI pattern (which also proves the USB-MIDI note path);
86+
# generative sketches are recorded as-is so the reference is purely their own output.
8687
WORLD_SUITE = [
8788
{"name": "acid_generator", "author": "shorepine", "generative": True, "min_sim": 0.80},
8889
{"name": "house_generator", "author": "shorepine", "generative": True, "min_sim": 0.80},
@@ -176,9 +177,20 @@ def send_python(self, code, timeout=ACK_TIMEOUT):
176177
return self.link.send_python(code, timeout=timeout)
177178

178179
def load_world_sketch(self, text, settle=1.5):
179-
"""amy.reset() → transfer → environment_transfer_done() (restarts the
180-
sketch and starts the sequencer, so generative loop()s begin playing).
181-
Give the sketch a moment to init before we start recording it."""
180+
"""Silence the PREVIOUS sketch first, then amy.reset() → transfer →
181+
environment_transfer_done() (restarts the sketch and starts the
182+
sequencer, so generative loop()s begin playing). The old sketch's
183+
loop() keeps executing during the transfer and can re-arm sequencer
184+
events after our amy.reset(), so its audio bleeds into the next
185+
recording (heard as house_generator under woodpiano) unless the
186+
transport is stopped and the loop() killed before transferring.
187+
Give the new sketch a moment to init before we start recording it."""
188+
try:
189+
self.sysex("zY0Z") # stop sequencer transport
190+
self.send_python("import amyboard; amyboard.stop_sketch()") # kill loop()
191+
self.all_notes_off(0)
192+
except Exception:
193+
pass
182194
self.link.reset_amy()
183195
time.sleep(0.3)
184196
self.link.transfer_file(text)
@@ -446,8 +458,10 @@ def compare(rec, ref):
446458

447459
# ── AMYboard World sketch suite ──────────────────────────────────────────────
448460
def run_world_suite(args, m):
449-
"""Download each WORLD_SUITE sketch, push it onto the board, drive it with the
450-
simple MIDI pattern, and record it. Returns [(name, recording|None, min_sim)];
461+
"""Download each WORLD_SUITE sketch, push it onto the board, and record it.
462+
Generative sketches drive themselves and are recorded as-is; only
463+
non-generative patch sketches (woodpiano) get the simple MIDI pattern, which
464+
also proves the USB-MIDI note path. Returns [(name, recording|None, min_sim)];
451465
a None recording means fetch/load failed for that sketch (a test failure, but
452466
the run continues so the other sketches + artifacts are still produced)."""
453467
results = []
@@ -465,8 +479,11 @@ def run_world_suite(args, m):
465479
print(f"[world] fetched {len(text)} bytes; transferring + starting sketch")
466480
try:
467481
m.load_world_sketch(text)
468-
rec = record_and_drive(args, args.world_duration,
469-
lambda: m.play_pattern(args.world_duration))
482+
if spec["generative"]:
483+
rec = record_and_drive(args, args.world_duration, lambda: None)
484+
else:
485+
rec = record_and_drive(args, args.world_duration,
486+
lambda: m.play_pattern(args.world_duration))
470487
except Exception as e:
471488
print(f"[world] load/record failed for {author}/{name}: {e}")
472489
results.append((name, None, min_sim))
@@ -589,6 +606,12 @@ def main():
589606
m = Midi(args.midi_port)
590607
results = []
591608
try:
609+
# The board boots into its SAVED sketch (e.g. woodpiano left over from
610+
# a previous run's transfer), which also answers our MIDI notes and
611+
# contaminates the built-in-tones recording. Silence it first so
612+
# hwci_basic only measures the default patch.
613+
m.silence()
614+
time.sleep(0.5)
592615
rec = record_and_drive(args, args.duration, lambda: run_test_sequence(m))
593616
results.append((args.name, rec, args.min_similarity))
594617
if args.world:
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)