mk-fg / python-pulse-control

Python high-level interface and ctypes-based bindings for PulseAudio (libpulse)
https://pypi.org/project/pulsectl/
MIT License
170 stars 36 forks source link

`volume_set_all_chans` resets speaker balance setting #57

Closed itay-grudev closed 3 years ago

itay-grudev commented 3 years ago

Using volume_set_all_chans resets speaker balance setting.

https://user-images.githubusercontent.com/2123767/118301500-cfb51f00-b4eb-11eb-8c96-ab1e6cd44d79.mp4

mk-fg commented 3 years ago

Using volume_set_all_chans resets speaker balance setting.

If by that you mean "sets changes volume of all channels", then yes, that's exactly what it's supposed to do, which is why it's called "set volume of all channels".

itay-grudev commented 3 years ago

Would you accept an MR that corrects for that? I mean it just overrides the user's balance setting. I would be great to have a method that increases all channels, but preserves the balance setting.

mk-fg commented 3 years ago

It would be great to have a method that increases all channels, but preserves the balance setting.

Isn't that what volume_change_all_chans does already?

itay-grudev commented 3 years ago

Not exactly. Because in my use case I am mapping a single value from 0-1 to volume, but I would like the balance to remain preserved. I wouldn't know how much to change it with and even then that might end up boosting it above 100% from what I read.

In any case after a thorough reading I realised this is a PulseAudio shortcoming, because it does not save balance separately. Even if I fix it, every time you change your volume you will add error to the balance calculation. And setting volume to zero just deletes the balance information completely.

mk-fg commented 3 years ago

Yeah, pretty much - just stores volume values per channel, which you can adjust separately.

I don't know much about audio tech, but if you want to preserve balance as in difference in dB, then it's possible to convert float volume values here to those via something like pa_sw_volume_to_dB in src/pulseaudio/volume.c, first converting float to internal pulseaudio int by multiplying by PA_VOLUME_NORM constant.

I imagine then you can probably make a relatively simple function to adjust stuff while preserving the difference as necessary.

_pulsectl.py has python version of pa_sw_volume_from_dB too:

pa_sw_volume_from_dB = lambda db:\
  min(PA_VOLUME_MAX, int(round(((10.0 ** (db / 20.0)) ** (1/3)) * PA_VOLUME_NORM)))

Though again, I don't really know how audio balance on a perceptual level works, or what you really mean by it, so maybe missing the point entirely.