1pub mod action;
8pub mod algorithm;
10mod error;
11pub mod node;
13pub mod param;
15pub mod port;
17pub mod processable;
19pub mod rack;
21pub mod router;
23
24pub use action::*;
26pub use algorithm::*;
27pub use error::*;
28pub use node::*;
29pub use param::*;
30pub use port::*;
31pub use processable::*;
32pub use rack::*;
33pub use router::*;
34
35pub const DEFAULT_BLOCK_SIZE: usize = 64;
41
42pub type MonoBlock<T, const BUF_SIZE: usize> = [T; BUF_SIZE];
44
45pub type StereoBlock<T, const BUF_SIZE: usize> = [MonoBlock<T, BUF_SIZE>; 2];
47
48pub type ControlValue<T> = T;
50
51pub mod prelude {
57 pub use super::{
59 ActiveNode,
61 Eurorack,
62 IoNode,
63 Node,
64 NodeCategory,
65 NodeId,
67 NodeMetadata,
68 NodeState,
69
70 NodeTypeId,
71 ParamMetadata,
72
73 ParamRange,
74 ParamType,
75 ParamValue,
76 ParameterError,
77
78 ParameterId,
80 ParameterResult,
81 Port,
82
83 PortDirection,
84 PortId,
86 PortType,
87 ProcessError,
88 ProcessResult,
90 Processor,
91 Router,
92 Sink,
93
94 Source,
95 DEFAULT_BLOCK_SIZE,
97 };
98
99 pub use crate::math::Transcendental;
101}
102
103pub trait IntoParamValue: Sized {
109 fn into_param_value(self) -> ParamValue;
111
112 fn from_param_value(value: ParamValue) -> Option<Self>;
114}
115
116impl IntoParamValue for f32 {
117 fn into_param_value(self) -> ParamValue {
118 ParamValue::Float(self)
119 }
120
121 fn from_param_value(value: ParamValue) -> Option<Self> {
122 value.as_f32()
123 }
124}
125
126impl IntoParamValue for i32 {
127 fn into_param_value(self) -> ParamValue {
128 ParamValue::Int(self)
129 }
130
131 fn from_param_value(value: ParamValue) -> Option<Self> {
132 value.as_i32()
133 }
134}
135
136impl IntoParamValue for bool {
137 fn into_param_value(self) -> ParamValue {
138 ParamValue::Bool(self)
139 }
140
141 fn from_param_value(value: ParamValue) -> Option<Self> {
142 value.as_bool()
143 }
144}
145
146impl IntoParamValue for String {
147 fn into_param_value(self) -> ParamValue {
148 ParamValue::String(self)
149 }
150
151 fn from_param_value(value: ParamValue) -> Option<Self> {
152 match value {
153 ParamValue::String(s) => Some(s),
154 ParamValue::Choice(s) => Some(s),
155 _ => None,
156 }
157 }
158}
159
160pub trait AsAny: 'static {
166 fn as_any(&self) -> &dyn std::any::Any;
168
169 fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
171}
172
173impl<T: 'static> AsAny for T {
174 fn as_any(&self) -> &dyn std::any::Any {
175 self
176 }
177
178 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
179 self
180 }
181}
182
183#[cfg(test)]
188mod tests {
189 use super::prelude::*;
190 use crate::traits::IntoParamValue;
191
192 #[test]
193 fn test_prelude_imports() {
194 let _node_id = NodeId(0);
196 let _port_id = PortId::signal_in(_node_id, 0);
197 let _param_id = ParameterId::new("test").unwrap();
198
199 let f: f32 = 42.0;
201 let pv = f.into_param_value();
202 assert_eq!(pv.as_f32(), Some(42.0));
203
204 let back = f32::from_param_value(pv);
205 assert_eq!(back, Some(42.0));
206 }
207
208 #[test]
209 fn test_param_value_conversions() {
210 let f = ParamValue::Float(42.0);
211 assert_eq!(f.as_f32(), Some(42.0));
212 assert_eq!(f.as_i32(), Some(42));
213 assert_eq!(f.as_bool(), Some(true));
214
215 let i = ParamValue::Int(0);
216 assert_eq!(i.as_f32(), Some(0.0));
217 assert_eq!(i.as_i32(), Some(0));
218 assert_eq!(i.as_bool(), Some(false));
219
220 let b = ParamValue::Bool(true);
221 assert_eq!(b.as_f32(), Some(1.0));
222 assert_eq!(b.as_i32(), Some(1));
223 assert_eq!(b.as_bool(), Some(true));
224 }
225
226 #[test]
227 fn test_parameter_id_validation() {
228 assert!(ParameterId::new("gain").is_ok());
229 assert!(ParameterId::new("cutoff_freq").is_ok());
230 assert!(ParameterId::new("delay_time_2").is_ok());
231
232 assert!(ParameterId::new("").is_err());
233 assert!(ParameterId::new("1gain").is_err());
234 assert!(ParameterId::new("_gain").is_err());
235 assert!(ParameterId::new("gain.value").is_err());
236 }
237
238 #[test]
239 fn test_port_id_creation() {
240 let node = NodeId(42);
241
242 let signal_in = PortId::signal_in(node, 0);
243 assert_eq!(signal_in.node_id(), node);
244 assert_eq!(signal_in.port_type(), PortType::Signal);
245 assert_eq!(signal_in.direction(), PortDirection::Input);
246 assert_eq!(signal_in.index(), 0);
247 assert!(signal_in.is_input());
248 assert!(signal_in.is_signal());
249
250 let clock_out = PortId::clock_out(node, 0);
251 assert_eq!(clock_out.port_type(), PortType::Clock);
252 assert!(clock_out.is_output());
253 assert!(clock_out.is_clock());
254
255 let feedback_in = PortId::feedback_in(node, 0);
256 assert_eq!(feedback_in.port_type(), PortType::Feedback);
257 assert!(feedback_in.is_input());
258 assert!(feedback_in.is_feedback());
259 }
260
261 #[test]
262 fn test_node_metadata() {
263 let metadata = NodeMetadata {
264 name: "TestNode".to_string(),
265 type_name: None,
266 category: NodeCategory::Processor,
267 description: "A test node".to_string(),
268 author: "Rill".to_string(),
269 version: "1.0".to_string(),
270 signal_inputs: 2,
271 signal_outputs: 2,
272 control_inputs: 1,
273 control_outputs: 0,
274 clock_inputs: 1,
275 clock_outputs: 0,
276 feedback_ports: 0,
277 parameters: vec![],
278 };
279
280 assert_eq!(metadata.name, "TestNode");
281 assert_eq!(metadata.category, NodeCategory::Processor);
282 assert_eq!(metadata.signal_inputs, 2);
283 }
284
285 #[test]
286 fn test_param_range() {
287 let range = ParamRange::new().with_min(0.0).with_max(1.0).with_step(0.1);
288
289 assert!(range.contains(0.5));
290 assert!(!range.contains(1.5));
291 assert_eq!(range.clamp(1.5), 1.0);
292 assert_eq!(range.clamp(-0.5), 0.0);
293 }
294
295 #[test]
296 fn test_default_block_size() {
297 assert_eq!(DEFAULT_BLOCK_SIZE, 64);
298 }
299}