feat(viz): perf-safe keys, frozen pinch tuning
CI build oscope-of / build-check (push) Has been cancelled
CI build oscope-of / build-check (push) Has been cancelled
Live session outcomes: (1) pinch thresholds validated for inner fingers frozen as defaults (ratio_on 0.50, margin 0.05, ext_min 1); (2) panel frames + X/Y gauges now permanent (no early-return when nothing is detected); (3) wxcvbn source-bundle shortcuts gated off by default (VIZ_SOURCE_KEYS=1 re-enables) — a stray key mid-performance switched the audio scene.
This commit is contained in:
@@ -74,11 +74,12 @@ Toujours répondre en français à l'utilisateur. Code, commentaires de code, co
|
||||
| `FINGER_STRIKE_REFRACTORY_MS` | `120` | min ms between strikes per finger |
|
||||
| `FINGER_SOURCE` | `auto` | hand source for finger gestures: `auto` (iPhone Vision hands if fresh, else MediaPipe), `iphone`, `mediapipe` |
|
||||
| `FINGER_DEBUG` | `0` | `1` logs each detected strike/pinch (hand, finger) — for threshold tuning |
|
||||
| `PINCH_RATIO_ON` | `0.45` | thumb-to-finger distance / hand size below which a pinch engages (clip toggle) |
|
||||
| `PINCH_RATIO_ON` | `0.50` | thumb-to-finger distance / hand size below which a pinch engages (0.50 validated live 2026-07-02 for ring/pinky reach) |
|
||||
| `PINCH_RATIO_OFF` | `0.65` | distance/size above which the pinch re-arms (hysteresis) |
|
||||
| `PINCH_REFRACTORY_MS` | `250` | min ms between pinches per finger |
|
||||
| `PINCH_MARGIN` | `0.05` | closest-wins margin between nearest and runner-up fingertip (0.05 validated live: 0.20 rejected middle/ring/pinky pinches) |
|
||||
| `PINCH_EXT_RATIO` | `1.35` | tip-to-wrist distance / hand size above which a finger counts as extended (open-hand pinch gate) |
|
||||
| `PINCH_EXT_MIN` | `2` | min extended non-pinching fingers required for a pinch to engage; `0` disables the open-hand gate |
|
||||
| `PINCH_EXT_MIN` | `1` | min extended non-pinching fingers required for a pinch to engage; `0` disables the open-hand gate (1 validated live: inner-finger pinches curl neighbours) |
|
||||
| `PINCH_DEBOUNCE_FRAMES` | `3` | consecutive qualifying frames before a pinch engage fires (release stays immediate); `1` disables |
|
||||
| `HAND_CONF_MIN` | `0.45` | min Vision hand confidence to draw (raised from 0.3; applies to both overlay and side panels) |
|
||||
| `HAND_PERSIST_FRAMES` | `3` | consecutive frames a hand track must match before being drawn (1 = off, all hands drawn immediately) |
|
||||
|
||||
+12
-6
@@ -42,6 +42,7 @@ HAND_HOLD_FRAMES 2 int gesture slot hold: frames to carry
|
||||
ARKIT_BONE_MAX 0.5 float max bone length (norm) for ARKit skeleton
|
||||
ARKIT_FULL_SKELETON "1" bool draw full 91-joint ARKit body (!=0 = True)
|
||||
VIZ_HUD "0" bool show debug HUD overlay
|
||||
VIZ_SOURCE_KEYS "0" bool wxcvbn source-bundle shortcuts (off: perf safety)
|
||||
IPHONE_OSC_PORT 57128 int UDP port for iPhone ARBodyTracker /body3d/kp
|
||||
CONCERT_MIRROR "1" bool mirror video horizontally (!=0 = True)
|
||||
ICP_FUSION "0" bool enable ICP LiDAR fusion (only "1" = True)
|
||||
@@ -110,12 +111,12 @@ class VizConfig:
|
||||
|
||||
# ---- Pinch detection -------------------------------------------------
|
||||
pinch_enable: bool = False
|
||||
pinch_ratio_on: float = 0.45
|
||||
pinch_ratio_on: float = 0.50
|
||||
pinch_ratio_off: float = 0.65
|
||||
pinch_refractory_ms: float = 250.0
|
||||
pinch_margin: float = 0.20
|
||||
pinch_margin: float = 0.05
|
||||
pinch_ext_ratio: float = 1.35
|
||||
pinch_ext_min: int = 2
|
||||
pinch_ext_min: int = 1
|
||||
pinch_debounce_frames: int = 3
|
||||
|
||||
# ---- Hand display / gesture ------------------------------------------
|
||||
@@ -132,6 +133,10 @@ class VizConfig:
|
||||
|
||||
# ---- HUD -------------------------------------------------------------
|
||||
viz_hud: bool = False
|
||||
# Source-bundle keyboard shortcuts (wxcvbn): OFF by default — a stray
|
||||
# keypress during a matrix performance switches the audio scene
|
||||
# (user-disabled live 2026-07-02). VIZ_SOURCE_KEYS=1 re-enables.
|
||||
viz_source_keys: bool = False
|
||||
|
||||
# ---- iPhone OSC ------------------------------------------------------
|
||||
iphone_osc_port: int = 57128
|
||||
@@ -260,12 +265,12 @@ class VizConfig:
|
||||
finger_source=_str_lower("FINGER_SOURCE", "auto"),
|
||||
finger_debug=_bool_std("FINGER_DEBUG", False),
|
||||
pinch_enable=_bool_std("PINCH_ENABLE", False),
|
||||
pinch_ratio_on=_float("PINCH_RATIO_ON", 0.45),
|
||||
pinch_ratio_on=_float("PINCH_RATIO_ON", 0.50),
|
||||
pinch_ratio_off=_float("PINCH_RATIO_OFF", 0.65),
|
||||
pinch_refractory_ms=_float("PINCH_REFRACTORY_MS", 250.0),
|
||||
pinch_margin=_float("PINCH_MARGIN", 0.20),
|
||||
pinch_margin=_float("PINCH_MARGIN", 0.05),
|
||||
pinch_ext_ratio=_float("PINCH_EXT_RATIO", 1.35),
|
||||
pinch_ext_min=_int("PINCH_EXT_MIN", 2),
|
||||
pinch_ext_min=_int("PINCH_EXT_MIN", 1),
|
||||
pinch_debounce_frames=_int("PINCH_DEBOUNCE_FRAMES", 3),
|
||||
hand_conf_min=_float("HAND_CONF_MIN", 0.45),
|
||||
hand_persist_frames=_int("HAND_PERSIST_FRAMES", 3),
|
||||
@@ -279,6 +284,7 @@ class VizConfig:
|
||||
# ARKIT_FULL_SKELETON uses != "0" convention (empty = True)
|
||||
arkit_full_skeleton=_bool_ne0("ARKIT_FULL_SKELETON", True),
|
||||
viz_hud=_bool_std("VIZ_HUD", False),
|
||||
viz_source_keys=_bool_std("VIZ_SOURCE_KEYS", False),
|
||||
iphone_osc_port=_int("IPHONE_OSC_PORT", 57128),
|
||||
concert_mirror=_bool_ne0("CONCERT_MIRROR", True),
|
||||
# ICP_FUSION / MULTIHMR_AUTOCAST use strict "1" convention
|
||||
|
||||
@@ -71,6 +71,8 @@ class AppDelegate(NSObject):
|
||||
# Sender vers sclang pour les changements de scene depuis le clavier
|
||||
self._scClient = SimpleUDPClient("127.0.0.1", opts.sclang_port)
|
||||
self._pose_worker = None
|
||||
from .config import VizConfig as _VizConfig
|
||||
self._source_keys = _VizConfig.from_env().viz_source_keys
|
||||
return self
|
||||
|
||||
def applicationDidFinishLaunching_(self, notification): # noqa: N802
|
||||
@@ -627,8 +629,13 @@ class AppDelegate(NSObject):
|
||||
self._state.active_scene = scene
|
||||
LOG.info("[audio] scene -> %s", scene)
|
||||
return None
|
||||
# wxcvbn + 0-9 -> preset bundle (source + scene audio + viz video)
|
||||
for kk, source, scene, viz in (*KEYMAP_SOURCE, *KEYMAP_SOURCE_NUM):
|
||||
# wxcvbn -> preset bundle: gated OFF by default (VIZ_SOURCE_KEYS=1
|
||||
# re-enables) — a stray keypress mid-performance switches the audio
|
||||
# scene. The 0-9 numeric bundles stay active.
|
||||
_src_maps = ((*KEYMAP_SOURCE, *KEYMAP_SOURCE_NUM)
|
||||
if getattr(self, "_source_keys", False)
|
||||
else KEYMAP_SOURCE_NUM)
|
||||
for kk, source, scene, viz in _src_maps:
|
||||
if key == kk or k == kk:
|
||||
# Audio : envoie a sclang
|
||||
self._scClient.send_message("/control/doScene", [scene])
|
||||
|
||||
@@ -343,8 +343,10 @@ class MetalRenderer(NSObject):
|
||||
_arkit_now = time.perf_counter()
|
||||
use_arkit = (getattr(self, '_arkit_full', ARKIT_FULL) and bool(s.arkit_parents)
|
||||
and arkit_2d_fresh(s.persons_arkit_2d_t, _arkit_now))
|
||||
if not use_arkit and not s.pose_alive():
|
||||
return 0
|
||||
# NO early-return when nothing is detected: the panel frames and the
|
||||
# X/Y gauges are permanent screen furniture (user request: indicators
|
||||
# must stay visible with no hands). The overlay loops below iterate
|
||||
# empty collections at negligible cost.
|
||||
|
||||
buf = self._skel_cpu_buf
|
||||
segs = 0
|
||||
|
||||
@@ -48,12 +48,12 @@ def test_defaults_finger_piano():
|
||||
def test_defaults_pinch():
|
||||
cfg = VizConfig.from_env({})
|
||||
assert cfg.pinch_enable is False
|
||||
assert cfg.pinch_ratio_on == pytest.approx(0.45)
|
||||
assert cfg.pinch_ratio_on == pytest.approx(0.50)
|
||||
assert cfg.pinch_ratio_off == pytest.approx(0.65)
|
||||
assert cfg.pinch_refractory_ms == pytest.approx(250.0)
|
||||
assert cfg.pinch_margin == pytest.approx(0.20)
|
||||
assert cfg.pinch_margin == pytest.approx(0.05)
|
||||
assert cfg.pinch_ext_ratio == pytest.approx(1.35)
|
||||
assert cfg.pinch_ext_min == 2
|
||||
assert cfg.pinch_ext_min == 1
|
||||
assert cfg.pinch_debounce_frames == 3
|
||||
|
||||
|
||||
@@ -407,3 +407,9 @@ def test_hand_face_min_env_override():
|
||||
"""HAND_FACE_MIN env var is parsed as float and stored in hand_face_min."""
|
||||
cfg = VizConfig.from_env({"HAND_FACE_MIN": "0.3"})
|
||||
assert cfg.hand_face_min == pytest.approx(0.3)
|
||||
|
||||
|
||||
def test_viz_source_keys_default_off():
|
||||
cfg = VizConfig.from_env({})
|
||||
assert cfg.viz_source_keys is False
|
||||
assert VizConfig.from_env({"VIZ_SOURCE_KEYS": "1"}).viz_source_keys is True
|
||||
|
||||
Reference in New Issue
Block a user