Send presets and select on broadcast with groups; unicast only for per-device settings. V1 select as [preset_id, step?]. Sequence steps use beat counts; manual presets get select each beat, auto only on step change. Bridge downlink router, Pi envelope delivery, and tests. Co-authored-by: Cursor <cursoragent@cursor.com>
52 lines
1.5 KiB
Python
52 lines
1.5 KiB
Python
"""Sequence step ``beats`` hold (e.g. 12 beats on preset 42, then 4 on preset 5)."""
|
|
|
|
import asyncio
|
|
import os
|
|
import sys
|
|
|
|
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
SRC_PATH = os.path.join(PROJECT_ROOT, "src")
|
|
if SRC_PATH not in sys.path:
|
|
sys.path.insert(0, SRC_PATH)
|
|
|
|
from util import sequence_playback as sp # noqa: E402
|
|
|
|
|
|
def test_step_holds_beats_before_lane_send(monkeypatch):
|
|
sent = []
|
|
|
|
async def fake_send_lane(i, st, ctx):
|
|
sent.append((int(st.get("stepIdx", 0)), int(st.get("beatCount", 0))))
|
|
|
|
monkeypatch.setattr(sp, "_send_lane", fake_send_lane)
|
|
|
|
async def noop_stop(**_kwargs):
|
|
with sp._beat_run_lock:
|
|
sp._beat_run = None
|
|
|
|
monkeypatch.setattr(sp, "stop_playback", noop_stop)
|
|
|
|
ctx = {
|
|
"num_lanes": 1,
|
|
"loop": False,
|
|
"lanes": [[{"preset_id": "42", "beats": 12}, {"preset_id": "5", "beats": 4}]],
|
|
"lane_states": [{"stepIdx": 0, "beatCount": 0, "done": False}],
|
|
"sequence_loop_beat": 0,
|
|
}
|
|
with sp._beat_run_lock:
|
|
sp._beat_run = ctx
|
|
|
|
async def run():
|
|
for _ in range(11):
|
|
await sp.process_active_beat_advance()
|
|
await sp.process_active_beat_advance()
|
|
for _ in range(3):
|
|
await sp.process_active_beat_advance()
|
|
await sp.process_active_beat_advance()
|
|
|
|
asyncio.run(run())
|
|
assert sent == [(1, 0)]
|
|
assert ctx["lane_states"][0]["done"] is True
|
|
with sp._beat_run_lock:
|
|
sp._beat_run = None
|