Audio Ribbon System
Dynamic spatial audio system for rivers, waterfalls, and ambient sound ribbons. Computes closest-point-on-ribbon geometry per frame, managing near/far lists and 5-axis SFX emitter positioning relative
Dynamic spatial audio system for rivers, waterfalls, and ambient sound ribbons. Computes closest-point-on-ribbon geometry per frame, managing near/far lists and 5-axis SFX emitter positioning relative to the listener.
Public API
| Function | Signature | Returns | Description |
|---|---|---|---|
M.createEmitterHost | (eventName) | table | Creates an SFX emitter host data structure |
M.updateRibbonData | (ribbon) | nil | Recomputes segment count and pair widths after node changes |
M.removeRibbon | (idx) | nil | Removes ribbon at index, clears all SFX emitters |
M.recomputeMap | () | nil | Rebuilds ribbon name lookup table |
M.clearAllSFXEmitters | () | nil | Destroys all dynamic SFX emitter objects |
M.clearNearFarLists | () | nil | Clears near/far proximity lists |
M.clearRibbonNames | () | nil | Clears the ribbon name map |
M.getRibbons | () | table | Returns all ribbons |
M.setRibbons | (val) | nil | Replaces all ribbons |
M.getRibbonNames | () | table | Returns ribbon name lookup |
M.getNearList | () | table | Returns near-field ribbon list |
M.getFarList | () | table | Returns far-field ribbon list |
M.getSfxEmitters | () | table | Returns all 5-axis SFX emitters |
Hooks
| Hook | Purpose |
|---|---|
M.onUpdate | Per-frame emitter position/volume updates |
M.onSerialize | Serializes ribbons for Lua reload |
M.onDeserialized | Restores ribbons after reload |
M.onEditorBeforeSaveLevel | Writes ribbons to disk |
M.onClientCustomObjectSpawning | Loads ribbons from level file on level load |
Architecture
Each ribbon has 5 emitter hosts (axes):
- Center/Ambient - directly at closest point
- Forward - offset along listener forward
- Back - offset behind listener
- Right - offset along listener right
- Left - offset along listener left
Near/Far Lists
- Near list: All ribbons within 500m - fully updated every frame
- Far list: Ribbons beyond 500m - one ribbon updated per frame (round-robin)
Volume Calculation
Volume is computed from width × depth × speed with distance falloff, using the formula:
volumeC = volCoeff * (speed * width * depth) / (speed * width * depth + expOffset)Usage Examples
-- Get all ribbons for editor inspection
local ribbons = core_audioRibbon.getRibbons()
-- Remove a specific ribbon
core_audioRibbon.removeRibbon(3)
-- Clear everything on level unload
core_audioRibbon.clearAllSFXEmitters()
core_audioRibbon.clearNearFarLists()File Format
Ribbons are stored as JSONL (one JSON object per line) at:
levels/[levelName]/dynamicAudioEmitters/ribbonData.audioSFX.json
Audio Bank Manager
Manages FMOD sound bank loading, caching, hotloading, and level-specific audio. Handles string banks, preload banks, asset banks, meta banks, and ambient banks in the correct loading order.
Bus Route Manager
Manages bus route definitions and bus stop trigger events. Loads route data from JSON files, validates stop triggers against the scene, and dispatches events to bus vehicle controllers.