CamillaDSP
CamillaDSP is a powerful and flexible audio processing tool, designed for applications like active crossovers,
room correction, and advanced audio filtering.
The CamillaDSP project encompasses:
- CamillaDSP (the engine): The core DSP engine, written in Rust, responsible for real-time audio processing.
It’s a command-line application that runs on Linux, macOS, and Windows.
It can be used stand-alone, or together with the GUI and other related projects.
The CamillaDSP engine is the topic of this readme.
- CamillaDSP (the ecosystem): A broader family of related projects, including:
- CamillaGUI:
A user-friendly web-based interface for configuring and controlling the CamillaDSP engine.
- camilladsp-setupscripts:
Automated setup scripts.
- pyCamillaDSP:
A Python library for interacting with the CamillaDSP engine via its websocket interface.
- pyCamillaDSP-plot:
A Python library for visualizing CamillaDSP configurations and filter responses.
- camilladsp-config:
A repository of example configurations and scripts for common use cases.
- camilladsp-controller:
A controller for automatic sample rate switching.
CamillaDSP engine v4.1
The CamillaDSP engine is a command-line application that runs on Linux, macOS, and Windows.
Audio data is captured from a capture device and sent to a playback device.
ALSA, PulseAudio, PipeWire, Jack, Wasapi, ASIO and CoreAudio are
currently supported for both capture and playback.
The processing pipeline consists of any number of filters and mixers.
Mixers are used to route audio between channels and to change
the number of channels in the stream.
Filters can be both IIR and FIR. IIR filters are implemented as biquads,
while FIR use convolution via FFT/IFFT.
A filter can be applied to any number of channels.
All processing is done in chunks of a fixed number of samples.
A small number of samples gives a small in-out latency
while a larger number is more efficient.
The full configuration is given in a YAML file.
License
CamillaDSP is free software; you can redistribute it and/or modify it
under the terms of either of the following licenses:
- the GNU General Public License version 3,
available at www.gnu.org
or LICENSE_GPLv3.txt.
- the Mozilla Public License Version 2.0,
available at www.mozilla.org,
or LICENSE_MPL2.0.txt.
ASIO backend and license implications
The optional ASIO backend (asio-backend feature) depends on the ASIO SDK,
which is licensed under the GNU General Public License version 3.
When CamillaDSP is built with the asio-backend feature enabled,
the resulting binary is subject to the GPLv3 license only.
The MPL 2.0 option does not apply to binaries that include ASIO SDK code.
Disclaimer
The software is provided “as is” without any warranty.
You use it entirely at your own risk, and the creators/distributors
are not responsible for any damages that might result from its use or failure.
For more details, please see the GNU General Public License Version 3.0:
- §15. Disclaimer of Warranty
- §16. Limitation of Liability
and the Mozilla Public License Version 2.0:
- §6. Disclaimer of Warranty
- §7. Limitation of Liability
Table of Contents
Introduction
Installing
Building
How to run
Processing audio
Configuration
Related projects
Getting help
Introduction
Background
The purpose of CamillaDSP is to enable audio processing with combinations of FIR and IIR filters.
This functionality is available in EqualizerAPO, but for Windows only.
For Linux the best known FIR filter engine is probably BruteFIR, which works very well but doesn’t support IIR filters.
The goal of CamillaDSP is to provide both FIR and IIR filtering for Linux, Windows and macOS, to be stable, fast and flexible, and be easy to use and configure.
How it works
The audio pipeline in CamillaDSP runs in three separate threads.
One thread handles capturing audio, one handles the playback, and one does the processing in between.
The capture thread passes audio to the processing thread via a message queue.
Each message consists of a chunk of audio with a configurable size.
The processing queue waits for audio messages, processes them in the order they arrive,
and passes the processed audio via another message queue to the playback thread.
There is also a supervisor thread for control.
This chart shows the most important parts:

Capture
The capture thread reads a chunk samples from the audio device in the selected format.
It then converts the samples to 64-bit floats (or optionally 32-bit).
If resampling is enabled, the audio data is sent to the resampler.
At the end, the chunk of samples is packed as a message that is then posted to the input queue of the processing thread.
After this the capture thread returns to reading the next chunk of samples from the device.
Processing
The processing thread waits for audio chunk messages to arrive in the input queue.
Once a message arrives, it’s passed through all the defined filters and mixers of the pipeline.
Once all processing is done, the audio data is posted to the input queue of the playback device.
Playback
The playback thread simply waits for audio messages to appear in the queue.
Once a message arrives, the audio data is converted to the right sample format for the device, and written to the playback device.
The ALSA playback device supports monitoring the buffer level of the playback device.
This is used to send requests for adjusting the capture speed to the supervisor thread, on a separate message channel.
Supervisor
The supervisor monitors all threads by listening to their status messages.
The requests for capture rate adjust are passed on to the capture thread.
It’s also responsible for updating the configuration when requested to do so via the websocket server or a SIGHUP signal.
Websocket server
The websocket server launches a separate thread to handle each connected client.
All commands to change the config are sent to the supervisor thread.
System requirements
CamillaDSP runs on Linux, macOS and Windows.
The exact system requirements are determined by the amount of processing the application requires,
but even relatively weak CPUs like Intel Atom have much more processing power than most will need.
In general, a 64-bit CPU and OS will perform better.
A few examples, done with CamillaDSP v0.5.0:
-
A Raspberry Pi 4 doing FIR filtering of 8 channels, with 262k taps per channel, at 192 kHz.
CPU usage about 55%.
-
An AMD Ryzen 7 2700u (laptop) doing FIR filtering of 96 channels, with 262k taps per channel, at 192 kHz.
CPU usage just under 100%.
Linux requirements
Both 64 and 32 bit architectures are supported.
All platforms supported by the Rustc compiler should work.
Pre-built binaries are provided for:
- x86_64 (almost all PCs)
- armv6 (32-bit arm, for example a Raspberry Pi 1 and Zero)
- armv7 (32-bit arm, for example a Raspberry Pi 2,3,4 with a 32-bit OS)
- aarch64 (64-bit arm, for example Raspberry Pis running a 64 bit OS)
Windows requirements
An x86_64 CPU and the 64-bit version of Windows is recommended.
Any x86_64 CPU will likely be sufficient.
Pre-built binaries are provided for 64-bit systems.
macOS requirements
CamillaDSP can run on both Intel and Apple Silicon macs.
Any reasonably recent version of macOS should work.
Pre-built binaries are provided for both Intel and Apple Silicon
Usage example: crossover for 2-way speakers
A crossover must filter all sound being played on the system.
This is possible by setting up a virtual loopback device
and setting this device as the default output device.
Virtual loopback devices are available for most audio APIs,
either as built-in features or via third-party solutions.
CamillaDSP is then configured to capture from the output of this device
and play the processed audio on the real sound card.
See the tutorial for a step-by-step guide.
Dependencies
These are the key dependencies for CamillaDSP.
These projects are part of the CamillaDSP family:
GUI
CamillaGUI is a user interface for CamillaDSP that is accessed via a web browser.
Installing
The easiest way to install CamillaDSP is to download a pre-built binary.
Binaries for each release are available for the most common systems.
See the “Releases” page.
To see the files click “Assets”.
These are compressed files containing a single executable file that is ready to run.
The following configurations are provided:
| Filename |
Description |
Backends |
camilladsp-linux-amd64.tar.gz |
Linux on 64-bit Intel or AMD CPU |
ALSA |
camilladsp-linux-pulseaudio-amd64.tar.gz |
Linux on 64-bit Intel or AMD CPU |
ALSA, PulseAudio |
camilladsp-linux-pipewire-amd64.tar.gz |
Linux on 64-bit Intel or AMD CPU |
ALSA, PipeWire |
camilladsp-linux-armv6.tar.gz |
Linux on Armv6 (32-bit), intended for Raspberry Pi 1 and Pi Zero but should also work on others |
ALSA |
camilladsp-linux-armv7.tar.gz |
Linux on Armv7 with Neon (32-bit), intended for Raspberry Pi 2 and up but should also work on others |
ALSA |
camilladsp-linux-aarch64.tar.gz |
Linux on Armv8 (64-bit), for example Raspberry Pi 3 and up |
ALSA |
camilladsp-linux-pulseaudio-aarch64.tar.gz |
Linux on Armv8 (64-bit), for example Raspberry Pi 3 and up |
ALSA, PulseAudio |
camilladsp-linux-pipewire-aarch64.tar.gz |
Linux on Armv8 (64-bit), for example Raspberry Pi 3 and up |
ALSA, PipeWire |
camilladsp-macos-amd64.tar.gz |
macOS on 64-bit Intel CPU |
CoreAudio |
camilladsp-macos-aarch64.tar.gz |
macOS on Apple silicon |
CoreAudio |
camilladsp-windows-amd64.zip |
Windows on 64-bit Intel or AMD CPU |
Wasapi |
All builds include the Websocket server.
The .tar.gz-files can be uncompressed with the tar command:
tar -xvf camilladsp-linux-amd64.tar.gz
Running downloaded executables on macOS
If the binary was downloaded using Safari, then macOS most likely won’t allow it to be executed.
Trying will result in an error message such as:
"camilladsp" can't be opened because its integrity cannot be verified.
The solution is to remove the “quarantine” attribute from the binary using the xattr command.
Open a terminal and run:
xattr -d com.apple.quarantine /path/to/camilladsp
Building
Note: This section describes how to compile CamillaDSP from source.
Only do this if you for some reason cannot use any of the pre-built binaries (see Installing).
Use recent stable versions of rustc and cargo. The minimum rustc version is 1.85.
The recommended way to install rustc and cargo is by using the “rustup” tool.
This tool works on all supported platforms (Linux, macOS and Windows). Get it here: https://rustup.rs/
For Windows you also need the “Build Tools for Visual Studio”. Get them from here: https://aka.ms/buildtools
When building on Linux the ALSA backend is always enabled.
Similarly, building on Windows always enables the Wasapi backend.
The optional ASIO backend can be enabled with the asio-backend feature (see Customized build).
And building on macOS always enables the CoreAudio backend.
By default both the PulseAudio and Jack backends are disabled, but they can be enabled if desired.
Leaving them disabled also means that the corresponding system Jack/Pulse packages aren’t needed.
By default the internal processing is done using 64-bit floats.
There is a possibility to switch this to 32-bit floats.
This might be useful for speeding up the processing when running on a 32-bit CPU (or a 64-bit CPU running in 32-bit mode),
but the actual speed advantage has not been evaluated.
Note that the reduction in precision increases the numerical noise.
CamillaDSP includes a Websocket server that can be used to pass commands to the running process.
This feature is enabled by default, but can be left out. The feature name is “websocket”.
For usage see the section “Controlling via websocket”.
Building in Linux with standard features
These instructions assume that the Linux distribution used is one of Fedora, Debian, Ubuntu or Arch.
They should also work on distributions closely related to one of these, such as Manjaro (Arch),
or Raspberry Pi OS (Debian).
There are many others, including some specialized distributions for example targeting audio playback.
These often come with a slimmed down set of preinstalled packages.
Compiling CamillaDSP on one of these may require installing several more packages than the ones listed here.
If possible, it’s recommended to use a pre-built binary on these systems.
- Install pkg-config (very likely already installed):
-
- Fedora:
sudo dnf install pkgconf-pkg-config
-
- Debian/Ubuntu etc:
sudo apt-get install pkg-config
-
- Arch:
sudo pacman -S cargo pkg-config
- Install ALSA dependency:
-
- Fedora:
sudo dnf install alsa-lib-devel
-
- Debian/Ubuntu etc:
sudo apt-get install libasound2-dev
-
- Arch:
sudo pacman -S alsa-lib
- Install OpenSSL dependency:
-
- Fedora:
sudo dnf install openssl openssl-devel
-
- Debian/Ubuntu etc:
sudo apt-get install openssl libssl-dev
-
- Arch:
sudo pacman -S openssl
- Clone the repository
- Build with standard options:
cargo build --release
-
- see below for other options
- The binary is now available at ./target/release/camilladsp
- Optionally install with
cargo install --path .
-
- Note: the
install command takes the same options for features as the build command.
Customized build
All the available options, or “features” are:
pulse-backend: PulseAudio support.
pipewire-backend: Native PipeWire support (Linux only).
cpal-backend: Used for Jack support (automatically enabled when needed).
jack-backend: Jack support (Linux only).
asio-backend: ASIO support (Windows only, requires the ASIO SDK).
threaded-alsa: Experimental ALSA backend implementation (Linux only). When enabled, it replaces the legacy ALSA backend.
bluez-backend: Bluetooth support via BlueALSA (Linux only).
websocket: Websocket server for control.
secure-websocket: Enable secure websocket, also enables the websocket feature.
32bit: Perform all calculations with 32-bit floats (instead of 64).
debug: Enable extra logging, useful for debugging.
The websocket feature is included in the default features, meaning it will be enabled if you don’t specify anything.
Cargo doesn’t allow disabling a single default feature,
but you can disable the whole group with the --no-default-features flag.
Then you have to manually add all the ones you want.
Example 1: You want websocket and pulse-backend. The first one is included by default so you only need to add pulse-backend:
cargo build --release --features pulse-backend
(or)
cargo install --path . --features pulse-backend
Example 2: You want only 32bit. Since you don’t want websocket you have to disable the defaults:
cargo build --release --no-default-features --features 32bit
(or)
cargo install --path . --no-default-features --features 32bit
Additional dependencies
The pulse-backend feature requires PulseAudio and its development files. To install:
- Fedora:
sudo dnf install pulseaudio-libs-devel
- Debian/Ubuntu etc:
sudo apt-get install libpulse-dev
- Arch:
sudo pacman -S libpulse
The jack-backend feature requires jack and its development files. To install:
- Fedora:
sudo dnf install jack-audio-connection-kit jack-audio-connection-kit-devel
- Debian/Ubuntu etc:
sudo apt-get install jack libjack-dev
- Arch:
sudo pacman -S jack
The pipewire-backend feature requires PipeWire and its development files. To install:
- Fedora:
sudo dnf install pipewire-devel
- Debian/Ubuntu etc:
sudo apt-get install libpipewire-0.3-dev
- Arch:
sudo pacman -S pipewire
Optimize for your system
By default Cargo builds for a generic system, meaning the resulting binary might not run as fast as possible on your system.
This means for example that it will not use AVX on an x86-64 CPU, or NEON on a Raspberry Pi.
To make an optimized build for your system, you can specify this in your Cargo configuration file.
Or, just set the RUSTFLAGS environment variable by adding RUSTFLAGS=‘…’ in from of the “cargo build” or “cargo install” command.
Make an optimized build on x86-64:
RUSTFLAGS='-C target-cpu=native' cargo build --release
On a Raspberry Pi also state that NEON should be enabled:
RUSTFLAGS='-C target-feature=+neon -C target-cpu=native' cargo build --release
Building on Windows and macOS
The platform-specific backends are always enabled when building on Windows and macOS. The recommended build command is:
macOS:
RUSTFLAGS='-C target-cpu=native' cargo build --release
Windows (cmd.exe command prompt):
set RUSTFLAGS=-C target-cpu=native
cargo build --release
Windows (PowerShell):
$env:RUSTFLAGS="-C target-cpu=native"
cargo build --release
The PulseAudio backend can be used on macOS.
The necessary dependencies can be installed with brew:
brew install pkg-config
brew install pulseaudio
Building with ASIO backend (Windows)
To build CamillaDSP with ASIO support, enable the asio-backend feature.
This uses the asio-sys crate, which generates bindings via bindgen.
The ASIO SDK is downloaded/extracted automatically during the build,
so you normally do not need to download it manually.
Before building, ensure bindgen requirements are met:
- Install LLVM/Clang (Clang 9.0+). On Windows with winget:
- In most setups you do not need to set
LIBCLANG_PATH manually.
Keep this as a reference in case bindgen cannot find libclang:
- PowerShell:
$env:LIBCLANG_PATH="C:\\Program Files\\LLVM\\bin"
- cmd.exe:
set LIBCLANG_PATH=C:\Program Files\LLVM\bin
Reference: rust-bindgen requirements
Build command:
cargo build --release --features asio-backend
After a successful build, the binary is available at target/release/camilladsp.exe.
How to run
The command is simply:
camilladsp /path/to/config.yml
This starts the processing defined in the specified config file.
The config is first parsed and checked for errors.
This first checks that the YAML syntax is correct, and then checks that the configuration is complete and valid.
When an error is found it displays an error message describing the problem.
See more about the configuration file below.
Command line options
Starting with the --help flag prints a short help message:
> camilladsp --help
CamillaDSP v3.0.0
Henrik Enquist <[email protected]>
A flexible tool for processing audio
Built with features: websocket
Supported device types:
Capture: RawFile, WavFile, Stdin, SignalGenerator, CoreAudio
Playback: File, Stdout, CoreAudio
Usage: camilladsp [OPTIONS] [CONFIGFILE]
Arguments:
[CONFIGFILE] The configuration file to use
Options:
-c, --check Check config file and exit
-s, --statefile <STATEFILE> Use the given file to persist the state
-v... Increase message verbosity
-l, --loglevel <LOGLEVEL> Set log level [possible values: trace, debug, info, warn, error, off]
-o, --logfile <LOGFILE> Write logs to the given file path
--log_rotate_size <ROTATE_SIZE> Rotate log file when the size in bytes exceeds this value
--log_keep_nbr <KEEP_NBR> Number of previous log files to keep
-a, --address <ADDRESS> IP address to bind websocket server to
-p, --port <PORT> Port for websocket server
-w, --wait Wait for config from websocket
-g, --gain <GAIN> Initial gain in dB for main volume control
--gain1 <GAIN1> Initial gain in dB for Aux1 fader
--gain2 <GAIN2> Initial gain in dB for Aux2 fader
--gain3 <GAIN3> Initial gain in dB for Aux3 fader
--gain4 <GAIN4> Initial gain in dB for Aux4 fader
-m, --mute Start with main volume control muted
--mute1 Start with Aux1 fader muted
--mute2 Start with Aux2 fader muted
--mute3 Start with Aux3 fader muted
--mute4 Start with Aux4 fader muted
-e, --extra_samples <EXTRA_SAMPLES> Override number of extra samples in config
-n, --channels <CHANNELS> Override number of channels of capture device in config
-r, --samplerate <SAMPLERATE> Override samplerate in config
-f, --format <FORMAT> Override sample format of capture device in config [possible values: S16_LE, S24_3_LE, S24_4_LJ_LE, S24_4_RJ_LE, S32_LE, F32_LE, F64_LE]
-h, --help Print help
-V, --version Print version
Most flags and options have a long and a short form. For example --port 1234 and -p1234 are equivalent.
If the --check flag is given, the program will exit after checking the configuration file.
Use this if you only want to verify that the configuration is ok, and not start any processing.
Logging
The default logging setting prints messages of levels “error”, “warn” and “info”.
This can be changed with the loglevel option.
Setting this to for example warn will print messages of level warn and above, but suppress the lower levels of info, debug and trace.
Alternatively, the log level can be changed with the verbosity flag.
By passing the verbosity flag once, -v, debug messages are enabled.
If it’s given twice, -vv, it also prints trace messages.
The option custom_log_spec can be used to define custom filters for the logs.
When provided, this option overrides what is given by -v and --loglevel.
Using this option, the log level can be set to different values for different modules.
Example, set the base log level to info, but increase it to trace for the
Wasapi backend (which is the camillalib::wasapidevice module):
--custom_log_spec="info, camillalib::wasapidevice=trace
Module names are shown in square brackets in the log messages.
See the flexi-logger documentation
for more info on how to write the logger specification.
The log messages are normally written to the terminal via stderr,
but they can instead be written to a file by giving the --logfile option.
The argument should be the path to the logfile.
If this file is not writable, CamillaDSP will panic and exit.
Log rotation can be enabled by the --log_rotate_size option.
This creates a new log file whenever the log file size exceeds the given size in bytes.
When rotation is enabled the current log file gets an added infix of _rCURRENT,
so for example logfile.log becomes logfile_rCURRENT.log.
When the file is rotated, the old logs are kept with a timestamp as infix,
for example logfile_r2023-01-29_12-59-00.log.
The default is to keep all previous log files,
but this can be limited by setting the --log_keep_nbr option to the desired number.
Persistent storage of state
The --statefile option is used to give a path to a file where CamillaDSP will save the config file path, and the volume and mute settings.
On startup, these values will be read from the statefile if the file exists and is valid.
The values in the file will then be kept updated whenever they change.
If the file doesn’t exist, it will be created on the first write.
If the configfile argument is given, then this will be used instead of the value from the statefile.
Similarly, the --gain and --mute options also override the values in the statefile for the main fader
while the --gain1 to --gain4 and --mute1 to --mute4 do the same for the Aux faders.
Use this feature with caution! The volume setting given in the statefile will be applied immediately when CamillaDSP starts processing.
In systems that have a gain structure such that a too high volume setting can damage equipment or ears,
it is recommended to always use the --gain and --gain1..4 options to set the volume to start at a safe value.
Example statefile
The statefile is a small YAML file that holds the path to the active config file,
as well as mute and volume settings for the five faders (Main and Aux1 to Aux4)
---
config_path: /path/to/config.yml
mute:
- false
- false
- false
- false
- false
volume:
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
Websocket
To enable the websocket server, provide a port number with the --port option. Leave it out, or give 0 to disable.
By default the websocket server binds to the address 127.0.0.1 which means it’s only accessible locally (to clients running on the same machine).
If it should be also available to remote machines, give the IP address of the interface where it should be available with the --address option.
Giving 0.0.0.0 will bind to all interfaces.
If CamillaDSP was built with the “secure-websocket” feature, it has two additional options --cert and --pass.
These are used to provide an identity, to enable secure websocket connections.
See the websocket readme for more details.
If the “wait” flag, --wait is given, CamillaDSP will start the websocket server and wait for a configuration to be uploaded.
Then the config file argument must be left out.
Overriding config values
There are a few options to override values in the loaded config file.
Giving these options means the provided values will be used instead of the values in any loaded configuration.
To change the values, CamillaDSP has to be restarted.
If the config file has resampling disabled, then overriding the samplerate will change the samplerate parameter.
But if resampling is enabled, it will instead change the capture_samplerate parameter.
If then enable_rate_adjust is false and capture_samplerate=samplerate, then resampling will be disabled.
When overriding the samplerate, two other parameters are scaled as well.
Firstly, the chunksize is multiplied or divided by integer factors to try to keep the pipeline running at a constant number of chunks per second.
Secondly, the value of extra_samples is scaled to give the extra samples the same duration at the new samplerate.
But if the extra_samples override is used, the given value is used without scaling it.
Initial volume
The --gain and --gain1..4 options can accept negative values,
but this requires a little care since the minus sign can be misinterpreted as another option.
It works as long as there is no space in front of the minus sign.
These all work for positive values (with 12.3 dB used as an example):
-g12.3
--gain=12.3
-g 12.3
--gain 12.3
These work for negative values (note that there is no space before the minus sign):
-g-12.3
--gain=-12.3
These have a space before the minus sign and do NOT work:
-g -12.3
--gain -12.3
Exit codes
These are the exit codes CamillaDSP will give:
| Exit code |
Meaning |
| 0 |
Normal exit, no error |
| 101 |
Invalid config file, see the error message for details |
| 102 |
Error from DSP process, see the error message for details |
| 103 |
Forced exit by a second SIGINT before before a normal exit was completed |
Reloading the configuration
The configuration can be reloaded without restarting by sending a SIGHUP to the camilladsp process.
This will reload the config and if possible apply the new settings without interrupting the processing.
Note that for this to update the coefficients for a FIR filter, the filename of the coefficients file needs to change.
Controlling via websocket
See the separate readme for the websocket server
Processing audio
The goal is to insert CamillaDSP between applications and the sound card.
The details of how this is achieved depends on which operating system and which audio API is being used.
It is also possible to use pipes for apps that support reading or writing audio data from/to stdout.
These backends are supported on all platforms.
File or pipe
Audio can be read from a file or a pipe using the RawFile device type.
This can read raw interleaved samples in most common formats.
To instead read from stdin, use the Stdin type.
This makes it possible to pipe raw samples from some applications directly to CamillaDSP,
without going via a virtual soundcard.
Wav files can be read using the WavFile device type.
See the capture device section for more details.
Jack
Jack is most commonly used with Linux, but can also be used with both Windows and MacOS.
The Jack support of CamillaDSP version should be considered experimental.
It is implemented using the CPAL library, which currently only supports Jack on Linux.
Using Jack
The Jack server must be running.
Set device to “default” for both capture and playback.
The sample format is fixed at 32-bit float.
The samplerate must match the samplerate configured for the Jack server.
CamillaDSP will show up in Jack as “cpal_client_in” and “cpal_client_out”.
Windows
See the separate readme for Wasapi.
ASIO
The ASIO backend is an optional alternative audio backend for Windows.
It provides low-latency access to audio devices via ASIO drivers.
To use it, CamillaDSP must be compiled with the asio-backend feature enabled.
Note that the ASIO backend is licensed under GPLv3 only,
due to the ASIO SDK license requirements.
See the ASIO backend and license implications
section for details.
Set the device type to Asio for both capture and playback.
The device parameter should be set to the name of the ASIO driver to use.
Available ASIO drivers are listed in the log output at startup (at debug level).
Note that ASIO exposes drivers rather than actual device availability,
so drivers for disconnected or powered‑off devices are still included
in the listing.
Set the channels property to the number of channels you want to use.
The value may be lower than the number of channels the device provides,
any channels above the specified count are simply ignored.
The supported sample formats are:
S16_LE - 16-bit signed integer
S24_4_LE - 24-bit signed integer (in 32-bit container)
S24_3_LE - 24-bit signed integer (packed 3-byte)
S32_LE - 32-bit signed integer
F32_LE - 32-bit float
F64_LE - 64-bit float
If the format parameter is omitted, CamillaDSP will query the device
for its native sample format and use it automatically.
ASIO drivers do not perform sample format conversion,
so if a format is specified it must match the device’s native format.
A mismatch will result in an error at startup.
Full-duplex limitations
When both capture and playback use the ASIO backend,
CamillaDSP operates them in full-duplex mode
through a single shared driver instance. This implies:
- Same device: Capture and playback must specify the same ASIO driver name.
ASIO only supports one driver loaded at a time.
- Same sample rate: Resampling is not supported in full-duplex ASIO mode.
Both directions share the same hardware clock,
so
capture_samplerate must equal samplerate
and no resampler should be configured.
Example configuration:
capture:
type: Asio
channels: 2
device: "My ASIO Driver"
format: S32_LE
playback:
type: Asio
channels: 2
device: "My ASIO Driver"
format: S32_LE
MacOS (CoreAudio)
See the separate readme for CoreAudio.
Linux
Linux offers several audio APIs that CamillaDSP can use.
ALSA
See the separate readme for ALSA.
PulseAudio
PulseAudio provides a null-sink that can be used to capture audio from applications. To create a null sink type:
pacmd load-module module-null-sink sink_name=MySink
This device can be set as the default output, meaning any application using PulseAudio will use it.
The audio sent to this device can then be captured from the monitor output named “MySink.monitor”.
All available sinks and sources can be listed with the commands:
pacmd list-sinks
pacmd list-sources
PipeWire
Native PipeWire backend
CamillaDSP has native PipeWire support via the pipewire-backend feature.
This creates filter nodes in the PipeWire graph that can be connected to other nodes using WirePlumber rules or tools like Helvum.
See backend_pipewire.md for configuration details.
Using PipeWire via PulseAudio or Jack compatibility
PipeWire implements both the PulseAudio and Jack APIs.
CamillaDSP can therefore also be used with PipeWire via the Pulse and Jack backends.
PipeWire supports creating null-sinks like PulseAudio. Create one with:
pactl load-module module-null-sink sink_name=MySink object.linger=1 media.class=Audio/Sink
List sources and sinks with:
pw-cli ls Node
This will list all devices, and the null-sink should be included like this:
id 75, type PipeWire:Interface:Node/3
factory.id = "18"
node.description = "MySink Audio/Sink sink"
node.name = "MySink"
media.class = "Audio/Sink"
This device can be set as the default output in the Gnome sound settings, meaning all desktop audio will use it.
The audio sent to this device can then be captured from the monitor output named “MySink.monitor” using the PulseAudio backend.
To configure PipeWire so that this null-sink is loaded on startup, create the file /usr/share/pipewire/pipewire-pulse.conf.d/camilladsp-sink.conf containing:
pulse.cmd = [
{ cmd = "load-module" args = "module-null-sink sink_name=MySink object.linger=1 media.class=Audio/Sink" flags = [ ] }
]
PipeWire can also be configured to output to an ALSA Loopback.
This is done by adding an ALSA sink in the PipeWire configuration.
This sink then becomes available as an output device in the Gnome sound settings.
See the “camilladsp-config” repository under Related projects for an example PipeWire configuration.
TODO test with Jack.
BlueALSA
BlueALSA (bluez-alsa) is a project to receive or send audio through Bluetooth A2DP.
The Bluez source will connect to BlueALSA via D-Bus to get a file descriptor.
It will then read the audio directly from there, avoiding the need to go via ALSA.
Currently only capture (a2dp-sink) is supported.
BlueALSA is supported on Linux only, and requires building CamillaDSP with the bluez-backend Cargo feature.
Prerequisites
Start by installing bluez-alsa.
Both PipeWire and PulseAudio will interfere with BlueALSA and must be disabled.
The source device should be paired after disabling PipeWire or PulseAudio and enabling BlueALSA.
Configuration
Example configuration:
devices:
samplerate: 44100
chunksize: 4096
target_level: 8000
adjust_period: 3
resampler:
type: AsyncSinc
profile: Balanced
enable_rate_adjust: true
capture:
type: Bluez
format: S16_LE
channels: 2
dbus_path: /org/bluealsa/hci0/dev_A0_B1_C2_D3_E4_F5/a2dpsnk/source
service: org.bluealsa (*)
After connecting an A2DP device, for example a mobile phone, the D-Bus path can be found with this command:
gdbus call -y --dest org.bluealsa -o /org/bluealsa -m org.freedesktop.DBus.ObjectManager.GetManagedObjects
This should produce output similar to this:
({objectpath '/org/bluealsa/hci0/dev_A0_B1_C2_D3_E4_F5/a2dpsnk/source': {'org.bluealsa.PCM1': {'Device': <objectpath '/org/bluez/hci0/dev_A0_B1_C2_D3_E4_F5'>, 'Sequence': <uint32 0>, 'Transport': <'A2DP-sink'>, 'Mode': <'source'>, 'Format': <uint16 33296>, 'Channels': <byte 0x02>, 'Sampling': <uint32 44100>, 'Codec': <'AAC'>, 'CodecConfiguration': <[byte 0x80, 0x01, 0x04, 0x03, 0x5b, 0x60]>, 'Delay': <uint16 150>, 'SoftVolume': <true>, 'Volume': <uint16 32639>}}},)
The wanted path is the string after objectpath.
If the output is looking like (@a{oa{sa{sv}}} {},), then no A2DP source is connected or detected.
Connect an A2DP device and try again. If a device is already connected, try removing and pairing the device again.
The service property can be left out to get the default. This only needs changing if there is more than one instance of BlueALSA running.
You have to specify correct capture sample rate, number of channel and sample format.
These parameters can be found with bluealsa-aplay:
> bluealsa-aplay -L
bluealsa:DEV=A0:B1:C2:D3:E4:F5,PROFILE=a2dp,SRV=org.bluealsa
MyPhone, trusted phone, capture
A2DP (AAC): S16_LE 2 channels 44100 Hz
Note that Bluetooth transfers data in chunks, and the time between chunks can vary.
To avoid underruns, use a large chunksize and a large target_level.
The values in the example above are a good starting point.
Rate adjust should also be enabled.
Configuration
CamillaDSP is using the YAML format for the configuration file.
It is a standard format that was chosen because of its nice readable syntax.
This section is a very brief introduction to the YAML format
that is intended to cover only what is needed to read and write CamillaDSP config files.
Please see the full YAML specification for more details.
There are a few things to keep in mind with YAML.
The configuration is a tree, and the level is determined by the indentation level.
For YAML the indentation is as important as opening and closing brackets in other formats.
If it’s wrong, Serde might not be able to give a good description of what the error is, only that the file is invalid.
If you get strange errors, first check that the indentation is correct.
Also check that you only use spaces and no tabs.
Many text editors can help by highlighting syntax errors in the file.
The items at each level of the tree can be placed in any order. Consider the following example:
filters:
example_fir_a:
type: Conv
parameters:
filename: path/to/filter.txt <
format: TEXT <-- "filename", "format" and "type" can be in any order as long as they are properly indented to be part of the "parameters" block.
type: Raw <
example_fir_b:
parameters: <-- "parameters" can be placed before or after "type".
type: Wav
filename: path/to/filter.wav
type: Conv
mixers:
mono:
mapping:
- dest: 0
sources:
- channel: 0
gain: -6
- gain: -6 <-- The order of "gain" and "channel" can be reversed.
channel: 1 <
channels:
out: 1
in: 2
On the root level it contains filters and mixers. The mixers section could just as well be placed before the filters.
Looking at filters, the second filter swaps the order of parameters and type. Both variants are valid.
The mixer example shows that the gain and channel properties can be ordered freely.
Variable types
CamillaDSP uses values of several different types. The most basic are string, number and boolean.
| Expression |
Type |
value: 123 |
an integer, also acceptable for a parameter expecting a float |
value: "123" |
a string, because of the added quotes |
value: 123.0 |
a float |
value: 1.23e2 |
a float in scientific notation, also uppercase E is accepted |
value: true |
a boolean true, also accepts True and TRUE |
value: false |
a boolean false, also accepts False and FALSE |
value: Some text |
a string, written without quotes |
value: "Some text" |
a string, written with quotes |
value: null |
a null value, also accepts Null, NULL, ~ and empty |
Some parameters expect a list. These can be written inline or on multiple rows:
---
values_a: [ 1, 2, 3, 4, 5 ]
values_b:
- 1
- 2
- 3
- 4
- 5
Title and description
There are two properties that are used to name and describe the configuration file. They are both optional.
title: "Example"
description: "Example description of a configuration"
Both these properties are optional and can be set to null or left out.
The title property is intended for a short title, while description can be longer and more descriptive.
Volume control
There is a volume control that is enabled regardless of what configuration file is loaded.
CamillaDSP defines a total of five control “channels” for volume called “faders”.
The default volume control reacts to the Main fader.
When the volume or mute setting is changed, the gain is smoothly ramped to the new setting.
The duration of this ramp can be customized via the volume_ramp_time parameter
in the devices section.
The value must not be negative. If left out or set to null, it defaults to 400 ms.
The range of the volume control can be limited.
Set the volume_limit to the desired maximum volume value.
This setting is optional. If left out or set to null, it defaults to +50 dB.
In addition to this, there are four additional control channels, named Aux1 to Aux4.
These can be used to implement for example a separate volume control for a headphone output,
or crossfading between different input channels.
Devices
Example config:
devices:
samplerate: 96000
chunksize: 2048
queuelimit: 4 (*)
silence_threshold: -60 (*)
silence_timeout: 3.0 (*)
target_level: 500 (*)
adjust_period: 10 (*)
enable_rate_adjust: true (*)
resampler: null (*)
capture_samplerate: 44100 (*)
stop_on_rate_change: false (*)
rate_measure_interval: 1.0 (*)
volume_ramp_time: 400.0 (*)
volume_limit: -12.0 (*)
multithreaded: false (*)
worker_threads: 4 (*)
capture:
type: Pulse
channels: 2
device: "MySink.monitor"
labels: ["L", "R"] (*)
playback:
type: Alsa
channels: 2
device: "hw:Generic_1"
format: S32_LE
A parameter marked (*) in any example is optional. If they are left out from the configuration, or set to null, their default values will be used.
-
samplerate
The samplerate setting decides the sample rate that everything will run at.
This rate must be supported by both the capture and playback device.
-
chunksize
All processing is done in chunks of data.
The chunksize is the number of samples each chunk will have per channel.
Suggested starting points for different sample rates:
- 44.1 or 48 kHz: 1024
- 88.2 or 96 kHz: 2048
- 176.4 or 192 kHz: 4096
The duration in seconds of a chunk is chunksize/samplerate,
so the suggested values corresponds to about 22 ms per chunk.
This is a reasonable value.
A larger chunk size generally reduces CPU usage,
but since the entire chunk must be captured before processing,
it can cause unacceptably long delays.
Conversely, using a smaller chunk size can reduce latency
but will increase CPU usage.
Additionally, the shorter duration of each chunk makes CamillaDSP
more vulnerable to disruptions from other system activities,
potentially causing buffer underruns.
Choosing chunk size for best performance
FIR filters are automatically padded as needed,
so there is no need match chunk size and filter length.
CamillaDSP uses FFT for convolution, with an FFT length of 2 * chunksize.
Therefore, the chunk size should be chosen for optimal FFT performance.
Using a power of two for the chunk size is ideal for best performance.
The FFT also works well with numbers that can be expressed as products
of small primes, like 2^4 * 3^3 = 1296.
Avoid using prime numbers, such as 1297,
or numbers with large prime factors, like 29 * 43 = 1247.
Long FIR filters
When a FIR filter is longer than the chunk size, the convolver uses segmented convolution.
The number of segments is calculated as filter_length / chunk size,
and rounded up to the nearest integer.
Using a smaller chunk size (i.e. more segments) reduces latency
but makes the convolution process less efficient and thus needs more processing power.
Although a smaller chunk size leads to increased CPU usage for all filters,
the difference is larger for FIR filters than the other types.
If you have long FIR filters, try different chunk sizes
to find the best balance between latency and processing power.
When increasing the chunk size, try doubling it, like going from 1024 to 2048 or 4096 to 8192.
-
queuelimit (optional, defaults to 4)
The field queuelimit should normally be left out to use the default of 4.
It sets the limit for the length of the queues between the capture device and the processing thread,
as well as between the processing thread and the playback device.
The total queue size limit will be 2*chunksize*queuelimit samples per channel.
The value should only be changed if the capture device can provide data faster
than the playback device can play it, like when using the ALSA “cdsp” plugin.
If this case, set queuelimit to a low value like 1.
-
enable_rate_adjust (optional, defaults to false)
This enables correction of long-term clock drift between the capture device and playback device,
which can otherwise cause underruns or steadily changing delay when clocks are independent.
This is supported when using an ALSA, Wasapi, CoreAudio, PipeWire or ASIO playback device
(with any capture device).
CamillaDSP uses virtual clock tuning when available, otherwise async resampling,
and if neither method is available then rate adjust is disabled.
See also Rate adjust: what problem it solves, and how it works.
-
target_level (optional, defaults to the chunksize value)
The value is the number of samples that should be left
in the buffer of the playback device when the next chunk arrives.
When processing starts, the playback device will delay its startup
in order to get the initial buffer level near this value.
See also enable_rate_adjust which should be set to true to allow matching
capture and playback rates in order to keep the buffer level at the target value.
For details on how this value is used during drift correction,
see Rate adjust: what problem it solves, and how it works.
It may take some experimentation to find the optimal number.
If it’s too small there will be buffer underruns from time to time,
and making it too large increases end-to-end delay (capture input to playback output).
A suitable starting point is to use the chunksize value.
Usable values cover a large range, from very small values like 30 on lightly loaded systems
with tight latency requirements,
to a maximum of (2 + queuelimit) * chunksize for minimal underrun risk when latency is not a concern.
-
adjust_period (optional, defaults to 10)
The adjust_period parameter is used to set the interval between corrections, in seconds.
The default is 10 seconds. Only applies when enable_rate_adjust is set to true.
A smaller value reacts faster but can be less smooth,
while a larger value is steadier but slower to react.
Faster reaction can be useful if there are occasional
buffer underruns when running with a small target_level to minimize delay.
See Rate adjust: what problem it solves, and how it works
for how these periodic corrections are computed and applied.
-
silence_threshold & silence_timeout (optional)
The fields silence_threshold and silence_timeout are optional
and used to pause processing if the input is silent.
The threshold is the threshold level in dB, and the level is calculated as the difference
between the minimum and maximum sample values for all channels in the capture buffer.
0 dB is full level. Some experimentation might be needed to find the right threshold.
The silence_timeout (in seconds) is for how long the signal should be silent before pausing processing.
Set this to zero, or leave it out, to never pause.
-
resampler (optional, defaults to null)
Use this to configure a resampler. Setting it to null or leaving it out disables resampling .
Configure a resampler to enable resampling of the input signal.
In addition to resampling the input to a different sample rate,
this can be useful for rate-matching capture and playback devices with independent clocks.
See the Resampling section for more details.
-
capture_samplerate (optional, defaults to null)
The capture samplerate. Setting it to null sets the capture samplerate to the same value as samplerate.
If the resampler is only used for rate-matching, then the capture samplerate
is the same as the overall samplerate, and this setting can be left out.
-
stop_on_rate_change and rate_measure_interval (both optional)
Setting stop_on_rate_change to true makes CamillaDSP stop the processing
if the measured capture sample rate changes.
Default is false.
The rate_measure_interval setting is used for adjusting the measurement period.
A longer period gives a more accurate measurement of the rate, at the cost of slower response when the rate changes.
The default is 1.0 seconds.
Processing will stop after 3 measurements in a row are more than 4% off from the configured rate.
The value of 4% is chosen to allow some variation, while still catching changes between for example 44.1 to 48 kHz.
-
volume_ramp_time (optional, defaults to 400 ms)
This setting controls the duration of this ramp when changing volume of the default volume control.
The value must not be negative. If left out or set to null, it defaults to 400 ms.
-
multithreaded and worker_threads (optional, defaults to false and automatic)
Setting multithreaded to true enables multithreaded processing.
When this is enabled, CamillaDSP creates several filtering tasks by grouping the filters for each channel.
These tasks are then sent to a thread pool, where multiple threads are ready to pick up the work.
On a machine with multiple CPU cores, this allows filters to be processed in parallel,
potentially boosting performance.
Once all tasks are completed, the results are returned to the main processing thread.
However, Mixers and Processors, which work on all channels in the pipeline,
cannot be parallelized and are processed in the main thread.
Therefore, only the filters between mixers and/or processors can be parallelized.
Multithreaded processing is beneficial for configurations that require significant processing power,
such as using very long FIR filters, high sample rates, or a large number of channels.
It should only be enabled if necessary, as it typically should remain disabled.
Synchronizing with worker threads adds some overhead, increasing overall CPU usage.
It also makes CamillaDSP more susceptible to other processes using the CPU,
which may cause buffer underruns.
An exception to this recommendation is when both the input and output are files on disk,
allowing processing to run faster than real time.
In this scenario, multithreading is likely to improve throughput and should usually be enabled.
The number of worker threads can be set manually using the worker_threads setting.
If left out or set to zero, it defaults to one worker thread per hardware thread of the machine.
-
capture and playback
Input and output devices are defined in the same way.
A device needs:
-
type:
The available types depend on which features that were included when compiling. All possible types are:
RawFile (capture only)
WavFile (capture only)
File (playback only)
SignalGenerator (capture only)
Stdin (capture only)
Stdout (playback only)
Bluez (capture only)
Jack
Wasapi
Asio
CoreAudio
Alsa
Pulse
-
channels: number of channels
-
device: device name (for Alsa, Pulse, Wasapi, Asio, CoreAudio).
For CoreAudio and Wasapi, null will give the default device.
For Asio, use the ASIO driver name.
-
filename path to the file (for File, RawFile and WavFile)
-
format: sample format (for all except Jack and Pulse).
The available choices for format depend on the backend.
For File, Stdin, Stdout RawFile and Bluez, the choices are signed
little-endian integers of 16, 24 and 32 bits as well as floats of 32 and 64 bits:
For ALSA, CoreAudio, Wasapi and ASIO, see the respective backend documentation.
Note that there are three different 24-bit formats! Make sure to select the correct one.
File, RawFile, WavFile, Stdin, Stdout
The RawFile device type reads from a file, while Stdin reads from stdin.
File and Stdout writes to a file and stdout, respectively.
The format is raw interleaved samples, in the selected sample format.
If the capture device reaches the end of a file, the program will exit once all chunks have been played.
That delayed sound that would end up in a later chunk will be cut off.
To avoid this, set the optional parameter extra_samples for the File capture device.
This causes the capture device to yield the given number of samples (per channel) after reaching end of file,
allowing any delayed sound to be played back.
The Stdin capture device and Stdout playback device use stdin and stdout, so it’s possible
to easily pipe audio between applications:
> camilladsp stdio_capt.yml > rawfile.dat
> cat rawfile.dat | camilladsp stdio_pb.yml
Note: On Unix-like systems it’s also possible to use the File device
and set the filename to /dev/stdin for capture, or /dev/stdout for playback.
The File and Stdout playback devices can write a wav-header to the output.
Enable this by setting wav_header to true.
Setting it to false, null, or leaving it out disables the wav header.
This is a streaming header, meaning it contains a dummy value for the file length.
Most applications ignore this and calculate the correct length from the file size.
The wav format does not support right justified padded data, and therefore it is not
possible to enable the wav-header if the format is S24_4_RJ_LE.
To read from a wav file, use the WavFile capture device.
The samplerate and number of channels of the file is used to override the values in the config,
similar to how these values can be overridden from the command line.
Note that WavFile only supports reading from files. Reading from a pipe is not supported.
Example config for raw files:
capture:
type: RawFile
channels: 2
filename: "/path/to/inputfile.raw"
format: S16_LE
extra_samples: 123 (*)
skip_bytes: 0 (*)
read_bytes: 0 (*)
playback:
type: File
channels: 2
filename: "/path/to/outputfile.raw"
format: S32_LE
Example config for Stdin/Stdout:
capture:
type: Stdin
channels: 2
format: S16_LE
extra_samples: 123 (*)
skip_bytes: 0 (*)
read_bytes: 0 (*)
playback:
type: Stdout
channels: 2
format: S32_LE
Example config for wav input and output:
capture:
type: WavFile
filename: "/path/to/inputfile.wav"
playback:
type: File
channels: 2
format: S32_LE
wav_header: true
filename: "/path/to/outputfile.wav"
The RawFile and Stdin capture devices support two additional optional parameters,
for advanced handling of raw files and testing:
-
skip_bytes: Number of bytes to skip at the beginning of the file or stream.
This can be used to skip over the header of some formats like .wav
(which often has a 44-byte header).
Leaving it out or setting to zero means no bytes are skipped.
-
read_bytes: Read only up until the specified number of bytes.
Leave it out or set it to zero to read until the end of the file or stream.
-
Example, this will skip the first 50 bytes of the file (index 0-49)
and then read the following 200 bytes (index 50-249).
skip_bytes: 50
read_bytes: 200
The SignalGenerator capture device is intended for testing.
It accepts the number of channels as channels.
It also requires a block defining the signal properties, called signal.
The signal shape is give by type, which accepts Sine, Square and WhiteNoise.
All types require the signal level, which is given in dB in the level parameter.
Sine and Square also require a frequency, defined by the freq parameter.
When using the SignalGenerator, the resampler config and capture samplerate are ignored.
The same signal is generated on every channel.
Example config for sine wave at 440 Hz and -20 dB:
capture:
type: SignalGenerator
channels: 2
signal:
type: Sine
freq: 440
level: -20.0
Example config for white noise ad -10 dB:
capture:
type: SignalGenerator
channels: 2
signal:
type: WhiteNoise
level: -10.0
Wasapi
See the separate readme for Wasapi.
Alsa
See the separate readme for ALSA.
CoreAudio
See the separate readme for CoreAudio.
Pulse
The Pulse capture and playback devices have no advanced options.
Example config for Pulse:
capture:
type: Pulse
channels: 2
device: "MySink.monitor"
playback:
type: Pulse
channels: 2
device: "alsa_output.pci-0000_03_00.6.analog-stereo"
Jack
The Jack capture and playback devices do not have a format parameter, since they always uses the F32_LE format.
It seems that the device property should always be set to “default”.
This parameter may be removed in a future version.
Example config for Jack:
capture:
type: Jack
channels: 2
device: "default"
playback:
type: Jack
channels: 2
device: "default"
Channel labels
All capture device types have an optional labels property.
This accepts a list of strings, and is meant to be used by a GUI
to display meaningful channel names.
CamillaDSP itself does not use these labels.
Resampling
Resampling is provided by the Rubato library.
This library does asynchronous and synchronous resampling with adjustable parameters.
Asynchronous resampling can be done with or without anti-aliasing.
Resampler configuration
The resampler section under devices is used to specify the resampler.
Example:
resampler:
type: AsyncSinc
profile: Balanced
The resampler type is given by type, and the available options are:
- AsyncSinc
- AsyncPoly
- Synchronous
The types AsyncPoly and AsyncSinc need additional parameters, see each type below for details.
AsyncSinc: Asynchronous resampling with anti-aliasing
For asynchronous resampling with anti-aliasing, the overall strategy is to use a sinc interpolation filter
with a fixed oversampling factor,
and then use polynomial interpolation to get values for arbitrary times between those fixed points.
The AsyncSinc resampler takes an additional parameter profile.
This is used to select a pre-defined profile.
The Balanced profile is the best choice in most c</format:></extra_samples></keep_nbr></rotate_size>
README 内容过长,已截取前 64 KB。完整内容请前往 GitHub 仓库查看。
评论