Files
SoundGame Dev f0f0a9b50e 初始提交:3 款纯音频游戏 + 共享引擎 + 完整文档与资产管线
- 共享引擎(app/src/main):GestureEngine 6 手势识别、AudioEngine 三层音频
  (ExoPlayer BGM 交叉淡入 / 对白 ducking / SoundPool 低延迟)、Game/GameEngine
  状态机接口、MainActivity 全屏封面 + TalkBack
- 《声命线》storyline:末世互动广播剧,3 幕 8 抉择点 4 结局
- 《声东击西》reflex:听声辨位反应,12 波战斗 + BGM 三档 BPM 变速
- 《暗室》escape:3x3 网格密室逃脱,钥匙→铁柜→保险丝→电箱→大门谜题链
- 文档:setup(从零搭建)/ architecture(架构)/ engine-api(引擎 API)/
  asset-pipeline(资产流水线)/ games/*(三款游戏设计文档)
- 资产管线:Qwen3-TTS 对白 + 程序合成音效/BGM + Mureka BGM 的 gen 脚本与台账,
  全部 ogg 资产入库可复现
- env.d 环境脚本:android/tts 入库;sfx/mureka 含密钥不入库,仅提交 .example.sh 模板
2026-08-29 13:00:34 +08:00

157 lines
7.9 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# sa3_tflite bootstrap — Stable Audio 3 inference on CPU (LiteRT/TFLite) in one command.
#
# Hosted at:
# https://raw.githubusercontent.com/Stability-AI/stable-audio-3/main/optimized/tflite/bootstrap.sh
#
# Usage:
# curl -LsSf https://raw.githubusercontent.com/Stability-AI/stable-audio-3/main/optimized/tflite/bootstrap.sh | bash
# curl -LsSf https://raw.githubusercontent.com/Stability-AI/stable-audio-3/main/optimized/tflite/bootstrap.sh | bash -s -- --prompt "Death Metal" --dit medium --decoder same-l
#
# Default demo prompt is "Impending tribal, epic orchestral buildup".
#
# What it does:
# 1. Verifies curl + tar are present (portable CPU stack — runs on macOS/Linux, x86/ARM).
# 2. Fetches the project:
# - If git is installed → `git clone --depth=1` into ./stable-audio-3/,
# then cd into optimized/tflite/ (real repo; pullable, modifiable).
# - If not → tarball pull via curl + tar, extracting only optimized/tflite/
# into ./sa3_tflite/ (no git needed).
# 3. Runs ./install.sh -y inside it (uv + Python 3.11 + venv + weight downloads).
# 4. Runs ./sa3 with whatever args you passed (default: "Impending tribal, epic orchestral buildup" demo + --play).
#
set -euo pipefail
# uv's curl installer drops the binary at $XDG_BIN_HOME (~/.local/bin by default)
# and updates the user's shell profile — but that profile only takes effect in
# *new* shells. We pre-emptively put both locations on PATH so the just-installed
# uv (and anything else from this run) is findable in the current process tree.
export PATH="${XDG_BIN_HOME:-$HOME/.local/bin}:$HOME/.local/bin:$PATH"
REPO_OWNER="Stability-AI"
REPO_NAME="stable-audio-3"
BRANCH="main"
SUBDIR_IN_REPO="optimized/tflite"
LOCAL_DIR="sa3_tflite"
DEFAULT_ARGS=(--prompt "Impending tribal, epic orchestral buildup" --dit sm-music --decoder same-s --seconds 30 --play)
TAR_URL="https://github.com/$REPO_OWNER/$REPO_NAME/archive/refs/heads/$BRANCH.tar.gz"
TAR_INNER="$REPO_NAME-$BRANCH/$SUBDIR_IN_REPO"
# ── colours ─────────────────────────────────────────────────────────────────
if [[ -t 1 ]]; then
BOLD=$'\033[1m'; CYAN=$'\033[1;36m'; RED=$'\033[1;31m'
YELLOW=$'\033[1;33m'; GREEN=$'\033[1;32m'; DIM=$'\033[2m'; RESET=$'\033[0m'
else
BOLD=""; CYAN=""; RED=""; YELLOW=""; GREEN=""; DIM=""; RESET=""
fi
step() { printf '\n%s→ %s%s\n' "$CYAN" "$1" "$RESET"; }
fail() { printf '\n%serror%s: %s\n' "$RED" "$RESET" "$1" >&2; exit 1; }
ok() { printf ' %s✓%s %s\n' "$GREEN" "$RESET" "$1"; }
warn() { printf '%swarning%s: %s\n' "$YELLOW" "$RESET" "$1" >&2; }
# ── 1. platform note (portable — no gate) ───────────────────────────────────
OS="$(uname -s)"; ARCH="$(uname -m)"
ok "platform: $OS/$ARCH (LiteRT/TFLite is CPU-portable)"
# ── 2. preflight: curl + tar (preinstalled on macOS/most Linux) ─────────────
for tool in curl tar; do
command -v "$tool" >/dev/null 2>&1 || \
fail "$tool not found on PATH. Install it and re-run."
done
ok "curl + tar present"
# ── 3. fetch the project ────────────────────────────────────────────────────
# Prefer `git clone` if git is on the machine — the user gets a real repo
# they can pull updates from / navigate sibling subdirs in (mlx/, tensorRT/).
# Falls back to a tarball pull (curl + tar) if git is missing.
if command -v git >/dev/null 2>&1; then
GIT_DIR="$REPO_NAME"
WORK_DIR="$GIT_DIR/$SUBDIR_IN_REPO"
if [[ -d "$GIT_DIR/.git" ]]; then
step "Reusing existing ./$GIT_DIR (git pull --ff-only)"
git -C "$GIT_DIR" pull --ff-only
elif [[ -e "$GIT_DIR" ]]; then
fail "./$GIT_DIR exists but isn't a git repo — remove or rename it."
else
step "git clone https://github.com/$REPO_OWNER/$REPO_NAME → ./$GIT_DIR"
git clone --depth=1 "https://github.com/$REPO_OWNER/$REPO_NAME" "$GIT_DIR"
fi
[[ -d "$WORK_DIR" ]] || \
fail "Expected '$SUBDIR_IN_REPO' inside the repo but didn't find it."
ok "ready at ./$WORK_DIR"
else
# No git — pull a tarball and extract only optimized/tflite/.
WORK_DIR="$LOCAL_DIR"
if [[ -d "$LOCAL_DIR" && -x "$LOCAL_DIR/install.sh" ]]; then
step "Reusing existing $LOCAL_DIR/ (delete it to re-download)"
else
if [[ -e "$LOCAL_DIR" ]]; then
fail "./$LOCAL_DIR exists but doesn't look like a sa3_tflite checkout — remove or rename it."
fi
step "git not installed — downloading $REPO_OWNER/$REPO_NAME ($BRANCH) tarball → ./$LOCAL_DIR"
TMP_TAR="$(mktemp -t sa3_repo.XXXXXX).tar.gz"
TMP_EXTRACT="$(mktemp -d -t sa3_extract.XXXXXX)"
trap 'rm -rf "$TMP_TAR" "$TMP_EXTRACT"' EXIT
# --progress-bar writes to stderr; -f makes 404/5xx a real curl error
curl -fL --progress-bar "$TAR_URL" -o "$TMP_TAR"
# BSD tar (macOS) / GNU tar both extract only paths matching the pattern.
tar -xz -f "$TMP_TAR" -C "$TMP_EXTRACT" "$TAR_INNER"
SRC="$TMP_EXTRACT/$TAR_INNER"
[[ -d "$SRC" ]] || fail "Expected '$TAR_INNER' inside the tarball but didn't find it."
mv "$SRC" "$LOCAL_DIR"
ok "extracted $(find "$LOCAL_DIR" -type f | wc -l | tr -d ' ') files to ./$LOCAL_DIR"
fi
fi
# ── 4. install ──────────────────────────────────────────────────────────────
cd "$WORK_DIR"
[[ -x ./install.sh ]] || fail "install.sh missing or not executable in ./$WORK_DIR."
step "Running ./install.sh -y"
./install.sh -y
# ── 5. inference ────────────────────────────────────────────────────────────
# Run as a subprocess (not `exec`) so we can drop the user into an
# interactive shell here when it finishes.
if [[ $# -gt 0 ]]; then
step "Running ./sa3 $*"
./sa3 "$@" || true
else
step "Running demo: ./sa3 ${DEFAULT_ARGS[*]}"
printf ' %s(pass your own args via: curl -LsSf https://raw.githubusercontent.com/Stability-AI/stable-audio-3/main/optimized/tflite/bootstrap.sh | bash -s -- --prompt "..." ...)%s\n' "$DIM" "$RESET"
./sa3 "${DEFAULT_ARGS[@]}" || true
fi
# ── 6. drop user into an interactive shell sitting in the project dir ──────
# A subprocess can't change its parent shell's cwd — but we CAN replace
# ourselves with a fresh interactive shell, leaving the user at a prompt
# inside ./$WORK_DIR. `exit` (or Ctrl-D) returns them to their original
# shell, at their original cwd, just like a normal subshell.
#
# `< /dev/tty` is essential when bootstrap.sh was invoked via curl|bash:
# stdin at this point is the (closed) pipe; an interactive shell needs a
# real terminal. /dev/tty always refers to the user's controlling TTY.
if [[ ! -e /dev/tty ]]; then
# Headless / scripted invocation — skip the shell drop.
exit 0
fi
USER_SHELL="${SHELL:-/bin/bash}"
printf '\n%s━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━%s\n' "$BOLD" "$RESET"
printf ' %s✓ you are now in%s %s%s%s\n' "$GREEN" "$RESET" "$BOLD" "$(pwd)" "$RESET"
printf ' %stype %s./sa3 --help%s for options, or %sexit%s to return to your previous shell%s\n' \
"$DIM" "$RESET$BOLD" "$RESET$DIM" "$RESET$BOLD" "$RESET$DIM" "$RESET"
printf '%s━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━%s\n\n' "$BOLD" "$RESET"
exec "$USER_SHELL" -i < /dev/tty