From fa5c9bb36d48d67191ab48f2f2b6d2aa27571dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=27=C3=A9lectron=20rare?= <108685187+electron-rare@users.noreply.github.com> Date: Thu, 7 May 2026 17:38:19 +0200 Subject: [PATCH] fix: sclang auto-boot via boot.scd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context: launching sclang with 00_load.scd as argument was a no-op — the file is split into ~32 IDE-friendly Cmd+Enter blocks and sclang's parser only accepts ONE top-level expression per .load. So nothing actually ran, the engine never came up on the MBP, and every web tab that depends on /sync/* (Album, Mélodies, Kicks, Mixer real values, …) was empty. Same problem hit tracks/_index.scd which has shortcut blocks at the bottom : 'ERROR: syntax error, unexpected (, expecting end of file' at line 104, which aborted the load and never populated ~albums. Approach: a tiny single-block boot.scd that derives ~base from thisProcess.nowExecutingPath and just .load's live/_load.scd (which runs the whole engine + tracks + web_bridge chain). The launcher's default soundAlgoLoadFile picks boot.scd if it exists, falls back to 00_load.scd otherwise. tracks/_index.scd's IDE shortcut blocks at the bottom are wrapped in /* */ block comment so the file is .load-clean while staying useful in the IDE (uncomment to use). stopSclang() also runs pkill scsynth as a safety net so the next boot can grab :57110 — sclang.terminate() doesn't reliably kill its scsynth child. Changes: - sound_algo/boot.scd : new entry point, single block, sets ~base from disk location and loads live/_load.scd - sound_algo/tracks/_index.scd : 9 IDE shortcut lines (lines 104-114) wrapped in /* */ so .load no longer hits 'syntax error unexpected (, expecting end of file' - launcher/ProcessManager.swift : * default soundAlgoLoadFile prefers /sound_algo/boot.scd over /sound_algo/00_load.scd when both exist * stopSclang() runs /usr/bin/pkill -f scsynth after sclang.terminate() Impact: end-to-end verified on the Big Sur Intel MBP via SSH tunnel. After launcher start the Album tab shows the 23 expected cards (Acid Journey, Deep to Hard, …, Dub Techno) with working ▶ Album / ▶ Tracks buttons. scsynth :57110 is alive, web bridge is healthy (3 WS clients), oscope-of receives /sync/album in its HUD. --- .../AVLiveLauncher/ProcessManager.swift | 12 +++++++- sound_algo/boot.scd | 29 +++++++++++++++++++ sound_algo/tracks/_index.scd | 7 ++++- 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 sound_algo/boot.scd diff --git a/launcher/Sources/AVLiveLauncher/ProcessManager.swift b/launcher/Sources/AVLiveLauncher/ProcessManager.swift index 9ca969c..1fb15a2 100644 --- a/launcher/Sources/AVLiveLauncher/ProcessManager.swift +++ b/launcher/Sources/AVLiveLauncher/ProcessManager.swift @@ -64,8 +64,12 @@ final class ProcessManager: ObservableObject { sclangPath = defaults.string(forKey: "sclangPath") ?? "/Applications/SuperCollider.app/Contents/MacOS/sclang" + // Prefer boot.scd (single-block, auto-executable by sclang CLI) over + // 00_load.scd which is split into ~32 IDE-only Cmd+Enter blocks. + let bootCandidate = "\(avLive)/sound_algo/boot.scd" + let legacyCandidate = "\(avLive)/sound_algo/00_load.scd" soundAlgoLoadFile = defaults.string(forKey: "soundAlgoLoadFile") - ?? "\(avLive)/sound_algo/00_load.scd" + ?? (fm.fileExists(atPath: bootCandidate) ? bootCandidate : legacyCandidate) // openFrameworks Release produces a .app bundle in bin/. Default to the // executable inside the bundle, with fallback to the bare binary if @@ -215,6 +219,12 @@ final class ProcessManager: ObservableObject { func stopSclang() { sclangProc?.terminate() + // sclang's terminate doesn't always tear scsynth down cleanly — + // run a belt-and-braces pkill so the next boot can grab :57110. + let kill = Process() + kill.executableURL = URL(fileURLWithPath: "/usr/bin/pkill") + kill.arguments = ["-f", "scsynth"] + try? kill.run() } // MARK: - oscope-of diff --git a/sound_algo/boot.scd b/sound_algo/boot.scd new file mode 100644 index 0000000..4130de8 --- /dev/null +++ b/sound_algo/boot.scd @@ -0,0 +1,29 @@ +// ===================================================================== +// boot.scd -- Entry point auto-executable for sclang CLI +// +// 00_load.scd is split into ~32 IDE-friendly top-level blocks +// (Cmd+Enter per block in SCIDE), which means it does NOT auto-run +// when sclang is launched with `sclang 00_load.scd`. This file wraps +// the actual boot sequence in ONE single top-level block so the +// launcher (or any `sclang boot.scd` invocation) brings the engine +// + palette + live wrappers + tracks + web bridge up automatically. +// +// Execution order : +// 1. derive ~base from this file's location +// 2. .load live/_load.scd (which itself loads engine, synth, fx, +// palette, setup, ~setupAll, tracks/_index, web_bridge, then +// starts the Pdef sequencers) +// +// Usage : +// sclang /path/to/AV-Live/sound_algo/boot.scd +// OR (in IDE) +// Cmd+Enter on this block. +// ===================================================================== +( +~base = (thisProcess.nowExecutingPath !? { |p| p.dirname ++ "/" }) + ?? { File.getcwd ++ "/" }; + +("[boot] ~base = " ++ ~base).postln; + +(~base ++ "live/_load.scd").load; +) diff --git a/sound_algo/tracks/_index.scd b/sound_algo/tracks/_index.scd index f8dc410..2722aef 100644 --- a/sound_algo/tracks/_index.scd +++ b/sound_algo/tracks/_index.scd @@ -98,9 +98,13 @@ // ===================================================================== -// RACCOURCIS LIVE -- Cmd+Entree sur la ligne souhaitee +// RACCOURCIS LIVE -- Cmd+Entree sur la ligne souhaitee dans l'IDE. +// Commentes pour permettre `.load` de ce fichier sans erreur de parse : +// sclang refuse plusieurs blocs `(...)` top-level dans un meme load. +// Decommenter au besoin dans l'IDE. // ===================================================================== +/* ( ~listAlbums.(); ) // liste les 23 albums ( ~listTracks.(\A); ) // liste les 15 tracks de A ( ~listTracks.(\Q); ) // liste les 15 tracks de Q @@ -112,3 +116,4 @@ ( ~playAlbum.(\A); ) // album A en entier ( ~playAlbum.(\J); ) // album J ambient ( ~stopAlbum.(); ) // stop immediat +*/