1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! 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 as `Map` or `Const`. This feature is enabled by default.
//!
//! * **math:** Adds the `nodes::math` module that contains useful nodes related to mathematics as `Add` or `Oscillator`. This feature depends on the `num-traits` crate and the `nodes` feature.
//!
//! * **random:** Adds the `nodes::random` module that contains useful nodes related to random number generators as `SampleAndHold`. This feature depends on the `rand` crate and the `nodes` feature.
//!
//! # Example
//! ```rust
//! // Using the `nodes` feature
//!
//! use siraph::Graph;
//! use siraph::nodes::{Hold, Pulse, FromIter, Map};
//!
//! 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 is an iterator
//! for (i, val) in sink.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.
//! ```rust
//! 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>,
//! }
//!
//! impl Node 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) {
//! // 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;
//! }
//! }
//! ```
pub use ;
pub use ;
pub use ;