Skip to content

Commit 7439f8f

Browse files
committed
updated api so runtime params can be adjusted before audio is running
1 parent 9b46c45 commit 7439f8f

10 files changed

Lines changed: 257 additions & 67 deletions

File tree

TODO.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212

1313
- test speaker layout config on windows, validate code
1414

15+
- clean up transcode tab?
16+
1517
## Other Tasks for final packaging:
1618

17-
- clean up transcoder tab?
18-
- add render tab - update render code to match non linear channel handeling, give it render params ?
19-
- debug overall windows build \*\*\*
19+
OS AND COMPATIBILITY TESTING
20+
PACKAGING
2021

2122
# Future Work - move to future work md
2223

internalDocs/5_10_api_update.md

Whitespace-only changes.

internalDocs/AGENTS.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,16 +230,30 @@ Implementation: `SpatialRootPaths::appSettingsRoot()` / `DefaultLayoutManager`.
230230

231231
## Runtime Control Plane
232232

233+
**`RuntimeParams` is the canonical parameter struct.** Defaults come from `RuntimeParams::defaults()` — a single source of truth used by API, CLI, and GUI. Default values: `masterGainDb=0`, `dbapFocus=1.5`, `speakerMixDb=0`, `subMixDb=0`.
234+
235+
**Staging before Run:** `configureRuntime(params)` can be called before `start()` to set initial playback values. The engine starts from these staged values — it does not briefly use hardcoded defaults. GUI sliders are editable before Run as staged values.
236+
237+
**Live update after Run:** `configureRuntime()`, individual setters, and OSC callbacks all write to the same `RealtimeConfig` atomics and are safe to call while audio is running.
238+
239+
**Querying current state:** `getRuntimeParams()` returns the current values in dB, reflecting the latest `configureRuntime()`, setter, or OSC change. Use this to sync GUI controls after a `resetRuntimeParams()` call.
240+
241+
**Reset:** `resetRuntimeParams()` is equivalent to `configureRuntime(RuntimeParams::defaults())`. Safe before and after `start()`. Does not reload scene/layout, restart playback, or affect transport.
242+
233243
**Primary (in-process):** ImGui GUI calls direct C++ setters on `EngineSession`:
234244

235-
- `setMasterGainDb(float)`, `setDbapFocus(float)`, `setSpeakerMixDb(float)`, `setSubMixDb(float)`, `setElevationMode(ElevationMode)`
245+
- `setMasterGainDb(float)`, `setDbapFocus(float)`, `setSpeakerMixDb(float)`, `setSubMixDb(float)`, `setElevationMode(ElevationMode)`, `configureRuntime(RuntimeParams)`, `getRuntimeParams()`, `resetRuntimeParams()`
236246

237247
**Secondary (optional OSC):** Remains available for external tooling/remote control.
238248

239249
- Default port: `9009`; disable with `oscPort=0` in `EngineOptions`
250+
- OSC params are initialized from the current runtime state when `start()` is called
251+
- `configureRuntime()` and `resetRuntimeParams()` sync OSC param values if the server is running; individual setters do not
240252
- DBAP focus minimum is `0.1`; normalized DBAP preserves `sum(v_k^2) = 1`
241253
- See [REALTIME_ENGINE.md § OSC Parameter Reference](REALTIME_ENGINE.md#osc-parameter-reference) for full address/range table
242254

255+
**Output routing** is layout-derived and initialized in `applyLayout()``configureOutputRouting()`. `configureRuntime()` no longer touches routing setup. CSV remap override is retained as deprecated internal scaffolding only.
256+
243257
---
244258

245259
## Common Issues & Solutions

internalDocs/API_internal.md

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,16 @@ struct LayoutInput {
5757
```cpp
5858
struct RuntimeParams {
5959
float masterGainDb = 0.0f; // Master gain in dB. Range: -60–+12 dB. 0 dB = unity.
60-
float dbapFocus = 1.5f; // DBAP rolloff exponent, minimum 0.1
61-
float speakerMixDb = 0.0f; // post-DBAP main trim in dB, range -60–+12 dB
62-
float subMixDb = 0.0f; // post-DBAP sub trim in dB, range -60–+12 dB
60+
float dbapFocus = 1.5f; // DBAP rolloff exponent. Range: 0.1–5.0.
61+
float speakerMixDb = 0.0f; // Post-DBAP main trim in dB. Range: -60–+12 dB.
62+
float subMixDb = 0.0f; // Post-DBAP sub trim in dB. Range: -60–+12 dB.
63+
64+
static RuntimeParams defaults(); // Canonical defaults — single source of truth.
6365
};
6466
```
65-
All three dB fields are converted to linear at store time: `std::pow(10.0f, dB / 20.0f)`.
67+
All dB fields are converted to linear at store time via `clampDb``dbToLinear`.
68+
`getRuntimeParams()` performs the inverse conversion (`linearToDb`) and re-clamps; a zero or
69+
negative linear value returns `-60.0f` (never `-inf` or `NaN`).
6670

6771
---
6872

@@ -72,31 +76,40 @@ The engine enforces a strict, linear initialization sequence:
7276

7377
1. `configureEngine(const EngineOptions&)` — stores sampleRate, bufferSize, outputDeviceName, oscPort, elevationMode into `mConfig`. Always returns `true`.
7478
2. `loadScene(const SceneInput&)` — parses LUSID scene via `JSONLoader`, initializes `Streaming`. Returns `false` if scene file missing or no sources loaded.
75-
3. `applyLayout(const LayoutInput&)` — requires `loadScene` to have succeeded (`mSceneData` guard). Loads speaker layout, initializes `Pose` and `Spatializer`.
76-
4. `configureRuntime(const RuntimeParams&)` — writes gain/focus/mix atomics to `mConfig`. Loads remap CSV if path non-empty. **OSC ParameterServer is NOT started here — it starts in `start()`.**
77-
5. `start()` — creates and starts `al::ParameterServer` (if `oscPort > 0`), registers OSC callbacks, starts `RealtimeBackend` + loader thread. Prints `"ParameterServer listening"` to stdout when OSC is active.
79+
3. `applyLayout(const LayoutInput&)` — requires `loadScene` to have succeeded (`mSceneData` guard). Loads speaker layout, initializes `Pose` and `Spatializer`. Calls `configureOutputRouting()` internally.
80+
4. `configureRuntime(const RuntimeParams&)` — clamps and writes gain/focus/mix atomics to `mConfig`. **Does not perform output routing setup** (moved to `applyLayout()`). Safe before and after `start()`. Syncs OSC param values if the OSC server is already running. **OSC ParameterServer is NOT started here — it starts in `start()`.**
81+
5. `start()` — creates and starts `al::ParameterServer` (if `oscPort > 0`), initializes OSC params from current runtime state via `getRuntimeParams()`, registers OSC callbacks, starts `RealtimeBackend` + loader thread.
82+
83+
**Runtime control (before or after `start()`):**
7884

79-
**Runtime Control (after `start()`):**
85+
`configureRuntime()` is safe to call at any point after `configureEngine()`:
86+
- **Before `start()`:** stages the initial playback values; the engine will start from these.
87+
- **After `start()`:** applies values live through the same atomic path as the individual setters.
8088

81-
| Method | Writes to | Notes |
89+
| Method | Writes | Notes |
8290
|---|---|---|
91+
| `configureRuntime(const RuntimeParams&)` | all 4 gain/focus params | Clamps + converts dB→linear. Syncs OSC if running. |
92+
| `getRuntimeParams() -> RuntimeParams` | — (read only) | Returns current state in dB; reflects setters, OSC changes, and `configureRuntime`. |
93+
| `resetRuntimeParams()` | all 4 gain/focus params | Equivalent to `configureRuntime(RuntimeParams::defaults())`. Does not restart playback, reload scene/layout, or clear files. |
8394
| `setPaused(bool)` | `mConfig.paused` | Only supported transport control. Stop/seek unsupported. |
84-
| `update()` || Should be called from the main thread / host loop. Currently retained for API stability; no deferred focus-compensation work remains. |
95+
| `update()` || Should be called from the main thread / host loop. Currently retained for API stability. |
8596
| `queryStatus() -> EngineStatus` || Lock-free snapshot. No state mutation. |
8697
| `consumeDiagnostics() -> DiagnosticEvents` || Atomically exchanges event flags. Clears them on read. |
8798
| `shutdown()` || Terminal. Destroy and recreate `EngineSession` to restart. |
8899

89-
**Phase 6 runtime setters (direct C++ control, no OSC required):**
100+
**Runtime setters (direct C++ controlno OSC required; no OSC sync on individual setters):**
90101

91-
| Method | Writes | Notes |
102+
| Method | Writes | Range |
92103
|---|---|---|
93-
| `setMasterGainDb(float)` | `mConfig.masterGain` | dB → linear conversion at store time; range -60–+12 dB |
94-
| `setDbapFocus(float)` | `mConfig.dbapFocus` | Clamped to a minimum of `0.1f` |
95-
| `setSpeakerMixDb(float)` | `mConfig.loudspeakerMix` | dB → linear conversion at store time |
96-
| `setSubMixDb(float)` | `mConfig.subMix` | dB → linear conversion at store time |
97-
| `setElevationMode(ElevationMode)` | `mConfig.elevationMode` | Cast to int at store time |
98-
99-
All writes use `std::memory_order_relaxed`. Safe to call after `start()` and before `shutdown()`.
104+
| `setMasterGainDb(float)` | `mConfig.masterGain` | -60–+12 dB |
105+
| `setDbapFocus(float)` | `mConfig.dbapFocus` | min 0.1 |
106+
| `setSpeakerMixDb(float)` | `mConfig.loudspeakerMix` | -60–+12 dB |
107+
| `setSubMixDb(float)` | `mConfig.subMix` | -60–+12 dB |
108+
| `setElevationMode(ElevationMode)` | `mConfig.elevationMode` | cast to int |
109+
110+
All writes use `std::memory_order_relaxed`. Safe to call before and after `start()`.
111+
Individual setters do **not** sync OSC visible parameter values. Use `configureRuntime()` or
112+
`resetRuntimeParams()` when OSC sync is required.
100113

101114
### Error Model
102115

internalDocs/REALTIME_ENGINE.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,11 +278,16 @@ Threading model: audio thread (RT, AlloLib), loader thread (background disk I/O)
278278
- **Resume step calculation:** Fade-in step is now `(1.0f - mPauseFade) / fadeFrames` rather than always `1/fadeFrames`. Ramp continues from current gain instead of resetting to zero (Bug 11.3).
279279
- **`stop()` fade-before-hard-stop:** Arms pause fade and unconditionally sleeps 50ms before calling `mAudioIO.stop()`. Resets `mConfig.paused = false` afterward (Bugs 11.2, 11.4).
280280

281-
**Gain system (May 7, 2026):** All three gain controls now accept dB at every public surface. Conversion to linear (`std::pow(10.0f, dB / 20.0f)`) happens at the API boundary in `configureRuntime()`, `setMasterGainDb()`, `setSpeakerMixDb()`, `setSubMixDb()`, and OSC callbacks. Internal `RealtimeConfig` atomics remain linear.
281+
**Gain system (May 7, 2026; updated May 10, 2026):** All gain controls accept dB at every public surface. Conversion to linear (`clampDb``dbToLinear = std::pow(10.0f, dB / 20.0f)`) happens at the API boundary via `applyRuntimeParamsToConfig()`, called by `configureRuntime()`, individual setters, and OSC callbacks. `getRuntimeParams()` performs the inverse via `linearToDb`; zero/negative linear → `-60.0f` (never -inf). Internal `RealtimeConfig` atomics remain linear.
282+
283+
`configureRuntime()` no longer performs output routing setup. Output routing is now initialized in `applyLayout()``configureOutputRouting()`. `configureRuntime()` is safe to call before or after `start()`.
284+
285+
`RuntimeParams::defaults()` is the single canonical source of default values for API, CLI, and GUI. `resetRuntimeParams()` is equivalent to `configureRuntime(RuntimeParams::defaults())`.
282286

283287
| Control | Public API | Range | Default | OSC address |
284288
|---|---|---|---|---|
285289
| Master gain | `RuntimeParams::masterGainDb`, `setMasterGainDb(float)` | -60–+12 dB | 0.0 dB | `/realtime/gain_db` |
290+
| DBAP focus | `RuntimeParams::dbapFocus`, `setDbapFocus(float)` | 0.1–5.0 | 1.5 | `/realtime/focus` |
286291
| Speaker mix | `RuntimeParams::speakerMixDb`, `setSpeakerMixDb(float)` | -60–+12 dB | 0.0 dB | `/realtime/speaker_mix_db` |
287292
| Sub mix | `RuntimeParams::subMixDb`, `setSubMixDb(float)` | -60–+12 dB | 0.0 dB | `/realtime/sub_mix_db` |
288293

internalDocs/devHistory.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,40 @@
55

66
---
77

8+
## Runtime Parameter Staging, Reset, and Single-Source Defaults (May 10, 2026)
9+
10+
**Status:** Complete. Covers `EngineSession` API, CLI, GUI, and docs.
11+
12+
**Motivation:** Runtime controls (gain, focus, mix) were disabled in the GUI before playback started and reset to hardcoded defaults on every Start click. Default values were duplicated across `RuntimeParams`, CLI argument parsing, and `resetRuntimeToDefaults()` in App.cpp. `configureRuntime()` mixed parameter setup with output routing setup, making it unsafe to call before `applyLayout()`.
13+
14+
**What changed:**
15+
16+
- `EngineSession.hpp` / `EngineSession.cpp`:
17+
- Added `RuntimeParams::defaults()` — single canonical source of default values.
18+
- Added file-local helpers: `clampDb`, `clampFocus`, `dbToLinear`, `linearToDb` (defensive: zero/negative linear → -60 dB, not -inf).
19+
- Added private `sanitizeRuntimeParams()`, `applyRuntimeParamsToConfig()`, `configureOutputRouting()`.
20+
- Added public `getRuntimeParams()` — reads atomics, converts linear→dB, re-clamps; reflects setters, OSC, and `configureRuntime` changes.
21+
- Added public `resetRuntimeParams()` — equivalent to `configureRuntime(RuntimeParams::defaults())`.
22+
- Refactored `configureRuntime()`: now only writes gain/focus/mix atomics + syncs OSC if running. No longer touches `mSpatializer` or `OutputRemap`.
23+
- Moved output routing setup (remap CSV scaffolding + layout-derived routing) to `configureOutputRouting()`, called at the end of `applyLayout()`. `configureRuntime()` is now safe to call before `applyLayout()`.
24+
- Updated `start()`: initializes OSC param values from `getRuntimeParams()` instead of reading atomics directly.
25+
- Updated individual setters to use `clampDb`/`clampFocus`/`dbToLinear` helpers consistently.
26+
27+
- `main.cpp`: CLI now initializes `RuntimeParams` from `RuntimeParams::defaults()` and overrides from flags, eliminating duplicated literal defaults.
28+
29+
- `App.cpp`:
30+
- Removed `BeginDisabled` guard around runtime controls — sliders/inputs are always editable as staged values before Run.
31+
- Input callbacks always clamp; setters called only when running.
32+
- Added "Reset Parameters" SmallButton inline with the RUNTIME CONTROLS header. Before Run: resets GUI staged values via `resetRuntimeToDefaults()`. After Run: calls `mSession->resetRuntimeParams()` and syncs GUI from `mSession->getRuntimeParams()`.
33+
- Removed `resetRuntimeToDefaults()` call from `onStart()` — staged values are now preserved when playback starts.
34+
- Updated `resetRuntimeToDefaults()` to use `RuntimeParams::defaults()` instead of hardcoded literals.
35+
36+
- `internalDocs/API_internal.md`, `REALTIME_ENGINE.md`, `AGENTS.md`: updated to reflect new API methods, routing refactor, defaults source, and OSC sync semantics.
37+
38+
**OSC sync note:** `configureRuntime()` and `resetRuntimeParams()` sync OSC-visible parameter values when the OSC server is running. Individual setters (`setMasterGainDb` etc.) do not sync OSC values — they write atomics only. `getRuntimeParams()` reflects OSC changes because both OSC callbacks and setters write the same atomics.
39+
40+
---
41+
842
## Offline ADM Rendering — Phase 3B/3C: CULT Orchestration + Source Validation (May 10, 2026)
943

1044
**Status:** Complete. `--adm` without `--positions` now mirrors the realtime ADM architecture end-to-end.

0 commit comments

Comments
 (0)