I think that the Pipeline view could show the Channel name without having to open the down pointing arrow menu. By just scrolling down one should be able to find the right section to add a newly created filter without any interaction. When dealing with larger configurations this becomes a sewing issue if not... Preferably placed more to the left than my sketch... Leftmost possible I would say...
//
//
It shows all channel names up to 8 channels. When there are more, it takes too much space, so it switches to a more compact view with the indicator bars (which looks wrong in your screenshot, the selected channel should have a bright green little bar, not black) and the dropdown. It's not easy to make something that works equally well for everything from stereo to big interfaces with 30+ channels...I think that the Pipeline view could show the Channel name without having to open the down pointing arrow menu.
Aha OK, if more then 8 channels , it goes to the green bar layout instead - got it! Makes sense.
//
//
CamillaDSP v3.0.1 is out, fixes the issue where some Alsa devices don't resume after being paused. There is also a new gui that fixes a config import bug.
https://github.com/HEnquist/camilladsp/releases/tag/v3.0.1
https://github.com/HEnquist/camillagui-backend/releases/tag/v3.0.3
https://github.com/HEnquist/camilladsp-setupscripts/releases/tag/v3.0.3
The windows 7 build of the camilladsp binary failed. Doesn't really matter since there are no changes in the windows code in 3.0.1. But it means that v3.0.0 is the last published build that supports windows 7.
https://github.com/HEnquist/camilladsp/releases/tag/v3.0.1
https://github.com/HEnquist/camillagui-backend/releases/tag/v3.0.3
https://github.com/HEnquist/camilladsp-setupscripts/releases/tag/v3.0.3
The windows 7 build of the camilladsp binary failed. Doesn't really matter since there are no changes in the windows code in 3.0.1. But it means that v3.0.0 is the last published build that supports windows 7.
I see only version numbers changes in the 'new gui', no code change - https://github.com/HEnquist/camillagui-backend/compare/v3.0.2...v3.0.3
Is it just me?
No worries for the windows 7 version, 3.0.0 does the job perfectly well
Is it just me?
No worries for the windows 7 version, 3.0.0 does the job perfectly well
@QuickDraw McGraw the change is in the frontend code; https://github.com/HEnquist/camillagui/compare/v3.0.2...v3.0.3
@TNT yes sure, you can use the setup script to update, same procedure as when upgrading from v2.
@TNT yes sure, you can use the setup script to update, same procedure as when upgrading from v2.
I suspect I may have missed something fundamental - I am trying to control the CDSP volume from an external volume control (a Fosi VOL20):
Background: I have CSDP running on a Debian 6.1.0-32-amd64 headless with the latest CDSP version. An extract from my config is attached.
A web search for 'link_volume_control' yields nothing except Henrik's description "Linking volume control to device volume"
Thanks
- I have manged to control the ALSA Master Volume Control from the device
- I have set the 'link_volume_control' parameter to 'Master Playback Volume'
- I have a chain Toslink -> USB (UR23 SPDIF adaptor) -> CDSP -> Fosi DM7 DAC
Background: I have CSDP running on a Debian 6.1.0-32-amd64 headless with the latest CDSP version. An extract from my config is attached.
A web search for 'link_volume_control' yields nothing except Henrik's description "Linking volume control to device volume"
Thanks
Attachments
OK thanks Henrik, it's on the PCH device, the Rx USB TOSLINK capture device does not have a volume control. So no go then?
If you have no luck with that approach, it should be possible to use the Fosi VOL20 to control the CDSP master volume directly. There's an example script here: https://www.diyaudio.com/community/...overs-room-correction-etc.349818/post-7915438Rx USB TOSLINK capture device does not have a volume control. So no go then?
I have mine setup using an old Logitech Harmony remote configured to send keyboard shortcuts which then trigger the script. As you're using a headless system the best way to translate the VOL20's commands to a script might be via evdev, there's a python library here: https://python-evdev.readthedocs.io/en/latest/
@Roxymoron: IMO the volume functionality needs to be explained, to avoid confusion.
CDSP can control volume internally, as part of its DSP. The volume control is well-behaved, ramped, can be linked to loudness DSP, etc. The end result of the plain internal volume (when not linked to loudness) is still "just" a division of all samples by a fixed number, and audibility is identical to any other digital volume control in the chain.
Now this volume feature needs to be controlled during CDSP operation. There are several ways:
One option is the CDSP websocket server API which has a function for volume. That's what the python scripts utilize, via the python camilladsp library which implements the websocket client to the CDSP websocket server API.
Another (specialty) option to control the CDSP volume is when CDSP captures from USB audio gadget. That alsa device has a USB UAC2 device on the other side and this UAC2 device can present a volume control feature to the USB host. As a result the USB host can use this "hardware" USB volume control itself. E.g. the mpd config options mixer_type=hardware + mixer_device + mixer_index https://linux.die.net/man/5/mpd.conf . When user asks MPD to change volume (via some mpd client), mpd will send the request (via alsa layer + UAC2 driver) to the UAC2 device, and UAC2 gadget driver will instruct its alsa-device side to change value of its mixer element https://github.com/torvalds/linux/b...ers/usb/gadget/function/u_audio.c#L1363-L1392. If CDSP is configured with "link_volume_control" config string and it finds this control element name among the capture device controls, it will subscribe to changes of values of this element, track its value, and adjust its internal volume feature accordingly. That's why the config name starts with link_ - it really links CDSP to that ctl element.
In your case you have a USB HID volume knob which produces standard multimedia key events when rotating (just like multimedia keys on many PC keyboards). Therefore you need to use the first option - controlling CDSP via websockets. The @fb's post describes just that - monitoring input events for these multimedia keys from your particular input device and running a python script which sends websocket commands to running CDSP to change the volume accordingly. No alsa mixer control is involved here.
CDSP can control volume internally, as part of its DSP. The volume control is well-behaved, ramped, can be linked to loudness DSP, etc. The end result of the plain internal volume (when not linked to loudness) is still "just" a division of all samples by a fixed number, and audibility is identical to any other digital volume control in the chain.
Now this volume feature needs to be controlled during CDSP operation. There are several ways:
One option is the CDSP websocket server API which has a function for volume. That's what the python scripts utilize, via the python camilladsp library which implements the websocket client to the CDSP websocket server API.
Another (specialty) option to control the CDSP volume is when CDSP captures from USB audio gadget. That alsa device has a USB UAC2 device on the other side and this UAC2 device can present a volume control feature to the USB host. As a result the USB host can use this "hardware" USB volume control itself. E.g. the mpd config options mixer_type=hardware + mixer_device + mixer_index https://linux.die.net/man/5/mpd.conf . When user asks MPD to change volume (via some mpd client), mpd will send the request (via alsa layer + UAC2 driver) to the UAC2 device, and UAC2 gadget driver will instruct its alsa-device side to change value of its mixer element https://github.com/torvalds/linux/b...ers/usb/gadget/function/u_audio.c#L1363-L1392. If CDSP is configured with "link_volume_control" config string and it finds this control element name among the capture device controls, it will subscribe to changes of values of this element, track its value, and adjust its internal volume feature accordingly. That's why the config name starts with link_ - it really links CDSP to that ctl element.
In your case you have a USB HID volume knob which produces standard multimedia key events when rotating (just like multimedia keys on many PC keyboards). Therefore you need to use the first option - controlling CDSP via websockets. The @fb's post describes just that - monitoring input events for these multimedia keys from your particular input device and running a python script which sends websocket commands to running CDSP to change the volume accordingly. No alsa mixer control is involved here.
Last edited:
The default is to start at full volume, but you can decide another level to start at. See https://github.com/HEnquist/camilladsp/blob/master/README.md#initial-volume
.
.
I have to say that taking all universal fubar-unluck-someting_hits_the_fan-monday-planetary_constellation_why_o_why aspects... etc..., I would have set this to -36 dB ;-D
//
//
That would create too much confusion, in my opinion. I don't think most people are using CamillaDSP to implement volume control. This thread would be filled with people asking why they cannot get any volume out of their system when they turn the turn up the volume of the device they have controlling it.I would have set this to -36 dB
I'm looking for help, please, if possible. I'm not exactly a Linux/Raspberry Pi noob but I'm failing miserably with Raspberry Pi 5 and HifiBerry DAC8x.
I have Camilla and DAC8x working well in so far as I can play audio from any source through the DAC8x. I can play audio from audio files with Strawberry player through CamillaDSP and out through the DAC8x via an ALSA loopback, also works great.
What I can't seem to work out is how to get Pipewire to connect to the ALSA loopback to play audio from, for example, Firefox browser through CDSP to DAC8x. I've tried a few configurations and haven't found a working one. I should say I've removed PulseAudio from the system entirely, I can re-install if I have to but I don't think that's the problem since I couldn't make it work before I removed it.
I think I'll be directed here
https://github.com/HEnquist/camilladsp-config
but I tried this solution for Pipewire and didn't get any audio output at all afterwards. I suspect the solution will be here somewhere but I don't understand the configuration sufficiently to make suitable alterations. This is my unsuccessful pipewire.conf.
I have Camilla and DAC8x working well in so far as I can play audio from any source through the DAC8x. I can play audio from audio files with Strawberry player through CamillaDSP and out through the DAC8x via an ALSA loopback, also works great.
What I can't seem to work out is how to get Pipewire to connect to the ALSA loopback to play audio from, for example, Firefox browser through CDSP to DAC8x. I've tried a few configurations and haven't found a working one. I should say I've removed PulseAudio from the system entirely, I can re-install if I have to but I don't think that's the problem since I couldn't make it work before I removed it.
I think I'll be directed here
https://github.com/HEnquist/camilladsp-config
but I tried this solution for Pipewire and didn't get any audio output at all afterwards. I suspect the solution will be here somewhere but I don't understand the configuration sufficiently to make suitable alterations. This is my unsuccessful pipewire.conf.
Code:
# Daemon config file for PipeWire version "1.2.7" #
#
# Copy and edit this file in /etc/pipewire for system-wide changes
# or in ~/.config/pipewire for local changes.
#
# It is also possible to place a file with an updated section in
# /etc/pipewire/pipewire.conf.d/ for system-wide changes or in
# ~/.config/pipewire/pipewire.conf.d/ for local changes.
#
#See https://github.com/HEnquist/camilladsp-config/blob/master/README.md for changes I made to this file
context.properties = {
## Configure properties in the system.
#library.name.system = support/libspa-support
#context.data-loop.library.name.system = support/libspa-support
#support.dbus = true
#link.max-buffers = 64
link.max-buffers = 16 # version < 3 clients can't handle more
#mem.warn-mlock = false
#mem.allow-mlock = true
#mem.mlock-all = false
#clock.power-of-two-quantum = true
#log.level = 2
#cpu.zero.denormals = false
#loop.rt-prio = -1 # -1 = use module-rt prio, 0 disable rt
#loop.class = data.rt
#thread.affinity = [ 0 1 ] # optional array of CPUs
#context.num-data-loops = 1 # -1 = num-cpus, 0 = no data loops
#
#context.data-loops = [
# { loop.rt-prio = -1
# loop.class = [ data.rt audio.rt ]
# #library.name.system = support/libspa-support
# thread.name = data-loop.0
# #thread.affinity = [ 0 1 ] # optional array of CPUs
# }
#]
core.daemon = true # listening for socket connections
core.name = pipewire-0 # core name and socket name
## Properties for the DSP configuration.
default.clock.rate = 44100 # H. Enquist addition
#default.clock.allowed-rates = [ 48000 ]
#default.clock.quantum = 1024
#default.clock.min-quantum = 32
#default.clock.max-quantum = 2048
#default.clock.quantum-limit = 8192
#default.clock.quantum-floor = 4
#default.video.width = 640
#default.video.height = 480
#default.video.rate.num = 25
#default.video.rate.denom = 1
#
#settings.check-quantum = false
#settings.check-rate = false
# keys checked below to disable module loading
module.x11.bell = true
# enables autoloading of access module, when disabled an alternative
# access module needs to be loaded.
module.access = true
# enables autoloading of module-jackdbus-detect
module.jackdbus-detect = true
}
context.properties.rules = [
{ matches = [ { cpu.vm.name = !null } ]
actions = {
update-props = {
# These overrides are only applied when running in a vm.
default.clock.min-quantum = 1024
}
}
}
]
context.spa-libs = {
#<factory-name regex> = <library-name>
#
# Used to find spa factory names. It maps an spa factory name
# regular expression to a library name that should contain
# that factory.
#
audio.convert.* = audioconvert/libspa-audioconvert
avb.* = avb/libspa-avb
api.alsa.* = alsa/libspa-alsa
api.v4l2.* = v4l2/libspa-v4l2
api.libcamera.* = libcamera/libspa-libcamera
api.bluez5.* = bluez5/libspa-bluez5
api.vulkan.* = vulkan/libspa-vulkan
api.jack.* = jack/libspa-jack
support.* = support/libspa-support
video.convert.* = videoconvert/libspa-videoconvert
#videotestsrc = videotestsrc/libspa-videotestsrc
#audiotestsrc = audiotestsrc/libspa-audiotestsrc
}
context.modules = [
#{ name = <module-name>
# ( args = { <key> = <value> ... } )
# ( flags = [ ( ifexists ) ( nofail ) ] )
# ( condition = [ { <key> = <value> ... } ... ] )
#}
#
# Loads a module with the given parameters.
# If ifexists is given, the module is ignored when it is not found.
# If nofail is given, module initialization failures are ignored.
# If condition is given, the module is loaded only when the context
# properties all match the match rules.
#
# Uses realtime scheduling to boost the audio thread priorities. This uses
# RTKit if the user doesn't have permission to use regular realtime
# scheduling. You can also clamp utilisation values to improve scheduling
# on embedded and heterogeneous systems, e.g. Arm big.LITTLE devices.
{ name = libpipewire-module-rt
args = {
nice.level = -11
rt.prio = 88
#rt.time.soft = -1
#rt.time.hard = -1
#uclamp.min = 0
#uclamp.max = 1024
}
flags = [ ifexists nofail ]
}
# The native communication protocol.
{ name = libpipewire-module-protocol-native
args = {
# List of server Unix sockets, and optionally permissions
#sockets = [ { name = "pipewire-0" }, { name = "pipewire-0-manager" } ]
}
}
# The profile module. Allows application to access profiler
# and performance data. It provides an interface that is used
# by pw-top and pw-profiler.
{ name = libpipewire-module-profiler }
# Allows applications to create metadata objects. It creates
# a factory for Metadata objects.
{ name = libpipewire-module-metadata }
# Creates a factory for making devices that run in the
# context of the PipeWire server.
{ name = libpipewire-module-spa-device-factory }
# Creates a factory for making nodes that run in the
# context of the PipeWire server.
{ name = libpipewire-module-spa-node-factory }
# Allows creating nodes that run in the context of the
# client. Is used by all clients that want to provide
# data to PipeWire.
{ name = libpipewire-module-client-node }
# Allows creating devices that run in the context of the
# client. Is used by the session manager.
{ name = libpipewire-module-client-device }
# The portal module monitors the PID of the portal process
# and tags connections with the same PID as portal
# connections.
{ name = libpipewire-module-portal
flags = [ ifexists nofail ]
}
# The access module can perform access checks and block
# new clients.
{ name = libpipewire-module-access
args = {
# Socket-specific access permissions
#access.socket = { pipewire-0 = "default", pipewire-0-manager = "unrestricted" }
# Deprecated legacy mode (not socket-based),
# for now enabled by default if access.socket is not specified
#access.legacy = true
}
condition = [ { module.access = true } ]
}
# Makes a factory for wrapping nodes in an adapter with a
# converter and resampler.
{ name = libpipewire-module-adapter }
# Makes a factory for creating links between ports.
{ name = libpipewire-module-link-factory }
# Provides factories to make session manager objects.
{ name = libpipewire-module-session-manager }
# Use libcanberra to play X11 Bell
{ name = libpipewire-module-x11-bell
args = {
#sink.name = "@DEFAULT_SINK@"
#sample.name = "bell-window-system"
#x11.display = null
#x11.xauthority = null
}
flags = [ ifexists nofail ]
condition = [ { module.x11.bell = true } ]
}
{ name = libpipewire-module-jackdbus-detect
args = {
#jack.library = libjack.so.0
#jack.server = null
#jack.client-name = PipeWire
#jack.connect = true
#tunnel.mode = duplex # source|sink|duplex
source.props = {
#audio.channels = 2
#midi.ports = 1
#audio.position = [ FL FR ]
# extra sink properties
}
sink.props = {
#audio.channels = 2
#midi.ports = 1
#audio.position = [ FL FR ]
# extra sink properties
}
}
flags = [ ifexists nofail ]
condition = [ { module.jackdbus-detect = true } ]
}
]
context.objects = [
#{ factory = <factory-name>
# ( args = { <key> = <value> ... } )
# ( flags = [ ( nofail ) ] )
# ( condition = [ { <key> = <value> ... } ... ] )
#}
#
# Creates an object from a PipeWire factory with the given parameters.
# If nofail is given, errors are ignored (and no object is created).
# If condition is given, the object is created only when the context properties
# all match the match rules.
#
# Following block of code suggested H. Enquist
{ factory = adapter
args = {
factory.name = api.alsa.pcm.sink
node.name = "alsa-sink"
node.description = "Alsa Loopback"
media.class = "Audio/Sink"
api.alsa.path = "hw:Loopback,0,0"
#api.alsa.period-size = 1024
#api.alsa.headroom = 0
#api.alsa.disable-mmap = false
#api.alsa.disable-batch = false
audio.format = "S32LE"
audio.rate = 44100
audio.channels = 2
#audio.position = "FL,FR"
}
}
# Ends H. Enquist code
#{ factory = spa-node-factory args = { factory.name = videotestsrc node.name = videotestsrc node.description = videotestsrc "Spa:Pod:Object:Param:Props:patternType" = 1 } }
#{ factory = spa-device-factory args = { factory.name = api.jack.device foo=bar } flags = [ nofail ] }
#{ factory = spa-device-factory args = { factory.name = api.alsa.enum.udev } }
#{ factory = spa-node-factory args = { factory.name = api.alsa.seq.bridge node.name = Internal-MIDI-Bridge } }
#{ factory = adapter args = { factory.name = audiotestsrc node.name = my-test node.description = audiotestsrc } }
#{ factory = spa-node-factory args = { factory.name = api.vulkan.compute.source node.name = my-compute-source } }
# A default dummy driver. This handles nodes marked with the "node.always-process"
# property when no other driver is currently active. JACK clients need this.
{ factory = spa-node-factory
args = {
factory.name = support.node.driver
node.name = Dummy-Driver
node.group = pipewire.dummy
node.sync-group = sync.dummy
priority.driver = 200000
#clock.id = monotonic # realtime | tai | monotonic-raw | boottime
#clock.name = "clock.system.monotonic"
}
}
{ factory = spa-node-factory
args = {
factory.name = support.node.driver
node.name = Freewheel-Driver
priority.driver = 190000
node.group = pipewire.freewheel
node.sync-group = sync.dummy
node.freewheel = true
#freewheel.wait = 10
}
}
# This creates a new Source node. It will have input ports
# that you can link, to provide audio for this source.
#{ factory = adapter
# args = {
# factory.name = support.null-audio-sink
# node.name = "my-mic"
# node.description = "Microphone"
# media.class = "Audio/Source/Virtual"
# audio.position = "FL,FR"
# monitor.passthrough = true
# }
#}
# This creates a single PCM source device for the given
# alsa device path hw:0. You can change source to sink
# to make a sink in the same way.
#{ factory = adapter
# args = {
# factory.name = api.alsa.pcm.source
# node.name = "alsa-source"
# node.description = "PCM Source"
# media.class = "Audio/Source"
# api.alsa.path = "hw:0"
# api.alsa.period-size = 1024
# api.alsa.headroom = 0
# api.alsa.disable-mmap = false
# api.alsa.disable-batch = false
# audio.format = "S16LE"
# audio.rate = 48000
# audio.channels = 2
# audio.position = "FL,FR"
# }
#}
# Use the metadata factory to create metadata and some default values.
#{ factory = metadata
# args = {
# metadata.name = my-metadata
# metadata.values = [
# { key = default.audio.sink value = { name = somesink } }
# { key = default.audio.source value = { name = somesource } }
# ]
# }
#}
]
context.exec = [
#{ path = <program-name>
# ( args = "<arguments>" | [ <arg1> <arg2> ... ] )
# ( condition = [ { <key> = <value> ... } ... ] )
#}
#
# Execute the given program with arguments.
# If condition is given, the program is executed only when the context
# properties all match the match rules.
#
# You can optionally start the session manager here,
# but it is better to start it as a systemd service.
# Run the session manager with -h for options.
#
#{ path = "/usr/bin/pipewire-media-session" args = ""
# condition = [ { exec.session-manager = null } { exec.session-manager = true } ] }
#
# You can optionally start the pulseaudio-server here as well
# but it is better to start it as a systemd service.
# It can be interesting to start another daemon here that listens
# on another address with the -a option (eg. -a tcp:4713).
#
#{ path = "/usr/bin/pipewire" args = [ "-c" "pipewire-pulse.conf" ]
# condition = [ { exec.pipewire-pulse = null } { exec.pipewire-pulse = true } ] }
]
- Home
- Source & Line
- PC Based
- CamillaDSP - Cross-platform IIR and FIR engine for crossovers, room correction etc