ceres-dsp 0.0.8

A modular digital signal processing framework for Rust
Documentation
//! Core framework types and traits

use std::collections::HashMap;
use std::marker::PhantomData;
use std::any::{Any, TypeId};
use std::cell::UnsafeCell;
use crossbeam::channel::{Receiver, Sender, unbounded};

pub type ComponentFn<E> = Box<dyn FnMut(&mut Runtime<E>, &[f32], &mut [f32], f32) + Send>;

// === Event Bus ===
pub struct EventBus<E> {
    pub tx: Sender<E>,
    pub rx: Receiver<E>,
}

impl<E> EventBus<E> {
    fn new() -> Self {
        let (tx, rx) = unbounded();
        Self { tx, rx }
    }
    
    pub fn send(&self, event: E) -> Result<(), crossbeam::channel::SendError<E>> {
        self.tx.send(event)
    }
    
    pub fn sender(&self) -> Sender<E> {
        self.tx.clone()
    }
}

impl<E> Clone for EventBus<E> {
    fn clone(&self) -> Self {
        Self {
            tx: self.tx.clone(),
            rx: self.rx.clone(),
        }
    }
}

// === Handles ===
pub struct StateHandle<T> {
    pub(crate) slot: usize,
    _phantom: PhantomData<T>,
}

impl<T> Clone for StateHandle<T> {
    fn clone(&self) -> Self {
        StateHandle {
            slot: self.slot,
            _phantom: PhantomData,
        }
    }
}

impl<T> Copy for StateHandle<T> {}

pub struct ModulatorHandle<T> {
    pub(crate) slot: usize,
    _phantom: PhantomData<T>,
}

impl<T> Clone for ModulatorHandle<T> {
    fn clone(&self) -> Self {
        ModulatorHandle {
            slot: self.slot,
            _phantom: PhantomData,
        }
    }
}

impl<T> Copy for ModulatorHandle<T> {}

pub struct ParameterHandle<T> {
    pub(crate) slot: usize,
    _phantom: PhantomData<T>,
}

impl<T> Clone for ParameterHandle<T> {
    fn clone(&self) -> Self {
        ParameterHandle {
            slot: self.slot,
            _phantom: PhantomData,
        }
    }
}

impl<T> Copy for ParameterHandle<T> {}

// === Traits ===
pub trait Modulator<E>: Send + 'static {
    fn update(&mut self, sample_rate: f32, event: Option<E>);
    fn get_value(&self, index: usize) -> f32;
}

pub trait Parameters: Default + Send + 'static {
    type Runtime<E: Send + 'static>: ParameterRuntime<E> + Send;
    type Accessor<'a, E> where E: 'a;
    type Values: Copy;
    
    fn create_runtime<E: Send>() -> Self::Runtime<E>;
    fn create_accessor<E: Send>(runtime: &Self::Runtime<E>) -> Self::Accessor<'_, E>;
}

pub trait ParameterRuntime<E>: Send {
    fn update(&mut self, sources: &[Box<dyn Modulator<E>>]);
    fn route_parameter(&mut self, param_name: &str, source_index: usize, amount: f32);
}

// === Builder ===
pub struct Builder<E> {
    pub(crate) next_state_slot: usize,
    pub(crate) state_builders: Vec<Box<dyn FnOnce() -> Box<dyn Any + Send>>>,
    pub(crate) state_map: HashMap<TypeId, usize>,
    
    pub(crate) next_modulation_slot: usize,
    pub(crate) modulation_builders: Vec<Box<dyn FnOnce() -> Box<dyn ParameterRuntime<E>>>>,
    pub(crate) modulation_map: HashMap<TypeId, usize>,
    
    pub(crate) next_source_slot: usize,
    pub(crate) modulation_sources: Vec<Box<dyn Modulator<E>>>,
    pub(crate) source_map: HashMap<TypeId, usize>,
    
    _phantom: PhantomData<E>,
}

impl<E: Send + 'static> Builder<E> {
    fn new() -> Self {
        Self {
            next_state_slot: 0,
            state_builders: Vec::new(),
            state_map: HashMap::new(),
            next_modulation_slot: 0,
            modulation_builders: Vec::new(),
            modulation_map: HashMap::new(),
            next_source_slot: 0,
            modulation_sources: Vec::new(),
            source_map: HashMap::new(),
            _phantom: PhantomData,
        }
    }

    pub fn use_state<T: Default + Send + 'static>(&mut self) -> StateHandle<T> {
        let type_id = TypeId::of::<T>();
        let slot = *self.state_map.entry(type_id).or_insert_with(|| {
            let slot = self.next_state_slot;
            self.next_state_slot += 1;
            self.state_builders.push(Box::new(|| Box::new(T::default())));
            slot
        });
        StateHandle { slot, _phantom: PhantomData }
    }
    
    pub fn use_parameters<T: Parameters>(&mut self) -> ParameterHandle<T> 
    where T::Runtime<E>: ParameterRuntime<E> + 'static {
        let type_id = TypeId::of::<T>();
        let slot = *self.modulation_map.entry(type_id).or_insert_with(|| {
            let slot = self.next_modulation_slot;
            self.next_modulation_slot += 1;
            self.modulation_builders.push(Box::new(|| Box::new(T::create_runtime::<E>())));
            slot
        });
        ParameterHandle { slot, _phantom: PhantomData }
    }
    
    pub fn use_modulator<T: Modulator<E> + Default>(&mut self) -> ModulatorHandle<T> {
        let type_id = TypeId::of::<T>();
        let slot = self.next_source_slot;
        self.next_source_slot += 1;
        
        self.modulation_sources.push(Box::new(T::default()));
        self.source_map.insert(type_id, slot);
        
        ModulatorHandle { slot, _phantom: PhantomData }
    }
    
    pub fn build<F>(self, f: F) -> Runtime<E> 
    where 
        F: FnOnce(&mut Builder<E>) -> ComponentFn<E>
    {
        let mut builder = self;
        let component = f(&mut builder);
        
        Runtime {
            states: builder.state_builders
                .into_iter()
                .map(|builder| UnsafeCell::new(builder()))
                .collect(),
            modulation_targets: builder.modulation_builders
                .into_iter()
                .map(|builder| UnsafeCell::new(builder()))
                .collect(),
            modulation_sources: UnsafeCell::new(builder.modulation_sources),
            component: UnsafeCell::new(component),
        }
    }
}

// === Runtime ===
pub struct Runtime<E: 'static> {
    pub(crate) states: Vec<UnsafeCell<Box<dyn Any + Send>>>,
    pub(crate) modulation_targets: Vec<UnsafeCell<Box<dyn ParameterRuntime<E>>>>,
    pub(crate) modulation_sources: UnsafeCell<Vec<Box<dyn Modulator<E>>>>,
    pub(crate) component: UnsafeCell<ComponentFn<E>>,
}

impl<E: 'static + Send + Clone + Copy> Runtime<E> {
    pub fn get<T: 'static>(&self, handle: &StateHandle<T>) -> &T {
        unsafe {
            (*self.states[handle.slot].get()).downcast_ref().unwrap()
        }
    }
    
    pub fn get_mut<T: 'static>(&self, handle: &StateHandle<T>) -> &mut T {
        unsafe {
            (*self.states[handle.slot].get()).downcast_mut().unwrap()
        }
    }

    pub fn get_source_mut<T: Modulator<E> + 'static>(&self, handle: &ModulatorHandle<T>) -> &mut T {
        unsafe {
            let sources = &mut *self.modulation_sources.get();
            let boxed_modulator = &mut sources[handle.slot];
            &mut *(boxed_modulator.as_mut() as *mut dyn Modulator<E> as *mut T)
        }
    }

    pub fn route<S: 'static, T: Parameters + 'static>(
        &mut self, 
        source: ModulatorHandle<S>, 
        target: ParameterHandle<T>, 
        param: &str, 
        amount: f32
    ) {
        unsafe {
            let target_runtime = &mut *self.modulation_targets[target.slot].get();
            target_runtime.route_parameter(param, source.slot, amount);
        }
    }

    pub fn tick(&mut self, sample_rate: f32, event: Option<E>, input: &[f32], output: &mut [f32]) {
        unsafe {
            let sources = &mut *self.modulation_sources.get();

            for modulator in sources.iter_mut() {
                modulator.update(sample_rate, event);
            }
            
            let component = &mut *self.component.get();
            component(self, input, output, sample_rate);
        }
    }
    
    pub fn get_parameters<T: Parameters>(&self, handle: &ParameterHandle<T>) -> T::Accessor<'_, E> {
        unsafe {
            let sources = &*self.modulation_sources.get();
            
            let target_boxed = &mut *self.modulation_targets[handle.slot].get();
            let concrete_runtime = &mut *(target_boxed.as_mut() as *mut dyn ParameterRuntime<E> as *mut T::Runtime<E>);
            
            concrete_runtime.update(sources);
            T::create_accessor(concrete_runtime)
        }
    }
}

// === Main API ===
pub fn new<E: Clone + Send + 'static>() -> (EventBus<E>, Builder<E>) {
    (EventBus::new(), Builder::new())
}

// === Macros ===
#[macro_export]
macro_rules! parallel {
    ($(($weight:expr, $comp:expr)),+) => {
        |builder: &mut $crate::Builder<_>| -> $crate::ComponentFn<_> {
            let mut components: Vec<(f32, $crate::ComponentFn<_>)> = vec![$(($weight as f32, $comp(builder))),+];
            let mut temp_buffers = Vec::new();
            
            Box::new(move |runtime, input, output, sample_rate| {
                if temp_buffers.len() != components.len() {
                    temp_buffers.resize(components.len(), Vec::new());
                }
                for buf in &mut temp_buffers {
                    if buf.len() != output.len() {
                        buf.resize(output.len(), 0.0);
                    }
                }
                
                output.fill(0.0);
                for ((weight, comp), buf) in components.iter_mut().zip(temp_buffers.iter_mut()) {
                    buf.fill(0.0);
                    comp(runtime, input, buf, sample_rate);
                    
                    for (out, &sample) in output.iter_mut().zip(buf.iter()) {
                        *out += sample * *weight;
                    }
                }
            })
        }
    };
}

#[macro_export]
macro_rules! serial {
    ($($comp:expr),+) => {
        |builder: &mut $crate::Builder<_>| -> $crate::ComponentFn<_> {
            let mut components: Vec<$crate::ComponentFn<_>> = vec![$($comp(builder)),+];
            let mut buffer_a = Vec::new();
            let mut buffer_b = Vec::new();
            
            Box::new(move |runtime, input, output, sample_rate| {
                if components.is_empty() {
                    output.copy_from_slice(input);
                    return;
                }
                
                if buffer_a.len() != output.len() {
                    buffer_a.resize(output.len(), 0.0);
                    buffer_b.resize(output.len(), 0.0);
                }
                
                buffer_a.copy_from_slice(input);
                
                for (i, comp) in components.iter_mut().enumerate() {
                    let (inp, out) = if i % 2 == 0 {
                        (&buffer_a[..], &mut buffer_b[..])
                    } else {
                        (&buffer_b[..], &mut buffer_a[..])
                    };
                    out.fill(0.0);
                    comp(runtime, inp, out, sample_rate);
                }
                
                let final_buf = if components.len() % 2 == 1 { &buffer_b } else { &buffer_a };
                output.copy_from_slice(final_buf);
            })
        }
    };
}

struct ModulationRouting {
    source_index: usize,
    amount: f32,
}