Web Audio context the bus's nodes live on.
Name to register under, or null for an anonymous bus.
Optional input: GainNodeOptional pre-existing GainNode to use as the input. Used by
the master bus to alias cacophony.globalGainNode. If omitted, a
fresh GainNode is allocated.
Optional onDestroy: (() => void)Optional registry-cleanup hook fired by destroy().
Private Readonly _bypassedFilter nodes currently bypassed (skipped in the audible chain). A bypassed node stays in _filterNodes — so filters order, identity, and its live AudioParams are preserved — but _desiredFilterChainEdges builds the series chain over the NON-bypassed filters only, wiring the signal around it. Membership is by node identity.
Private Readonly _contextPrivate _destroyedPrivate Readonly _directPrivate Readonly _filterPrivate Readonly _filterPrivate Optional Readonly _onHook invoked by the owning Cacophony instance to remove this bus from the named-bus registry on destroy. Anonymous buses leave this undefined.
Private Readonly _routedInbound sources currently routed to this bus (primary route and/or sends). A Web Audio node cannot enumerate its own inputs, so sources register themselves here (via _registerRoutedSource) when they route to this bus and unregister on reroute/cleanup. drainTo walks this set to move live sounds off the bus before it is torn down.
Private Readonly _sendReadonly inputEntry node — connect upstream sources here (sound playbacks, other bus outputs).
Readonly nameStable name for registry lookup, or null for anonymous buses.
Readonly outputExit node — connected to downstream targets (other bus inputs, master, raw nodes) via connect.
True after destroy has been called.
Output node gain — controls the overall level the bus sends downstream.
Private _connectPrivate _desiredCompute the desired ordered chain edge list from the current
_filterNodes, skipping any node in _bypassedFilters: the series
chain is built over the NON-bypassed filters only. With no active (non-
bypassed) filters — whether the bus has no filters at all or every filter is
bypassed — the desired list is [[input, output]] (the direct edge);
otherwise [[input, a1], [a1, a2], ..., [aN, output]] over the active
filters a1..aN. Bypassed nodes stay in _filterNodes (and thus in
filters) but receive no inbound/outbound chain edge.
Private _disconnectPrivate _isStructural AudioParam check: a value is treated as an AudioParam if it
exposes the ramp scheduling methods. Avoids instanceof AudioParam so it
works under the standardized-audio-context mock (which may lack the global).
Private _refreshReconcile the live chain to input → [filter1 → ... → filterN] → output.
Called after any add/remove/reorder of a filter. This is an INCREMENTAL
diff, not a full rebuild: it disconnects only edges that are no longer part
of the desired chain and connects only edges that are newly required,
leaving edges present in both the old and new chain connected and
untouched (no audible click on the unchanged portion of the chain).
Edges are matched by OBJECT IDENTITY on both endpoints. Only this bus's own
internal input → ... → output edges are touched — never a broad
node.disconnect(), never the outbound send/direct edges.
Internal Register an inbound source that routes to this bus (primary and/or send). Called by the source when it begins routing here. Idempotent (Set). Safe to call without a destroyed guard — registration during normal routing must never throw — but a destroyed bus has nothing to drain, so this early-returns once destroyed.
Private _resolveResolve the named AudioParam on a node. Tries the worklet
parameters map first, then a directly-exposed native param
(node[paramName]). Returns undefined if neither yields an AudioParam.
Detection is structural (duck-typed), never instanceof — the mocked test
context may not provide the AudioParam global.
Private _throwAdd a filter node to the bus's chain. Accepts:
cacophony.createBiquadFilter) → added directly to the chain.build(context) is awaited; the resulting
node is added to the chain.cacophony.shareEffect(node) (or a proper CacophonyEffect class) to
make the shared-state intent explicit.the built AudioNode that was added to the chain. For a biquad this
is the argument itself; for a CacophonyEffect it is the node
produced by build. The returned handle can be passed to
rampFilterParam to automate the node's parameters. Existing
callers that ignore the result keep working unchanged.
if the bus has been destroyed, or if the argument is a raw AudioNode that is not a Cacophony-built biquad.
Connect this bus's output to another bus or to a raw AudioNode.
If gain is omitted or equal to 1, connect directly (output →
targetInput). If gain is provided, allocate an internal GainNode for
per-edge attenuation: output → sendGain → targetInput. The sendGain is
tracked so disconnect can tear it down cleanly.
Re-connecting a target that is already wired is a no-op for the direct
case; for a gained connection, the existing sendGain's gain.value is
updated in place (no new edge is allocated).
Optional gain: numberif the bus has been destroyed.
Tear down the bus — disconnects input, output, every send-gain, every
filter, then deregisters from the owner Cacophony's named-bus map.
Subsequent addFilter/removeFilter/connect/disconnect calls throw.
If options.drainTo is provided, every source routed to this bus is first
rerouted onto that bus (via drainTo) so live sounds keep playing
through a live bus. With no options the default teardown is unchanged:
sounds routed to the destroyed bus fall back to master on their next
playback (the routeTo machinery checks destroyed at preplay).
Disconnect this bus's output from a target previously connected with connect. Tears down the allocated sendGain (if any). No-op if the target was never connected.
if the bus has been destroyed.
Move every source currently routed to this bus onto target, so live
sounds keep feeding a live bus instead of the dead input after this bus
is torn down. Each registered source's BusRoutedSource._onBusDrained
reroutes its primary route and/or the send that targeted this bus.
if this bus has been destroyed, or if target is this bus.
Whether node is currently bypassed (skipped in the audible chain). Returns
false for nodes that were never added to this bus.
Ramp an effect node's parameter to a target value over time. This is the uniform automation handle for filter-chain effects: pass a node obtained from addFilter (or the filters getter) and the name of the parameter to drive.
Parameter resolution:
node exposes a worklet-style parameters AudioParamMap, the param
is resolved via parameters.get(paramName) (e.g. a worklet effect's
named params).node[paramName] is itself an AudioParam (native nodes
such as a biquad expose .frequency / .Q / .gain directly), that is
used.Ramp shape (mirrors the codebase fade convention): the target time base is
node.context.currentTime. With no duration (or duration <= 0) the
value is set immediately via setValueAtTime(value, now). Otherwise the
start is pinned with setValueAtTime(param.value, now) and the value ramps
to now + duration / 1000 (milliseconds) using linearRampToValueAtTime
(default) or exponentialRampToValueAtTime when type is "exponential"
(an exponential target of 0 is floored to 0.0001, matching fadeTo).
Automation degrades gracefully: if node is not on this bus, or the
parameter cannot be resolved to an AudioParam, a warning is logged and the
call is a no-op. The only condition that throws is a destroyed bus.
A filter node currently on this bus (from addFilter).
The name of the parameter to automate.
The target value.
Optional options: { Optional duration?: numberRamp duration in milliseconds. Absent/<= 0 sets
the value immediately.
Optional type?: FadeTypeRamp curve, "linear" (default) or "exponential".
if the bus has been destroyed.
Bypass (or un-bypass) a filter without removing it from the chain. A bypassed filter stays in filters — its order, identity, and live AudioParams are preserved (so an automation target survives a bypass) — but it is skipped in the audible series chain: the signal is wired around it. Un-bypassing wires it back in at its original position.
The reconnect goes through the incremental _refreshFilters, so only
the seam around node is touched — the rest of the chain is left connected.
true to skip the node, false to wire it back in. A no-op
if the node is already in the requested state.
if the bus has been destroyed, or if node was never added to this
bus.
Reorder the existing filter chain. nodes must be a PERMUTATION of the
current filters — the same set of node objects (matched by identity), the
same length, with no duplicates — just in a new order. Because
_refreshFilters is incremental, only the edges that actually move
are reconnected; unchanged edges are left untouched.
if the bus has been destroyed, or if nodes is not a permutation
of the current filters.
A named summing node with a filter chain and per-edge send gain. See module-level docstring for topology.