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                if let Some(ref cs) = s.control_strategy {
74                    servo = servo.with_control(*cs);
75                }
76                if let Some(ref cf) = s.conflict_strategy {
77                    servo = servo.with_conflict(*cf);
78                }
79                servo.spawn(system)
80            }
81            AutomatonDef::Envelope {
82                id,
83                attack,
84                decay,
85                sustain,
86                release,
87                curve,
88                ..
89            } => {
90                let a = EnvelopeAutomaton::adsr(id, *attack, *decay, *sustain, *release)
91                    .with_curve(*curve);
92                let mut servo = Servo::new(
93                    id,
94                    a,
95                    nid,
96                    &s.target_param,
97                    mapping,
98                    s.min,
99                    s.max,
100                    system.clone(),
101                    graph_ref.clone(),
102                );
103                if let Some(ref cs) = s.control_strategy {
104                    servo = servo.with_control(*cs);
105                }
106                if let Some(ref cf) = s.conflict_strategy {
107                    servo = servo.with_conflict(*cf);
108                }
109                servo.spawn(system)
110            }
111            AutomatonDef::Sequencer {
112                id,
113                steps,
114                play_mode,
115                tempo,
116            } => {
117                let seq_steps: Vec<Step> = steps
118                    .iter()
119                    .map(|sd| Step {
120                        duration: sd.duration,
121                    })
122                    .collect();
123                let a = SequencerAutomaton::new(id, seq_steps)
124                    .with_mode(*play_mode)
125                    .with_tempo(*tempo);
126                let mut servo = Servo::new(
127                    id,
128                    a,
129                    nid,
130                    &s.target_param,
131                    mapping,
132                    s.min,
133                    s.max,
134                    system.clone(),
135                    graph_ref.clone(),
136                );
137                if let Some(ref t) = s.table {
138                    servo = servo.with_table(t.clone());
139                }
140                if let Some(ref cs) = s.control_strategy {
141                    servo = servo.with_control(*cs);
142                }
143                if let Some(ref cf) = s.conflict_strategy {
144                    servo = servo.with_conflict(*cf);
145                }
146                servo.spawn(system)
147            }
148            AutomatonDef::NamedFunction { id, .. } => {
149                return Err(ModuleError::ConstructionFailed(format!(
150                    "NamedFunction automaton '{}' requires manual setup",
151                    id
152                )));
153            }
154            AutomatonDef::Custom { id, type_name, .. } => {
155                return Err(ModuleError::ConstructionFailed(format!(
156                    "Custom automaton '{}' (type '{}') not yet supported via ServoConstructor",
157                    id, type_name,
158                )));
159            }
160        };
161
162        Ok(actor_ref)
163    }
164
165    fn clone_box(&self) -> Box<dyn ModuleConstructor> {
166        Box::new(ServoConstructor)
167    }
168}