Signal Graph Reference¶
pulp::host::SignalGraph is the DAG engine that connects PluginSlot
instances (and built-in nodes: input, output, gain, MIDI in/out) into a
routable audio topology.
Nodes¶
| NodeType | Role | Ports |
|---|---|---|
Input |
Source from the host's input bus | 0 in → N out |
Output |
Sink to the host's output bus | N in → 0 out |
Gain |
Scalar gain, no allocation | 1 in → 1 out |
Plugin |
Wraps a PluginSlot |
N in → N out |
MidiInput |
Source for MIDI events | 0 in → 1 out |
MidiOutput |
Sink for MIDI events | 1 in → 0 out |
Each node has a stable NodeId that survives connection edits. The graph
owns the nodes; removing a node invalidates its id.
Connections¶
connect(from, from_port, to, to_port) adds an audio edge and returns
false if it would create a cycle (would_create_cycle() exposes the same
check without mutating). Disconnect by NodeId, port, or by full edge.
Three connection variants cover the non-audio-passthrough cases:
connect_midi(from, to)routesMidiBufferevents between node-scoped MIDI in/out buffers (ports are ignored). Participates in cycle detection the same way audio edges do.inject_midi(node, buf)loads aMidiInput's output before a block;extract_midi(node, &out)drains aMidiOutput's input after a block.connect_feedback(from, port, to, port)closes a cycle with an explicit one-block delay — the destination reads the source's previous block's output. Invisible to the topological sort and PDC so the runtime stays DAG-ordered.- Sidechain is not a separate API: connect a secondary source to the
plugin node's sidechain audio-port indices (e.g.
connect(side, 0, p, 2)when the plugin exposes ports 2/3 as its sidechain bus).
Processing order¶
processing_order() returns the topological sort. The audio callback
walks this vector once per block:
- Input nodes copy from the host buffer to their output port.
- Plugin nodes call
PluginSlot::process()with their gathered inputs. - Gain nodes multiply in place.
- MIDI nodes route events the same way audio flows.
- Output nodes copy to the host buffer.
Topological sort is stable: for a given set of nodes and connections, the resulting order is deterministic, so routing is reproducible across runs.
Latency & PDC¶
Every PluginSlot reports latency_samples(). During prepare() the
graph walks the topology, computes each node's input / output latency,
and allocates per-connection delay lines so parallel branches converge
aligned. Query results with SignalGraph::latency_samples() (graph-wide
total) and node_latency_samples(id) (alignment at a specific node).
Feedback edges (connect_feedback) don't contribute to PDC — the
one-block delay absorbs their alignment.
Parameters¶
set_node_parameter(node, id, value) forwards a normalized value to the
plugin via PluginSlot::set_parameter(); get_node_parameter(node, id)
reads back. Full automation-curve routing (one node's output driving
another node's parameter over a block) is not yet available — track via
the plan.
Thread model¶
- Build & edit (add / connect / remove) runs on the UI thread.
- Process runs on the audio thread over the snapshotted processing order. The snapshot is swapped under a lock-free publish so edits never tear the running order.
- Load (
PluginSlot::load) runs on a worker thread; the returned slot is handed to the graph only after it's fully loaded.
See also¶
- Hosting guide — end-to-end example.
pulp::host::PluginSlotpulp::host::SignalGraph