Logo

CamillaDSP v0.6.1

CI test and lint

A tool to create audio processing pipelines for applications such as active crossovers or room correction. It is written in Rust to benefit from the safety and elegant handling of threading that this language provides.

Supported platforms: Linux, macOS, Windows.

Audio data is captured from a capture device and sent to a playback device. Alsa, PulseAudio, Jack, Wasapi 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 required for long FIR filters. The full configuration is given in a yaml file.

Table of Contents

Introduction

Installing

Building

How to run

Processing audio

Configuration

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:

Overview

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:

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:

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 with both PulseAudio and Alsa by setting up a loopback device (Alsa) or null sink (Pulse) and setting this device as the default output device. 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 are part of the CamillaDSP family:

Other projects meant to be used with CamillaDSP:

Projects of general nature which can be useful together with CamillaDSP:

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, Pulseaudio
camilladsp-linux-armv7.tar.gz Linux on Armv7 with Neon, intended for Raspberry Pi 2 and up but should also work on others Alsa
camilladsp-macos-amd64.tar.gz macOS on 64-bit Intel CPU 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

Building

Use recent stable versions of rustc and cargo. The minimum rustc version is 1.43.0.

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

By default both the Alsa and PulseAudio backends are enabled, but they can be disabled if desired. That also removes the need for the the corresponding system Alsa/Pulse packages.

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".

The default FFT library is RustFFT, but it's also possible to use FFTW. This is enabled by the feature "FFTW". When the chunksize is a power of two, like 1024 or 4096, FFTW is only a few percent faster than RustFFT. The difference gets much larger if the chunksize is a "strange" number, like a large prime. FFTW is a much larger and more complicated library, so using FFTW is only recommended if you for some reason can't use an "easy" chunksize and this makes RustFFT much slower.

Building in Linux with standard features

Customized build

All the available options, or "features" are:

The first two (alsa-backend, websocket) are included in the default features, meaning if you don't specify anything you will get those two. 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.

The jack-backend feature requires jack and its development files to be installed. To install:

Example 1: You want alsa-backend, websocket, pulse-backend and FFTW. The first two are included by default so you only need to add FFTW and pulse-backend:

cargo build --release --features FFTW --features pulse-backend
(or)
cargo install --path . --features FFTW --features pulse-backend

Example 2: You want alsa-backend, 32bit and FFTW. Since you don't want websocket you have to disable the defaults, and then add back alsa-backend:

cargo build --release --no-default-features --features alsa-backend --features FFTW --features 32bit
(or)
cargo install --path . --no-default-features --features alsa-backend --features FFTW --features 32bit

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 Alsa and Pulse backends should not be included when building on Windows and macOS. The recommended build command is:

macOS:

RUSTFLAGS='-C target-cpu=native' cargo build --release --features cpal-backend

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

On macOS both the PulseAudio and FFTW features can be used. The necessary dependencies can be installed with brew:

brew install fftw
brew install pkg-config
brew install pulseaudio

The FFTW feature can also be used on Windows. There is no need to install anything extra.

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.exe --help
CamillaDSP 0.6.1
Henrik Enquist <henrik.enquist@gmail.com>
A flexible tool for processing audio

Built with features: websocket

Supported device types:
Capture: File, Stdin, Wasapi
Playback: File, Stdout, Wasapi

USAGE:
    camilladsp.exe [FLAGS] [OPTIONS] <configfile>

FLAGS:
    -m, --mute       Start with Volume and Loudness filters muted
    -c, --check      Check config file and exit
    -h, --help       Prints help information
    -V, --version    Prints version information
    -v               Increase message verbosity
    -w, --wait       Wait for config from websocket

OPTIONS:
    -o, --logfile <logfile>                Write logs to file
    -l, --loglevel <loglevel>              Set log level [possible values: trace, debug, info, warn, error, off]
    -a, --address <address>                IP address to bind websocket server to
    -g, --gain <gain>                      Set initial gain in dB for Volume and Loudness filters
    -p, --port <port>                      Port for websocket server
    -n, --channels <channels>              Override number of channels of capture device in config
    -e, --extra_samples <extra_samples>    Override number of extra samples in config
    -r, --samplerate <samplerate>          Override samplerate in config
    -f, --format <format>                  Override sample format of capture device in config [possible values: S16LE,
                                           S24LE, S24LE3, S32LE, FLOAT32LE, FLOAT64LE]

ARGS:
    <configfile>    The configuration file to use

Most flags 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 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.

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.

Volume control

The --gain option 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 work (for a gain of +/- 12.3 dB):

-g12.3
-g 12.3
--gain 12.3
--gain=12.3

-g-12.3
--gain=-12.3

These will 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

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.

Cross-platform

These backends are supported on all platforms.

File or pipe

Audio can be read from a file or a pipe using the File 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.

Jack

Jack is most commonly used with Linux, but can also be used with both Windows and MacOS.

The Jack support of the current CamillaDSP version (v0.6.0 at the time of writing) should be considered experimental.

The jack server must be running.

Set device to "default" for both capture and playback. The sample format is fixed at 32-bit float (FLOAT32LE).

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.

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

Pipewire implements both the PulseAudio and Jack APIs. It is therefore supported both via the Pulse and the Jack backends, and there is no need for a specific Pipewire backend.

Pipewire supports creating null-sink like PulseAudio. Create it 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.

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.

Configuration

The YAML format

CamillaDSP is using the YAML format for the configuration file. This is a standard format that was chosen because of its nice readable syntax. The Serde library is used for reading the configuration. 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.

Devices

Example config:

devices:
  samplerate: 96000
  chunksize: 1024
  queuelimit: 4 (*)
  silence_threshold: -60 (*)
  silence_timeout: 3.0 (*)
  target_level: 500 (*)
  adjust_period: 10 (*)
  enable_rate_adjust: true (*)
  enable_resampling: true (*)
  resampler_type: BalancedAsync (*)
  capture_samplerate: 44100 (*)
  stop_on_rate_change: false (*)
  rate_measure_interval: 1.0 (*)
  capture:
    type: Pulse
    channels: 2
    device: "MySink.monitor"
    format: S16LE
  playback:
    type: Alsa
    channels: 2
    device: "hw:Generic_1"
    format: S32LE

Any parameter marked (*) in all examples in this section are optional. If they are left out from the configuration, their default values will be used.

Resampling

Resampling is provided by the Rubato library.

This library does asynchronous and synchronous resampling with adjustable parameters. For asynchronous resampling, the overall strategy is to use a sinc interpolation filter with a fixed oversampling ratio, and then use polynomial interpolation to get values for arbitrary times between those fixed points. For synchronous resampling it instead works by transforming the waveform with FFT, modifying the spectrum, and then getting the resampled waveform by inverse FFT.

CamillaDSP provides four preset profiles for the resampler:

The "BalancedAsync" preset is the best choice in most cases, if an asynchronous resampler is needed. It provides good resampling quality with a noise threshold in the range of -150 dB along with reasonable CPU usage. As -150 dB is way beyond the resolution limit of even the best commercial DACs, this preset is thus sufficient for all audio use. The "FastAsync" preset is faster but have a little more high-frequency roll-off and give a bit higher resampling artefacts. The "AccurateAsync" preset provide the highest quality result, with all resampling artefacts below -200dB, at the expense of higher CPU usage. There is also a "FreeAsync" mode as well where all parameters can be set freely. The configuration is specified like this:

...
  resampler_type:
    FreeAsync:
      f_cutoff: 0.9
      sinc_len: 128
      window: Hann2
      oversampling_ratio: 128
      interpolation: Cubic

For reference, the asynchronous presets are defined according to this table:

FastAsync BalancedAsync AccurateAsync
sinc_len 64 128 256
oversampling_ratio 1024 1024 256
interpolation Linear Linear Cubic
window Hann2 Blackman2 BlackmanHarris2
f_cutoff 0.915 0.925 0.947

For performing fixed ratio resampling, like resampling from 44.1kHz to 96kHz (which corresponds to a precise ratio of 147/320) choose the "Synchronous" variant. This is considerably faster than the asynchronous variants, but does not support rate adjust. The quality is comparable to the "AccurateAsync" preset.

When using the rate adjust feature to match capture and playback devices, one of the "Async" variants must be used. These asynchronous presets do not rely on a fixed resampling ratio. When rate adjust is enabled the resampling ratio is dynamically adjusted in order to compensate for drifts and mismatches between the input and output sample clocks.
Using the "Synchronous" variant with rate adjust enabled will print warnings, and any rate adjust request will be ignored.

See the library documentation for more details. Rubato on docs.rs

Mixers

A mixer is used to route audio between channels, and to increase or decrease the number of channels in the pipeline. Example for a mixer that copies two channels into four:

mixers:
  ExampleMixer:
    channels:
      in: 2
      out: 4
    mapping:
      - dest: 0
        mute: false (*)
        sources:
          - channel: 0
            gain: 0
            inverted: false
      - dest: 1
        mute: false (*)
        sources:
          - channel: 1
            gain: 0
            inverted: false
      - dest: 2
        sources:
          - channel: 0
            gain: 0
            inverted: false
      - dest: 3
        sources:
          - channel: 1
            gain: 0
            inverted: false

Parameters marked with (*) are optional. The "channels" group define the number of input and output channels for the mixer. The mapping section then decides how to route the audio. This is a list of the output channels, and for each channel there is a "sources" list that gives the sources for this particular channel. Each source has a channel number, a gain value in dB, and if it should be inverted (true/false). A channel that has no sources will be filled with silence. The mute option determines if an output channel of the mixer should be muted. This parameter is optional, and defaults to not muted. Another example, a simple stereo to mono mixer:

mixers:
  mono:
    channels:
      in: 2
      out: 1
    mapping:
      - dest: 0
        sources:
          - channel: 0
            gain: -6
            inverted: false
          - channel: 1
            gain: -6
            inverted: false

Skip processing of unused channels

Some audio interfaces bundle all their inputs together, meaning that it might be necessary to capture a large number of channels to get access to a particular input. To reduce the CPU load, CamillaDSP will try to avoid processing of any channel that is captured but not used in the pipeline.

Let's say we have an interface with one analog input, and one SPDIF. These are presented as a single 4-channel input where channels 0 and 1 are analog, 2 and 3 SPDIF. Then, setting the number of capture channels to 4 will enable both inputs. In this case we are only interested in the SPDIF input. This is then done by adding a mixer that reduces the number of channels to 2. In this mixer, input channels 0 and 1 are not mapped to anything. This is then detected, and no format conversion, resampling or processing will be done on these two channels.

Filters

The filters section defines the filter configurations to use in the pipeline. It's enough to define each filter once even if it should be applied on several channels. The supported filter types are Biquad, BiquadCombo and DiffEq for IIR and Conv for FIR. There are also filters just providing gain and delay. The last filter type is Dither, which is used to add dither when quantizing the output.

Gain

The gain filter simply changes the amplitude of the signal. The inverted parameter simply inverts the signal. This parameter is optional and the default is to not invert. The gain value is given in dB, and a positive value means the signal will be amplified while a negative values attenuates. The gain value must be in the range -150 to +150 dB. The mute parameter determines if the the signal should be muted. This is optional and defaults to not mute.

Example Gain filter:

filters:
  gainexample:
    type: Gain
    parameters:
      gain: -6.0 
      inverted: false
      mute: false (*)

Volume

The Volume filter is intended to be used as a volume control. The initial volume and muting state can be set with the gain and mute command line parameters. The volume can then be changed via the websocket. A request to set the volume will be applied to all Volume filters. When the volume or mute state is changed, the gain is ramped smoothly to the new value. The duration of this ramp is set by the ramp_time parameter (unit milliseconds). The value must not be negative. If left out, it defaults to 200 ms. The value will be rounded to the nearest number of chunks. To use this filter, insert a Volume filter somewhere in the pipeline for each channel. It's possible to use this to make a dithered volume control by placing the Volume filter somewhere in the pipeline, and having a Dither filter as the last step.

Example Volume filter:

filters:
  volumeexample:
    type: Volume
    parameters:
      ramp_time: 200

Loudness

The Loudness filter is intended to be used as a volume control, similarly to the Volume filter. See the Volume filter for a description of how it is used. The difference is that the Loudness filter applies loudness correction when the volume is lowered. The method is the same as the one implemented by the RME ADI-2 DAC FS. The loudness correction is done as shelving filters that boost the high (above 3500 Hz) and low (below 70 Hz) frequencies. The amount of boost is adjustable with the high_boost and low_boost parameters. If left out, they default to 10 dB.

Loudness

In this figure, the reference_level was set to -5 dB, and high_boost = low_boost = 10 dB. At a gain of 0 and -5, the curve is flat. Below that the boost increases. At -15 dB half of the boost, and at -25 the full boost is applied. Below -25 dB, the boost value stays constant.

Example Loudness filter:

filters:
  loudnessvol:
    type: Loudness
    parameters:
      ramp_time: 200.0
      reference_level: -25.0 
      high_boost: 7.0
      low_boost: 7.0

Allowed ranges:

Delay

The delay filter provides a delay in milliseconds or samples. The unit can be ms or samples, and if left out it defaults to ms. If the subsample parameter is set to true, then it will use use an IIR filter to achieve subsample delay precision. If set to false, the value will instead be rounded to the nearest number of full samples. This is a little faster and should be used if subsample precision is not required.

The delay value must be positive or zero.

Example Delay filter:

filters:
  delayexample:
    type: Delay
    parameters:
      delay: 12.3
      unit: ms
      subsample: false

FIR

A FIR filter is given by an impulse response provided as a list of coefficients. The coefficients are preferably given in a separate file, but can be included directly in the config file. If the number of coefficients (or taps) is larger than the chunksize setting it will use segmented convolution. The number of segments is the filter length divided by the chunksize, rounded up.

Example FIR filters:

filters:
  example_fir_a:
    type: Conv
    parameters:
      type: Raw 
      filename: path/to/filter.txt
      format: TEXT
      skip_bytes_lines: 0 (*)
      read_bytes_lines: 0 (*)
  example_fir_b:
    type: Conv
    parameters:
      type: Wav 
      filename: path/to/filter.txt
      channel: 0 (*)

The type can be Raw, Wav or Values. Use Wav to load a standard .wav file, Raw to load a raw file (see list of allowed raw formats below), and Values for giving the coefficients directly in the configuration file. The filename field should hold the path to the coefficient file. Using the absolute path is recommended in most cases.

If a relative path is given it will first try to find the file relative to the config file path. If it's not found there, the path is assumed to be relative to the current working directory. Note that this only applies when the config is loaded from a file. When a config is supplied via the websocket server only the current working dir of the CamillaDSP process will be searched.

If the filename includes the tokens $samplerate$ or $channels$, these will be replaced by the corresponding values from the config. For example, if samplerate is 44100, the filename /path/to/filter_$samplerate$.raw will be updated to /path/to/filter_44100.raw.

Values directly in config file

Example for giving values:

filters:
  lowpass_fir:
    type: Conv
    parameters:
      type: Values
      values: [0.0, 0.1, 0.2, 0.3]
      length: 12345

The length setting is optional. It is used to extend the number of coefficients past the ones given in values. The added coefficients are all zeroes. This is intended to provide an easy way to evaluating the CPU load for different filter lengths.

For testing purposes the entire "parameters" block can be left out (or commented out with a # at the start of each line). This then becomes a dummy filter that does not affect the signal.

Coefficients from Wav-file

Supplying the coefficients as .wav file is the most convenient method. The Wav type takes only one parameter channel. This is used to select which channel of a multi-channel file to load. For a standard stereo file, the left track is channel 0, and the right is channel 1. This parameter is optional and defaults to 0 if left out. The sample rate of the file is ignored.

Coefficient Raw (headerless) data file

To load coefficients from a raw file, use the Raw type. This is also used to load coefficients from text files. Raw files are often saved with a .dbl, .raw, or .pcm ending. The lack of a header means that the files doesn't contain any information about data format etc. CamillaDSP supports loading coefficients from such files that contain a single channel only (stereo files are not supported), in all the most common sample formats. The Raw type supports two additional optional parameters, for advanced handling of raw files and text files with headers:

The filter coefficients can be provided either as text, or as raw samples. Each file can only hold one channel. The "format" parameter can be omitted, in which case it's assumed that the format is TEXT. This format is a simple text file with one value per row:

-0.000021
-0.000020
-0.000018
...
-0.000012

The other possible formats are raw data:

IIR

IIR filters are implemented as Biquad filters. CamillaDSP can calculate the coefficients for a number of standard filters, or you can provide the coefficients directly.

Examples:

filters:
  free_nbr1:
    type: Biquad
    parameters:
      type: Free
      a1: 1.0
      a2: 1.0
      b0: 1.0
      b1: 1.0
      b2: 1.0
  hp_80:
    type: Biquad
    parameters:
      type: Highpass
      freq: 80
      q: 0.5
  peak_100:
    type: Biquad
    parameters:
      type: Peaking
      freq: 100
      q: 0.5
      gain: -7.3
  peak_100_bw:
    type: Biquad
    parameters:
      type: Peaking
      freq: 100
      bandwidth: 0.7
      gain: -7.3
  exampleshelf:
    type: Biquad
    parameters:
      type: Highshelf
      freq: 1000
      slope: 6
      gain: -12
  exampleshelf_q:
    type: Biquad
    parameters:
      type: Highshelf
      freq: 1000
      q: 1.5
      gain: -12
  LR_highpass:
    type: BiquadCombo
    parameters:
      type: LinkwitzRileyHighpass
      freq: 1000
      order: 4

Single Biquads are defined using the type "Biquad". The available filter types are:

To build more complex filters, use the type "BiquadCombo". This automatically adds several Biquads to build other filter types. The available types are:

Other types such as Bessel filters can be built by combining several Biquads. See the separate readme for more filter functions.

Dither

The "Dither" filter should only be added at the very end of the pipeline for each channel, and adds noise shaped dither to the output. This is intended for 16-bit output, but can be used also for higher bit depth if desired. There are several types, and the parameter "bits" sets the target bit depth. For the best result this should match the bit depth of the playback device. Setting it to a higher value is not useful since then the applied dither will be rounded off. On the other hand, setting it to a much lower value, for example 5 or 6 bits (minimum allowed value is 2), makes the noise very audible and can be useful for comparing the different types.

Example:

  dither_fancy:
    type: Dither
    parameters:
      type: Lipshitz
      bits: 16

The available types are

Lipshitz, Fweighted and Shibata give the least amount of audible noise. See the SOX documentation for more details. To test the different types, set the target bit depth to something very small like 5 bits and try them all.

For sample rates above 48 kHz there is no need for anything more advanced than the "Simple" type. For the low sample rates there is no spare bandwidth and the dither noise must use the audible range, with shaping to makes it less audible. But at 96 or 192 kHz there is all the bandwidth from 20kHz up to 48 or 96kHz where the noise can be placed without issues. The Simple type will place almost all of it there.

Difference equation

The "DiffEq" filter implements a generic difference equation filter with transfer function: H(z) = (b0 + b1z^-1 + .. + bnz^-n)/(a0 + a1z^-1 + .. + anz^-n). The coefficients are given as a list a0..an in that order. Example:

  example_diffeq:
    type: DiffEq
    parameters:
      a: [1.0, -0.1462978543780541, 0.005350765548905586]
      b: [0.21476322779271284, 0.4295264555854257, 0.21476322779271284]

This example implements a Biquad lowpass, but for a Biquad the Free Biquad type is faster and should be preferred. Both a and b are optional. If left out, they default to [1.0].

Pipeline

The pipeline section defines the processing steps between input and output. The input and output devices are automatically added to the start and end. The pipeline is essentially a list of filters and/or mixers. There are no rules for ordering or how many are added. For each mixer and for the output device the number of channels from the previous step must match the number of input channels.

Example:

pipeline:
  - type: Mixer
    name: to4channels
  - type: Filter
    channel: 0
    names:
      - lowpass_fir
      - peak1
  - type: Filter
    channel: 1
    names:
      - lowpass_fir
      - peak1
  - type: Filter
    channel: 2
    names:
      - highpass_fir
  - type: Filter
    channel: 3
    names:
      - highpass_fir

In this config first a mixer is used to copy a stereo input to four channels. Then for each channel a filter step is added. A filter block can contain one or several filters that must be define in the "Filters" section. Here channel 0 and 1 get filtered by "lowpass_fir" and "peak1", while 2 and 3 get filtered by just "highpass_fir". If the names of mixers or filters includes the tokens $samplerate$ or $channels$, these will be replaced by the corresponding values from the config. For example, if samplerate is 44100, the filter name fir_$samplerate$ will be updated to fir_44100.

Visualizing the config

Please note that the show_config.py script mentioned here is deprecated, and has been replaced by the plotcamillaconf tool from the pycamilladsp-plot library. The new tool provides the same functionality as well as many improvements. The show_config.py does not support any of newer config options, and the script will be removed in a future version.

A Python script is included to view the configuration. This plots the transfer functions of all included filters, as well as plots a flowchart of the entire processing pipeline. Run it with:

python show_config.py /path/to/config.yml

Example flowchart:

Example

Note that the script assumes a valid configuration file and will not give any helpful error messages if it's not, so it's a good idea to first use CamillaDSP to validate the file. The script requires the following:

Getting help

FAQ

See the list of frequently asked questions.

Troubleshooting

See the trouble troubleshooting guide for explanations of most error messages.