Automatic sample rate switcher for CamillaDSP
This tool provides two useful services:
- Automatic updating of the sample rate when that of the audio stream being captured changes.
CamillaDSP works at a fixed sample rate. However, sample rate may change during a session, e.g. when listening to a playlist. In this case, if the incoming sample rate does not match the one CamillaDSP is using for processing, playback will not be correct.
camilladsp-setrate solves this problem by changing CamillaDSP's configuration on-the-fly to match the sample rate of the captured audio.
This tool may also allow resampling to a fixed playback rate and upsampling by a fixed factor. Details are provided below in the "Running" section (see --capture
flag and --uppsampling
option).
- Automatic reloading of a valid configuration whenever the playback device becomes available.
CamillaDSP as it must be, stops working when the playback device is no longer available. This happens, for example, when your DAC is switched off or you switch to another input. Unfortunately, CamillaDSP remains blocked even when the playback device becomes available again.
camilladsp-setrate reloads a valid configuration as soon as the playback device reappears, thus unlocking CamillaDSP.
In order for camilladsp-setrate to work the audio capture device must provide the necessary information about the sample rate change. camilladsp-setrate is designed to work with a USB gadget capture device, which is one of the few that fulfils this requirement.
The term USB Gadget refers to a device that uses a USB port and its control hardware to act as a peripheral (the term 'gadget' here is to be understood as 'peripheral'). This type of device was chosen for this project because it is available for cheap on certain types of Raspberry Pi boards after proper software configuration (on this subject, see this thread and this guide).
It is not excluded, however, that this tool may work with other capture devices, but it is necessary to check carefully that all requirements are met. Feel free to do your own experiments.
I have tested camilladsp-setrate on my Raspberry Pi 4 with its USB-C port configured in gadget mode for audio capture. I expect it may also work on other boards supporting USB gadget mode, such as Raspberry Pi Zero, Raspberry Pi 3A+, Raspberry Pi CM4 and BeagleBones.
This project was developed on DietPi 64-bit. It should also work on other Debian-based Linux distributions and arguably on other Linux flavors as well. The software is coded in C language with use of the alsa and libwebsockets C API's.
The DSP unlocking functionality has only been tested with USB playback devices.
- Linux operating system
- C language development environment
- Alsa sound system
- Alsa C library
- Libwebsockets C library
- CamillaDSP up and running
- A capture device providing information about sample rate change
For camilladsp-setrate to work, the capture device driver must feature an alsa control function informing when the sample rate changes and what its value is. You can check if your capture device meets this requirement by issuing the following command:
amixer -D <your device> controls
If the device driver sports the required alsa control, the above command should list a control whose name contains the word 'rate' (or something like that). In any case, please check the documentation of your device.
For example, in the case of a USB gadget, the command:
amixer -D hw:UAC2Gadget controls
produces this output:
numid=2,iface=MIXER,name='PCM Capture Switch'
numid=3,iface=MIXER,name='PCM Capture Volume'
numid=1,iface=PCM,name='Capture Pitch 1000000'
numid=4,iface=PCM,name='Capture Rate'
NOTE that since the USB gadget device acts as a peripheral, it must be connected to a USB device that acts as a host. Thus, your audio source must be equipped with a host USB port (usually a female USB Type A).
To achieve sample rate switching camilladsp-setrate subscribes to alsa events, reads the value of the sample rate when it changes, reads the current configuration of CamillaDSP and overwrites the samplerate and/or capture_samplerate parameters. To this end, some commands of the CamillaDSP websocket interface are issued. The command GetConfig
provides the current configuration; if the current configuration is not valid, the GetPreviousConfig
command is issued. Then the samplerate and/or capture_samplerate values in the current configuration of CamillaDSP are replaced with the new ones. The chunksize parameter value is as well updated as a function of the sample rate, calculating the value suggested in the section "Devices" of the CamillaDSP home page. Finally, the updated configuration is flushed to the DSP with the command SetConfig.
To achieve DSP unlocking when the playback device reappears, camilladsp-setrate goes through the same procedure described above for sample rate. In this case, however, the procedure is initiated by a signal sent by the operating system to the camilladsp-setrate process when the playback device is detected. This is obtained by means of an udev rule
(see the 88-DAC.rules
file).
- Install git, the C development environment and the required libraries:
sudo apt update
sudo apt install git build-essential libasound2-dev libwebsockets-dev
- Clone the git repository and move to the home of the project:
git clone https://github.com/marcoevang/camilladsp-setrate
cd camilladsp-setrate
- Build the executable file:
make
Instructions for installing the required packages are valid on debian-based Linux distributions. On other Linux flavors (e.g. Fedora) the package manager might differ, and the name of the libraries might also differ slightly.
If you use this tool on a Raspberry Pi 4 64-bit OS, you can probably directly use the camilladsp-setrate executable file provided under the bin folder of this repository. In that case, skip steps 1. and 3., complete the Install phase and then check if the provided executable file works.
- Copy the executable file to
/usr/local/bin
:
make install
If the executable file is already running, stop it before issuing make install.
-
Edit the file
camilladsp-setrate.service
and replace the values of the parameters User and Group with yours. You might want to make other changes, e.g. the options on the command line of the ExecStart parameter (see below for a description of command options and flags). -
Copy the file
camilladsp-setrate.service
to the system services folder and enable that service:
sudo cp camilladsp-setrate.service /etc/systemd/system
sudo systemctl enable camilladsp-setrate
- Make sure the user that runs the service (e.g. dietpi in the example .service file) is a member of the audio group, otherwise the started process cannot access the audio devices. If it is not, add it to the audio group:
sudo usermod -a <user running the camilladsp-setrate service> -G audio
Example:
sudo usermod -a dietpi -G audio
- Edit the file
85-DAC.rules
and replace the values of the parametersID_VENDOR_ID
andID_MODEL_ID
with those of your USB DAC. You can obtain those values with the following command :
usb-devices
(Vendor corresponds to ID_VENDOR_ID
and ProdID corresponds to ID_MODEL_ID
)
- Copy the file
85-DAC.rules
to theudev
rules folder:
sudo cp 85-DAC.rules /etc/udev/rules.d
- Reboot the system:
sudo shutdown -r now
USAGE:
camilladsp-setrate [FLAGS] [OPTIONS]
FLAGS:
-c, --capture
Update capture_samplerate instead of samplerate-t, --timestamp
Causes a timestamp to be prepended to log messages-s, --syslog
Redirect log messages to syslog (if this flag is omitted, messages are sent to standard error)-v, --version
Print software version-h, --help
Print help
OPTIONS:
-d, --device <capture device>
Set alsa capture device [default: hw:UAC2Gadget]-a, --address <address>
Set server IP address [default: localhost]-p, --port <port>
Set server IP port [default: 1234]-u, --upsampling <factor>
Set upsampling factor [default: 1]-l, --loglevel <log level>
Set log level [values: err, warn, user, notice, off. Default: err]
All options require an argument. If an option is omitted, the default value is applied.
Arguments must not be specified for flags.
The --capture
flag and --upsampling
options change the way camilladsp-setrate processes the samplerate, chunksize and capture_samplerate parameters, as follows:
-
if
--capture
and--upsampling
are both omitted, samplerate is set to that of the audio being captured and chunksize is updated as a function of samplerate. The capture_samplerate parameter is left unchanged.In this case resampling shall be disabled and capture_samplerate shall not be set in the configuration file.
-
if
--capture
is used, capture_samplerate is set to that of the audio being captured. The samplerate and chunksize parameters are left unchanged. This flag should be used to achieve resampling of the captured audio to the fixed playback rate set by the samplerate parameter in the configuration file.In this case resampling shall be enabled in the configuration file.
-
If
--upsampling
is used, capture_samplerate is set to that of the audio being captured and samplerate is set equal to the input rate multiplied by the specified upsampling factor (the latter must be positive). The chunksize parameter is as well updated as a function of samplerate. This option should be used to obtain in playback upsampled audio by a constant factor. For example, this flag can be used to instruct CamillaDSP to perform 2X or 4X oversampling regardless of the sample rate of the incoming audio. Make sure your playback device supports the resulting upsampled rate.In this case resampling shall be enabled in the configuration file.
Note that --capture
and --upsampling
cannot be used at the same time.
If the --device
option is used, the name of the capture device shall be given in the format required by thearecord
command.
The --loglevel
option sets the following logging levels:
-
err
: only errors are logged -
warn
: errors and warnings are logged -
user
: errors, warnings and key events are logged, such as sample rate change -
notice
: errors, warnings, key events and debugging information are logged.
camilladsp-setrate should start as a service at boot time. To this end, the camilladsp-setrate.service
file is provided. You can edit that file to set the desired options.
After modifications to the service file you have to make the udev
daemon reload the rules:
sudo systemctl daemon-reload
sudo systemctl restart camilladsp-setrate
or reboot the system.
I strongly recommend not running camilladsp-setrate as super-user.
-
This tool is useful if the audio player and CamillaDSP run on distinct computers. In case they run on the same computer, I recommend using the alsa_cdsp plugin instead to get automatic sample rate switching.
-
Starting with version 2.0.0 the sample rate change process is driven by a finite-state machine whose diagram is provided under the doc folder. You can find tons of information about this technique on the Internet (start here and here)
-
Starting with version 2.1.0 the flags
--err
,--warn
,--user
and--notice
have been removed as unnecessary. The--loglevel
option can be used instead. -
Capture devices other than USB gadgets may not provide the necessary information on sample rate change.
-
If using a capture device other than the USB gadget, you may need to change the
ALSA_CONTROL_NAME
constant value in thesetrate.h
file according to the name of the alsa control. -
camilladsp-setrate can handle CamillaDSP configuration files of a maximum size of about 16 KBytes. If the size of your configuration file is larger than this, you need to increase the size of the message buffer by updating the
MAX_PAYLOAD_SIZE
constant value in thesetrate.h
file. -
camilladsp-setrate works with all released versions of CamillaDSP.
-
Comments in the source code will, hopefully, help to understand the what and the how.