Crate rundsp

Source
Expand description

§rundsp makes fundsp even more fun

The fundsp crate is a fantastic way to do audio processing in Rust, but actually recording and playing live audio with it requires a certain amount of boilerplate to plug it into an audio I/O backend like cpal.

I want to live in a world where playing a sound could be as simple as this:

use rundsp::fundsp::hacker::*;

rundsp::output(sine_hz(110.0)).run();

§Input and output

And I want it to be just as easy to scale up to simultaneous stereo input and output:

// Let's make it sound like we're in a giant cave
let reverb = reverb2_stereo(20.0, 3.0, 1.0, 0.2, highshelf_hz(1000.0, 1.0, db_amp(-1.0)));
let chorus = chorus(0, 0.0, 0.03, 0.2) | chorus(1, 0.0, 0.03, 0.2);
let effects = chorus >> ((0.8 * reverb) & (0.2 * multipass()));

// Feed the input directly into the output effects
rundsp::mic().output(effects).run();

To contextualize part of what rundsp is doing on your behalf, contrast this with the equivalent example from the fundsp documentation, which requires 150 lines of boilerplate code, using cpal directly to play these 3 lines of effects.

I built rundsp so that I could live in that world today. Maybe you can too!

§What does it do?

  • Stereo, mono, and nullary inputs and outputs: The rundsp interface accepts input audio nodes with 0, 1, or 2 input channels and output audio nodes with 0, 1, or 2 output channels, automatically up- or down-mixing the available channels in the selected audio configuration, and checking at compile-time that the input and output nodes (if both are present) can be plugged into one another with no dangling channels.

  • Automatic configuration with good defaults: It then configures audio backend streams using cpal (see configuration for how to customize this) for the input and output nodes, plugging the output channels of the input into the input channels of the output to form one cohesive pipeline from input to output. If you choose to use only one half of the pipeline, the other half will never be constructed.

  • Error recovery and state-preserving manual restarts: In the event of an error while constructing or running an audio stream, a user-specified retry handler is invoked to determine whether to restart the stream. If you are building an audio application on a platform that can provide notifications of device hotplug events, you can also manually restart one or both ends of the audio pipeline upon notification. Either way, all restarts of either or both ends will re-run the device and configuration selection process and restart the processing pipeline without losing any state.

  • Asynchronous audio control interface: The Running audio pipeline is Send (unlike cpal::Stream), which means it can be used in threads and multi-threaded asynchronous tasks. It exposes an asynchronous (Tokio required) interface to play, pause, restart, and stop the audio, either collectively or one end (input or output) at a time. The Running audio can also be split into a Running<Waited> and Waiting future, which allows commands to be sent to the audio streams concurrently while another task waits for it to complete (either after being stopped or when encountering an error that wasn’t retried).

§Configuration

With rundsp, the defaults are often exactly what you want (they’re lifted from cpal’s configuration defaults), but when they’re not, you can configure precisely what you want about your audio playback:

  • the audio host of the ones supported by the platform,
  • the device for each end of the I/O pipeline,
  • the configuration for each end of the I/O pipeline (including parameters like sample format, sample rate, buffer size, etc.),
  • whether to start paused and require pressing play manually,
  • what to do when the stream encounters an error, including your own arbitrary asynchronous retry policy

§Who is this not for?

This library is intended for use in the Tokio asynchronous runtime, and has not been tested in any other asynchronous runtime. If you need to use another runtime, or if you need a blocking interface, this library does not provide either of those options.

Inputs and outputs are limited by design to stereo inputs and outputs, since beyond stereo sound, there is no general way to correctly map between an arbitrary number of node inputs/outputs and physical device channels. Rather than increasing the interface complexity of the library, we choose to support only mono and stereo devices.

Fundamentally, rundsp is an opinionated and abstracted wrapper around cpal, specialized for use with fundsp audio nodes. It is not generalized over other audio I/O backends, and it seems tricky (though not necessarily impossible!) to achieve this generalization while keeping the simple configuration interface.

Re-exports§

pub use error::Error;
pub use end::End::Input;
pub use end::End::Output;
pub use cpal;
pub use fundsp;

Modules§

error
Errors that can happen when running audio.
run
Details for the configuration of an audio Run, not usually required to be imported.
wait
Futures related to waiting for audio streams to finish.

Structs§

Retry
After an error, should we restart the stream, and if so, when?
Run
The configuration for an audio pipeline.
Running
A running audio pipeline.

Enums§

End
Which end of the audio pipeline are we talking about: the Input or the Output?

Traits§

FromStereo
Channel counts of 0, 1, and 2 can be produced by down-mixing from stereo audio.
StereoInput
An AudioNode which can be used as a stereo input.
StereoOutput
An AudioNode which can be used as a stereo output.
ToStereo
Channel counts of 0, 1, and 2 can be consumed by up-mixing to stereo audio.

Functions§

config
Create a new Run using the given closure to select an audio SupportedStreamConfig.
device
Create a new Run using the given closure to select an audio Device.
host
Create a new Run using a given audio Host.
input
Create a new Run using the given audio node as the input end.
mic
Create a new Run that feeds the microphone’s input directly to the output of the pipeline.
mono_mic
Create a new Run that feeds the microphone’s input directly to the output of the pipeline, as mono audio.
mono_speaker
Create a new Run that feeds the output of the pipeline directly to the speaker (or headphones), as mono audio.
on_error
Create a new Run which will use the given closure to determine how to retry in the event of an error while building or running a stream. See Retrying for more information.
on_input
Create a new Run which will call the given closure every time an input buffer is received.
on_output
Create a new Run which will call the given closure every time an output buffer is produced.
output
Create a new Run using the given audio node as the output end.
speaker
Create a new Run that feeds the output of the pipeline directly to the speaker (or headphones).
start_paused
Create a new Run which will start paused, so that it has to be manually played before audio will happen.
stereo_mic
Create a new Run that feeds the microphone’s input directly to the output of the pipeline, as stereo audio.
stereo_speaker
Create a new Run that feeds the output of the pipeline directly to the speaker (or headphones), as stereo audio.