Request/RFC: Tying a filter-chain parameter to its node's volume control
Related somewhat to #2210
Background and use case
Pipewire's ability to act as a plugin host makes it extremely convenient to seamlessly integrate in an audio processing pipeline for a variety of purposes. As discussed in #2210, one potential use for this is "transparently" handling embedded devices which do not present themselves to userspace as a user would expect. Such embedded/microspeaker devices rarely perform anywhere near linearly across their volume range, particularly in the bass and sub-bass frequencies. To get around this, they are often tuned at their full operational volume and then loudness compensation based on ISO 226:2003 is applied to the signal at lower volumes to maintain a consistent sonic profile at those volumes.
Apple Silicon Macs are no exception. Applying IIRs and bass enhancement filtering to the
sound such that they sound good at lower volumes causes distortion and artefacting at
higher volumes, while tuning them at their maximum "safe" volume causes the sonic profile
to become thin and mid-heavy at lower volumes. Attaching a loudness compensation plugin
to the filter chain would eliminate this issue entirely. When a loudness compensation
plugin is used in this kind of scenario, its output control becomes the "global" volume,
as it governs how much compensation and attenuation is applied to the signal. While Pipewire
can change plugin parameters at runtime, the only way to do this currently is via pw-cli
which is not really viable for daily use as a global volume control.
Solution
The solution to this and the feature being requested is to provide the ability for a Node's volume control to act as a control for a specified plugin's parameter, rather than just directly attenuating/boosting the signal at the Node. This would enable proper volume control for devices like those mentioned above, and additional possibilities for other similar plugins.
Considerations
- A stream may have multiple channels but the plugin's control will only have a single value. How can we reconcile this with, e.g. KDE's "balance" controls?
- How do we express what "0%" (0.0) and "100%" (1.0) are? LV2 plugins should provide this for each ControlPort but there are other plugin types. Should we explicitly provide min and max values and interpolate a range from that?
- Could this be extended into the concept of a "virtual" volume control? Can the idea of a "virtual" Node be better expressed such that the rest of userspace can better deal with such Nodes?
Further reading: https://github.com/chadmed/asahi-audio