Downstream Volume Control

Putting volume control as far downstream as possible in the audio signal chain is a well established best practice for maximizing signal/noise(+distortion) ratio while avoiding clipping. It’s why “Hardware” volume control (i.e. in the analog domain after A/D conversion) in external DACs is generally recommended over “Software” volume control (i.e. in the digital domain before A/D conversion) when available.

Unless I’ve missed something, at present post-D/A volume control via the Volumio UI (or Volumio APIs) is only available if a DAC meeting all other system requirements (#channels, hopes, dreams, budget, etc, etc) also has an accessible Hardware volume control (mixer). If you want volume control downstream of some (heaven forfend) analog stages post-DAC, or want to run multiple DACs in parallel for any reason, you’re just out of luck. It seems difficult or impossible to delegate hardware volume control anywhere besides the directly connected playback device (DAC). If I misunderstand, please correct me and ignore the question below.

I want to use a dedicated hardware device to handle analog gain (volume) control for an abitrary (or at least reasonably scalable) number of channels, just ahead of power amplification, under control of a Raspberry Pi Volumio host. I have working gain control prototype using AD5234 digital potentiometer circuits controlled via I2C. There are apparently many similar alternative devices/circuits.

I also have a reasonably clean prototype Volumio plugin that listens to Volumio’s volume setting and sets the external circuit gain accordingly. It’s not packaged and tested for prime time but seems to work well.

The problem:

If this plugin is enabled with a standard HW or SW mixer active, it does what it’s supposed to do, but so does the standard mixer. The system sort of works, but passing through two voloume controls screws up the gain curve and entirely defeats the purpose :(. If the Mixer Type is set to “None” the Volume slider doesn’t operate at all, again :(. What’s needed is a mode that disables the standard mixer while keeping the volume slider and state notification active. I have a hack - editing mixer.value in /data/configuration/audio_interface/alsa_controller/config.json to something invalid, then write-protecting the file so volumio can’t overwrite it. This seems to work fine for my purposes, but it results in “Cannot set ALSA Volume” log messages, surely breaks the “Volume Options” UI, likely interferes with future system upgrades, and who knows what other evil. I’ve seen enough related questions on this forum to convince me others might find it useful if I could fix these issues and get the plugin into a releaseable form.

My question:

Is there a clean and proper way to configure Volumio’s volume control so it operates and notifies, but doesn’t do or connect to anything else, leaving actual volume control to external hardware via a plugin? Ideally such configuration should happen as part of plugin installation/enabling, correct?

Hello!
There is no way, currently, to do what you want.
This is something I’d like to see too :wink: , for BT speaker output, for CamillaDsp internal volume control in FusionDsp…
Let’s hope to see it in a future release! :grinning:

1 Like

I’ve built a Volumio plugin that solves exactly the same problem you’re describing — keep the Volumio volume UI fully functional, but redirect all volume changes to an external hardware volume controller while keeping the digital path bit-perfect.

In my case the “external DAC” is a Genelec GLM adapter. I’ve reverse-engineered the USB protocol so I can set system volume directly from the Raspberry Pi, without the GLM PC software. This means the audio stream stays completely unaltered end-to-end (Volumio → digital out → Genelec DSP/room correction → finally the analog stage in the monitors applies gain). No double volume control, no digital attenuation, no clipping losses.

The key insight:
You don’t need to hack ALSA or create a fake mixer file. Volumio already supports mixer overrides cleanly.

My plugin works by:

  1. Registering itself as a volume override via
    volumioUpdateVolumeSettings({ volumeOverride: true, ... })
  2. Providing its own alsavolume() implementation, which catches every incoming volume command (e.g. +, -, absolute values) and never touches ALSA.
  3. Emitting proper volume state objects back to Volumio, so the UI slider, REST API, WebSocket events, and plugins keep working as if nothing changed.
  4. Redirecting the volume value to my external device (in my case by issuing a USB command to the GLM network adapter).

Your situation with AD5234 digital pots, I2C gain elements, or multi-channel analog gain blocks fits the same pattern perfectly.

Here’s the relevant pattern from my plugin:

  • initVolumeSettings() sets up a dummy mixer with volumeOverride: true
  • Volumio now calls my plugin for all volume actions
  • My alsavolume() method updates my hardware instead of ALSA
  • getVolumeObject() reports the resulting state back to Volumio
  • No ALSA mixertype, no MPD softvol, no double attenuation

No UI elements break, no configuration files are write-protected, no system logs fill with ALSA errors, and everything survives updates.

So yes — what you’re trying to do is possible without hacks. You just need to register your own mixer override and implement the volume interface inside a plugin. Volumio is perfectly happy to delegate all volume responsibilities to an external controller as long as you provide the correct callback functions.

I used this plugin as reference for my own custom plugin:

Yes, this sounds like precisely what I had in mind. I was actually a bit surprised not to have found such, though serialampcontroller is one place I’d been looking for a pattern I might “borrow”. Being lazy I thought I’d ask before digging into it too much further, though.

I’m unclear as to whether you’re referring to SAC or another plugin you made using it as a reference. SAC has been around a while, has it not? Is it your work? If you’re referring to separate piece of code is that code released or otherwise available? I’m certainly interested.