Skip to main content

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.

PyPI version Python 3.11+ License: MIT CI Tests


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:

  1. Every WAV arrives with inconsistent silence, loudness, and sample rates.
  2. Filenames encode the routing contract (VO_Hero_Quest01_Line03_v1_EN) but parsing that by hand into Wwise/Unreal is hours of clerical work.
  3. 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)
  • silenceremove strips 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 AssetMetadata dataclass
  • Case-insensitive — vo_hero_... and VO_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.json for 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 objects
  • resonator wwise reconcile — compare manifest vs. Wwise object tree
  • --dry-run uses 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 reportsresonator 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 CSV
  • resonator wwise push — bulk-create Voice objects via WAAPI
  • resonator 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

resonator-1.1.0.tar.gz (70.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

resonator-1.1.0-py3-none-any.whl (58.3 kB view details)

Uploaded Python 3

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

Hashes for resonator-1.1.0.tar.gz
Algorithm Hash digest
SHA256 3aeb2e385333e7190f50f49a7f71aadfe679c4983c51e429838bd536ae9a5bb5
MD5 34183df9249a47602acb39cd752923d6
BLAKE2b-256 cb31ae12ce953952c96c7b0bce0c2175494dc65be5b4c8ab65ad44c38eee43f9

See more details on using hashes here.

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

Hashes for resonator-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 186dbc32abcff4e960dc73cb17ac1286962086e933f9747eb5bac5c054245126
MD5 b564c03ea23750bf0ecb543e22e03a76
BLAKE2b-256 da6e5dd11ebfd1cfea86377dc86639b875360d79aa5e4e1729f45a333570a026

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page