pub struct Graph { /* private fields */ }
Expand description
A Graph
contains nodes, which are wrappers around a dyn Gen
, and
connections between those nodes. Connections can eiterh be normal/forward
connections or feedback connections. Graphs can themselves be used as
Gen
s in a different Graph
.
To run a Graph
it has to be split so that parts of it are mirrored in a
GraphGen
(private). This is done internally when calling Graph::push
ing a Graph
.
You can also do it yourself using a RunGraph
. The Graph
behaves
slightly differently when split:
- changes to constants are always scheduled to be performed by the
GraphGen
instead of applied directly - adding/freeing nodes/connections are scheduled to be done as soon as possible when it is safe to do so and
Graph::commit_changes
is called
Manipulating the Graph
Graph::push
creates a node from aGen
or aGraph
, returning aNodeId
which is a handle to that node.Graph::connect
usesConnection
to add or clear connections between nodes and theGraph
they are in. You can also connect a constant value to a node input.Graph::commit_changes
recalculates node order and applies changes to connections and nodes to the runningGraphGen
from the next time it is called. It also tries to free any resources it can that have been previously removed.Graph::schedule_change
adds a parameter/input constant change to the scheduler.Graph::update
updates the internal scheduler so that it sends scheduled updates that are soon due on to theGraphGen
. This has to be called regularly if you are scheduling changes. Changes are only sent on to the GraphGen when they are soon due for performance reasons.
When a node has been added, it cannot be retreived from the Graph
. You can, however, send any data you want out from the Gen::process
trait method using your own synchronisation method e.g. a channel.
Example
use knyst::prelude::*;
use knyst::wavetable::*;
use knyst::graph::RunGraph;
let graph_settings = GraphSettings {
block_size: 64,
sample_rate: 44100.,
num_outputs: 2,
..Default::default()
};
let mut graph = Graph::new(graph_settings);
let resources = Resources::new(ResourcesSettings::default());
let (mut run_graph, _, _) = RunGraph::new(&mut graph, resources, RunGraphSettings::default())?;
// Adding a node gives you an address to that node
let sine_node_address = graph.push(WavetableOscillatorOwned::new(Wavetable::sine()));
// Connecting the node to the graph output
graph.connect(sine_node_address.to_graph_out())?;
// Set the frequency of the oscillator to 220 Hz. This will
// be converted to a scheduled change because the graph is running.
graph.connect(constant(220.0).to(sine_node_address).to_label("freq"))?;
// You need to commit changes if the graph is running.
graph.commit_changes();
// You also need to update the scheduler to send messages to the audio thread.
graph.update();
// Process one block of audio data. If you are using an
// [`crate::AudioBackend`] you don't need to worry about this step.
run_graph.process_block();
Implementations§
source§impl Graph
impl Graph
sourcepub fn new(options: GraphSettings) -> Self
pub fn new(options: GraphSettings) -> Self
sourcepub fn num_inputs(&self) -> usize
pub fn num_inputs(&self) -> usize
Return the number of input channels to the Graph
sourcepub fn num_outputs(&self) -> usize
pub fn num_outputs(&self) -> usize
Return the number of output channels from the Graph
sourcepub fn graph_settings(&self) -> GraphSettings
pub fn graph_settings(&self) -> GraphSettings
Return a GraphSettings
matching this Graph
sourcepub fn num_stored_nodes(&self) -> usize
pub fn num_stored_nodes(&self) -> usize
Returns a number including both active nodes and nodes waiting to be safely freed
pub fn id(&self) -> GraphId
sourcepub fn set_node_mortality(
&mut self,
node_id: NodeId,
is_mortal: bool
) -> Result<(), ScheduleError>
pub fn set_node_mortality( &mut self, node_id: NodeId, is_mortal: bool ) -> Result<(), ScheduleError>
Set the mortality of a node. An immortal node (false) cannot be manually freed and will not be accidentally freed e.g. through Graph::free_disconnected_nodes
.
sourcepub fn push(&mut self, to_node: impl Into<GenOrGraphEnum>) -> NodeId
pub fn push(&mut self, to_node: impl Into<GenOrGraphEnum>) -> NodeId
sourcepub fn push_at_time(
&mut self,
to_node: impl Into<GenOrGraphEnum>,
start_time: Time
) -> NodeId
pub fn push_at_time( &mut self, to_node: impl Into<GenOrGraphEnum>, start_time: Time ) -> NodeId
sourcepub fn push_to_graph(
&mut self,
to_node: impl Into<GenOrGraphEnum>,
graph_id: GraphId
) -> Result<NodeId, PushError>
pub fn push_to_graph( &mut self, to_node: impl Into<GenOrGraphEnum>, graph_id: GraphId ) -> Result<NodeId, PushError>
sourcepub fn push_to_graph_at_time(
&mut self,
to_node: impl Into<GenOrGraphEnum>,
graph_id: GraphId,
start_time: Time
) -> Result<NodeId, PushError>
pub fn push_to_graph_at_time( &mut self, to_node: impl Into<GenOrGraphEnum>, graph_id: GraphId, start_time: Time ) -> Result<NodeId, PushError>
sourcepub fn push_with_existing_address(
&mut self,
to_node: impl Into<GenOrGraphEnum>,
node_address: &mut NodeId
)
pub fn push_with_existing_address( &mut self, to_node: impl Into<GenOrGraphEnum>, node_address: &mut NodeId )
sourcepub fn push_with_existing_address_at_time(
&mut self,
to_node: impl Into<GenOrGraphEnum>,
node_address: &mut NodeId,
start_time: Time
)
pub fn push_with_existing_address_at_time( &mut self, to_node: impl Into<GenOrGraphEnum>, node_address: &mut NodeId, start_time: Time )
sourcepub fn push_with_existing_address_to_graph(
&mut self,
to_node: impl Into<GenOrGraphEnum>,
node_address: &mut NodeId,
graph_id: GraphId
) -> Result<(), PushError>
pub fn push_with_existing_address_to_graph( &mut self, to_node: impl Into<GenOrGraphEnum>, node_address: &mut NodeId, graph_id: GraphId ) -> Result<(), PushError>
sourcepub fn push_with_existing_address_to_graph_at_time(
&mut self,
to_node: impl Into<GenOrGraphEnum>,
node_address: &mut NodeId,
graph_id: GraphId,
start_time: Time
) -> Result<(), PushError>
pub fn push_with_existing_address_to_graph_at_time( &mut self, to_node: impl Into<GenOrGraphEnum>, node_address: &mut NodeId, graph_id: GraphId, start_time: Time ) -> Result<(), PushError>
sourcepub fn free_disconnected_nodes(&mut self) -> Result<(), FreeError>
pub fn free_disconnected_nodes(&mut self) -> Result<(), FreeError>
Remove all nodes in this graph and all its subgraphs that are not connected to anything.
sourcepub fn free_node_mend_connections(
&mut self,
node: NodeId
) -> Result<(), FreeError>
pub fn free_node_mend_connections( &mut self, node: NodeId ) -> Result<(), FreeError>
Remove the node and connect its input edges to the sinks of its output edges
sourcepub fn free_node(&mut self, node: NodeId) -> Result<(), FreeError>
pub fn free_node(&mut self, node: NodeId) -> Result<(), FreeError>
Remove the node and any edges to/from the node. This may lead to other nodes being disconnected from the output and therefore not be run, but they will not be freed.
sourcepub fn get_current_time_musical(&self) -> Option<Beats>
pub fn get_current_time_musical(&self) -> Option<Beats>
Returns the current audio thread time in Beats based on the MusicalTimeMap, or None if it is not available (e.g. if the Graph has not been started yet).
sourcepub fn generate_inspection(&self) -> GraphInspection
pub fn generate_inspection(&self) -> GraphInspection
Generate inspection metadata for this graph and all sub graphs. Can be used to generate static or dynamic inspection and manipulation tools.
sourcepub fn schedule_changes(
&mut self,
node_changes: Vec<NodeChanges>,
time: Time
) -> Result<(), ScheduleError>
pub fn schedule_changes( &mut self, node_changes: Vec<NodeChanges>, time: Time ) -> Result<(), ScheduleError>
Schedule changes to input channel constants. The changes will only be
applied if the Graph
is running and its scheduler is regularly
updated. NodeChanges
must all be in the same Graph. If you want to
schedule chagnes to nodes in multiple graphs, separate them and call
Graph::schedule_changes
multiple times.
sourcepub fn schedule_change(
&mut self,
change: ParameterChange
) -> Result<(), ScheduleError>
pub fn schedule_change( &mut self, change: ParameterChange ) -> Result<(), ScheduleError>
Schedule a change to an input channel constant. The change will only be
applied if the Graph
is running and its scheduler is regularly
updated.
sourcepub fn disconnect(
&mut self,
connection: Connection
) -> Result<(), ConnectionError>
pub fn disconnect( &mut self, connection: Connection ) -> Result<(), ConnectionError>
Disconnect the given connection if it exists. Will return Ok if the Connection doesn’t exist, but the data inside it is correct and the graph could be found.
Disconnecting a constant means setting that constant input to 0. Disconnecting a feedback edge will remove the feedback node under the hood if there are no remaining edges to it. Disconnecting a Connection::Clear will do the same thing as “connecting” it: clear edges according to its parameters.
sourcepub fn connect_bundle(
&mut self,
bundle: impl Into<ConnectionBundle>
) -> Result<(), ConnectionError>
pub fn connect_bundle( &mut self, bundle: impl Into<ConnectionBundle> ) -> Result<(), ConnectionError>
Make several connections at once. If one connection fails the function will return and any remaining connections will be lost.
sourcepub fn connect(&mut self, connection: Connection) -> Result<(), ConnectionError>
pub fn connect(&mut self, connection: Connection) -> Result<(), ConnectionError>
Create or clear a connection in the Graph. Will call child Graphs until the graph containing the nodes is found or return an error if the right Graph or Node cannot be found.
sourcepub fn change_musical_time_map(
&mut self,
change_fn: impl FnOnce(&mut MusicalTimeMap)
) -> Result<(), ScheduleError>
pub fn change_musical_time_map( &mut self, change_fn: impl FnOnce(&mut MusicalTimeMap) ) -> Result<(), ScheduleError>
Apply a change to the internal MusicalTimeMap
shared between all
Graph
s in a tree. Call this only on the top level Graph.
Errors
If the scheduler was not yet created, meaning the Graph is not running.
sourcepub fn calculate_node_order(&mut self)
pub fn calculate_node_order(&mut self)
Calculate the node order of the graph based on the outputs Post-ordered depth first search NB: Not real-time safe
sourcepub fn block_size(&self) -> usize
pub fn block_size(&self) -> usize
Returns the block size of the Graph
, not corrected for oversampling.
sourcepub fn num_nodes(&self) -> usize
pub fn num_nodes(&self) -> usize
Return the number of nodes currently held by the Graph, including nodes that are queued to be freed, but have not yet been freed.
sourcepub fn commit_changes(&mut self)
pub fn commit_changes(&mut self)
Applies the latest changes to connections and added nodes in the graph on the audio thread and updates the scheduler.
sourcepub fn update(&mut self)
pub fn update(&mut self)
This function needs to be run regularly to be sure that scheduled changes are carried out.
sourcepub fn dump_nodes(&self) -> Vec<NodeDump>
pub fn dump_nodes(&self) -> Vec<NodeDump>
Create a dump of all nodes in the Graph. Currently only useful for debugging.
Trait Implementations§
source§impl GenOrGraph for Graph
impl GenOrGraph for Graph
fn components( self, parent_graph_block_size: usize, parent_graph_sample_rate: Sample, parent_graph_oversampling: Oversampling ) -> (Option<Graph>, Box<dyn Gen + Send>)
fn into_gen_or_graph_enum(self) -> GenOrGraphEnum
fn num_outputs(&self) -> usize
fn num_inputs(&self) -> usize
impl Send for Graph
Safety: The GraphGen
is given access to an Arc<UnsafeCell<SlotMap<NodeKey,
Node>>, but won’t use it unless the Graph is dropped and it needs to keep
the SlotMap
alive, and the drop it when the GraphGen
is dropped.
Auto Trait Implementations§
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.