Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Klingt
A lock-free audio graph library with message-passing parameter control.
Quick Start
The simplest way to play audio is with [Klingt::default_output]:
use klingt::{Klingt, nodes::Sine};
// 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 - call process() repeatedly
loop {
klingt.process();
std::thread::sleep(std::time::Duration::from_micros(500));
}
Core Concepts
Nodes and Handles
Audio processing is done by nodes that implement [AudioNode]. When you add a node
to Klingt, you get back a [Handle] that lets you:
- Connect nodes together with [
Klingt::connect] - Send parameter updates with [
Handle::send]
# 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();
Automatic Sample Rate Conversion
Klingt automatically handles sample rate mismatches. If you add a node that has a different native sample rate (like a pre-decoded audio file), Klingt creates a sub-graph at that rate and resamples to match the output device:
// Audio file at 48000Hz + device at 44100Hz = automatic resampling
let player = SamplePlayer::new(samples, 2, 48000);
let handle = klingt.add(player); // Sub-graph created automatically
klingt.output(&handle); // Routed through resampler
Message Passing (No Locks!)
All parameter updates use lock-free ring buffers. The audio thread never blocks waiting for the main thread. Messages are processed at the start of each audio block (64 samples by default).
Built-in Nodes
See the [nodes] module for available nodes:
- Sources:
Sine,SamplePlayer - Effects:
Gain,Mixer,SlewLimiter - Sinks:
CpalSink(withcpal_sinkfeature)
Custom Nodes
Implement [AudioNode] to create your own nodes. Here's a complete example
of a square wave oscillator with message-based parameter control:
use ;
use ;
// Define messages for runtime parameter control
Then use it like any built-in node:
let mut square = klingt.add(Square::new(440.0));
klingt.output(&square);
// Modulate pulse width for PWM synthesis
square.send(SquareMessage::SetPulseWidth(0.25)).ok();
Node Types
The three types of nodes differ by their input/output counts:
| Type | Inputs | Outputs | Examples |
|---|---|---|---|
| Source | 0 | 1+ | Oscillators, sample players |
| Effect | 1+ | 1+ | Gain, filters, delays |
| Sink | 1+ | 0 | Audio output, recorders |
Override num_inputs and num_outputs
to define your node's channel configuration.
Feature Flags
cpal_sink- Enable CPAL audio output (adds [CpalDevice] andCpalSink)std- Enable standard library (enabled by default)
Design Principles
- Lock-free audio thread: No
Arc, noMutexon the hot path - Message passing: Parameters sent via ring buffers, not shared state
- Automatic resampling: Nodes at different sample rates just work
- Fixed block size: 64 samples per block (from dasp_graph)