Crate oxcable [−] [src]
A signal processing framework for making music with rust.
oxcable
is designed with simple but powerful abstractions, with minimal
performance loss, while functioning in real-time.
oxcable
seeks to provide the basic building blocks necessary to build
digital instruments and effects, and provide the tools to chain these
devices together quickly and easily.
Getting started
Let's start with a simple example. This script will generate a sine wave at 440Hz, and play it on your computer's speakers or headphones in an infinite loop:
extern crate oxcable; use oxcable::chain::{DeviceChain, Tick}; use oxcable::io::audio::AudioEngine; use oxcable::oscillator::{Oscillator, Sine}; fn main() { let engine = AudioEngine::with_buffer_size(256).unwrap(); let mut chain = DeviceChain::from( Oscillator::new(Sine).freq(440.0) ).into( engine.default_output(1).unwrap() ); chain.tick_forever(); }
Devices
Defining an audio device can be done by implenting the
AudioDevice
trait.
Let's define a very simple audio device: one that simply passes its input straight to the output. This can be done in just a few lines:
use oxcable::types::{AudioDevice, Sample, Time}; struct IdentityFilter; impl AudioDevice for IdentityFilter { fn num_inputs(&self) -> usize { 1 } fn num_outputs(&self) -> usize { 1 } fn tick(&mut self, _: Time, inputs: &[Sample], outputs: &mut[Sample]) { outputs[0] = inputs[0]; } }
Once we've defined a device, it is simple to use the device in isolation. Say I want to test my filter. I can manually call tick a few times to generate outputs:
let mut input = [0.0]; let mut output = [0.0]; let mut filter = IdentityFilter; for i in 0..8 { input[0] = i as f32; filter.tick(i, &input, &mut output); assert_eq!(i as f32, output[0]); }
By adhering to the AudioDevice
trait, however, this new device will drop
straight into generic containers like DeviceChain
or
DeviceGraph
, and into wrappers such as the Buffered
wrapper.
oxcable
defines many simple devices itself. A list of these devices may be
found under the AudioDevice
documentation.
Message Passing
To allow modifying audio device parameters while they are inside containers
or processesing in seperate threads, all setter behavior is instead
encapsulated inside a message passing system. Each device has its own
message enum
type that describes the different actions it can handle. The
device then handles those messages by implementing the
MessageReceiver
trait.
Using this trait, setters can be used by calling the handle_message
function and passing the specific message directly to the device.
However, when devices are hidden behind trait objects or used to process in
a seperate thread, there is no way to get to the device to hand it the
message directly. In this case the Messaged
wrapper provides an abstraction using
Rust channels.
Thread Safety
Unfortunately, oxcable
is not able to provide AudioDevice
containers
that are Send
. This is due to a limitation in the rust-portaudio
crate,
in which audio streams are not Send
. This prohibits binding AudioDevice
trait objects with Send
.
Therefore, when using generic containers, the signal chain must be initialized in the thread it will eventually process audio.
Modules
chain |
A container for a series of audio devices. |
error |
Provides a standardized error type for oxcable. |
filters |
Linear IIR filters. |
graph |
A container for audio devices in an acyclic graph. |
io |
Tools for interacting with the outside world. |
level_detector |
An envelope estimator. |
mixers |
Tools for combining several audio signals. |
oscillator |
A antialiasing oscillator. |
tick |
A trait for objects that process in discrete time steps. |
types |
Global types and constants. |
utils |
Utility functions and objects for signal processing. |
voice_array |
A polyphonic voice array. |
wrappers |
Tools for wrapping devices. |