Cult DSP — Open Spatial Audio Infrastructure
Lead Developer: Lucian Parisi
This repository contains a comprehensive spatial audio infrastructure for decoding Audio Definition Model Broadcast WAV (ADM BWF) files — Atmos masters — with mapping to speaker arrays using multiple spatializers (DBAP, VBAP, LBAP). Includes both offline rendering pipeline and real-time spatial audio engine with GUI interfaces.
Run this once to set up everything:
macOS/Linux:
git clone https://github.com/Cult-DSP/spatialroot.git
cd spatialroot
source init.shWindows (PowerShell):
git clone https://github.com/Cult-DSP/spatialroot.git
cd spatialroot
.\init.ps1Important: Use source init.sh (not ./init.sh) on macOS/Linux to ensure the virtual environment activates in your current shell. On Windows, the PowerShell/Command Prompt scripts handle activation automatically.
If you need to reactivate the virtual environment in a new PowerShell session:
cd spatialroot
. .\spatialroot\bin\Activate.ps1You'll know the virtual environment is active when you see (spatialroot) in your PowerShell prompt.
The setup scripts will:
-- Create a Python virtual environment (spatialroot/)
- Install all Python dependencies
- Initialize git submodules (AlloLib, libbw64, libadm)
-- Build the embedded ADM extractor (
spatialroot_adm_extract[.exe]) - Build the Spatial renderer (supports DBAP, VBAP, LBAP)
- Activate the virtual environment automatically
After setup completes, you'll see (spatialroot) in your terminal prompt.
python utils/getExamples.pyThis downloads example Atmos ADM files for testing.
python runPipeline.py sourceData/driveExampleSpruce.wavCommand options:
# Default mode (uses example file)
python runPipeline.py
# With custom ADM file
python runPipeline.py path/to/your_file.wav
# Full options
python runPipeline.py <adm_wav_file> <speaker_layout.json> <true|false>Arguments:
adm_wav_file- Path to ADM BWF WAV file (Atmos master)speaker_layout.json- Speaker layout JSON (default:spatialRender/allosphere_layout.json)true|false- Create PDF analysis of render (default:true)
For live spatial audio playback:
# With LUSID scene and mono stems
python realtimeMain.py --scene processedData/stageForRender/scene.lusid.json --sources processedData/stageForRender/ --layout spatialRender/allosphere_layout.json
# With ADM file (direct streaming, no stem splitting)
python realtimeMain.py --adm sourceData/driveExampleSpruce.wav --scene processedData/scene.lusid.json --layout spatialRender/allosphere_layout.json
# With GUI
python realtimeMain.py --scene processedData/stageForRender/scene.lusid.json --sources processedData/stageForRender/ --layout spatialRender/allosphere_layout.json --guiRealtime options:
--scene- LUSID scene JSON file--sources- Directory with mono WAV stems (for LUSID packages)--adm- Multichannel ADM WAV file (direct streaming)--layout- Speaker layout JSON--gui- Launch realtime GUI for parameter control--osc_port- OSC port for external control (default: 12345)
See internalDocsMD/Realtime_Engine/realtimeEngine_designDoc.md for full documentation.
For a graphical interface to configure and run the offline pipeline:
python gui/main.pyThe GUI provides file pickers, render settings, progress tracking, and log viewing.
The project supports three spatializers from AlloLib:
- DBAP (default) - Distance-Based Amplitude Panning, works with any layout
- VBAP - Vector Base Amplitude Panning, best for layouts with good 3D coverage
- LBAP - Layer-Based Amplitude Panning, designed for multi-ring layouts
See internalDocsMD/Spatialization/RENDERING.md for full documentation.
If you need to rebuild after code changes:
rm -rf spatial_engine/spatialRender/build
python -c "from src.config.configCPP import buildSpatialRenderer; buildSpatialRenderer()"Or manually:
cd spatial_engine/spatialRender
mkdir -p build && cd build
cmake ..
make -j$(nproc)rm -rf spatial_engine/realtimeEngine/build
python -c "from src.config.configCPP import buildRealtimeEngine; buildRealtimeEngine()"Or manually:
cd spatial_engine/realtimeEngine
mkdir -p build && cd build
cmake ..
make -j$(nproc)The realtime engine performs live spatial audio rendering using the same LUSID scenes and spatializers as the offline pipeline. It streams audio through your system's audio device for real-time playback.
Key Features:
- Live Playback: Real-time spatial audio with OSC control
- Multiple Input Modes: LUSID packages (mono stems) or direct ADM streaming
- Spatializers: DBAP, VBAP, LBAP with configurable parameters
- OSC Integration: External control via Open Sound Control
- GUI Control: Optional PySide6 interface for parameter adjustment
Architecture:
The engine uses a sequential agent model with double-buffered streaming, pose interpolation, and DBAP spatialization. All agents share thread-safe configuration via atomics.
Supported Spatializers:
| Feature | DBAP (default) | VBAP | LBAP |
|---|---|---|---|
| Coverage | No gaps (works anywhere) | Can have gaps | No gaps |
| Layout Req | Any layout | Good 3D triangulation | Multi-ring layers |
| Localization | Moderate | Precise | Moderate |
| Best For | Unknown/irregular layouts | Dense 3D arrays | Allosphere, TransLAB |
See internalDocsMD/Realtime_Engine/realtimeEngine_designDoc.md for detailed architecture documentation.
IMPORTANT: If you close your terminal and come back later, you need to reactivate the virtual environment:
cd spatialroot
source activate.shYou'll know the virtual environment is active when you see (spatialroot) at the start of your terminal prompt.
Why? Virtual environments only last for your current terminal session. This is standard Python practice and keeps your system Python clean and isolated from project dependencies.
Problem: The virtual environment is not active.
Solution: Run this in your terminal:
source activate.shCheck that you see (spatialroot) in your prompt. If you don't see it, the venv is not active.
If you encounter dependency errors:
rm .init_complete
source init.shAfter making changes to C++ source files (spatial_engine/src/ or spatial_engine/realtimeEngine/src/), rebuild the renderers:
Option 1: Force rebuild (recommended)
# Rebuild spatial renderer
rm -rf spatial_engine/spatialRender/build/
python -c "from src.config.configCPP import buildSpatialRenderer; buildSpatialRenderer()"
# Rebuild realtime engine
rm -rf spatial_engine/realtimeEngine/build/
python -c "from src.config.configCPP import buildRealtimeEngine; buildRealtimeEngine()"Option 2: Clean and rebuild
# Clean and rebuild spatial renderer
cd spatial_engine/spatialRender/build/
make clean
make -j$(sysctl -n hw.ncpu)
cd ../../../
# Clean and rebuild realtime engine
cd spatial_engine/realtimeEngine/build/
make clean
make -j$(sysctl -n hw.ncpu)
cd ../../../Option 3: Manual CMake build
# Full manual rebuild of spatial renderer
cd spatial_engine/spatialRender/
rm -rf build/
mkdir build && cd build/
cmake ..
make -j$(sysctl -n hw.ncpu)
# Full manual rebuild of realtime engine
cd spatial_engine/realtimeEngine/
rm -rf build/
mkdir build && cd build/
cmake ..
make -j$(sysctl -n hw.ncpu)The built executables will be at:
spatial_engine/spatialRender/build/spatialroot_spatial_renderspatial_engine/realtimeEngine/build/spatialroot_realtime
If init.sh fails, you can set up manually:
# 1. Create virtual environment
python3 -m venv spatialroot
# 2. Install Python dependencies
spatialroot/bin/pip install -r requirements.txt
# 3. Initialize submodules and build all C++ tools (ADM extractor + renderer)
spatialroot/bin/python -c "from src.config.configCPP import setupCppTools; setupCppTools()"init.sh- One-time setup script (creates venv, installs dependencies, builds C++ tools, activates venv)activate.sh- Reactivates the virtual environment in new terminal sessions (use:source activate.sh)utils/getExamples.py- Downloads example ADM filesutils/deleteData.py- Cleans processed data directorysrc/config/configCPP.py- C++ build utilities (usebuildSpatialRenderer()andbuildRealtimeEngine()to rebuild renderers)gui/main.py- Desktop GUI for offline pipeline configuration and executionrealtimeMain.py- Command-line interface for realtime spatial audio engine
- Check Initialization - Verify all dependencies are installed
- Setup C++ Tools - Initialize AlloLib, libbw64, libadm submodules; build embedded ADM extractor and spatial renderer
- Extract Metadata - Use embedded
spatialroot_adm_extractto extract ADM XML from WAV - Parse ADM - Convert ADM XML to internal data structure
- Analyze Audio - Detect which channels contain audio content
- Package for Render - Split audio stems (X.1.wav naming) and build LUSID scene (scene.lusid.json)
- Spatial Render - Generate multichannel spatial audio (renderer reads LUSID scene directly)
- Analyze Render - Create PDF with dB analysis of each output channel
- Load Scene - Parse LUSID JSON scene file
- Load Layout - Read speaker layout and compute output channels
- Initialize Streaming - Set up double-buffered audio streaming (mono stems or ADM direct)
- Initialize Pose - Load keyframes and prepare interpolation
- Initialize Spatializer - Build speakers and DBAP spatializer
- Start Audio I/O - Open AlloLib audio device and begin real-time processing
- OSC Server - Start parameter server for external control
- Process Blocks - Real-time audio processing with spatialization
The spatial renderer supports multiple spatializers (DBAP, VBAP, LBAP) and render resolution modes:
| Mode | Description | Recommended |
|---|---|---|
block |
Compute direction once per block (default, blockSize=64) | ✓ Yes |
sample |
Compute direction for every sample (highest accuracy) | For critical work |
smooth |
Deprecated - gain interpolation can cause artifacts | No |
./spatialroot_spatial_render <input.json> <layout.json> <output.wav> [options]
Options:
--render_resolution <mode> Set render mode: block (recommended), sample, smooth
--block_size <n> Set block size for block mode (default: 64)
--spatializer <type> Set spatializer: dbap (default), vbap, lbapThe LUSID scene JSON supports an explicit timeUnit field:
{
"sampleRate": 48000,
"timeUnit": "seconds",
"sources": [...]
}Valid values: "seconds" (default), "samples", "milliseconds"
For detailed documentation, see:
- Spatialization/RENDERING.md - Full rendering documentation
- Dependencies/json_schema_info.md - JSON schema reference
Example ADM files: https://zenodo.org/records/15268471
- Python 3.8+ - Core runtime for the Python components
- CMake 3.12+ - Required to build the spatial audio renderer and embedded ADM extractor (C++17)
- Build tools - make, clang/gcc compiler toolchain
- macOS: Fully supported via
./init.sh - Windows/Linux: CMake + make/ninja required to build
spatialroot_adm_extract
- Primary:
spatialroot_adm_extract(embedded, built byinit.sh) — no external install needed