| Crates.io | klingt |
| lib.rs | klingt |
| version | 0.3.3 |
| created_at | 2025-02-25 09:31:15.953227+00 |
| updated_at | 2025-12-04 19:16:23.913984+00 |
| description | Lock-free audio graph library with message-passing parameter control |
| homepage | |
| repository | https://github.com/dwbrite/klingt |
| max_upload_size | |
| id | 1568971 |
| size | 3,343,408 |
A lock-free audio graph library with message-passing parameter control.
Arc/Mutex on the hot pathprocess()use klingt::{Klingt, nodes::Sine};
fn main() {
// Create engine with default audio device
let mut klingt = Klingt::default_output().expect("No audio device");
// Add a sine oscillator and connect to output
let sine = klingt.add(Sine::new(440.0));
klingt.output(&sine);
// Main audio loop
loop {
klingt.process();
std::thread::sleep(std::time::Duration::from_micros(500));
}
}
Send messages to nodes without locks:
use klingt::{Klingt, nodes::{Sine, SineMessage, Gain}};
let mut klingt = Klingt::default_output().unwrap();
let mut sine = klingt.add(Sine::new(440.0));
let gain = klingt.add(Gain::new(0.5));
klingt.connect(&sine, &gain);
klingt.output(&gain);
// Change frequency at runtime (lock-free!)
sine.send(SineMessage::SetFrequency(880.0)).ok();
Add nodes at their native sample rate – Klingt handles the rest:
// Audio file at 48kHz + device at 44.1kHz = automatic resampling
let player = SamplePlayer::new(samples, 2, 48000);
let handle = klingt.add(player); // Sub-graph created automatically
klingt.output(&handle); // Routed through resampler
Sine, SamplePlayerGain, Mixer, SlewLimiterCpalSink (with cpal_sink feature)Implement the AudioNode trait to create your own:
use klingt::{AudioNode, ProcessContext};
use dasp_graph::{Buffer, Input};
pub enum SquareMessage {
SetFrequency(f32),
SetPulseWidth(f32),
}
pub struct Square {
frequency: f32,
pulse_width: f32,
phase: f32,
}
impl AudioNode for Square {
type Message = SquareMessage;
fn process(
&mut self,
ctx: &ProcessContext,
messages: impl Iterator<Item = SquareMessage>,
_inputs: &[Input],
outputs: &mut [Buffer],
) {
// Handle messages
for msg in messages {
match msg {
SquareMessage::SetFrequency(f) => self.frequency = f,
SquareMessage::SetPulseWidth(pw) => self.pulse_width = pw,
}
}
// Generate audio
let phase_inc = self.frequency / ctx.sample_rate as f32;
for sample in outputs[0].iter_mut() {
*sample = if self.phase < self.pulse_width { 0.25 } else { -0.25 };
self.phase = (self.phase + phase_inc) % 1.0;
}
}
fn num_outputs(&self) -> usize { 1 }
}
cpal_sink – Enable CPAL audio outputstd – Enable standard library (enabled by default)MIT