#!/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): # .wasm — compiled audio DSP binary # .json — Faust UI descriptor (consumed by faustJsonToParamMeta) # .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 — class name prefix in generated JS # -O — 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';"