feat(tosc): clip quantize and queued blink
CI build oscope-of / build-check (push) Has been cancelled

Add 4 /launch/quant buttons (1/2, 1, 1BAR, 2BAR) with constf args
0.5/1/4/8 to LIVE page top bar. Extend pad.lua: onReceiveOSC reads
state int 0-3 (off/playing/queued-launch/queued-stop); onFrame pulses
amber when blinking=true. Test: test_live_page_quant_buttons asserts
CONSTANT/FLOAT args. 22 tests pass; dist rebuilt (8482 bytes).
This commit is contained in:
L'électron rare
2026-06-28 14:52:12 +02:00
parent b071c31b86
commit 16f68efe01
4 changed files with 54 additions and 4 deletions
Binary file not shown.
+8
View File
@@ -138,6 +138,14 @@ def live_page():
messages=[s.osc("/sync/beat", [s.val()], send=0, receive=1, feedback=1)],
))
# Quantize selector row (send-only momentary): 1/2 beat / 1 beat / 1 bar / 2 bars
quant_defs = [("1/2", 0.5), ("1", 1), ("1 BAR", 4), ("2 BAR", 8)]
qx_start, qy, qw, qh, qgap = 625, 8, 130, 50, 8
for i, (lbl, beats) in enumerate(quant_defs):
qx = qx_start + i * (qw + qgap)
ch.append(button(lbl, "/launch/quant", qx, qy, qw, qh, args=[s.constf(beats)]))
ch.append(label("QUANT", qx_start, 62, 120, 20))
# 4x4 pad grid -----------------------------------------------------------
gx, gy, pw, ph, gap = 10, 96, 283, 178, 10
for i, name in enumerate(PATTERNS):
+21 -4
View File
@@ -1,16 +1,33 @@
-- Pad GROUP: reflect armed state from SC engine onto the arm button color.
-- API verified on GrosMac at fidelity gate.
-- self.children[1] is the arm BUTTON; color driven by /armed/<name>.
-- State int: 0=off, 1=playing (solid green), 2=queued-launch (blink), 3=queued-stop (blink).
local blinking = false
function onReceiveOSC(message, connections)
local path = message[1]
local name = self.name:gsub("pad_", "")
if path == "/armed/" .. name then
local args = message[2]
local on = (args and args[1] and tonumber(args[1].value)) or 0
local state = math.floor((args and args[1] and tonumber(args[1].value)) or 0)
if self.children and self.children[1] then
self.children[1].color = on > 0.5
and Color(0.27, 0.80, 0.40, 1)
or Color(0.11, 0.11, 0.11, 1)
if state == 0 then
blinking = false
self.children[1].color = Color(0.11, 0.11, 0.11, 1)
elseif state == 1 then
blinking = false
self.children[1].color = Color(0.27, 0.80, 0.40, 1)
else
-- state 2 (queued-launch) or 3 (queued-stop): blink amber
blinking = true
end
end
end
end
function onFrame()
if blinking and self.children and self.children[1] then
local phase = (math.sin(getTime() * math.pi * 2.5) + 1) * 0.5
self.children[1].color = Color(0.80 * phase, 0.60 * phase, 0.10, 1)
end
end
+25
View File
@@ -249,6 +249,31 @@ def test_seq_page_no_sync_amp():
assert "/sync/amp" not in addrs, "/sync/amp found — per-voice VU was supposed to be omitted"
# ---------------------------------------------------------------------------
# Page 1 — LIVE: quantize selector
# ---------------------------------------------------------------------------
def test_live_page_quant_buttons():
"""LIVE page must have 4 /launch/quant buttons with CONSTANT/FLOAT args {0.5,1,4,8}."""
page = layout.live_page()
quant_args = []
for osc_el in page.findall(".//messages/osc"):
path_val = osc_el.find("path/partial/value")
if path_val is not None and path_val.text == "/launch/quant":
for part in osc_el.findall("arguments/partial"):
typ = part.find("type")
conv = part.find("conversion")
val = part.find("value")
if typ is not None and conv is not None and val is not None:
quant_args.append((typ.text, conv.text, val.text))
assert len(quant_args) == 4, f"expected 4 /launch/quant arg partials, got {len(quant_args)}"
for typ, conv, _ in quant_args:
assert typ == "CONSTANT", f"quant arg type must be CONSTANT, got {typ}"
assert conv == "FLOAT", f"quant arg conversion must be FLOAT, got {conv}"
vals = {v for _, _, v in quant_args}
assert vals == {"0.5", "1", "4", "8"}, f"expected quant values {{0.5,1,4,8}}, got {vals}"
# ---------------------------------------------------------------------------
# Pad armed receive on GROUP — FIX 1 regression guard
# ---------------------------------------------------------------------------