Game-audio asset automation pipeline: silence strip, EBU R128 loudnorm, naming-convention parsing, Wwise/UE5 manifest emission, DSP audit, and WAAPI integration.
Project description
Resonator — Game-Audio Asset Automation Pipeline
A daemon + CLI that watches an ingest directory for incoming WAV assets, strips silence, normalizes loudness to EBU R128, parses complex naming conventions, and emits engine-ready manifests and packages for Wwise and Unreal Engine 5 bulk import. Includes DSP auditing, SQLite processing history, asset-class presets, and direct WAAPI integration.
Author: Amir Pourtaghavy — Senior Audio Engineer & Studio Systems Technician (14+ yrs) transitioning to Technical Audio Programmer / Audio Lead.
Install
# From PyPI (recommended)
pip install resonator
# With Wwise WAAPI support (optional)
pip install resonator[wwise]
# Or from source
git clone https://github.com/Bloody-Crow/Resonator.git
cd Resonator
pip install -e .
System dependency: ffmpeg + ffprobe must be on PATH.
- Linux:
sudo apt install ffmpeg - macOS:
brew install ffmpeg - Windows:
choco install ffmpeg
Verify your setup:
resonator doctor
Why this exists — the real-world bottleneck
Game localization at scale is a pipeline problem, not a craft problem. A single AAA title ships 40,000+ voice lines across 12+ languages. The bottleneck is never the recording — it's the per-asset preparation between the booth and the engine:
- Every WAV arrives with inconsistent silence, loudness, and sample rates.
- Filenames encode the routing contract (
VO_Hero_Quest01_Line03_v1_EN) but parsing that by hand into Wwise/Unreal is hours of clerical work. - A single corrupted or mis-named file breaks a bulk import.
Resonator removes all three. Drop files into ingest/; out come
loudness-normalized, silence-trimmed, correctly-named assets plus
engine-ready manifests — with zero manual tagging.
Quick start
# Scaffold directories
resonator init
# Drop WAV files into the ingest directory
cp VO_Hero_Quest01_Line03_v1_EN.wav data/ingest/
# One-shot batch process
resonator process --ingest data/ingest
# Or start the long-running watcher daemon
resonator run
CLI reference
| Command | Purpose |
|---|---|
resonator init |
Scaffold the directory layout + print a sample .env |
resonator run |
Long-running watcher daemon (blocks until SIGINT/SIGTERM) |
resonator process |
One-shot batch: scan → process → manifest → exit |
resonator validate |
Dry-run: naming-convention + dependency checks, no audio touched |
resonator analyze |
DSP audit: loudness, clipping, DC offset, format — no processing |
resonator doctor |
Health-check: dependencies, directories, config, end-to-end test |
resonator history list |
Query the processing history database |
resonator history failed |
List failed processing attempts |
resonator history report |
Loudness compliance report |
resonator export |
Re-export a manifest for a specific engine (wwise/ue5/generic) |
resonator wwise push |
Push a manifest into Wwise Authoring as Voice objects |
resonator wwise reconcile |
Compare a manifest against the current Wwise object tree |
resonator presets |
List available asset-class and naming-convention presets |
Global flags: -v/--verbose (DEBUG logs), --plain-logs (human-readable file logs).
Feature overview
1. Directory watcher & ingestion
watchdog(inotify/FSEvents) observation with polling fallback- Write-completion detection: tracks mtime+size, waits for stability cooldown
- Thread-safe queue decouples ingest latency from DSP latency
2. Audio signal processing & normalization
- Two-pass EBU R128 loudnorm (measure → linear gain → encode)
silenceremovestrips head/tail silence, preserves interior pacing- 48k/16-bit PCM canonicalization for Wwise/UE5
- Atomic writes (
.part+os.replace) — crashes never leave corrupt files
3. Filename parsing & metadata extraction
- Regex-driven:
VO_Hero_Quest01_Line03_v2_EN.wav - Typed, frozen
AssetMetadatadataclass - Case-insensitive —
vo_hero_...andVO_Hero_...group together
4. Asset-class presets
Different asset types have different loudness standards. Use --preset:
| Preset | LUFS | TP | Channels | Use case |
|---|---|---|---|---|
dialogue |
-23 | -1 | mono | Voice-over (EBU R128) |
music |
-14 | -1 | stereo | Streaming music |
broadcast |
-18 | -1 | stereo | Broadcast music |
sfx |
-18 | -3 | mono | Sound effects (peak-driven) |
cinematic |
-27 | -2 | stereo | Theatrical/cutscene |
ui |
-20 | -3 | mono | UI clicks/notifications |
5. Naming-convention presets
Ship presets for common studio schemas:
| Convention | Example | Separator |
|---|---|---|
default |
VO_Hero_Quest01_Line03_v2_EN.wav |
underscore |
ubisoft |
VO_Hero_Quest01_Line03_v2_EN.wav |
underscore |
naughty-dog |
VO-Hero-Q01-L03-v2-EN.wav |
hyphen |
ea |
vo.hero.q01.l03.v2.en.wav |
dot, lowercase |
6. DSP analysis & audit
resonator analyze produces a per-asset signal report:
- EBU R128 loudness (integrated, true peak, loudness range)
- DC offset detection
- Clipping detection (samples at 0 dBFS)
- Silence ratio estimation
- Format inspection (sample rate, bit depth, channels, codec)
- Warnings for non-standard formats, very loud input, high silence ratio
Outputs audit.json (structured) + audit.md (human-readable table).
7. Game engine integration manifests
- manifest.json — full audit trail with loudness measurements
- localization.csv — flat CSV for UE5/Wwise import
--export-target wwise— Wwise external-sources CSV with language mapping--export-target ue5— UE5 Localization Dashboard CSV + StringTable JSON- Per-group zips with embedded
_manifest.jsonfor traceability
8. Wwise Authoring API (WAAPI) integration
pip install resonator[wwise] enables direct Wwise Authoring control:
resonator wwise push --manifest manifest.json— bulk-create Voice objectsresonator wwise reconcile— compare manifest vs. Wwise object tree--dry-runuses mock transport for testing without Wwise running- Language mapping: EN → English(US), FA → Farsi, etc.
9. SQLite processing history
Every processed asset is recorded with source hash, loudness, and timestamp:
- Content-hash idempotency — skip reprocessing unchanged files
- Audit trails — "when did we process this line, and what did we do?"
- Loudness compliance reports —
resonator history report
10. System resilience & DevOps
- Quarantine on failure; daemon never crashes on one bad file
- Multi-stage Docker (non-root,
tini, healthcheck) + docker-compose - NixOS systemd module with
ProtectSystem=strict - Structured JSON logging with rotation + Rich console
- CI: ruff + mypy + pytest (187 tests) across Python 3.11/3.12 + Docker build
Architecture
src/resonator/
├── __init__.py # package marker, version
├── config.py # frozen PipelineConfig, env loading, validation
├── exceptions.py # typed exception hierarchy
├── logging_config.py # structured JSON logging w/ rotation + Rich
├── watcher.py # watchdog + write-completion detection
├── metadata.py # regex filename parser → AssetMetadata
├── processor.py # ffmpeg 2-pass EBU R128 loudnorm + silence strip
├── manifest.py # manifest.json + localization.csv + zip packaging
├── analysis.py # DSP audit: loudness, clipping, DC offset, format
├── history.py # SQLite processing history + idempotency
├── presets.py # asset-class + naming-convention presets
├── export.py # engine-specific export (generic/wwise/ue5)
├── waapi_client.py # Wwise Authoring API client (mock-first)
├── pipeline.py # orchestrator: worker pool, signals, history
└── cli.py # click CLI: 12 subcommands
Resilience guarantees
| Failure mode | Behavior |
|---|---|
| File still being written | Stability tracker waits for unchanged mtime+size |
| Corrupted WAV | ProcessingError → quarantined, worker continues |
| Mis-named file | MetadataParseError → quarantined, pattern logged |
| ffmpeg/ffprobe missing | DependencyMissingError at startup, exit non-zero |
| Daemon killed mid-batch | Manifest flushed after every asset (atomic write) |
| Same file re-dropped | Output-exists + content-hash check → skipped (idempotent) |
| inotify unavailable | Automatic polling fallback for restricted mounts |
| Ultra-short / all-silence | Single-pass loudnorm fallback (no -inf crash) |
Configuration
Every parameter is an environment variable (twelve-factor). See
.env.example for the full list. Key parameters:
| Variable | Default | Notes |
|---|---|---|
RESONATOR_LUFS_TARGET |
-23.0 |
EBU R128 integrated loudness |
RESONATOR_TRUE_PEAK_DBTP |
-1.0 |
True-peak ceiling |
RESONATOR_SILENCE_THRESHOLD_DB |
-50.0 |
Below this = "silence" to strip |
RESONATOR_SAMPLE_RATE |
48000 |
UE5/Wwise native rate |
RESONATOR_CHANNELS |
1 |
Mono VO; set 2 for stereo |
RESONATOR_STABILITY_COOLDOWN |
2.0 |
Seconds a file must be unchanged |
RESONATOR_MAX_WORKERS |
4 |
Parallel DSP threads |
RESONATOR_PACKAGE_BY |
character |
character / quest / language |
RESONATOR_NAMING_PATTERN |
(regex) | Override the naming convention |
Engine integration
Wwise
resonator export --target wwise— external-sources CSVresonator wwise push— bulk-create Voice objects via WAAPIresonator wwise reconcile— compare manifest vs. Wwise tree- Language mapping: EN → English(US), FA → Farsi, JA → Japanese, etc.
Unreal Engine 5
resonator export --target ue5— Localization Dashboard CSV + StringTable JSON- SoundCue paths in
/Game/Audio/VO/<Character>/convention - Output WAVs are 48k/16-bit PCM — no resample on import
Development
pip install -e ".[dev]"
ruff check src tests # lint
mypy src/resonator # type-check (strict)
pytest # 187 tests
License
MIT — see LICENSE.
Author
Amir Pourtaghavy — Tehran, Iran
14+ years in studio infrastructure, FOH engineering, and massive localization pipelines (1000+ recording sessions, 1000+ dubbed titles, FOH/Studio Lead for post-rock band Crows In The Rain). Worked with Oscar-winning directors (Asghar Farhadi) and classical masters (Homayoun Shajarian). Transitioning to Technical Audio Programmer / Audio Lead.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file resonator-1.1.0.tar.gz.
File metadata
- Download URL: resonator-1.1.0.tar.gz
- Upload date:
- Size: 70.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3aeb2e385333e7190f50f49a7f71aadfe679c4983c51e429838bd536ae9a5bb5
|
|
| MD5 |
34183df9249a47602acb39cd752923d6
|
|
| BLAKE2b-256 |
cb31ae12ce953952c96c7b0bce0c2175494dc65be5b4c8ab65ad44c38eee43f9
|
File details
Details for the file resonator-1.1.0-py3-none-any.whl.
File metadata
- Download URL: resonator-1.1.0-py3-none-any.whl
- Upload date:
- Size: 58.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
186dbc32abcff4e960dc73cb17ac1286962086e933f9747eb5bac5c054245126
|
|
| MD5 |
b564c03ea23750bf0ecb543e22e03a76
|
|
| BLAKE2b-256 |
da6e5dd11ebfd1cfea86377dc86639b875360d79aa5e4e1729f45a333570a026
|