Commit ba8e84a7 by PLN (Algolia)

feat(gig): 1-click ordered launcher — SuperDirt-first, then Ardour, killing the MIDI dance

Start-of-gig pain: whichever of SuperDirt or Ardour opens the LaunchControl XL first
wins it, and when Ardour wins, sclang can't get the controller → the manual
"disconnect MIDI / reconnect MIDI" dance mid-setup. The fix is ordering + a real
readiness gate.

gig-up.sh (repo root): brings SuperDirt up FIRST and WAITS until it has actually
claimed the controller, then launches Ardour + Pulsar. Readiness = three unambiguous
signals, all of which appear during main_fairbanks.scd's boot: scsynth alive +
UDP :57120 listening (SuperDirt.start) + a "SuperCollider" ALSA-seq client present
(MIDIClient.init has run). 120s timeout (sample loads can be slow) → proceeds with a
clear warning rather than hanging. Best-effort throughout: terminal auto-detected
(konsole/kitty/…, background-log fallback), Ardour/Pulsar binaries probed by name,
skips SuperDirt if scsynth is already up.

gig-boot.scd: one eval that runs the real boot (main_fairbanks.scd) + the LaunchControl
CC->OSC bridge (start_and_midi.scd) so the rig comes up fully armed in a single file;
loaded by relative path to stay portable.

Validated offline: bash -n clean; the three probes correctly read 'down' with SuperDirt
dead; ardour9 + pulsar resolve; the Tidal Multi session path exists. End-to-end (the
live MIDI gate) to be confirmed on the next real boot.
parent d8346672
// gig-boot — canonical 1-click gig boot, loaded by gig-up.sh.
//
// Runs the real SuperDirt boot (main_fairbanks.scd: server + SuperDirt on :57120 +
// MIDIClient.init + note handlers) followed by the LaunchControl XL CC->OSC bridge
// (start_and_midi.scd — the fader/knob handlers). One eval = a fully armed rig.
//
// gig-up.sh runs this, then waits EXTERNALLY (scsynth up + :57120 listening + a
// SuperCollider ALSA-seq MIDI client present) before it starts Ardour — so Ardour
// can never grab the LaunchControl before SuperDirt has, killing the old
// disconnect/reconnect dance. Loaded by relative path so the repo stays portable.
(
var dir = PathName(thisProcess.nowExecutingPath).pathOnly;
thisProcess.interpreter.executeFile(dir ++ "main_fairbanks.scd"); // SuperDirt (async boot)
thisProcess.interpreter.executeFile(dir ++ "start_and_midi.scd"); // LCXL CC -> /ctrl bridge
"gig-boot: SuperDirt boot + MIDI bridge dispatched (SuperDirt finishes loading async).".postln;
)
#!/usr/bin/env bash
# gig-up — ordered 1-click gig launch.
#
# The problem it kills: at the start of a gig/reboot, whichever of SuperDirt or
# Ardour opens the LaunchControl XL first wins it; when Ardour wins, sclang can't
# get the controller and you're stuck doing the "disconnect MIDI / reconnect MIDI"
# dance mid-setup. So: bring SuperDirt up FIRST, WAIT until it has actually claimed
# MIDI, and only THEN start Ardour + Pulsar.
#
# Order:
# 1. sclang gig-boot.scd (SuperDirt on :57120 + LCXL CC->OSC bridge) in a terminal
# 2. wait for READY = scsynth alive + :57120 listening + a SuperCollider MIDI client
# 3. Ardour (the Tidal Multi session) — now it can't beat SuperDirt to the LCXL
# 4. Pulsar (the Tidal folder)
#
# Everything is best-effort: a step that can't run warns and the rest still proceeds.
set -u
DIR="$(cd "$(dirname "$0")" && pwd)" # repo root (this script lives here)
ARDOUR_SESSION="$HOME/Work/Sound/Ardour/Tidal Multi/Tidal Multi.ardour"
READY_TIMEOUT="${READY_TIMEOUT:-120}" # s to wait for SuperDirt (samples can be slow)
C_OK=$'\e[32m'; C_WARN=$'\e[33m'; C_INFO=$'\e[36m'; C_DIM=$'\e[2m'; C_RST=$'\e[0m'
ok(){ printf '%s✓ %s%s\n' "$C_OK" "$*" "$C_RST"; }
info(){ printf '%s• %s%s\n' "$C_INFO" "$*" "$C_RST"; }
warn(){ printf '%s! %s%s\n' "$C_WARN" "$*" "$C_RST"; }
# --- readiness probes (the three signals that mean "SuperDirt owns the rig") ---
scsynth_up(){ pgrep -x scsynth >/dev/null 2>&1; }
osc_up(){ ss -uln 2>/dev/null | grep -q ':57120'; }
# SuperCollider's ALSA-seq client appears once MIDIClient.init has run.
midi_claimed(){ aconnect -l 2>/dev/null | grep -qiE "client [0-9]+: 'SuperCollider'"; }
# --- terminal for the sclang post window ---
pick_term(){
if [ -n "${TERMINAL:-}" ] && command -v "$TERMINAL" >/dev/null 2>&1; then echo "$TERMINAL"; return; fi
for t in konsole kitty alacritty wezterm gnome-terminal xterm; do
command -v "$t" >/dev/null 2>&1 && { echo "$t"; return; }
done
echo ""
}
open_term(){ # open_term "<shell command>" — run cmd in a new terminal window
local term; term="$(pick_term)"; local cmd="$1"
if [ -z "$term" ]; then
warn "no terminal emulator found — running SuperDirt in the background (post → $DIR/gig-sclang.log)"
( cd "$DIR" && QT_QPA_PLATFORM=offscreen setsid sclang gig-boot.scd >gig-sclang.log 2>&1 & )
return
fi
# konsole/gnome-terminal want `-e`; most others accept it too.
setsid "$term" -e bash -lc "cd '$DIR'; QT_QPA_PLATFORM=offscreen sclang gig-boot.scd; exec bash" \
>/dev/null 2>&1 &
}
launch_bin(){ # launch_bin "<label>" <binary names...> — first found, detached, with LAUNCH_ARGS
local label="$1"; shift
local bin
for bin in "$@"; do
if command -v "$bin" >/dev/null 2>&1; then
info "launching $label ($bin)…"
setsid "$bin" "${LAUNCH_ARGS[@]}" >/dev/null 2>&1 &
return 0
fi
done
warn "$label not found (tried: $*) — start it by hand."
return 1
}
# ---------------------------------------------------------------------------
echo
info "gig-up — ordered launch from $DIR"
# 1) SuperDirt (skip if already running)
if scsynth_up; then
ok "SuperDirt already running — skipping boot."
else
info "starting SuperDirt (sclang gig-boot.scd, headless)…"
open_term
fi
# 2) wait for the rig to own MIDI
info "waiting for SuperDirt to boot & claim the LaunchControl (timeout ${READY_TIMEOUT}s)…"
deadline=$(( $(date +%s) + READY_TIMEOUT ))
while :; do
if scsynth_up && osc_up && midi_claimed; then
sleep 1.5 # settle: let MIDIIn.connectAll + CC bridge attach
ok "SuperDirt ready — scsynth up, :57120 listening, MIDI claimed."
break
fi
if [ "$(date +%s)" -ge "$deadline" ]; then
warn "timed out — proceeding anyway. Check the sclang window; if MIDI isn't claimed,"
warn "you may still need the disconnect/reconnect dance for the LaunchControl."
printf '%s (scsynth=%s :57120=%s midi=%s)%s\n' "$C_DIM" \
"$(scsynth_up && echo y || echo n)" "$(osc_up && echo y || echo n)" \
"$(midi_claimed && echo y || echo n)" "$C_RST"
break
fi
sleep 1
done
# 3) Ardour — now safe to open (SuperDirt already holds the controller)
if [ -f "$ARDOUR_SESSION" ]; then
LAUNCH_ARGS=("$ARDOUR_SESSION"); launch_bin "Ardour" ardour ardour9 ardour8 Ardour
else
warn "Ardour session not found at: $ARDOUR_SESSION"
fi
# 4) Pulsar — the Tidal folder
LAUNCH_ARGS=("$DIR"); launch_bin "Pulsar" pulsar
echo
ok "gig-up done. SuperDirt owns the LaunchControl; Ardour + Pulsar are coming up."
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment