[−][src]Crate siraph
The siraph
crate is a node-based digital signal processing crate.
Features
-
nodes: Adds the
nodes
module that contains a couple of basic useful nodes asMap
orConst
. This feature is enabled by default. -
math: Adds the
nodes::math
module that contains useful nodes related to mathematics asAdd
orOscillator
. This feature depends on thenum-traits
crate and thenodes
feature. -
random: Adds the
nodes::random
module that contains useful nodes related to random number generators asSampleAndHold
. This feature depends on therand
crate and thenodes
feature.
Example
// Using the `nodes` feature use siraph::Graph; use siraph::nodes::{Hold, Pulse, FromIter, Map}; // The `()` is a context that will be given to the nodes. // The nodes that we are going to use do not need such a context. let mut graph = Graph::<()>::new(); // First, we can insert nodes into the graph. // This node just takes the values given by an iterator // and send them into its output. let from_iter = graph.insert(FromIter::new(std::iter::successors(Some(0u32), |&i| Some(i + 1)))); // This node infinitly outputs 4 `false` then 1 `true`. let pulse = graph.insert(Pulse::new(4)); // This one wait for a pulse and holds the value its has in its input // until a new pulse. let hold = graph.insert(Hold::<u32>::new()); // Simply uses the given function to maps its input to its output. let map = graph.insert(Map::new(|val: u32| val * val)); // Then, we can plug them together. graph.plug(from_iter, "output", hold, "input").unwrap(); graph.plug(pulse, "output", hold, "resample").unwrap(); graph.plug(hold, "output", map, "input").unwrap(); // Once our graph is done, we can retreive values from it using a sink. let mut sink = graph.sink(map, "output").unwrap(); // Here is a simple schem of what we have so far /* +------------------------+ | from_iter output i32 >----+ +------------------------------+ +------------------------+ +---> input | +----------------------+ | hold output i32 >--> input map output > sink +---> resample | +----------------------+ +---------------------+ | +------------------------------+ | pulse output bool >-------+ +---------------------+ */ // Values can be retreived with the `next` function on the sink // Once again, the `()` is the context provided to the nodes. assert_eq!(sink.next(&()), Some(0)); assert_eq!(sink.next(&()), Some(0)); assert_eq!(sink.next(&()), Some(0)); assert_eq!(sink.next(&()), Some(0)); assert_eq!(sink.next(&()), Some(0)); assert_eq!(sink.next(&()), Some(25)); assert_eq!(sink.next(&()), Some(25)); assert_eq!(sink.next(&()), Some(25)); assert_eq!(sink.next(&()), Some(25)); assert_eq!(sink.next(&()), Some(25)); // The sink can be turned into an iterator using the `with_ctx` function. for (i, val) in sink.with_ctx(|| &()).take(1000).enumerate() { let i = ((i/5)*5) as u32 + 10; assert_eq!(val, i*i) }
Create your own nodes
You can create your own nodes using the Node
trait.
use siraph::{Node, Register, Input, Output}; // Our node will take an input and smooth it using a basic interpolation function. #[derive(Default)] pub struct Smooth { input: Input<f64>, output: Output<f64>, last_value: Option<f64>, } // The ctx must stay generic because even if this node does not need // a global context, other nodes in the graph may need it. impl<Ctx> Node<Ctx> for Smooth { fn register(&self, r: &mut Register) { // This function will register the inputs and outputs of this node. r.input("input", &self.input); r.output("output", &self.output); } fn process(&mut self, _ctx: &Ctx) { // It is in this function that all the processing will be done. const X: f64 = 1.0/3.0; // In our case, our computation is not very expensive but // in other cases, things can get complicated. // We can skip certain part of the processing by // checking if our outputs are used. if self.output.is_used() { if let Some(cur) = self.input.get() { if let Some(last) = self.last_value { self.last_value = Some(last * X + (1.0 - X) * cur); self.output.set(self.last_value); } else { self.output.set(cur); self.last_value = Some(cur); } } else { self.output.set(None); } } } fn reset(&mut self) { // In this function, the inputs of the node should not be used even // if they may return valid values. self.last_value = None; } }
Modules
nodes |
Structs
Dependencies | An iterator that look for the dependencies of a node within a |
Graph | The central structure of the crate. The graph manages a bunch of nodes and makes them work together. |
Input | A read-only interface to a |
Name | The name of an input or an output. |
NodeHandle | A handle to a node. |
Output | A write-only reference to a |
Register | A simple structure responsible for registering the inputs and outputs of a node. |
Sink | |
SinkWithCtx | An iterator that yield the values of a |
Enums
Error | A generic error type for the crate. |
Traits
Node | Nodes are signal processing units. They take data from their inputs to and send it back through their outputs. |
Type Definitions
Result | The result type for the crate. |