Repository: ultrabug/py3status

Issue:
volume_status: too big jumps when using scroll wheel (Rpi3)
**Describe the bug**
When mouse wheel is used to change volume in `volume_status` module the jumps are too big rendering this setup almost unusable:
  - 0 %
  - 2 %
  - 70 %
  - 100 %

**Your py3status version**
`py3status version 3.44 (python 3.10.4) on i3`

**To Reproduce**
1. Add module `volume_status` with the following configuration
```
volume_status {
  format_muted = '[\?if=is_input 😶|♪] MUT'
  format = '[\?if=is_input 😮|♪] {percentage}%'
  on_click 2 = 'exec pavucontrol'
  channel = 'PCM'
}
```
2. Use wheel to change volume
3. See how it is impossible to set volume e. g. to 80 %

**Expected behavior**
It should be possible to set volume in steps of 5 (default).

**Additional context**
Running on RPi3/ArchLinuxARM with `alsa` driver (`bcm2835` module). Volume control via `alsamixer` works without issues and changes are reflected by the module too. By tracing `execve` syscalls I saw the following commands are being executed:
```
amixer -q -c 0 -D default sset PCM 5%-
amixer -q -c 0 -D default sset PCM 5%+
```
Running these commands from terminal reveals a similar issue. Increasing volume in 5% increments simply does nothing:
```console
# set volume to zero prior to running
for i in (seq 0 5 100); echo "Setting volume to $i"; amixer -q -c 0 -D default sset PCM 5%+; amixer -q -c 0 | tail -1; sleep 1; end
Setting volume to 0
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 5
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 10
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 15
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 20
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 25
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 30
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 35
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 40
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 45
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 50
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 55
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 60
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 65
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 70
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 75
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 80
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 85
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 90
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 95
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
Setting volume to 100
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
```
Same script works fine on my PC (using `Master` instead of `PCM`) so I wonder if this is something platform/driver-specific. Although using absolute values works there is not 1:1 mapping between what `amixer` and `alsamixer`, e. g. `amixer` shows 67% while `alsamixer` displays 26%.


Discussion:
It looks like we're using `amixer -M -c {card} -D {device} sget {channel}` to get volume, not `amixer -q -c 0 | tail -1`. Try using that in your script. Also, check to ensure you're not parsing against wrong output or control (i.e. `Capture`).
> It looks like we're using `amixer -M -c {card} -D {device} sget {channel}` to get volume, not `amixer -q -c 0 | tail -1`. Try using that in your script.

The output is unchanged.

> Also, check to ensure you're not parsing against wrong output or control (i.e. `Capture`).

Pi does not have a Capture control (at least when pulseaudio is not running - see below):
```console
$ amixer -q
Simple mixer control 'PCM',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback -10239 - 400
  Mono: Playback -10239 [0%] [-99999.99dB] [on]
```
What I noticed: if pulseaudio is running then `Master` control is indeed present and volume control via `amixer` works as expected. Also for some strange reason `Capture` exists in the setup with Pulseaudio but it must be some kind of virtual device.

In order to achieve the default step of 5% I would need to use the following absolute numbers in `amixer`:
```
amixer - alsamixer
  0% -   0
 25% -   5
 44% -  10
 53% -  15
 60% -  20
 66% -  25
 70% -  29
 74% -  35
 77% -  39
 80% -  44
 83% -  50
 85% -  54
 87% -  59
 89% -  64
 91% -  69
 93% -  75
 94% -  78
 96% -  85
 97% -  88
 99% -  96
100% - 100
```
Putting this into spreadsheet and adding exponential trend line it yields R<sup>2</sup> of 0.9997 hence strong correlation.
![obrázok](https://user-images.githubusercontent.com/1406222/173206693-3ecbc0b7-f6e9-4903-a2ac-57b1604ce2ce.png)

That means that Raspberry Pis (and least those I am running - one with Arch Linux, the other with Debian) are only affected when only Alsa and no PulseAudio are being used.

Edit: created https://github.com/raspberrypi/linux/issues/5061 as I believe this may be a better place.
>The output is unchanged

Okay. From your command, your output is different than my output. Also, I recall seeing a different numbers between amixer and alsamixer long time ago. I *do not* remember the solution, but it might be due to lack of `-M`.

```man
$ man amixer
  -R     Use the raw value for evaluating the percentage representation.  This is the default mode.
  -M     Use the mapped volume for evaluating the percentage representation like alsamixer, to be more natural for human ear.
> > The output is unchanged
> 
> Okay. From your command, your output is different than my output. Also, I recall seeing a different numbers between amixer and alsamixer long time ago. I _do not_ remember the solution, but it might be due to lack of `-M`.
> 
> ```
> $ man amixer
>   -R     Use the raw value for evaluating the percentage representation.  This is the default mode.
>   -M     Use the mapped volume for evaluating the percentage representation like alsamixer, to be more natural for human ear.
> ```

Thank you. :tada: !! That did it. The `-M` switch was the answer. You said you're using it to get volume, but.. if I use it also to set the volume the volume issue is immediately fixed. So what I did was manually patching https://github.com/ultrabug/py3status/blob/8e155ea848ce22a8c9ce309a6b54100f5be75777/py3status/modules/volume_status.py#L122 to include this extra argument. The question is whether it should not be the new default (since it's also used for reading the volume value).
I guess `-M` was added to only a command *to read volume*... and that we should include it in other command too *to set volume*. If `-M` works fine with Pulseaudio too, then you likely should make a PR for this one... and another one for the `Master|PCM` issue.

Resolving patch:
diff --git a/py3status/modules/volume_status.py b/py3status/modules/volume_status.py
--- a/py3status/modules/volume_status.py
+++ b/py3status/modules/volume_status.py
@@ -119,6 +119,7 @@ def setup(self, parent):
             self.device = "default"
         self.cmd = [
             "amixer",
+            "-M",
             "-q",
             "-c",
             self.card,


Test patch: