| Editable graph, project, history and asset paths | One serialized control thread (the GUI thread in the application). Borrowed model pointers expire on mutation/destruction. Never traverse these objects in the callback. |
| Compiled graph routing/specifications | Copied during compilation; independent of the editable graph. Immutable after publication. All nodes, including disconnected nodes, are scheduled; only explicit outputs (or compatibility terminals) are mixed. |
| DSP buffers, native instances, phases, meter peaks and graph-local clock | One processing consumer. Reset and meter reads require that owner or quiescence; these are not atomic GUI snapshots. Native callback code must remain loaded until all instances are destroyed. |
| Pending graph | Single control producer publishes with release; the consumer acquires it at a block boundary. The revision is read before releasing the pending slot, preventing producer reuse of its metadata. A full pending slot rejects submission. |
| Active graph | Consumer only until the consumer is stopped/joined. No producer access to mutable DSP state. |
| Retired graph | Consumer releases only after its final access. Control acquires/exchanges the slot and destroys the plan. If the slot is occupied, adoption waits while processing the current graph continues. The callback never destroys plans. |
| Realtime status | Individual atomic counters/revisions; a status read is not a transaction spanning every field. Required pointer/integer atomics must be always lock-free. |
| JACK client, ports and backend control fields | Serialized control thread. JACK owns callback scheduling. Successful deactivate establishes processing quiescence; successful close synchronizes callbacks before freeing context. Failed deactivate/close preserves ownership for retry. Server-loss notification alone is not permission to free context. |
| Preloaded audio/MIDI plans and source buffers | Backend owns them; prepare/replace while stopped, callback alone renders while running. MIDI voices/panic state follow the same rule; panic requests use atomics. |
| Recorder | Caller owns it; backend borrows it. Attach/detach only while stopped. Audio is sole ring producer, control is sole drain/file writer. Acquire/release indices protect samples; errors are sticky. Detach/quiesce before finish/destroy. |
| Widgets and GUI timers | GUI thread only; status polling and retired-plan collection occur there, never through FLTK calls from audio. |
The public realtime API is SPSC: multiple producers, simultaneous process calls,
collection from arbitrary threads, and destruction during processing are not
supported. Atomics do not remove those ownership requirements.