| Crates.io | ceres-dsp |
| lib.rs | ceres-dsp |
| version | 0.0.8 |
| created_at | 2025-06-05 21:33:02.478576+00 |
| updated_at | 2025-06-06 20:58:46.849345+00 |
| description | A modular digital signal processing framework for Rust |
| homepage | |
| repository | https://github.com/MoofSoup/ceres-dsp |
| max_upload_size | |
| id | 1702390 |
| size | 24,301 |
At Ceres DSP, we believe in making the impossible fun. Ceres DSP is an ergonomics-first, component based digital signal processing framework. Using the Ceres Runtime lets you focus on what matters: writing digital signal processors.
use_state<T>() hook enables Ceres Runtime to manage processor stateserial!() and parallel!() macrosceres::new<E>() provides channel based api to send events to audio runtimeuse_parameters<T>() hook + #[parameters] proc macroCurrently, we are working on redoing our routing API to support fluent rerouting between components at runtime. We are also working on a feedback based drum synthesizer VST, inspired by SOPHIE. For updates, to contribute, or just to make cool projects and share your work, please join the official Ceres Discord
You can find the example code's repo here. Alternatively:
git clone https://github.com/MoofSoup/hello-ceres.git
Here, we use Ceres' Synth Engine to set up a basic synthesizer:
// main.rs
#[derive(Clone, Copy)]
enum Event {
midi([u8; 3])
}
fn main() {
let engine = Engine::<Event>::new(|builder|{
let runtime = builder.build(sawtooth);
runtime
});
engine.run();
println!("Audio Engine is running! Press Ctrl + C to stop!");
std::thread::park();
}
Here is how our sawtooth oscillator is defined:
// this struct holds our oscillator's internal state
#[derive(Default)]
struct SawOscState {
phase: f32,
}
pub fn sawtooth(builder: &mut Builder<Event>) -> ComponentFn<Event>{
// Here, we get a handle to our state at build time
// When the runtime eventually gets constructed, it will:
// - Create and manage an instance of the saw osc state struct
// - that is shared across componants
// this means you have to create structs specific to each component's state
let osc_state_handle = builder.use_state::<SawOscState>();
Box::new(move |runtime, input, output, sample_rate|{
// Now, we use our handle to access our state each tick
let state = runtime.get_mut(&osc_state_handle);
// Now, we write to our output buffer.
// We use the phase in our calculations, and update it
// The use_state hook makes managing this state effortless.
for (i, sample) in output.iter_mut().enumerate() {
let freq = 261.63;
let amplitude = 1.0;
let saw_wave = state.phase * 2.0 - 1.0;
*sample = saw_wave * amplitude;
state.phase += freq / sample_rate;
if state.phase >= 1.0 { state.phase -= 1.0; }
}
})
}