Struct knyst::graph::Graph

source ·
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 Gens 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::pushing 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 a Gen or a Graph, returning a NodeId which is a handle to that node.
  • Graph::connect uses Connection to add or clear connections between nodes and the Graph 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 running GraphGen 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 the GraphGen. 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

source

pub fn new(options: GraphSettings) -> Self

Create a new empty Graph with a unique atomically generated GraphId

source

pub fn num_inputs(&self) -> usize

Return the number of input channels to the Graph

source

pub fn num_outputs(&self) -> usize

Return the number of output channels from the Graph

source

pub fn graph_settings(&self) -> GraphSettings

Return a GraphSettings matching this Graph

source

pub fn num_stored_nodes(&self) -> usize

Returns a number including both active nodes and nodes waiting to be safely freed

source

pub fn id(&self) -> GraphId

source

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.

source

pub fn push(&mut self, to_node: impl Into<GenOrGraphEnum>) -> NodeId

Push something implementing Gen or a Graph to self creating a new node whose address is returned.

source

pub fn push_at_time( &mut self, to_node: impl Into<GenOrGraphEnum>, start_time: Time ) -> NodeId

Push something implementing Gen or a Graph to self creating a new node whose address is returned. The node will start at start_time.

source

pub fn push_to_graph( &mut self, to_node: impl Into<GenOrGraphEnum>, graph_id: GraphId ) -> Result<NodeId, PushError>

Push something implementing Gen or a Graph to the graph with the id provided, creating a new node whose address is returned.

source

pub fn push_to_graph_at_time( &mut self, to_node: impl Into<GenOrGraphEnum>, graph_id: GraphId, start_time: Time ) -> Result<NodeId, PushError>

Push something implementing Gen or a Graph to the graph with the id provided, creating a new node whose address is returned.

source

pub fn push_with_existing_address( &mut self, to_node: impl Into<GenOrGraphEnum>, node_address: &mut NodeId )

Push something implementing Gen or a Graph to self, storing its address in the NodeAddress provided.

source

pub fn push_with_existing_address_at_time( &mut self, to_node: impl Into<GenOrGraphEnum>, node_address: &mut NodeId, start_time: Time )

Push something implementing Gen or a Graph to self, storing its address in the NodeAddress provided. The node will start processing at the start_time.

source

pub fn push_with_existing_address_to_graph( &mut self, to_node: impl Into<GenOrGraphEnum>, node_address: &mut NodeId, graph_id: GraphId ) -> Result<(), PushError>

Push something implementing Gen or a Graph to the graph with the id provided, storing its address in the NodeAddress provided.

source

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>

Push something implementing Gen or a Graph to the graph with the id provided, storing its address in the NodeAddress provided. The node will start processing at the start_time.

source

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.

source

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

source

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.

source

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).

source

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.

source

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.

source

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.

source

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.

source

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.

source

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.

source

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 Graphs 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.

source

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

source

pub fn block_size(&self) -> usize

Returns the block size of the Graph, not corrected for oversampling.

source

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.

source

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.

source

pub fn update(&mut self)

This function needs to be run regularly to be sure that scheduled changes are carried out.

source

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 Default for Graph

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl GenOrGraph for Graph

source§

fn components( self, parent_graph_block_size: usize, parent_graph_sample_rate: Sample, parent_graph_oversampling: Oversampling ) -> (Option<Graph>, Box<dyn Gen + Send>)

source§

fn into_gen_or_graph_enum(self) -> GenOrGraphEnum

source§

fn num_outputs(&self) -> usize

source§

fn num_inputs(&self) -> usize

source§

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§

§

impl !RefUnwindSafe for Graph

§

impl !Sync for Graph

§

impl Unpin for Graph

§

impl !UnwindSafe for Graph

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> Downcast for T
where T: Any,

source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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>

Convert 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)

Convert &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)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<S> FromSample<S> for S

§

fn from_sample_(s: S) -> S

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

§

fn into_sample(self) -> T

§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

§

fn to_sample_(self) -> U

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,