xtc/docs/ROUTING.md
2026-11-06 14:12:22 +01:00

6.7 KiB

Modular routing workflow

Open Modular Graph (Ctrl+3). Select a node or wire to inspect it in the feedback line. Nodes have stable IDs, role labels and distinct colors: teal sources, purple gain/bus nodes, blue processors/meters and red output sums. LADSPA nodes also show the saved plugin label. Track names remain in Sequencer/Mixer; the Audio mix and MIDI mix graph sources represent their shared mix buffers, not individual tracks. MIDI mix is the internal sine-instrument mix; its graph ports carry audio, not MIDI events. Native nodes are trusted extensions.

Wires show arrows from right-hand audio outputs to left-hand inputs. Selecting a node highlights all its incoming/outgoing wires; selecting a wire shows its endpoint IDs. Inputs sum all connected signals without normalization; fan-out sends the same signal to each destination. Multiple output nodes sum into the engine output. Gain/bus nodes are ordinary summing gain processors, not a new bus/mixer-strip type. Add gain retains its existing 0.10 preset.

A yellow ! no output path badge and dim wires identify branches that cannot reach a rendered output. This is a structural warning, not an invalid graph: isolated nodes are allowed, and may still consume processing time. Conversely, “path to engine output” does not guarantee audible music: clips, MIDI, gain, mute, plugin behavior and external hardware routing still matter. Graph output is not an automatic JACK hardware connection.

An ext in port means it has no incoming graph wire: the existing renderer uses external audio input there (subject to its input gain), rather than silence. Connecting a wire replaces this fallback with the wired sum; deleting the last input wire restores fallback. This applies to unwired effects, meters and outputs. Generator/audio/MIDI sources have no input port. Removing an output path is not a substitute for stopping playback or muting a track. The graph models one audio lane per port; stereo compilation processes paired independent lanes. It does not expose separate left/right, MIDI or control wires.

Commands

Action Operation
Connect Drag an output circle to an input circle
Disconnect Select a wire and press Delete/Backspace
Remove node Select node, Delete; its incident wires are removed too
Inspect nodes Click, or Left / Right within the focused graph
Arrange by signal flow View menu, L with graph focus, or context menu
Insert unity gain Select wire, Edit menu, I with graph focus, or context menu
Move / pan Drag node body; scroll the canvas
Cancel drag Escape

Right-click opens commands for the current selection. Auto-layout places each node in a column matching its longest source-to-node path and in a distinct row within that column. Disconnected roots remain in the first column. It enlarges the scrollable canvas when necessary. Moving, selecting and arranging are session UI changes; they do not publish audio plans, alter routing, or add undo steps. Open/undo may rebuild layout. Node positions are not persisted. Whole- project binding gives distinct initial grid positions to all new nodes.

Inserting unity gain replaces an existing wire A -> B by A -> gain -> B, with gain exactly 1. This simple reusable routing operation preserves level, allocates a fresh stable node ID and is one semantic edit/undo step. It preserves all other edges. Failure (including capacity, a missing/stale wire or backend refusal) keeps the previous graph and plan. It introduces no new node type or project record: v8 persistence already represents the resulting graph. One-level stereo mix buses are added before shared graph sources (see MIXER.md). Track templates, folders and independent per-track/bus graph inserts remain deferred because graph sources still expose shared mixes.

Transactions, cycles and realtime ownership

The public C xtc_graph_apply_edit command constructs a private candidate. XTC_EDIT_INSERT_GAIN uses data.connection and returns the fresh ID through out_added_id only on complete success. It disconnects, inserts and reconnects inside that private copy. Any failure destroys it; the source and output ID remain unchanged, and the graph output pointer is NULL. Ordinary connect/delete commands retain their existing transactional behavior. Self-edges, direct and indirect feedback cycles, wrong port directions, duplicate wires and missing ports are explicitly rejected. No feedback/delay-loop processing is supported.

The GUI clones its project and compiles/publishes the exact candidate through the existing backend before replacing the displayed model/history. When running, a complete immutable plan is adopted at a block boundary; the control thread collects acknowledged retired plans. The feedback line distinguishes prepared, queued and active revisions. A queued graph can appear before it becomes audible. The single pending slot can reject a busy edit with CAPACITY: wait for adoption and retry. There is no hidden unbounded edit queue or callback mutation. Normal graph edits can run during playback; undo/redo uses the existing stopped-plan installation contract. Recording still blocks semantic graph edits. Plan swaps may reset oscillator/plugin state and are not crossfaded.

xtc_graph_analyze computes input/output edge counts, longest-path level, rendered-output reachability and external-input fallback in dense-node order. It is a bounded, allocation-free control-thread API, not a callback service. It never loads plugins. It honors explicit outputs; legacy terminal fallback applies only when there are no explicit output nodes and the caller has not required them. Errors leave result storage/count unchanged. The GUI caches this analysis when binding a graph; drawing reads cached metadata only. It uses public C snapshots/commands and never engine internals or callback storage.

Verification and limits

make test-routing checks branch reachability, external input, levels, capacity rollback, exact unity-insertion rendering and complete plan handoff. make test also retains concurrent publication/lifecycle tests. make test-reliability retains the callback-allocation guards. make test-gui-plugins checks selection diagnostics, unique placement/layout, failed backend publication, atomic insertion undo/redo and keyboard focus. make test-gui-jack inserts/disconnects/restores real routes during live software playback and checks engine revision acknowledgements and cycle rejection.

Physical routing/listening and hardware endurance remain unqualified. This is an audio-lane DAG editor with a default 64-node project capacity (standalone C graphs up to 256), no zoom/lasso or persisted layout, no latency compensation and no plugin crash isolation. Unconnected branches are diagnosed, not pruned.