ceres/
core.rs

1//! Core framework types and traits
2
3use std::collections::HashMap;
4use std::marker::PhantomData;
5use std::any::{Any, TypeId};
6use std::cell::UnsafeCell;
7use crossbeam::channel::{Receiver, Sender, unbounded};
8
9pub type ComponentFn<E> = Box<dyn FnMut(&mut Runtime<E>, &[f32], &mut [f32], f32) + Send>;
10
11// === Event Bus ===
12pub struct EventBus<E> {
13    pub tx: Sender<E>,
14    pub rx: Receiver<E>,
15}
16
17impl<E> EventBus<E> {
18    fn new() -> Self {
19        let (tx, rx) = unbounded();
20        Self { tx, rx }
21    }
22    
23    pub fn send(&self, event: E) -> Result<(), crossbeam::channel::SendError<E>> {
24        self.tx.send(event)
25    }
26    
27    pub fn sender(&self) -> Sender<E> {
28        self.tx.clone()
29    }
30}
31
32impl<E> Clone for EventBus<E> {
33    fn clone(&self) -> Self {
34        Self {
35            tx: self.tx.clone(),
36            rx: self.rx.clone(),
37        }
38    }
39}
40
41// === Handles ===
42pub struct StateHandle<T> {
43    pub(crate) slot: usize,
44    _phantom: PhantomData<T>,
45}
46
47impl<T> Clone for StateHandle<T> {
48    fn clone(&self) -> Self {
49        StateHandle {
50            slot: self.slot,
51            _phantom: PhantomData,
52        }
53    }
54}
55
56impl<T> Copy for StateHandle<T> {}
57
58pub struct ModulatorHandle<T> {
59    pub(crate) slot: usize,
60    _phantom: PhantomData<T>,
61}
62
63impl<T> Clone for ModulatorHandle<T> {
64    fn clone(&self) -> Self {
65        ModulatorHandle {
66            slot: self.slot,
67            _phantom: PhantomData,
68        }
69    }
70}
71
72impl<T> Copy for ModulatorHandle<T> {}
73
74pub struct ParameterHandle<T> {
75    pub(crate) slot: usize,
76    _phantom: PhantomData<T>,
77}
78
79impl<T> Clone for ParameterHandle<T> {
80    fn clone(&self) -> Self {
81        ParameterHandle {
82            slot: self.slot,
83            _phantom: PhantomData,
84        }
85    }
86}
87
88impl<T> Copy for ParameterHandle<T> {}
89
90// === Traits ===
91pub trait Modulator<E>: Send + 'static {
92    fn update(&mut self, sample_rate: f32, event: Option<E>);
93    fn get_value(&self, index: usize) -> f32;
94}
95
96pub trait Parameters: Default + Send + 'static {
97    type Runtime<E: Send + 'static>: ParameterRuntime<E> + Send;
98    type Accessor<'a, E> where E: 'a;
99    type Values: Copy;
100    
101    fn create_runtime<E: Send>() -> Self::Runtime<E>;
102    fn create_accessor<E: Send>(runtime: &Self::Runtime<E>) -> Self::Accessor<'_, E>;
103}
104
105pub trait ParameterRuntime<E>: Send {
106    fn update(&mut self, sources: &[Box<dyn Modulator<E>>]);
107    fn route_parameter(&mut self, param_name: &str, source_index: usize, amount: f32);
108}
109
110// === Builder ===
111pub struct Builder<E> {
112    pub(crate) next_state_slot: usize,
113    pub(crate) state_builders: Vec<Box<dyn FnOnce() -> Box<dyn Any + Send>>>,
114    pub(crate) state_map: HashMap<TypeId, usize>,
115    
116    pub(crate) next_modulation_slot: usize,
117    pub(crate) modulation_builders: Vec<Box<dyn FnOnce() -> Box<dyn ParameterRuntime<E>>>>,
118    pub(crate) modulation_map: HashMap<TypeId, usize>,
119    
120    pub(crate) next_source_slot: usize,
121    pub(crate) modulation_sources: Vec<Box<dyn Modulator<E>>>,
122    pub(crate) source_map: HashMap<TypeId, usize>,
123    
124    _phantom: PhantomData<E>,
125}
126
127impl<E: Send + 'static> Builder<E> {
128    fn new() -> Self {
129        Self {
130            next_state_slot: 0,
131            state_builders: Vec::new(),
132            state_map: HashMap::new(),
133            next_modulation_slot: 0,
134            modulation_builders: Vec::new(),
135            modulation_map: HashMap::new(),
136            next_source_slot: 0,
137            modulation_sources: Vec::new(),
138            source_map: HashMap::new(),
139            _phantom: PhantomData,
140        }
141    }
142
143    pub fn use_state<T: Default + Send + 'static>(&mut self) -> StateHandle<T> {
144        let type_id = TypeId::of::<T>();
145        let slot = *self.state_map.entry(type_id).or_insert_with(|| {
146            let slot = self.next_state_slot;
147            self.next_state_slot += 1;
148            self.state_builders.push(Box::new(|| Box::new(T::default())));
149            slot
150        });
151        StateHandle { slot, _phantom: PhantomData }
152    }
153    
154    pub fn use_parameters<T: Parameters>(&mut self) -> ParameterHandle<T> 
155    where T::Runtime<E>: ParameterRuntime<E> + 'static {
156        let type_id = TypeId::of::<T>();
157        let slot = *self.modulation_map.entry(type_id).or_insert_with(|| {
158            let slot = self.next_modulation_slot;
159            self.next_modulation_slot += 1;
160            self.modulation_builders.push(Box::new(|| Box::new(T::create_runtime::<E>())));
161            slot
162        });
163        ParameterHandle { slot, _phantom: PhantomData }
164    }
165    
166    pub fn use_modulator<T: Modulator<E> + Default>(&mut self) -> ModulatorHandle<T> {
167        let type_id = TypeId::of::<T>();
168        let slot = self.next_source_slot;
169        self.next_source_slot += 1;
170        
171        self.modulation_sources.push(Box::new(T::default()));
172        self.source_map.insert(type_id, slot);
173        
174        ModulatorHandle { slot, _phantom: PhantomData }
175    }
176    
177    pub fn build<F>(self, f: F) -> Runtime<E> 
178    where 
179        F: FnOnce(&mut Builder<E>) -> ComponentFn<E>
180    {
181        let mut builder = self;
182        let component = f(&mut builder);
183        
184        Runtime {
185            states: builder.state_builders
186                .into_iter()
187                .map(|builder| UnsafeCell::new(builder()))
188                .collect(),
189            modulation_targets: builder.modulation_builders
190                .into_iter()
191                .map(|builder| UnsafeCell::new(builder()))
192                .collect(),
193            modulation_sources: UnsafeCell::new(builder.modulation_sources),
194            component: UnsafeCell::new(component),
195        }
196    }
197}
198
199// === Runtime ===
200pub struct Runtime<E: 'static> {
201    pub(crate) states: Vec<UnsafeCell<Box<dyn Any + Send>>>,
202    pub(crate) modulation_targets: Vec<UnsafeCell<Box<dyn ParameterRuntime<E>>>>,
203    pub(crate) modulation_sources: UnsafeCell<Vec<Box<dyn Modulator<E>>>>,
204    pub(crate) component: UnsafeCell<ComponentFn<E>>,
205}
206
207impl<E: 'static + Send + Clone + Copy> Runtime<E> {
208    pub fn get<T: 'static>(&self, handle: &StateHandle<T>) -> &T {
209        unsafe {
210            (*self.states[handle.slot].get()).downcast_ref().unwrap()
211        }
212    }
213    
214    pub fn get_mut<T: 'static>(&self, handle: &StateHandle<T>) -> &mut T {
215        unsafe {
216            (*self.states[handle.slot].get()).downcast_mut().unwrap()
217        }
218    }
219
220    pub fn get_source_mut<T: Modulator<E> + 'static>(&self, handle: &ModulatorHandle<T>) -> &mut T {
221        unsafe {
222            let sources = &mut *self.modulation_sources.get();
223            let boxed_modulator = &mut sources[handle.slot];
224            &mut *(boxed_modulator.as_mut() as *mut dyn Modulator<E> as *mut T)
225        }
226    }
227
228    pub fn route<S: 'static, T: Parameters + 'static>(
229        &mut self, 
230        source: ModulatorHandle<S>, 
231        target: ParameterHandle<T>, 
232        param: &str, 
233        amount: f32
234    ) {
235        unsafe {
236            let target_runtime = &mut *self.modulation_targets[target.slot].get();
237            target_runtime.route_parameter(param, source.slot, amount);
238        }
239    }
240
241    pub fn tick(&mut self, sample_rate: f32, event: Option<E>, input: &[f32], output: &mut [f32]) {
242        unsafe {
243            let sources = &mut *self.modulation_sources.get();
244
245            for modulator in sources.iter_mut() {
246                modulator.update(sample_rate, event);
247            }
248            
249            let component = &mut *self.component.get();
250            component(self, input, output, sample_rate);
251        }
252    }
253    
254    pub fn get_parameters<T: Parameters>(&self, handle: &ParameterHandle<T>) -> T::Accessor<'_, E> {
255        unsafe {
256            let sources = &*self.modulation_sources.get();
257            
258            let target_boxed = &mut *self.modulation_targets[handle.slot].get();
259            let concrete_runtime = &mut *(target_boxed.as_mut() as *mut dyn ParameterRuntime<E> as *mut T::Runtime<E>);
260            
261            concrete_runtime.update(sources);
262            T::create_accessor(concrete_runtime)
263        }
264    }
265}
266
267// === Main API ===
268pub fn new<E: Clone + Send + 'static>() -> (EventBus<E>, Builder<E>) {
269    (EventBus::new(), Builder::new())
270}
271
272// === Macros ===
273#[macro_export]
274macro_rules! parallel {
275    ($(($weight:expr, $comp:expr)),+) => {
276        |builder: &mut $crate::Builder<_>| -> $crate::ComponentFn<_> {
277            let mut components: Vec<(f32, $crate::ComponentFn<_>)> = vec![$(($weight as f32, $comp(builder))),+];
278            let mut temp_buffers = Vec::new();
279            
280            Box::new(move |runtime, input, output, sample_rate| {
281                if temp_buffers.len() != components.len() {
282                    temp_buffers.resize(components.len(), Vec::new());
283                }
284                for buf in &mut temp_buffers {
285                    if buf.len() != output.len() {
286                        buf.resize(output.len(), 0.0);
287                    }
288                }
289                
290                output.fill(0.0);
291                for ((weight, comp), buf) in components.iter_mut().zip(temp_buffers.iter_mut()) {
292                    buf.fill(0.0);
293                    comp(runtime, input, buf, sample_rate);
294                    
295                    for (out, &sample) in output.iter_mut().zip(buf.iter()) {
296                        *out += sample * *weight;
297                    }
298                }
299            })
300        }
301    };
302}
303
304#[macro_export]
305macro_rules! serial {
306    ($($comp:expr),+) => {
307        |builder: &mut $crate::Builder<_>| -> $crate::ComponentFn<_> {
308            let mut components: Vec<$crate::ComponentFn<_>> = vec![$($comp(builder)),+];
309            let mut buffer_a = Vec::new();
310            let mut buffer_b = Vec::new();
311            
312            Box::new(move |runtime, input, output, sample_rate| {
313                if components.is_empty() {
314                    output.copy_from_slice(input);
315                    return;
316                }
317                
318                if buffer_a.len() != output.len() {
319                    buffer_a.resize(output.len(), 0.0);
320                    buffer_b.resize(output.len(), 0.0);
321                }
322                
323                buffer_a.copy_from_slice(input);
324                
325                for (i, comp) in components.iter_mut().enumerate() {
326                    let (inp, out) = if i % 2 == 0 {
327                        (&buffer_a[..], &mut buffer_b[..])
328                    } else {
329                        (&buffer_b[..], &mut buffer_a[..])
330                    };
331                    out.fill(0.0);
332                    comp(runtime, inp, out, sample_rate);
333                }
334                
335                let final_buf = if components.len() % 2 == 1 { &buffer_b } else { &buffer_a };
336                output.copy_from_slice(final_buf);
337            })
338        }
339    };
340}
341
342struct ModulationRouting {
343    source_index: usize,
344    amount: f32,
345}