#!/usr/bin/env bash # Audio subcommands — sourcing pipeline + design app DX. # # The launch-pack assets are sourced via per-pack TSV mappings under # `tools/audio-batch-*.tsv`. Each row goes: # curl → ffmpeg loudnorm + Ogg Vorbis encode → write to assets tree → # append `sources.csv` → re-render LICENSES.md → run audio-validate.py. # Idempotent: re-running skips files already on disk + already in the # ledger. # # ./run audio show status (file count, manifest health) # ./run audio:fetch run every batch in tools/audio-batch-*.tsv # ./run audio:fetch:01 run a single numbered batch (01/02/03/04) # ./run audio:design start the design-app dev server (port 7777) # ./run audio:validate python3 tools/audio-validate.py # ./run audio:render regenerate LICENSES.md from sources.csv # # `./run validate` (in test.sh) already calls audio-validate.py + # audio-licenses-render.py --check; the audio:* targets here are the # write-side complement. AUDIO_THEME="${AUDIO_THEME:-age-of-dwarves}" AUDIO_ASSETS="$REPO_ROOT/public/games/$AUDIO_THEME/assets/audio" AUDIO_MANIFEST="$REPO_ROOT/public/games/$AUDIO_THEME/data/audio.json" AUDIO_DESIGN_APP="$REPO_ROOT/.project/designs/app" AUDIO_DESIGN_PORT="${AUDIO_DESIGN_PORT:-7777}" cmd_audio() { echo -e "${BLUE}Audio status — theme '$AUDIO_THEME'${NC}" if [[ ! -f "$AUDIO_MANIFEST" ]]; then echo -e " ${RED}✗ manifest missing: $AUDIO_MANIFEST${NC}" return 1 fi local ogg_count ogg_count=$(find "$AUDIO_ASSETS" -name '*.ogg' 2>/dev/null | wc -l | tr -d ' ') local sources_rows sources_rows=$(grep -c '^audio/' "$AUDIO_ASSETS/sources.csv" 2>/dev/null || echo 0) local manifest_refs manifest_refs=$(python3 -c " import json m = json.load(open('$AUDIO_MANIFEST')) n = 0 for e in m['sfx'].values(): streams = e.get('streams') or ([e['stream']] if e.get('stream') else []) n += len(streams) n += len(m['music']['tracks']) print(n) ") echo " Manifest references: $manifest_refs streams" echo " Files on disk: $ogg_count .ogg" echo " Sources.csv rows: $sources_rows" if [[ -x "$REPO_ROOT/tools/audio-validate.py" ]]; then echo "" python3 "$REPO_ROOT/tools/audio-validate.py" --theme "$AUDIO_THEME" fi echo "" echo " Available batches:" for tsv in "$REPO_ROOT"/tools/audio-batch-*.tsv; do [[ -f "$tsv" ]] || continue local rows rows=$(grep -cE '^audio/' "$tsv") printf " %-50s %d rows\n" "$(basename "$tsv")" "$rows" done echo "" echo -e " ${DIM}./run audio:fetch run every batch${NC}" echo -e " ${DIM}./run audio:design open the design app at http://localhost:$AUDIO_DESIGN_PORT/audio${NC}" } cmd_audio_validate() { python3 "$REPO_ROOT/tools/audio-validate.py" --theme "$AUDIO_THEME" "$@" } cmd_audio_render() { python3 "$REPO_ROOT/tools/audio-licenses-render.py" --theme "$AUDIO_THEME" "$@" } _audio_run_batch() { local tsv="$1" if [[ ! -f "$tsv" ]]; then echo -e "${RED}batch not found: $tsv${NC}" return 1 fi bash "$REPO_ROOT/tools/audio-fetch-batch.sh" "$tsv" } cmd_audio_fetch() { # Run every TSV under tools/audio-batch-*.tsv in lexical order. Each # batch is idempotent so re-running is cheap. local any=0 local failed=0 for tsv in "$REPO_ROOT"/tools/audio-batch-*.tsv; do [[ -f "$tsv" ]] || continue any=1 echo "" echo -e "${BLUE}── $(basename "$tsv") ─────────────────${NC}" if ! _audio_run_batch "$tsv"; then failed=$((failed + 1)) fi done if [[ $any -eq 0 ]]; then echo -e "${YELLOW}No tools/audio-batch-*.tsv files found.${NC}" return 1 fi if [[ $failed -gt 0 ]]; then echo "" echo -e "${RED}$failed batch(es) had failures — see output above${NC}" return 1 fi } # Numbered batch shortcuts: ./run audio:fetch:01 → tools/audio-batch-01-*.tsv cmd_audio_fetch_01() { _audio_fetch_numbered 01; } cmd_audio_fetch_02() { _audio_fetch_numbered 02; } cmd_audio_fetch_03() { _audio_fetch_numbered 03; } cmd_audio_fetch_04() { _audio_fetch_numbered 04; } cmd_audio_fetch_05() { _audio_fetch_numbered 05; } cmd_audio_fetch_06() { _audio_fetch_numbered 06; } cmd_audio_fetch_07() { _audio_fetch_numbered 07; } cmd_audio_fetch_08() { _audio_fetch_numbered 08; } cmd_audio_fetch_09() { _audio_fetch_numbered 09; } _audio_fetch_numbered() { local n="$1" local matches=( "$REPO_ROOT"/tools/audio-batch-${n}-*.tsv ) if [[ ! -f "${matches[0]}" ]]; then echo -e "${RED}no batch matching tools/audio-batch-${n}-*.tsv${NC}" return 1 fi _audio_run_batch "${matches[0]}" } cmd_audio_options() { bash "$REPO_ROOT/tools/audio-fetch-options.sh" "$@" } cmd_audio_design() { if [[ ! -d "$AUDIO_DESIGN_APP" ]]; then echo -e "${RED}design app not found: $AUDIO_DESIGN_APP${NC}" return 1 fi if [[ ! -d "$AUDIO_DESIGN_APP/node_modules" ]]; then echo -e "${BLUE}Installing design-app dependencies...${NC}" (cd "$AUDIO_DESIGN_APP" && pnpm install) || return 1 fi echo -e "${BLUE}Starting audio design app on http://localhost:$AUDIO_DESIGN_PORT/audio${NC}" exec pnpm --dir "$AUDIO_DESIGN_APP" dev -- --port "$AUDIO_DESIGN_PORT" }