Phase 4: Add modular graph editor and transactional graph edits
This commit is contained in:
parent
2ecc03b482
commit
5c41d7f6da
27 changed files with 1023 additions and 64 deletions
|
|
@ -28,8 +28,8 @@ tempo automation.
|
|||
|
||||
## Phase 1 offline API
|
||||
|
||||
`xtc_graph_create` accepts 1..256 nodes; IDs are insertion indexes, stable for
|
||||
that graph's lifetime. Supported nodes are gain (any finite multiplier), sine
|
||||
`xtc_graph_create` accepts 1..256 nodes; IDs are monotonic stable identifiers, never reused
|
||||
within a graph's lifetime. Enumeration indexes are dense and distinct from IDs. Supported nodes are gain (any finite multiplier), sine
|
||||
oscillator (finite nonnegative Hz), pass-through peak meter and audio output.
|
||||
Ports carry mono float audio: input 0, output 1. Oscillators have no input and
|
||||
output nodes have no output. Port lookup reports direction, signal type and
|
||||
|
|
@ -39,7 +39,7 @@ edit becomes visible. Fan-out copies a source to consumers; fan-in sums inputs
|
|||
without normalization. Failed additions leave IDs and graph contents unchanged.
|
||||
|
||||
`xtc_graph_compile(graph, sample_rate, max_frames, &plan)` runs on the control
|
||||
thread. Empty graphs are rejected. Sample rate must be finite and positive,
|
||||
thread. Empty graphs compile to silence. Sample rate must be finite and positive,
|
||||
oscillators must be at or below Nyquist, and max_frames is 1..65536. Compilation
|
||||
allocates and copies topology/parameters, builds a topological schedule and
|
||||
input adjacency, and allocates one max_frames float buffer per node. The
|
||||
|
|
@ -56,7 +56,9 @@ with processing, including reset, meter reads or destruction.
|
|||
Unconnected non-oscillator nodes receive external input. Connected inputs
|
||||
receive only the sum of their upstream buffers. Explicit output nodes are
|
||||
summed to the caller's output. If none exist, terminal nodes are summed for
|
||||
compatibility with the original gain-chain API. Disconnected components cannot
|
||||
compatibility with the original gain-chain API, unless
|
||||
`xtc_graph_require_output_nodes(graph, 1)` is set. The GUI uses that policy;
|
||||
no output nodes means silence. Disconnected components cannot
|
||||
contribute when explicit outputs exist, but they are still processed. Floating
|
||||
point overflow and nonfinite input become silence per sample. No clipping or
|
||||
normalization is applied to finite samples.
|
||||
|
|
@ -103,7 +105,10 @@ Use `xtc_backend.h` on one serialized control thread:
|
|||
between enumeration and connection; route failures are returned as I/O errors.
|
||||
4. During playback, submit edited graphs and periodically collect retired
|
||||
resources. Capacity means one pending graph is still awaiting adoption;
|
||||
keep the current graph and retry later. get_status is a nonblocking snapshot
|
||||
keep the current graph and retry later. Stopped submissions instead compile
|
||||
a replacement engine off-thread and swap only after success, while callbacks
|
||||
are quiescent. Its block/revision counters restart and oscillator phase resets;
|
||||
no edit is blocked behind a plan that cannot be adopted until playback. get_status is a nonblocking snapshot
|
||||
of rate, frames, running/server-loss/rate-change flags, xruns, processed
|
||||
blocks and last process result. No active DSP memory is exposed.
|
||||
5. Stop pauses the retained DSP state after deactivation. Restart resumes it.
|
||||
|
|
@ -133,4 +138,46 @@ test README. Current limitations: mono input/output, no parameter ramping or
|
|||
crossfaded graph changes, no realtime meter bridge, no automatic reconnect,
|
||||
no physical-device or long-duration endurance qualification. Phase 3 connects
|
||||
the FLTK shell to backend controls and status; see GUI.md. Its editors remain
|
||||
placeholders and the GUI submits no playback graph yet.
|
||||
placeholders except the Phase 4 modular editor described below.
|
||||
|
||||
## Phase 4 graph snapshots and edits
|
||||
|
||||
The control-thread API exposes copies through get_counts, get_node(index) and
|
||||
get_connection(index), including node IDs/types/values and port endpoints. No
|
||||
mutable graph/engine storage is exposed. Node IDs increase monotonically;
|
||||
removing a node compacts private storage and adjusts private edge indexes but
|
||||
leaves surviving IDs unchanged. Exhausted ID space returns capacity. Compiled
|
||||
meter lookup resolves stable IDs too.
|
||||
|
||||
`xtc_graph_apply_edit(source, edit, &candidate, &added_id)` accepts ADD_NODE,
|
||||
REMOVE_NODE, CONNECT or DISCONNECT. It copies the source, validates the edit,
|
||||
and returns a caller-owned candidate on success. On failure candidate is NULL,
|
||||
source and added_id are unchanged. added_id is optional and written only for
|
||||
ADD_NODE. ADD_NODE validates type and the used parameter (finite gain, or finite
|
||||
nonnegative oscillator Hz). Meter/output do not use the value field. Compile
|
||||
additionally checks the oscillator against the actual sample rate. Removing
|
||||
a node removes its incident connections; disconnecting a nonexistent edge
|
||||
returns not-found. Missing nodes/ports, reversed directions, duplicate edges,
|
||||
cycles and unknown command/type values are rejected without visible edits.
|
||||
|
||||
The GUI keeps a 64-node graph requiring explicit output nodes. It creates a
|
||||
candidate, submits that exact candidate to the backend, then swaps its owned
|
||||
graph and refreshes the canvas only if submission succeeds. Failed compile or
|
||||
pending-slot pressure destroys the candidate and retains both the displayed
|
||||
graph and previously submitted engine plan. When disconnected at startup,
|
||||
edits can be stored locally and are submitted on reconnect. Lost/changed active
|
||||
backends reject edits until reconnect. Reconnect submits the retained graph.
|
||||
|
||||
Submitted/active revision counters expose adoption without exposing plan
|
||||
pointers. A submission increments the submitted revision; only the audio
|
||||
consumer acknowledges the revision when adopting the plan at a block boundary.
|
||||
The editor shows prepared while stopped, queued while an older plan is active,
|
||||
and active when those revisions agree. Atomic fields remain independent
|
||||
snapshots and wrap modulo UINT_MAX + 1. Rebuilding a stopped engine or reopening
|
||||
a backend starts a new counter epoch. See decision 0004 for slot ordering.
|
||||
|
||||
Movement, selection and scroll position are GUI-only state; they never compile
|
||||
or publish audio plans. Empty graphs and graphs without explicit outputs are
|
||||
silent under the GUI policy. Terminal fallback remains the default for earlier
|
||||
offline/standalone callers. Input on unconnected nodes retains the existing
|
||||
external-input contract; the GUI does not connect external JACK ports.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue