Ids, tracks and routing
Idis au64.Project::alloc_idhands outnext_idand increments it; the counter is saved, so ids are unique within a project and never reused. Tracks, regions, clips, plug-in instances (PluginSlot::uid), groups, markers and takes all draw from it.MASTER_ID= 0 is reserved for Stereo Out (theMasterstruct, not aTrack).- Plug-in instance ids restart in every project, which is why
openclears all controllers before loading.
Tracks and the track tree
Section titled “Tracks and the track tree”Track::kind is one of Audio, Instrument, Folder (folder stack), Summing (summing
stack) or Aux. Stacks are expressed with Track::parent, pointing at the stack’s main
track; collapsed hides a stack’s subtracks in the views.
Invariants, maintained by Project::normalize_tree and prune_routes:
project.tracksis in display order, and every stack’s subtracks sit directly below it (depth first).normalize_treere-sorts the list that way, dropsparentlinks to tracks that aren’t stacks (or to the track itself) and breaks cycles.- Auxes are never inside stacks;
move_tracksrefuses it andprune_routesclears it. - Every track has
SEND_SLOTS(8) send slots andINSERT_SLOTS(8) insert slots.
Session::sync_tracks is the one call to make after tracks are added, removed, moved or
restacked: it runs prune_routes, normalize_tree, sends Cmd::Order(process_order()) and
then every track’s parameters.
Processing order (Project::process_order) is different from display order: every track
comes before whatever it plays into (its summing stack, its output aux, the auxes it sends
to). The base order is the tree with subtracks before their stack; a depth-first walk over the
“who feeds me” graph then moves receivers after their senders. The engine processes tracks in
exactly this order, so a bus’s input (sum_l/sum_r) is complete by the time the bus runs.
What the engine plays for a track is worked out by Session::track_params, which applies
the stacks above it: a folder’s fader adds to its subtracks’ volume (stack_gain), a muted
stack mutes them (stack_mute), solo reaches down from a soloed stack and up from a soloed
subtrack, and solo follows routing (a soloed track keeps the auxes it feeds audible; a soloed
aux keeps its feeders audible). Because one track’s change can reach others, stack members and
solo changes resend every track (push_all_params).
VCA faders (Project::vcas, Track::vca; rules in vca.rs, edits in session/vca.rs)
never reach the engine as objects. track_params adds the VCA chain’s offset (levels add up
through nested VCAs; one at -96 dB silences) to the volume and to stack_gain, and its mute to
mute and stack_mute, exactly like a folder’s fader. So the fader smoothing covers VCA moves,
volume and mute automation of a member combine with the VCA (the engine multiplies the
automated value by stack_gain), and every render path (bounce, export, Bounce in Place with
the fader on) follows it. A freeze is rendered before the fader, so a frozen track’s VCA keeps
working. VCA edits resend all tracks’ parameters without re-solving delay compensation
(push_vca_params); undo needs nothing extra, since restore() ends with push_all_params.
VCA levels can’t be automated: automation lanes belong to tracks, and a VCA has none.
Routing and loop prevention
Section titled “Routing and loop prevention”session/routing.rs and model/project.rs:
Track::output:Noneis the default route (the nearest summing stack the track sits in, else Stereo Out),Some(MASTER_ID)forces Stereo Out (skipping the stack),Some(aux)plays into an aux.Project::output_ofresolves it.Track::sends: up to 8TrackSend { bus, level_db, pre_fader, muted }.busis an aux’s track id. Auxes are fed by “Bus N” (Track::bus), assigned byfree_bus.Project::feeds(id)is the set of tracksidplays into directly;reaches(from, to)is its transitive closure.- Loops are refused at edit time:
check_routerejects a send or output to a non-aux, to itself, or to an aux that already reaches the track.prune_routesalso drops dangling routes, routing on folders, and any edge that closes a loop in a loaded file, soprocess_orderalways terminates. - The engine re-resolves routes (
Engine::resolve_routes) whenever the order or a track’s routing changes, storing the index of each destination (out_idx,send_idx). A route that points backwards in the list is ignored, and that track plays to Stereo Out.