Skip to main content

rill_patchbay/
servo_constructor.rs

1//! ServoConstructor — creates Servo actors from [`ModuleDef::Servo`] descriptors.
2
3use std::sync::Arc;
4
5use rill_core::queues::CommandEnum;
6use rill_core::traits::NodeId;
7use rill_core_actor::{ActorRef, ActorSystem};
8
9use crate::automaton::envelope::EnvelopeAutomaton;
10use crate::automaton::lfo::LfoAutomaton;
11use crate::automaton::sequencer::{SequencerAutomaton, Step};
12use crate::engine::Servo;
13use crate::module_def::{AutomatonDef, ModuleDef};
14use crate::module_factory::{ModuleConstructor, ModuleError};
15
16/// Module constructor for the `"servo"` type — bridges an automaton to a graph parameter.
17pub struct ServoConstructor;
18
19impl ModuleConstructor for ServoConstructor {
20    fn type_name(&self) -> &'static str {
21        "servo"
22    }
23
24    fn construct(
25        &self,
26        module: &ModuleDef,
27        automaton_defs: &[AutomatonDef],
28        system: &Arc<ActorSystem>,
29        graph_ref: &ActorRef<CommandEnum>,
30    ) -> Result<ActorRef<CommandEnum>, ModuleError> {
31        let ModuleDef::Servo(s) = module else {
32            return Err(ModuleError::ConstructionFailed(
33                "ServoConstructor requires ModuleDef::Servo".into(),
34            ));
35        };
36
37        let def = automaton_defs
38            .iter()
39            .find(|a| a.id() == s.automaton_id)
40            .ok_or_else(|| {
41                ModuleError::ConstructionFailed(format!(
42                    "servo '{}' references unknown automaton '{}'",
43                    s.automaton_id, s.automaton_id
44                ))
45            })?;
46
47        let nid = NodeId(s.target_node);
48        let mapping = s.mapping.to_parameter_mapping();
49
50        let actor_ref = match def {
51            AutomatonDef::Lfo {
52                id,
53                frequency,
54                amplitude,
55                offset,
56                waveform,
57            } => {
58                let a = LfoAutomaton::new(id, *frequency, *amplitude, *offset, *waveform);
59                let mut servo = Servo::new(
60                    id,
61                    a,
62                    nid,
63                    &s.target_param,
64                    mapping,
65                    s.min,
66                    s.max,
67                    system.clone(),
68                    graph_ref.clone(),
69                );
70                if let Some(ref t) = s.table {
71                    servo = servo.with_table(t.clone());
72                }
73                servo.spawn(system)
74            }
75            AutomatonDef::Envelope {
76                id,
77                attack,
78                decay,
79                sustain,
80                release,
81                curve,
82                ..
83            } => {
84                let a = EnvelopeAutomaton::adsr(id, *attack, *decay, *sustain, *release)
85                    .with_curve(*curve);
86                let servo = Servo::new(
87                    id,
88                    a,
89                    nid,
90                    &s.target_param,
91                    mapping,
92                    s.min,
93                    s.max,
94                    system.clone(),
95                    graph_ref.clone(),
96                );
97                servo.spawn(system)
98            }
99            AutomatonDef::Sequencer {
100                id,
101                steps,
102                play_mode,
103                tempo,
104            } => {
105                let seq_steps: Vec<Step> = steps
106                    .iter()
107                    .map(|sd| Step {
108                        duration: sd.duration,
109                    })
110                    .collect();
111                let a = SequencerAutomaton::new(id, seq_steps)
112                    .with_mode(*play_mode)
113                    .with_tempo(*tempo);
114                let mut servo = Servo::new(
115                    id,
116                    a,
117                    nid,
118                    &s.target_param,
119                    mapping,
120                    s.min,
121                    s.max,
122                    system.clone(),
123                    graph_ref.clone(),
124                );
125                if let Some(ref t) = s.table {
126                    servo = servo.with_table(t.clone());
127                }
128                servo.spawn(system)
129            }
130            AutomatonDef::NamedFunction { id, .. } => {
131                return Err(ModuleError::ConstructionFailed(format!(
132                    "NamedFunction automaton '{}' requires manual setup",
133                    id
134                )));
135            }
136            AutomatonDef::Custom { id, type_name, .. } => {
137                return Err(ModuleError::ConstructionFailed(format!(
138                    "Custom automaton '{}' (type '{}') not yet supported via ServoConstructor",
139                    id, type_name,
140                )));
141            }
142        };
143
144        Ok(actor_ref)
145    }
146
147    fn clone_box(&self) -> Box<dyn ModuleConstructor> {
148        Box::new(ServoConstructor)
149    }
150}