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