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.