From a98957ce4695d3f0cc5ab0519b58e98599471907 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 21:17:38 +0200 Subject: [PATCH] feat: AV-Live Concert.app one-click launcher --- launcher/concert/Info.plist | 26 +++++++++++++ launcher/concert/README.md | 43 +++++++++++++++++++++ launcher/concert/build_concert_app.sh | 20 ++++++++++ launcher/concert/launch_concert.sh | 55 +++++++++++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 launcher/concert/Info.plist create mode 100644 launcher/concert/README.md create mode 100755 launcher/concert/build_concert_app.sh create mode 100755 launcher/concert/launch_concert.sh diff --git a/launcher/concert/Info.plist b/launcher/concert/Info.plist new file mode 100644 index 0000000..778318c --- /dev/null +++ b/launcher/concert/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleName + AV-Live Concert + CFBundleDisplayName + AV-Live Concert + CFBundleIdentifier + cc.saillant.avlive.concert + CFBundleVersion + 1.0 + CFBundleShortVersionString + 1.0 + CFBundleExecutable + launch + CFBundlePackageType + APPL + LSUIElement + + LSMinimumSystemVersion + 11.0 + NSHighResolutionCapable + + + diff --git a/launcher/concert/README.md b/launcher/concert/README.md new file mode 100644 index 0000000..e36a7d8 --- /dev/null +++ b/launcher/concert/README.md @@ -0,0 +1,43 @@ +# AV-Live Concert.app + +One double-click boots the whole iPhone-USB concert on macm1. + +## What it does + +`launch_concert.sh` (the app's executable) runs the full boot sequence: + +1. Launches the **iPhone ARBodyTracker** app (camera + ARKit skeleton over USB). +2. Starts the **pose pipeline** (`data_only_viz --pose --iphone-usb`: HEVC decode, + MediaPipe, horizontal mirror, OSC out). +3. Boots **SuperCollider** (`sound_algo/data_only/boot.scd` → body-play: the + concert engine, 13 body gestures, 11 morceaux). +4. Switches to the **`\concert`** scene. + +Re-running restarts cleanly (it kills any prior stack first). + +## Build / install + +On macm1 (where the stack runs): + +```sh +cd ~/Documents/Projets/AV-Live/launcher/concert +./build_concert_app.sh # -> ~/Desktop/AV-Live Concert.app +``` + +Then double-click **AV-Live Concert.app** on the Desktop. A notification confirms +each stage; the Metal window + sound come up after ~45 s. + +## Live controls (once running) + +- **Space** — next morceau (random) +- **Bras croisés** (wrists) — jump to a random morceau +- **Body gestures** — jump/stomp/squat/spin/T-pose (FX), step/lean/tilt (harmony), + arm-raise/head (melody) +- `/control/concertChain 1` — hands-free auto-chain; `/control/concertSeq 1` — + sequential instead of random; `CONCERT_MIRROR=0` — disable the video mirror + +## Notes + +- The iPhone device UDID (`DEV`) is hardcoded in `launch_concert.sh` — update it if + the phone changes (`xcrun devicectl list devices`). +- Logs: `/tmp/concert_viz.log` (pose) and `/tmp/sc_boot.log` (SuperCollider). diff --git a/launcher/concert/build_concert_app.sh b/launcher/concert/build_concert_app.sh new file mode 100755 index 0000000..a930ea5 --- /dev/null +++ b/launcher/concert/build_concert_app.sh @@ -0,0 +1,20 @@ +#!/bin/zsh +# Assemble "AV-Live Concert.app" from launch_concert.sh + Info.plist. +# Usage: ./build_concert_app.sh [output-path] +# default output: ~/Desktop/AV-Live Concert.app +set -eu +cd "$(dirname "$0")" + +APP="${1:-$HOME/Desktop/AV-Live Concert.app}" +rm -rf "$APP" +mkdir -p "$APP/Contents/MacOS" +cp Info.plist "$APP/Contents/Info.plist" +cp launch_concert.sh "$APP/Contents/MacOS/launch" +chmod +x "$APP/Contents/MacOS/launch" + +# Ad-hoc sign so Gatekeeper lets it run locally without a quarantine prompt. +codesign --force --deep --sign - "$APP" 2>/dev/null || true +xattr -dr com.apple.quarantine "$APP" 2>/dev/null || true + +echo "Built: $APP" +echo "Double-click it, or: open \"$APP\"" diff --git a/launcher/concert/launch_concert.sh b/launcher/concert/launch_concert.sh new file mode 100755 index 0000000..9165a46 --- /dev/null +++ b/launcher/concert/launch_concert.sh @@ -0,0 +1,55 @@ +#!/bin/zsh +# AV-Live Concert launcher. +# Boots the full iPhone-USB concert stack in one shot: +# iPhone ARBodyTracker (camera + ARKit skeleton over USB) +# -> data_only_viz pose pipeline (HEVC decode + MediaPipe + mirror + OSC) +# -> SuperCollider engine (body-play boot: concert + 13 gestures + 11 morceaux) +# -> switch to the \concert scene. +# Used as the executable of "AV-Live Concert.app" (double-click to start). +# Re-running restarts cleanly (it kills any prior stack first). +set -u + +REPO="$HOME/Documents/Projets/AV-Live" +DEV="AC1CDE5F-DDC4-5B2C-80D7-9953D8ABA0AC" # iPhone 16 Pro (xcrun devicectl list devices) +export PATH=/opt/homebrew/bin:$PATH +export MEDIAPIPE_DELEGATE=cpu +export POSE_FILTER=median+kalman+lookahead+ik+arkit_fuse +# CONCERT_MIRROR=0 in the environment disables the video mirror. + +PY="$REPO/data_only_viz/.venv/bin/python" +SCLANG="/Applications/SuperCollider.app/Contents/MacOS/sclang" + +notify() { osascript -e "display notification \"$1\" with title \"AV-Live Concert\"" 2>/dev/null; } + +cd "$REPO" || { notify "repo introuvable"; exit 1; } + +# 0) clean any prior run +pkill -9 -f "data_only_viz.main" 2>/dev/null +pkill -9 -f sclang 2>/dev/null +pkill -9 -f scsynth 2>/dev/null +lsof -ti UDP:57121 2>/dev/null | xargs kill -9 2>/dev/null +lsof -ti UDP:57123 2>/dev/null | xargs kill -9 2>/dev/null +sleep 2 + +notify "Demarrage..." + +# 1) iPhone ARBodyTracker (camera + skeleton over USB) +xcrun devicectl device process launch --device "$DEV" cc.saillant.ARBodyTracker >/dev/null 2>&1 +sleep 3 + +# 2) pose pipeline (iPhone USB HEVC -> MediaPipe -> mirror -> OSC) +nohup "$PY" -m data_only_viz.main --pose --iphone-usb > /tmp/concert_viz.log 2>&1 & +disown +sleep 11 + +# 3) SuperCollider engine (boots to body-play; loads concert + gestures + morceaux) +cd "$REPO/sound_algo/data_only" || exit 1 +nohup "$SCLANG" boot.scd > /tmp/sc_boot.log 2>&1 & +disown +sleep 30 + +# 4) switch to the concert scene +"$PY" -c "from pythonosc.udp_client import SimpleUDPClient; SimpleUDPClient('127.0.0.1',57121).send_message('/control/doScene','concert')" +sleep 1 + +notify "Concert lance. Espace = morceau suivant. Bras croises = morceau au hasard."