1
0
Fork 0
forked from hanez/xtc

Phase 4: Add modular graph editor and transactional graph edits

This commit is contained in:
Johannes Findeisen 2026-10-26 23:55:35 +01:00
commit 5c41d7f6da
27 changed files with 1023 additions and 64 deletions

View file

@ -39,7 +39,7 @@ objects. There is no mutex or libatomic fallback in the callback path.
One serialized control producer and one audio consumer share two pointer slots:
- `pending`: producer publishes a fully compiled plan with release; consumer
exchanges it for NULL with acquire at the next eligible block boundary.
exchanges it for NULL with acquire/release at the next eligible block boundary.
- `retired`: consumer releases its previous active plan into this slot only
after its final access. Producer exchanges with NULL using acquire/release,
then destroys that acknowledged plan on the control thread.
@ -82,3 +82,27 @@ crossfade. Smooth parameter ramps and click-free graph transitions are future wo
No stereo, recording, MIDI, native PipeWire API, GUI engine controls or hardware
configuration dialogs are part of this phase.
## Phase 4 adoption acknowledgement and stopped editing
The pending pointer has an associated atomic revision. Producer stores the
revision before release-publishing the pointer. Consumer acquire-loads a
non-NULL pending pointer, reads its revision, and only then releases that slot
with an acquire/release exchange to NULL. Thus producer cannot reuse the
revision field until the previous consumer read is complete. Consumer publishes
active_revision when selecting that plan; the GUI compares it with the
producer's submitted_revision. These are wrapping counters and individual
snapshots, not plan pointers or a multi-field transactional snapshot.
While JACK is stopped, a backend submission builds a separate realtime engine,
submits/compiles the graph there, and replaces the retained engine only on
success. Process callbacks cannot run on an inactive client or after successful
deactivation, and notification callbacks do not access the engine pointer.
The control thread can therefore reclaim all old state safely. Counters and
oscillator phases restart for that new engine epoch. The standalone realtime
API keeps its one-pending-slot contract regardless of external stop state.
The callback still adopts at most one plan and never allocates/frees. Revision
ordering is tested alongside the plan's rendered gain under 2,000 concurrent
submissions and ThreadSanitizer. Stopped compile failure and active pending
capacity are checked with backend fault injection.