Thank you for your donation!


Cloudsmith graciously provides open-source package management and distribution for our project.


Instruction Guide Loudness compensated volume control with CamillaDSP
#1
The human ear is not equally responsive across the audio range. It is more sensitive to mid-frequencies than to the lower and higher frequencies. This situation becomes more pronounced at low volume levels. This is exactly what a loudness compensated volume control does: the more the volume is turned down, the more the bass and treble are boosted so it sounds the same.

   
   

This post shows how to implement such a volume control for a wide variety of audio renderers by using the Alsa dummy driver and the wonderful CamillaDSP that are all aboard on moOde already. The working principle is that the renderers set their volume in the dummy's mixer, which we continuously monitor with a script called dummyvol2cdsp, and forward to CamillaDSP using a websocket. And with this guide, it should sound more complicated than it really is :-)

You must have SSH enabled and know your way around the command line.

Set up Alsa dummy driver

First, set up the Alsa dummy driver. Later we will use its mixer control as a proxy to CamillaDSP's volume filters.
Code:
# sudo su -
# echo "options snd-dummy fake_buffer=0 pcm_substreams=1" >> /etc/modprobe.d/snd_dummy.conf
# echo "snd-dummy" >> /etc/modules-load.d/modules.conf
Note: although we do not need any of the dummy's PCM streams or substreams, do not set them to 0. Doing so will cause the system to hang on reboot, and you will need to reinstall or recover on another system.

Optional: make the dummy mixer control the system-wide default. This helps to immediately show the dummy mixer controls with amixer and alsamixer, for example.
Code:
# echo "defaults.ctl.card 0" >> /etc/alsa/conf.d/00-defaults.conf
# chmod a+x /etc/alsa/conf.d/00-defaults.conf
Note: the dummy driver should register as card 0 because it is registered first when booting. If it does not, use aplay -l to find out the right card number after rebooting.

Now reboot and verify that the dummy driver is set up correctly:
Code:
# reboot

# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: Dummy [Dummy], device 0: Dummy PCM [Dummy PCM]
 Subdevices: 1/1
 Subdevice #0: subdevice #0
card 1: ...

# amixer scontrols
Simple mixer control 'Master',0
Simple mixer control 'Synth',0
Simple mixer control 'Line',0
Simple mixer control 'CD',0
Simple mixer control 'Mic',0
Simple mixer control 'External I/O Box',0

Set up CamillaDSP loudness filters

Now at the other end of the chain we add volume filters to CamillaDSP. You can use a Volume filter or a Loudness filter. The loudness filter in fact is a volume filter, but with extra parameters and functionality to apply loudness correction when the volume is lowered.

The relevant configuration lines are as follows. Read on on how to configure this via the web interface.
Code:
devices:
 chunksize: 1024
 queuelimit: 1
filters:
 loudnessvol:
   type: Loudness
   parameters:
     ramp_time: 200.0
     reference_level: -10.0
     high_boost: 3.0
     low_boost: 8.5
pipeline:
- type: Filter
 channel: 0
 names:
 - loudnessvol
- type: Filter
 channel: 1
 names:
 - loudnessvol

A few notes on these values:
  • Recommended values for chunksize are 1024 for 44.1/48 kHz, 2048 for 88.2/96 kHz, 4096 for 176.4/192 kHz, and so on.
  • A queuelimit of 1 ensures the lowest audio latency to user input.
  • The ramptime gently increases or decreases the volume for the given duration in milliseconds. This prevents popping noises that could by caused by abrupt volume changes. 200 milliseconds is a sane default.
  • The reference_level very much depends on your audio chain, source material and personal preferences. You may try values between 0 and 30.
  • The high_boost and low_boost were chosen as averages from the ISO 226 equal-loudness contours. Again this depends on your needs and preferences, and plays along with the chosen reference_level.
  • If you have other mixers or filters, loudnessvol should be last in the pipeline.
  • Only if your output device is limited to 16-bit audio, you may choose to add a Dither filter after loudnessvol in the pipeline.
To configure this via the web interface, the following instructions should get you started:
  1. Edit the CamillaDSP settings.
  2. Under Pipeline configuration, create a New one or Copy one you will use as foundation. (*)
  3. Under General, select the desired pipeline configuration from the drop-down list and Save to make it active.
  4. Under Pipeline editor, set Status to On.
  5. Under Pipeline editor, Open the pipeline editor.
  6. If you only see the menu and "Pipeline editor" header, reload your browser as the GUI was still starting.
  7. In the Devices tab, set the chunksize and queuelimit.
  8. In the Filters tab, press the green + sign at the bottom to add the loudnessvol filter and its parameters.
  9. In the Pipeline tab, press the green + sign at the bottom to add the loudnessvol filter to the pipeline for channel 0.
  10. Repeat to add the loudnessvol filter to the pipeline for channel 1.
  11. If necessary, drag & drop the two loudnessvol filters to be at the bottom (end) of the pipeline.
  12. Under Config at the left, Save to file or if possible Apply and save (only available when already running).
(*) If you are a headphones user, I can recommend using one of the provided crossfeed filters. With CamillaDSP enabled, you cannot use the crossfeed under DSP options in moOde's audio configuration, but CamillaDSP can do that and more.

CamillaDSP is now ready to get its volume settings over a websocket. We will get to that later.

Set up audio renderers

Warning: during this step turn your amplifier off! Risk of damage and/or injury!
If you start playback, it will output at full volume and the volume slider will do nothing yet!

AirPlay:

Change the following lines in /etc/shairport-sync.conf. The lines are commented by the default, uncomment them.
Code:
mixer_control_name = “Master”;
mixer_device = "hw:Dummy”;
Note: although the dummy device mixer registers as a hardware mixer, it does not support hardware mute. Keep use_hardware_mute_if_available set to no.

Spotify:

Edit /var/www/inc/renderer.php. The first line you have to change, the second you have to add immediately after:
Code:
               ' --mixer alsa' .
               ' --alsa-mixer-device hw:Dummy --alsa-mixer-control Master' .
Note: moOde version updates may overwrite this. If so, change it again.

MPD:

I do not use MPD so am not certain. But editing /etc/mpd.conf like this should do it:
Code:
audio_output {
...
mixer_type "hardware"
mixer_control “Master”
mixer_device "hw:Dummy”
mixer_index "0"
...
}
Note: moOde audio setting changes overwrite this. If so, change it again.

Bluetooth:

Not supported yet. It requires bluez-alsa v4.0.0 or higher: https://github.com/Arkq/bluez-alsa/pull/390 and moOde 8.2.1 has v3.0.0. In the meantime its software volume control works fine, just not with loudness correction.

Others:

Unknown, I do not use them. But if you find out, drop a reply and I will add it to this post!

Set up dummyvol2cdsp

dummvol2cdsp is a Python script that runs in the background, monitoring the dummy mixer control and forwards its volume setting to CamillaDSP over a websocket. It also provides a cubic volume control to maximise the usable range of the volume sliders.

First install the pyalsaaudio library:
Code:
# sudo su -
# pip install pyalsaaudio

Now download `dummyvol2cdsp.py` from https://github.com/roderickvd/dummyvol2cdsp and put it somewhere. This guide assumes /home/pi/dummyvol2cdsp.py. At the top of the script, there are some user-configurable settings. The defaults should be sane.

Don't forget to make the script executable, then launch it to start testing:
Code:
# chmod a+x /home/pi/dummyvol2cdsp.py
# /home/pi/dummyvol2cdsp.py

Open another terminal, launch alsamixer and change the volume. You should now see the script printing lines like alsa=49% cubic=-50.5 dB. If it also prints along the lines of setting cdsp volume failed: [Errno 111] Connection refused, that means that CamillaDSP is not running yet. A likely cause is that playback has not started yet (regardless of whether an audio renderer is connected or not).

If you see volume settings being printed without errors, then look at the CamillaDSP GUI via the web interface and change the volume again. Under Volume at the left, you should see the volume changes coming in.

Now everything is working, hit Ctrl+C to exit. Then edit /etc/rc.local to launch dummyvol2cdsp in the background when booting. The following lines should just be before the final exit 0 at the bottom:
Code:
# Forward Alsa dummy mixer volume to CamillaDSP
/home/pi/dummyvol2cdsp.py > /dev/null 2>&1 &
Note: moOde version updates may overwrite this. If so, add it again.

Finally, reboot and verify that volume changes are still being forwarded to CamillaDSP.

If you have convinced yourself volume changes are coming in properly, you can now turn up the amplifier again -- in small steps, just as a final precaution. Congratulations, you have yourself a working loudness-corrected volume control!

FAQ

Q: Which volume type should I set in moOde's audio configuration? Hardware, software, anything else?
A: For the supported renderers I do not think it really matters. Principally the dummy driver is a hardware control, but it is not related to the output device. MPD should be set to hardware, but still overwrites the mixer device with the output device instead of the dummy device.


Q: How do I use my DAC's hardware volume control then?
A: You cannot. CamillaDSP does this in software only. Here is the good news: sound-quality wise, that will the best. CamillaDSP uses a 64-bit floating point pipeline which is better than any DAC does in hardware. Then running your DAC at full line level will improve dynamic range to your amplifier (unless the connection is balanced, in which case it will not matter). You may only miss out on fancy readings from your DAC's display or comfort of using your DAC's remote.

If anyone has any tips or tricks to share, please reply and I will add it to this post.
Reply
#2
Pretty cool :-) A loudness compensation feature for MPD and all the renderers is quite sophisticated and very desirable since Low Level Listening (LLL) is a common usage scenario.

So basically we configure MPD and the renderers to use the ALSA Dummy device as mixer and then a daemon monitors it and proxies volume changes to Camilla, right?

Is dummvol2cdsp in a Git repo?
Enjoy the Music!
moodeaudio.org | Mastodon Feed | GitHub
Reply
#3
(10-11-2022, 02:26 AM)Tim Curtis Wrote: Pretty cool :-) A loudness compensation feature for MPD and all the renderers is quite sophisticated and very desirable since Low Level Listening (LLL) is a common usage scenario.

Thanks! Certainly scratches my own itch and that of others too I imagine. I have always loudness correction that for its bass boost. Audyssey EQ pulls off the same trick, although a bit more sophisticated.

I also thought about making a tight integration with moOde and its UI. Of course this would be a much larger effort. What do you think?

Quote:So basically we configure MPD and the renderers to use the ALSA Dummy device as mixer and then a daemon monitors it and proxies volume changes to Camilla, right?

Exactly.

It could even be easier, but I would need your expertise with Alsa configuration files. Would it be possible to slave the dummy mixer control to the output device? In this case you could do it system-wide without touching any of the renderers.

Quote:Is dummvol2cdsp in a Git repo?

I will make it so tonight.

If it helps I could do any or more of the following:
- make it into a daemon
- have it accept command line options or environment variables
- parse variables from a configuration file

Let me know.
Reply
#4
I don't have much experience with Camilla but what happens to volume without the Dummy mixer and volume proxy config? Isn't it still processed by Camilla before it outputs the PCM stream to the device?
Enjoy the Music!
moodeaudio.org | Mastodon Feed | GitHub
Reply
#5
(10-11-2022, 10:33 AM)Tim Curtis Wrote: I don't have much experience with Camilla but what happens to volume without the Dummy mixer and volume proxy config? Isn't it still processed by Camilla before it outputs the PCM stream to the device?

In that case CamillaDSP does no volume attenuation, and does all other processing at 0.0 dB. Before the PCM “enters” CamillaDSP it is up to the renderer to control the volume.

Because CamillaDSP is a plug-in to Alsa and not an output device, it offers no Alsa mixer itself.
Reply
#6
(10-11-2022, 12:21 PM)roderickvd Wrote:
(10-11-2022, 10:33 AM)Tim Curtis Wrote: I don't have much experience with Camilla but what happens to volume without the Dummy mixer and volume proxy config? Isn't it still processed by Camilla before it outputs the PCM stream to the device?

In that case CamillaDSP does no volume attenuation, and does all other processing at 0.0 dB. Before the PCM “enters” CamillaDSP it is up to the renderer to control the volume.

Because CamillaDSP is a plug-in to Alsa and not an output device, it offers no Alsa mixer itself.

I don't think Camilla is an ALSA plugin (LADSPA) but rather a standalone application that does DSP. On Linux it's fed by an ALSA output plugin named alsa-cdsp. My understanding is that its purpose is to automatically configure the correct source sample rate in Camilla when song files of varying sample rates are being played.

I'm still a bit confused about volume handling though because Camilla can do things like EQ which manipulates volume and the Pipeline editor also has a volume Mixer tab.
Enjoy the Music!
moodeaudio.org | Mastodon Feed | GitHub
Reply
#7
(10-11-2022, 02:41 PM)Tim Curtis Wrote:
(10-11-2022, 12:21 PM)roderickvd Wrote:
(10-11-2022, 10:33 AM)Tim Curtis Wrote: I don't have much experience with Camilla but what happens to volume without the Dummy mixer and volume proxy config? Isn't it still processed by Camilla before it outputs the PCM stream to the device?

In that case CamillaDSP does no volume attenuation, and does all other processing at 0.0 dB. Before the PCM “enters” CamillaDSP it is up to the renderer to control the volume.

Because CamillaDSP is a plug-in to Alsa and not an output device, it offers no Alsa mixer itself.

I don't think Camilla is an ALSA plugin (LADSPA) but rather a standalone application that does DSP. On Linux it's fed by an ALSA output plugin named alsa-cdsp. My understanding is that its purpose is to automatically configure the correct source sample rate in Camilla when song files of varying sample rates are being played.

Yes and no:
  • Yes, CamillaDSP is a standalone process.
  • Yes, alsa-cdsp is an Alsa I/O plugin that launches a CamillaDSP process and pipes data to it.
  • No, its purpose is not to correct source sample rates. CamillaDSP handles PCM sample input at any rate (well, up to 384 kHz I think). In fact CamillaDSP (the process, not the plugin) can then be configured to resample it before sending it to the output. Specifying channels and rates in /etc/alsa/conf.d/camilladsp.conf only aids to limit CamillaDSP to supported output configurations.
Quote:I'm still a bit confused about volume handling though because Camilla can do things like EQ which manipulates volume and the Pipeline editor also has a volume Mixer tab.

I can imagine. It may help to recognise that CamillaDSP's mixer is not the same as an Alsa mixer. In CamillaDSP:
  • Mixers route audio between channels, and increase or decrease the number of channels in the pipeline. Do not be misled by the gain parameter of a mixer it is there to set a fixed pregain, not to serve as volume control. Example use case: crossfeeding, level-matching and preventing clipping. 
  • Filters manipulate samples in one way or the other. With respect to volume, there are three relevant filters: Gain (again, fixed pregain, not a volume control), Volume (volume control with ramp-up and ramp-down) and Loudness (like Volume but with loudness correction).
  • The pipeline defines the processing steps between input and output. It is essentially a list of filters and/or mixers in sequential order. So mixers and filters only actually do something if you hook them up in a pipeline.
To give you an idea, this is a pipeline which first does a Chu Moy crossfeed and then loudness corrected volume control:

   

In this screenshot you see CamillaDSP's current volume setting alongside the defined loudnessvol filter. How this works is that Loudness filter "listens" to this volume setting and does the actual attenuation. You could also have used a simple Volume filter of course:

   

To reiterate, the volume setting at the top left (here: -21.2 dB) is just the setting. By itself it does not attenuation. It needs a filter for that, and the filter must be hooked into the pipeline.

By default CamillaDSP's volume is set to 0.0 dB. It requires manipulation to make it anything else: be it the volume slider in CamillaDSP's GUI, be it dummyvol2cdsp or some other means. CamillaDSP does not provide a Alsa mixer control for volume control.

Hopefully this clears things up? Let me know if you have any further questions. CamillaDSP is an amazing tool in the shed and I can heartily recommend it.
Reply
#8
GitHub repository for dummyvol2cdsphttps://github.com/roderickvd/dummyvol2cdsp. I updated the original post.
Reply
#9
Nice :-)

Yes alsa-cdsp does not do resampling but IIRC it update the camilla config with the source sample rate before piping the output to Camilla because Camilla itself does not do sample rate switching on-the-fly. Correct?

I love learning curves ;-)
Enjoy the Music!
moodeaudio.org | Mastodon Feed | GitHub
Reply
#10
(10-11-2022, 11:44 PM)Tim Curtis Wrote: Yes alsa-cdsp does not do resampling but IIRC it update the camilla config with the source sample rate before piping the output to Camilla because Camilla itself does not do sample rate switching on-the-fly. Correct?

CamillaDSP does rate detection itself (and so does switch on the fly). I believe that alsa-cdsp can help by "hinting" the incoming sample rate but it's not necessary.

Do you think it is possible to slave the Alsa dummy mixer to _audioout? My asoundrc-fu is not up to par.
Reply


Forum Jump: