# dadtool — offline beat-sync & song importer for *Dead as Disco* > [!IMPORTANT] > **AI Assistance Disclosure & Disclaimer** > This project was developed with the assistance of an AI Large Language Model (LLM). It is a purely personal, non-profit project built for fun to speed up development and make it easier to enjoy the game. If you are not comfortable using software that has been touched or written with the help of AI, please do not proceed. A Windows CLI that analyzes a track's beat **offline** and writes the sync data **straight into *Dead as Disco*'s per-song save metadata** — so you never have to use the in-game tap-calibration tool. It can also import songs end to end (transcode → auto-named → loudness-normalized → beat-synced), making the in-game importer optional. While the game has its own built-in auto-BPM estimation and manual tap-calibration, **dadtool** handles beat tracking externally with significantly higher precision (using transformer neural nets and drift-criterion multi-tempo section fitting). It also integrates directly with the companion [Marquee HUD mod](https://github.com/sudravirodhin/dadtool-marquee-hud) by fetching and generating synced `.lrc` lyrics with optional Romaji transliteration. The offline grids land roughly **2× tighter than hand-tapping** and don't drift over a full song. > [!WARNING] > **Unofficial and personal.** *Dead as Disco* (Brain Jar Games) is in early access, and > this reads and rewrites its undocumented save files, which can change with any patch. > It ships with safety gates — refuses to write while the game is running, backs up the > whole save folder before every write, checks the game build + a format canary, and > verifies each write by re-reading — but you use it at your own risk. **Last validated against > Steam build `26426937`** (Dead as Disco build `CL-35029`, 2026-11-04). > **Windows 11 · Python 3.12.** ## Companion Mod This tool is designed to work hand-in-hand with the **[Marquee HUD Mod](https://github.com/sudravirodhin/dadtool-marquee-hud)**. While `dadtool` handles offline beat tracking, song importing, and lyrics generation, Marquee runs in-game to provide synced karaoke lyrics display, career stats tracking, and session leveling. ## What it does - **Writes beat-sync directly** into each song's `Meta.json` — tempo, beat offset, tempo-change sections, and silence trim — replacing in-game estimation and tap calibration. - **Imports songs end to end:** transcodes any audio to the game's 48 kHz Ogg Vorbis, fabricates the song folder the game expects, and writes a synced `Meta.json`. - **Tracks tempo with high precision** using a transformer beat tracker (beat_this), including true downbeats, per-section tempo changes, and automatic half-time-shift correction. - **Produces synced `.lrc` lyrics** for the [Marquee companion HUD mod](https://github.com/sudravirodhin/dadtool-marquee-hud) via duration-matched online lookup or local Whisper ASR with romaji transliteration. - **Generates custom challenges** procedurally based on audio spectral profiles and intensity curves. - **Auto-builds playlists (`.bjpl`)** grouped by album tags. - **Names songs** from an AcoustID audio fingerprint (canonical title/artist via MusicBrainz), falling back to file tags + filename. - **Normalizes loudness** to a consistent −14 LUFS. - **Runs as a watch daemon** that auto-imports anything dropped into a folder. - **Plays it safe:** game-running refusal, timestamped full backups, version/format gates, verify-by-reread, and a per-song override file for anything it gets wrong. ## Requirements - **Windows** (uses Windows save paths + process checks) and **Python 3.12**. - A **separate conda/Miniforge env for the beat tracker** — `beat_this` needs PyTorch (CPU-only is fine). - **ffmpeg is bundled** via `imageio-ffmpeg`; no system install needed. - *Optional, for auto-naming:* an **AcoustID API key** and the **Chromaprint `fpcalc`** binary. ## Setup ```powershell # 1. main environment python -m venv .venv .\.venv\Scripts\pip install -r requirements.txt # 2. beat tracker in an isolated conda env (CPU torch is fine) conda create -n dad-beat python=3.11 conda activate dad-beat pip install beat_this torch soundfile # 3. config — copy the example and fill in YOUR paths copy dad_config.example.json dad_config.json ``` Then edit `dad_config.json`: `saved_dir`, the game exe paths, `beat_this_python` (the `dad-beat` interpreter), and optionally `acoustid_api_key` + `fpcalc_path`. It's git-ignored (it holds machine paths + your API key). The game directory is resolved **only** in `dadtool/paths.py`, via `dad_config.json` or the `DAD_SAVED_DIR` env var. ## Usage Run through the venv (or the bundled `dad.cmd` / `watch.cmd` launchers): ``` .\.venv\Scripts\python.exe -m dadtool.cli ``` | command | what it does | |---|---| | `status` | resolved paths, game-running state, live game version | | `revalidate` | check game build + format canary before writing | | `analyze ""` | print analysis JSON for an ImportedSongs name or audio file | | `preview ""` | render a click-track WAV to `previews/` to ear-check sync | | `write ""` | analyze + write one song (`--dry-run`, `--tempo/--offset/--start`) | | `batch` | analyze + write every imported song (`--dry-run`, `--force`, `--limit N`) | | `import-song ` | fabricate a full ImportedSongs entry from a source file | | `list` | list every imported song with an index (the selector for `remove --index`) | | `remove` | bulk-delete songs by name, `--index 2,4,6-9`, `--match '*pattern*'`, or `--all` | | `playlist list` | list playlists and their songs | | `playlist create "" ` | create a playlist from song-name matches | | `playlist auto` | auto-create a playlist per album with 3+ songs (`--min N`, `--dry-run`) | | `playlist delete ""` | delete a playlist | | `challenge plan ""` | preview a procedural wave/difficulty plan (no write) | | `challenge generate ""` | generate + write a Challenge (`--difficulty`, `--boss`/`--no-boss`, `--arena`) | | `challenge sync` | generate auto challenges for the whole library (`--purge`, `--dry-run`) | | `watch` | daemon: auto-import audio dropped into `audio/pending/` (`--once`, `--interval N`) | | `lyrics ` \| `--all` \| `--queue [--limit N]` \| `--remap` | synced .lrc lyrics for the Marquee companion mod (`--purge`, `--retry-missing`, `--romaji`, `--dry-run`) | | `normalize` | LUFS-normalize every `Audio.ogg` to −14 (`--force`) | | `rename` | set Song Name/Artist from AcoustID for all songs (`--dry-run`) | | `relabel` | rewrite every Song Name to `Artist - Title` so the in-game list sorts by artist (`--dry-run`) | | `restore` | re-write cached metadata after a game patch wipes it | | `collect` / `ingest` | file source audio into `audio/processed/` | | `snapshot