pub struct NodeConfigurator {
Show 14 fields pub(crate) nodes: Vec<(NodeInfo, Option<NodeInstance>, Node)>, pub(crate) node2idx: HashMap<NodeId, usize>, pub(crate) shared: SharedNodeConf, pub(crate) node_global: NodeGlobalRef, feedback_filter: FeedbackFilter, sample_lib: SampleLibrary, errors: Vec<String>, params: HashMap<ParamId, NodeInputParam>, param_values: HashMap<ParamId, f32>, param_modamt: HashMap<ParamId, Option<f32>>, atoms: HashMap<ParamId, NodeInputAtom>, atom_values: HashMap<ParamId, SAtom>, output_fb_values: Vec<f32>, output_fb_cons: Option<Output<Vec<f32>>>,
}
Expand description

This struct holds the frontend node configuration.

It stores which nodes are allocated and where. Allocation of new nodes is done here, and parameter management and synchronization is also done by this. It generally acts as facade for the executed node graph in the backend.

This API is the most low level API provided by HexoDSP. It shows how to create nodes and connect them. The execution of the nodes in the audio thread is controlled by a NodeProg, which defines the order the nodes are executed in.

This only showcases the non-realtime generation of audio samples. For a real time application of this library please refer to the examples that come with this library.

use hexodsp::*;

let (mut node_conf, mut node_exec) = new_node_engine();

node_conf.create_node(NodeId::Sin(0));
node_conf.create_node(NodeId::Amp(0));

let mut prog = node_conf.rebuild_node_ports();

node_conf.add_prog_node(&mut prog, &NodeId::Sin(0));
node_conf.add_prog_node(&mut prog, &NodeId::Amp(0));

node_conf.set_prog_node_exec_connection(
    &mut prog,
    (NodeId::Amp(0), NodeId::Amp(0).inp("inp").unwrap()),
    (NodeId::Sin(0), NodeId::Sin(0).out("sig").unwrap()));

node_conf.upload_prog(prog, true);

let (out_l, out_r) = node_exec.test_run(0.1, false, &[]);

Fields

nodes: Vec<(NodeInfo, Option<NodeInstance>, Node)>

Holds all the nodes, their parameters and type.

node2idx: HashMap<NodeId, usize>

An index of all nodes ever instanciated. Be aware, that currently there is no cleanup implemented. That means, any instanciated NodeId will persist throughout the whole runtime. A garbage collector might be implemented when saving presets.

shared: SharedNodeConf

The shared parts of the NodeConfigurator and the crate::nodes::NodeExecutor.

node_global: NodeGlobalRef

Reference to the crate::NodeGlobalData that is used to initialize the crate::dsp::DspNode instances creates by this NodeConfigurator.

feedback_filter: FeedbackFiltersample_lib: SampleLibrary

Loads and Caches audio samples that are set as parameters for nodes.

errors: Vec<String>

Error messages:

params: HashMap<ParamId, NodeInputParam>

Contains (automateable) parameters

param_values: HashMap<ParamId, f32>

Stores the most recently set parameter values

param_modamt: HashMap<ParamId, Option<f32>>

Stores the modulation amount of a parameter

atoms: HashMap<ParamId, NodeInputAtom>

Contains non automateable atom data for the nodes

atom_values: HashMap<ParamId, SAtom>

Stores the most recently set atoms

output_fb_values: Vec<f32>

Holds a copy of the most recently updated output port feedback values. Update this by calling NodeConfigurator::update_output_feedback.

output_fb_cons: Option<Output<Vec<f32>>>

Holds the channel to the backend that sends output port feedback. This is queried by NodeConfigurator::update_output_feedback.

Implementations

Returns the current modulation amount of the given parameter. Returns None if no modulation amount if set and thus no implicit attenuverter is set.

Set the modulation amount of a parameter. Returns true if a new NodeProg needs to be created, which can be necessary if there was no modulation amount assigned to this parameter yet.

Retrieve SAtom values for input parameters and atoms.

Assign SAtom values to input parameters and atoms.

Only updates the DSP backend if NodeConfigurator::rebuild_node_ports was called before calling this. If no graph or the corresponding parameter is not active yet, then the value will be remembered until NodeConfigurator::rebuild_node_ports is called.

Dumps all set parameters (inputs and atoms). Most useful for serialization and saving patches.

Loads parameter values from a dump. You will still need to upload a new NodeProg which contains these values.

Iterates over every parameter and calls the given function with it’s current value.

Returns the current phase value of the given node.

It usually returns something like the position of a sequencer or the phase of an oscillator.

Returns the current status LED value of the given node.

A status LED might be anything a specific node deems the most important value. Often it might be just the current value of the primary signal output.

Triggers recalculation of the filtered values from the current LED values and output feedback.

This function internally calls NodeConfigurator::update_output_feedback for you, so you don’t need to call it yourself.

See also NodeConfigurator::filtered_led_for and NodeConfigurator::filtered_out_fb_for.

Returns a filtered LED value that is smoothed a bit and provides a min and max value.

Make sure to call NodeConfigurator::update_filters before calling this function, or the values won’t be up to date.

 use hexodsp::*;

 let (mut node_conf, mut node_exec) = new_node_engine();

 node_conf.create_node(NodeId::Sin(0));
 node_conf.create_node(NodeId::Amp(0));

 let mut prog = node_conf.rebuild_node_ports();

 node_conf.add_prog_node(&mut prog, &NodeId::Sin(0));
 node_conf.add_prog_node(&mut prog, &NodeId::Amp(0));

 node_conf.set_prog_node_exec_connection(
     &mut prog,
     (NodeId::Amp(0), NodeId::Amp(0).inp("inp").unwrap()),
     (NodeId::Sin(0), NodeId::Sin(0).out("sig").unwrap()));

 node_conf.upload_prog(prog, true);

 node_exec.test_run(0.1, false, &[]);
 assert!((node_conf.led_value_for(&NodeId::Sin(0)) - (-0.062522)).abs() < 0.001);
 assert!((node_conf.led_value_for(&NodeId::Amp(0)) - (-0.062522)).abs() < 0.001);

 for _ in 0..10 {
     node_exec.test_run(0.1, false, &[]);
     node_conf.update_filters();
     node_conf.filtered_led_for(&NodeId::Sin(0));
     node_conf.filtered_led_for(&NodeId::Amp(0));
 }

 assert_eq!((node_conf.filtered_led_for(&NodeId::Sin(0)).0 * 1000.0).floor() as i64, 62);
 assert_eq!((node_conf.filtered_led_for(&NodeId::Amp(0)).0 * 1000.0).floor() as i64, 62);

Returns a filtered output port value that is smoothed a bit and provides a min and max value.

Make sure to call NodeConfigurator::update_filters before calling this function, or the values won’t be up to date. That function also calls NodeConfigurator::update_output_feedback for you conveniently.

For an example on how to use see NodeConfigurator::filtered_led_for which has the same semantics as this function.

Monitor the given inputs and outputs of a specific node.

The monitor data can be retrieved using NodeConfigurator::get_minmax_monitor_samples.

Returns the first instance of the given NodeId (starting with the instance of the NodeId) that has not been used.

Primarily used by the (G)UI when creating new nodes to be added to the graph.

Should be called after the NodeProg has been created (and after NodeConfigurator::rebuild_node_ports was called).

If new nodes were created/deleted/reordered in between this function might not work properly and assign already used instances.

Rebuilds Input/Output/Atom indices for the nodes, which is necessary if nodes were created/deleted or reordered. It also assigns input parameter and atom values for new nodes.

Returns a new NodeProg with space for all allocated nodes inputs, outputs and atoms.

Execute this after a NodeConfigurator::create_node.

Creates a new NodeOp and add it to the NodeProg.

It will fail silently if the nodes have not been created yet or NodeConfigurator::rebuild_node_ports was not called before. So make sure this is the case or don’t expect the node and input to be executed.

Adds an adjacent output connection to the given node input. Will either create a new NodeOp in the NodeProg or append to an existing one. This means the order you set the to be executed node connections, is the order the NodeProg is going to be executed by the DSP thread later.

It will fail silently if the nodes have not been created yet or NodeConfigurator::rebuild_node_ports was not called before. So make sure this is the case or don’t expect the node and input to be executed.

Uploads a new NodeProg instance.

Create a new NodeProg instance with NodeConfigurator::rebuild_node_ports for each call to this function. Otherwise things like the NodeConfigurator::out_fb_for might not work properly!

The copy_old_out parameter should be set if there are only new nodes appended to the end of the node instances. It helps to prevent clicks when there is a feedback path somewhere.

It must not be set when a completely new set of node instances was created, for instance when a completely new patch was loaded.

Here is an example on how to use the NodeConfigurator directly to setup and upload a NodeProg:

 use hexodsp::*;

 let (mut node_conf, mut node_exec) = new_node_engine();

 node_conf.create_node(NodeId::Sin(0));
 node_conf.create_node(NodeId::Amp(0));

 let mut prog = node_conf.rebuild_node_ports();

 node_conf.add_prog_node(&mut prog, &NodeId::Sin(0));
 node_conf.add_prog_node(&mut prog, &NodeId::Amp(0));

 node_conf.set_prog_node_exec_connection(
     &mut prog,
     (NodeId::Amp(0), NodeId::Amp(0).inp("inp").unwrap()),
     (NodeId::Sin(0), NodeId::Sin(0).out("sig").unwrap()));

 node_conf.upload_prog(prog, true);

Retrieves the feedback value for a specific output port of the given NodeId. You need to call NodeConfigurator::update_output_feedback before this, or otherwise your output values might be outdated or not available at all.

See also NodeConfigurator::filtered_out_fb_for for a filtered variant suitable for UI usage.

Checks if the backend has new output feedback values. Call this function for each frame of the UI to get the most up to date output feedback values that are available.

Retrieve the output value by calling NodeConfigurator::out_fb_for.

Injects a HxMidiEvent directly into audio thread, so that it can trickle back to the GUI thread the standard way. This is mostly used for automated testing. And maybe some day for some kind of remote control script from WLambda?

Returns the next GraphEvent from the DSP/audio/backend thread.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.