rill_patchbay/
servo_constructor.rs1use 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
16pub 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}