用于音频处理和合成的库
FunDSP is an audio DSP (digital signal processing) library for audio processing and synthesis.
FunDSP features a powerful inline graph notation for describing audio processing networks. The notation taps into composable, zero-cost abstractions that express the structure of audio networks as Rust types.
Another innovative feature of FunDSP is its signal flow system, which can determine analytic frequency responses for any linear network.
FunDSP comes with a combinator environment containing a suite of audio components, math and utility functions and procedural generation tools.
To discuss FunDSP and other topics, come hang out with us at the Rust Audio Discord.
bevy_fundsp integrates FunDSP into the Bevy game engine.
bevy_procedural_audio is a fork
of bevy_fundsp that is more up to date.
bgawk is a sandbox for playing with physics and sound.
lapis is an interpreter for FunDSP expressions.
midi_fundsp enables the easy creation of live synthesizer software using FunDSP for synthesis.
quartz is a visual programming and DSP playground with releases for Linux, Mac and Windows.
Add fundsp to your Cargo.toml as a dependency.
[dependencies]
fundsp = "0.23.0"
The files feature is enabled by default. It adds support for
loading of audio files into Wave objects
via the Symphonia crate.
The fft feature is also enabled by default.
It adds support for efficient FFT convolutions via the
fft_convolver crate.
FunDSP supports no_std environments. To enable no_std, disable
the feature std, which is enabled by default. The alloc crate
is still needed for components that allocate memory.
Audio file reading and writing is not available in no_std.
The convolution engine is also missing in action, as it depends on rustfft.
[dependencies]
fundsp = { version = "0.23.0", default-features = false }
FunDSP Composable Graph Notation expresses audio networks in algebraic form, using graph operators. It was developed together with the functional environment to minimize the number of typed characters needed to accomplish common audio tasks.
Many common algorithms can be expressed in a natural form
conducive to understanding.
For example, an FM oscillator
can be written simply (for some f and m) as:
sine_hz(f) * f * m + f >> sine()
The above expression defines an audio graph that is compiled into a stack allocated, inlined form using the powerful generic abstractions built into Rust. Connectivity errors are detected during compilation, saving development time.
With no macros needed, the FunDSP graph notation integrates audio DSP tightly into the Rust programming language as a first-class citizen. Native Rust operator precedences work in harmony with the notation, minimizing the number of parentheses needed.
FunDSP graph expressions offer even more economy in being generic over channel arities, which are encoded at the type level. A mono network can be expressed as a stereo network simply by replacing its mono generators and filters with stereo ones, the graph notation remaining the same.
There are two parallel component systems: the static AudioNode and the dynamic AudioUnit.
| Trait | Dispatch | Allocation Strategy | Connectivity |
|---|---|---|---|
AudioNode |
static, inlined | stack | input and output arity fixed at compile time |
AudioUnit |
dynamic, object safe | heap | input and output arity fixed after construction |
All AudioNode and AudioUnit components use 32-bit floating point samples (f32).
The main property of a component in either system is that it is a processing node in a graph with a specific number of input and output connections, called its arity. Audio and control signals flow through input and output connections.
Both systems operate on signals synchronously as an infinite stream. The stream can be
rewound to the start at any time using the reset method.
AudioNodes can be stack allocated for the most part.
Some nodes may use the heap for audio buffers and the like.
The allocate method preallocates all needed memory. It should be called last before
sending something into a real-time context. This is done automatically in
the Net and Sequencer frontends.
The purpose of the AudioUnit system is to grant more flexibility in dynamic situations:
decisions about input and output arities and contents can be deferred to runtime.
AudioNodes are converted to the AudioUnit system
using the wrapper type An, which implements AudioUnit.
Opcodes in the preludes return nodes already wrapped.
AudioUnits can in turn be converted to AudioNode with the wrapper unit.
In this case, the input and output arities must be provided as type-level constants
U0, U1, ..., for example:
use fundsp::prelude32::*;
// The number of inputs is zero and the number of outputs is one.
let type_erased: An> = unit::(Box::new(white() >> lowpass_hz(5000.0, 1.0) >> highpass_hz(1000.0, 1.0)));
Processing samples is easy in both AudioNode and AudioUnit systems.
The tick method is for processing single
sample frames, while the process method processes whole blocks.
If maximum speed is important, then it is a good idea to use block processing, as it reduces function calling, processing setup and dynamic network overhead, and enables explicit SIMD support.
Mono samples can be retrieved with get_mono and filter_mono methods. The get_mono method
returns the next sample from a generator that has no inputs and one or two outputs,
while the filter_mono method filters the next sample from
a node that has one input and one output:
let out_sample = node.get_mono();
let out_sample = node.filter_mono(sample);
Stereo samples can be retrieved with get_stereo and filter_stereo methods.
The get_stereo method returns the next stereo sample pair from a generator that
has no inputs and one or two outputs,
while the filter_stereo method filters the next sample
from a node that has two inputs and two outputs.
let (out_left_sample, out_right_sample) = node.get_stereo();
let (out_left_sample, out_right_sample) = node.filter_stereo(left_sample, right_sample);
The buffer module contains buffers for block processing.
The buffers contain 32-bit float samples. There are two types of owned
buffers: the static BufferArray and the dynamic BufferVec.
Buffers are always 64 samples long (MAX_BUFFER_SIZE),
have an arbitrary number of channels, and are explicitly
SIMD
accelerated with the type f32x8 from the wide crate.
The samples are laid out noninterleaved in a flat array.
BufferArray is an audio buffer backed by an array.
The number of channels is a generic parameter which must be known at compile time.
Using this buffer type it is possible to do block processing without allocating heap memory.
BufferVec is an audio buffer backed by a dynamic vector. The buffer is heap allocated.
The number of channels can be decided at runtime.
…
To call process automatically behind the scenes, use the BlockRateAdapter adapter component.
However, it works only with generators, which are components with no inputs.
To access f32 values in a buffer, use methods with the f32 suffix, for example,
at_f32 or channel_f32.
Of the signals flowing in graphs, some contain audio while others are controls of different kinds.
With control signals and parameters in general, we prefer to use natural units like Hz and seconds. It is useful to keep parameters independent of the sample rate, which we can then adjust as we like.
In addition to sample rate adjustments, natural units enable support for
selective oversampling (with the oversample component)
in nested sections that are easy to configure and modify.
Some low-level components ignore the sample rate by design, such as the single sample delay tick.
The default sample rate is 44.1 kHz.
In both systems, the sample rate can be set for component A, and any children it may have,
via A.set_sample_rate(sample_rate).
FunDSP preludes define convenient combinator environments for audio processing.
There are three name-level compatible versions of the prelude.
The default environment (fundsp::prelude) offers a generic interface.
The 64-bit prelude environment (fundsp::prelude64) for audio hacking
uses 64-bit internal state for components to maximize audio quality.
The 32-bit prelude environment (fundsp::prelude32) uses 32-bit internal
state for components. It aims to offer maximum processing speed.
An application interfacing fundsp can mix and match preludes as needed.
The aims of the environments are:
Minimize the number of characters needed to type to express an idiom.
Keep the syntax clean so that a subset of the prelude environment can be parsed straightforwardly as a high-level DSL for quick prototyping. This has been done in the lapis project.
Make the syntax usable even to people with no prior exposure to programming.
Custom operators are available for combining audio components inline. In order of precedence, from highest to lowest:
| Expression | Meaning | Inputs | Outputs | Notes |
|---|---|---|---|---|
-A |
negate A |
a |
a |
Negates any number of outputs, even zero. |
!A |
thru A |
a |
same as inputs | Passes through extra inputs. |
A * B |
multiply A with B |
a + b |
a = b |
Aka amplification, or ring modulation when both are audio signals. Number of outputs in A and B must match. |
A * constant |
multiply A |
a |
a |
Broadcasts constant. Same applies to constant * A. |
A + B |
sum A and B |
a + b |
a = b |
Aka mixing. Number of outputs in A and B must match. |
A + constant |
add to A |
a |
a |
Broadcasts constant. Same applies to constant + A. |
A - B |
difference of A and B |
a + b |
a = b |
Number of outputs in A |
暂无开放 Issues,或尚未同步最近议题。