From 4285d160c3643740d46b00ecefe9397d287fbb27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=27=C3=A9lectron=20rare?= <108685187+electron-rare@users.noreply.github.com> Date: Sat, 27 Jun 2026 17:58:44 +0200 Subject: [PATCH] feat(sound): wrist-backed hands for morceaux At full-body concert distance MediaPipe cannot detect the hands (/pose/hands all zero), muting every morceau hand mapping. ~ccPose now fills pose[hands] from the body wrists (~poseWrist) when the hands are not live, shaped exactly like ~handFeat (wrist height/x, arm spread -> openness, per-tick wrist motion -> speed). All 8 morceaux are driven by the arms at distance with NO per-morceau change (they read pose[hands]). Verified headless. --- sound_algo/data_only/scene_concert.scd | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/sound_algo/data_only/scene_concert.scd b/sound_algo/data_only/scene_concert.scd index 6cf9ca4..a1c9718 100644 --- a/sound_algo/data_only/scene_concert.scd +++ b/sound_algo/data_only/scene_concert.scd @@ -10,12 +10,35 @@ ~ccCrossCool = 3.0; // cooldown apres declenchement (s) // -- snapshot pose (premiere personne), tout nil-garde -- +// Wrist-derived hand-features. At full-body (concert) distance MediaPipe can't +// see the hands (/pose/hands all zero), but the body WRISTS are tracked. We +// shape the wrists exactly like ~handFeat so every morceau (which reads +// pose[\hands]) is driven by the arms transparently — no morceau changes. +// openness -> arm spread ; speed -> per-tick wrist motion (gain'd into a usable +// range, tune thresholds live). +~ccWristFeat = { + var w = (~poseWrist.notNil.if({ ~poseWrist.values.detect({ |v| v.notNil }) })) ? (); + var lx = (w[\lx] ? 0.5); var ly = (w[\ly] ? 0.5); + var rx = (w[\rx] ? 0.5); var ry = (w[\ry] ? 0.5); + var spread = (rx - lx).abs; + var rsp = 0; var lsp = 0; var prev = ~concert[\wprev]; + if(prev.notNil) { + rsp = (((rx - prev[\rx]).squared + (ry - prev[\ry]).squared).sqrt * 8).min(1); + lsp = (((lx - prev[\lx]).squared + (ly - prev[\ly]).squared).sqrt * 8).min(1); + }; + ~concert[\wprev] = (lx: lx, ly: ly, rx: rx, ry: ry); + (lx: lx, ly: ly, rx: rx, ry: ry, + lopen: spread, ropen: spread, lspeed: lsp, rspeed: rsp, dist: spread); +}; ~ccPose = { var kin = ~poseKin.notNil.if({ ~poseKin.values.detect({ |v| v.notNil }) }); var st = ~poseState.notNil.if({ ~poseState.values.detect({ |v| v.notNil }) }); var ctr = ~poseCenter.notNil.if({ ~poseCenter.values.detect({ |v| v.notNil }) }); + var hf = ~handFeat ? (); + var handsLive = ((hf[\rx] ? 0) > 0.001) or: { (hf[\lx] ? 0) > 0.001 }; + var hands = handsLive.if({ hf }, { ~ccWristFeat.value }); (kin: (kin ? ()), state: (st ? ()), center: (ctr ? ()), - hands: (~handFeat ? ()), hasBody: kin.notNil); + hands: hands, hasBody: kin.notNil); }; // -- registre des morceaux --