memlnaut-nisps/playground/faust/build.sh
monkey-w1n5t0n 0de64463fd build(faust): auto re-exec under nix-shell when faust is missing
If faust isn't in PATH but nix-shell is, transparently re-exec the
script via `nix-shell -p faust --run` instead of erroring out with a
hint. NISPS_BUILD_IN_NIX_SHELL guards against infinite recursion if the
shell somehow still lacks faust.
2026-04-11 07:58:43 +02:00

123 lines
4.4 KiB
Bash
Executable file

#!/usr/bin/env bash
# build.sh — compile all Faust DSP files in this directory to WASM + JSON
#
# Required tools:
# faust >= 2.60.0 (https://faust.grame.fr / nix: faust)
# emcc >= 3.1.x (Emscripten, already present at /usr/lib/emscripten/emcc)
#
# Usage:
# cd playground/faust && ./build.sh
#
# Outputs (alongside each .dsp):
# <name>.wasm — compiled audio DSP binary
# <name>.json — Faust UI descriptor (consumed by faustJsonToParamMeta)
# <name>.js — JS glue / AudioWorklet wrapper generated by faust2wasm
#
# The JSON descriptor is the key artifact: it contains the full UI tree
# (hslider / vslider / nentry / groups) that faustJsonToParamMeta.js parses
# into the playground's standard paramMeta format.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# ---------------------------------------------------------------------------
# Dependency checks
# ---------------------------------------------------------------------------
#
# If faust isn't in PATH, automatically re-exec under `nix-shell -p faust`
# when nix-shell is available. NISPS_BUILD_IN_NIX_SHELL prevents infinite
# recursion if the nix-shell environment somehow still lacks faust.
if ! command -v faust &>/dev/null; then
if [ "${NISPS_BUILD_IN_NIX_SHELL:-0}" = "1" ]; then
echo "ERROR: 'faust' still not found inside nix-shell. Check your nixpkgs channel."
exit 1
fi
if command -v nix-shell &>/dev/null; then
echo "faust not in PATH — re-exec under nix-shell -p faust ..."
exec env NISPS_BUILD_IN_NIX_SHELL=1 nix-shell -p faust --run "\"$0\" $*"
fi
echo ""
echo "ERROR: 'faust' not found in PATH (and nix-shell is unavailable)."
echo ""
echo "Install options:"
echo " nix-shell -p faust # one-off"
echo " nix profile install nixpkgs#faust # permanent"
echo " Or download from: https://faust.grame.fr/downloads/"
echo ""
echo "Required version: >= 2.60.0"
echo "Check: faust --version"
exit 1
fi
FAUST_VER="$(faust --version 2>&1 | head -1)"
echo "faust: $FAUST_VER"
# emcc is optional — faust -lang wasm doesn't require it.
# It is needed if you want to link extra C++ into the WASM module.
if command -v emcc &>/dev/null; then
EMCC_VER="$(emcc --version 2>&1 | head -1)"
echo "emcc : $EMCC_VER"
else
echo "emcc : not found (not required for basic faust -lang wasm builds)"
fi
echo ""
# ---------------------------------------------------------------------------
# Compile each .dsp
# ---------------------------------------------------------------------------
DSP_FILES=("$SCRIPT_DIR"/*.dsp)
if [ ${#DSP_FILES[@]} -eq 0 ]; then
echo "No .dsp files found in $SCRIPT_DIR"
exit 0
fi
for DSP in "${DSP_FILES[@]}"; do
NAME="$(basename "$DSP" .dsp)"
echo "Compiling $NAME.dsp ..."
# Faust -o is interpreted relative to -O (so we must cd into SCRIPT_DIR
# and pass just the filename). Class names (-cn) must be valid C identifiers,
# so dash characters are replaced with underscores.
CLASSNAME="$(echo "$NAME" | tr '-' '_')"
# Step 1: emit WASM binary + JS glue
# -lang wasm — target WebAssembly
# -cn <Name> — class name prefix in generated JS
# -O <dir> — output directory
#
# NB: do NOT pass -e here. In Faust 2.79, -e means "export expanded DSP
# (textual)" — it causes the .wasm output to be Faust source text, not a
# real WebAssembly binary. This script historically used -e by mistake.
( cd "$SCRIPT_DIR" && \
faust -lang wasm \
-cn "$CLASSNAME" \
-O "$SCRIPT_DIR" \
"${NAME}.dsp" \
-o "${NAME}.wasm" )
# Note: `faust -lang wasm -O . foo.dsp -o foo.wasm` already writes
# foo.json alongside foo.wasm with the wasm-native descriptor (including
# numeric `index` fields that workers use as setParamValue zone addresses).
# The old standalone `-json` pass produced a smaller JSON WITHOUT the
# `index` field, which is the wrong shape for workers — don't run it.
if [ ! -f "$SCRIPT_DIR/${NAME}.json" ]; then
echo " WARNING: ${NAME}.json not produced — check faust version"
fi
if [ -f "$SCRIPT_DIR/${NAME}.wasm" ]; then
WASM_SIZE="$(du -h "$SCRIPT_DIR/${NAME}.wasm" | cut -f1)"
echo " -> ${NAME}.wasm (${WASM_SIZE})"
fi
if [ -f "$SCRIPT_DIR/${NAME}.json" ]; then
echo " -> ${NAME}.json"
fi
done
echo ""
echo "Done. Load engines in the playground via FaustEngineBase:"
echo " import { AdditiveEngine } from './js/synth/additive-engine.js';"