1use crate::queues::signal::SetParameter;
10use crate::time::ClockTick;
11use crate::traits::param::{ParamMetadata, ParamValue, ParameterId};
12use crate::traits::ProcessResult;
13use std::any::TypeId;
14use std::fmt;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct NodeId(pub u32);
23
24impl NodeId {
25 pub const fn new(id: u32) -> Self {
27 Self(id)
28 }
29
30 pub const fn inner(&self) -> u32 {
32 self.0
33 }
34}
35
36impl fmt::Display for NodeId {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(f, "Node({})", self.0)
39 }
40}
41
42impl From<u32> for NodeId {
43 fn from(id: u32) -> Self {
44 Self(id)
45 }
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
54pub enum NodeCategory {
55 Source,
57
58 Processor,
60
61 Sink,
63
64 Utility,
66
67 Analyzer,
69
70 Sequencer,
72}
73
74impl NodeCategory {
75 pub const fn name(&self) -> &'static str {
77 match self {
78 Self::Source => "source",
79 Self::Processor => "processor",
80 Self::Sink => "sink",
81 Self::Utility => "utility",
82 Self::Analyzer => "analyzer",
83 Self::Sequencer => "sequencer",
84 }
85 }
86}
87
88impl fmt::Display for NodeCategory {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 write!(f, "{}", self.name())
91 }
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
100pub struct NodeTypeId(TypeId);
101
102impl NodeTypeId {
103 pub fn of<T: 'static + ?Sized>() -> Self {
105 Self(TypeId::of::<T>())
106 }
107
108 pub fn as_type_id(&self) -> TypeId {
110 self.0
111 }
112}
113
114#[derive(Debug, Clone)]
120pub struct NodeMetadata {
121 pub name: String,
123
124 pub category: NodeCategory,
126
127 pub description: String,
129
130 pub author: String,
132
133 pub version: String,
135
136 pub audio_inputs: usize,
138
139 pub audio_outputs: usize,
141
142 pub control_inputs: usize,
144
145 pub control_outputs: usize,
147
148 pub clock_inputs: usize,
150
151 pub clock_outputs: usize,
153
154 pub feedback_ports: usize,
156
157 pub parameters: Vec<ParamMetadata>,
159}
160
161impl NodeMetadata {
162 pub fn new(name: &str, category: NodeCategory) -> Self {
164 Self {
165 name: name.to_string(),
166 category,
167 description: String::new(),
168 author: String::new(),
169 version: String::new(),
170 audio_inputs: 0,
171 audio_outputs: 0,
172 control_inputs: 0,
173 control_outputs: 0,
174 clock_inputs: 0,
175 clock_outputs: 0,
176 feedback_ports: 0,
177 parameters: Vec::new(),
178 }
179 }
180}
181
182#[derive(Debug, Clone)]
189pub struct NodeState<T: crate::math::Transcendental, const BUF_SIZE: usize> {
190 pub sample_pos: u64,
192
193 pub blocks_processed: u64,
195
196 pub sample_rate: f32,
198
199 pub active: bool,
201
202 pub phase: T,
204}
205
206impl<T: crate::math::Transcendental, const BUF_SIZE: usize> NodeState<T, BUF_SIZE> {
207 pub fn new(sample_rate: f32) -> Self {
209 Self {
210 sample_pos: 0,
211 blocks_processed: 0,
212 sample_rate,
213 active: true,
214 phase: T::ZERO,
215 }
216 }
217
218 pub fn advance(&mut self) {
220 self.sample_pos += BUF_SIZE as u64;
221 self.blocks_processed += 1;
222 }
223
224 pub fn current_time_seconds(&self) -> f64 {
226 self.sample_pos as f64 / self.sample_rate as f64
227 }
228
229 pub fn reset(&mut self) {
231 self.sample_pos = 0;
232 self.blocks_processed = 0;
233 self.phase = T::ZERO;
234 }
235}
236
237pub trait AudioNode<T: crate::math::Transcendental, const BUF_SIZE: usize>: Send + Sync {
253 fn metadata(&self) -> NodeMetadata;
255
256 fn node_type_id(&self) -> NodeTypeId
258 where
259 Self: 'static + Sized,
260 {
261 NodeTypeId::of::<Self>()
262 }
263
264 fn init(&mut self, sample_rate: f32);
266
267 fn reset(&mut self);
269
270 fn get_parameter(&self, id: &ParameterId) -> Option<ParamValue>;
272
273 fn set_parameter(&mut self, id: &ParameterId, value: ParamValue) -> ProcessResult<()>;
275
276 fn apply_set_parameter(&mut self, cmd: &SetParameter) -> ProcessResult<()> {
281 use crate::traits::port::{PortDirection, PortType};
282 let value = T::from_f32(cmd.value);
283 let port = match cmd.port.port_type() {
284 PortType::Control => self.control_port_mut(cmd.port.index() as usize),
285 PortType::Audio => match cmd.port.direction() {
286 PortDirection::Input => self.input_port_mut(cmd.port.index() as usize),
287 PortDirection::Output => self.output_port_mut(cmd.port.index() as usize),
288 },
289 PortType::Param => self.input_port_mut(cmd.port.index() as usize),
290 PortType::Clock | PortType::Feedback => None,
291 };
292 match port {
293 Some(p) => {
294 p.set_value(value);
295 Ok(())
296 }
297 None => self.set_parameter(&cmd.parameter, ParamValue::Float(cmd.value)),
298 }
299 }
300
301 fn id(&self) -> NodeId;
303
304 fn set_id(&mut self, id: NodeId);
306
307 fn input_port(&self, index: usize) -> Option<&crate::traits::port::Port<T, BUF_SIZE>>;
309
310 fn input_port_mut(
312 &mut self,
313 index: usize,
314 ) -> Option<&mut crate::traits::port::Port<T, BUF_SIZE>>;
315
316 fn output_port(&self, index: usize) -> Option<&crate::traits::port::Port<T, BUF_SIZE>>;
318
319 fn output_port_mut(
321 &mut self,
322 index: usize,
323 ) -> Option<&mut crate::traits::port::Port<T, BUF_SIZE>>;
324
325 fn control_port(&self, index: usize) -> Option<&crate::traits::port::Port<T, BUF_SIZE>>;
327
328 fn control_port_mut(
330 &mut self,
331 index: usize,
332 ) -> Option<&mut crate::traits::port::Port<T, BUF_SIZE>>;
333
334 fn state(&self) -> &NodeState<T, BUF_SIZE>;
336
337 fn state_mut(&mut self) -> &mut NodeState<T, BUF_SIZE>;
339
340 fn num_audio_inputs(&self) -> usize {
346 0
347 }
348
349 fn num_audio_outputs(&self) -> usize {
351 0
352 }
353
354 fn num_control_inputs(&self) -> usize {
356 0
357 }
358
359 fn num_control_outputs(&self) -> usize {
361 0
362 }
363
364 fn num_clock_inputs(&self) -> usize {
366 0
367 }
368
369 fn num_clock_outputs(&self) -> usize {
371 0
372 }
373
374 fn num_feedback_ports(&self) -> usize {
376 0
377 }
378
379 fn num_inputs(&self) -> usize {
381 self.num_audio_inputs()
382 + self.num_control_inputs()
383 + self.num_clock_inputs()
384 + self.num_feedback_ports()
385 }
386
387 fn num_outputs(&self) -> usize {
389 self.num_audio_outputs() + self.num_control_outputs() + self.num_clock_outputs()
390 }
391}
392
393pub trait Source<T: crate::math::Transcendental, const BUF_SIZE: usize>: AudioNode<T, BUF_SIZE> {
402 fn generate(
412 &mut self,
413 clock: &ClockTick,
414 control_inputs: &[T],
415 clock_inputs: &[ClockTick],
416 ) -> ProcessResult<()>;
417
418 fn num_audio_outputs(&self) -> usize {
420 1
421 }
422
423 fn num_control_inputs(&self) -> usize {
425 0
426 }
427
428 fn num_clock_inputs(&self) -> usize {
430 0
431 }
432}
433
434pub trait Processor<T: crate::math::Transcendental, const BUF_SIZE: usize>:
443 AudioNode<T, BUF_SIZE>
444{
445 fn process(
457 &mut self,
458 clock: &ClockTick,
459 audio_inputs: &[&[T; BUF_SIZE]],
460 control_inputs: &[T],
461 clock_inputs: &[ClockTick],
462 feedback_inputs: &[&[T; BUF_SIZE]],
463 ) -> ProcessResult<()>;
464
465 fn latency(&self) -> usize {
467 0
468 }
469}
470
471pub trait Sink<T: crate::math::Transcendental, const BUF_SIZE: usize>: AudioNode<T, BUF_SIZE> {
480 fn consume(
489 &mut self,
490 clock: &ClockTick,
491 audio_inputs: &[&[T; BUF_SIZE]],
492 control_inputs: &[T],
493 clock_inputs: &[ClockTick],
494 feedback_inputs: &[&[T; BUF_SIZE]],
495 ) -> ProcessResult<()>;
496}
497
498#[cfg(test)]
503mod tests {
504 use super::*;
505 use crate::math::Transcendental;
506
507 struct TestNode;
508
509 impl<T: Transcendental, const BUF_SIZE: usize> AudioNode<T, BUF_SIZE> for TestNode {
510 fn metadata(&self) -> NodeMetadata {
511 NodeMetadata {
512 name: "Test".to_string(),
513 category: NodeCategory::Utility,
514 description: "Test node".to_string(),
515 author: "Rill".to_string(),
516 version: "1.0".to_string(),
517 audio_inputs: 0,
518 audio_outputs: 0,
519 control_inputs: 0,
520 control_outputs: 0,
521 clock_inputs: 0,
522 clock_outputs: 0,
523 feedback_ports: 0,
524 parameters: vec![],
525 }
526 }
527
528 fn init(&mut self, _sample_rate: f32) {}
529 fn reset(&mut self) {}
530 fn get_parameter(&self, _id: &ParameterId) -> Option<ParamValue> {
531 None
532 }
533 fn set_parameter(&mut self, _id: &ParameterId, _value: ParamValue) -> ProcessResult<()> {
534 Ok(())
535 }
536
537 fn id(&self) -> NodeId {
538 NodeId(0)
539 }
540 fn set_id(&mut self, _id: NodeId) {}
541
542 fn input_port(&self, _index: usize) -> Option<&crate::traits::port::Port<T, BUF_SIZE>> {
543 None
544 }
545 fn input_port_mut(
546 &mut self,
547 _index: usize,
548 ) -> Option<&mut crate::traits::port::Port<T, BUF_SIZE>> {
549 None
550 }
551 fn output_port(&self, _index: usize) -> Option<&crate::traits::port::Port<T, BUF_SIZE>> {
552 None
553 }
554 fn output_port_mut(
555 &mut self,
556 _index: usize,
557 ) -> Option<&mut crate::traits::port::Port<T, BUF_SIZE>> {
558 None
559 }
560 fn control_port(&self, _index: usize) -> Option<&crate::traits::port::Port<T, BUF_SIZE>> {
561 None
562 }
563 fn control_port_mut(
564 &mut self,
565 _index: usize,
566 ) -> Option<&mut crate::traits::port::Port<T, BUF_SIZE>> {
567 None
568 }
569
570 fn state(&self) -> &NodeState<T, BUF_SIZE> {
571 unimplemented!()
572 }
573
574 fn state_mut(&mut self) -> &mut NodeState<T, BUF_SIZE> {
575 unimplemented!()
576 }
577 }
578
579 #[test]
580 fn test_node_id() {
581 let id = NodeId::new(42);
582 assert_eq!(id.inner(), 42);
583 assert_eq!(format!("{}", id), "Node(42)");
584 }
585
586 #[test]
587 fn test_node_category() {
588 assert_eq!(NodeCategory::Source.name(), "source");
589 assert_eq!(NodeCategory::Processor.name(), "processor");
590 assert_eq!(NodeCategory::Sink.name(), "sink");
591 assert_eq!(NodeCategory::Utility.name(), "utility");
592 }
593
594 #[test]
595 fn test_node_metadata_new() {
596 let metadata = NodeMetadata::new("Test", NodeCategory::Source);
597 assert_eq!(metadata.name, "Test");
598 assert_eq!(metadata.category, NodeCategory::Source);
599 }
600
601 #[test]
602 fn test_node_state() {
603 let mut state = NodeState::<f32, 64>::new(44100.0);
604 assert_eq!(state.sample_pos, 0);
605 assert_eq!(state.sample_rate, 44100.0);
606
607 state.advance();
608 assert_eq!(state.sample_pos, 64);
609 assert_eq!(state.blocks_processed, 1);
610
611 state.reset();
612 assert_eq!(state.sample_pos, 0);
613 assert_eq!(state.blocks_processed, 0);
614 }
615}